fix(ab-corpus): preserve markdown structure across kept @domain blocks
Codex stop-time review caught that the Phase 2 domain filter corrupted output when two adjacent kept blocks abutted: the regex's trailing `\s*` consumed every character of whitespace BEFORE the next match's leading `\s*`, so block N's body ended on its closing ``` and block N+1's body started on its `### heading` with no separator at all. Output: ` ```### Audit / activity feed` on a single line — fence left unclosed, heading swallowed. Replace the greedy `\s*` on both sides of each marker with a literal `\n`, so the regex only consumes the single newline immediately adjoining the comment. Surrounding blank lines stay in the surrounding text where they belong, separating adjacent kept blocks naturally. Adds a regression guard test that searches the output for ` ```###` (closing fence directly followed by a level-3 heading on the same line). Codex effectively asked for it. 3767 vitest pass, format clean. Side effect: dropped blocks now leave their surrounding blank lines intact, so dropped-block savings shrink by ~3-5 chars per block; total Phase 2 savings stay within the 500-char floor the existing test asserts.
This commit is contained in:
parent
c835976479
commit
f0a575e210
|
|
@ -176,4 +176,24 @@ describe('buildSystemPrompt', () => {
|
|||
expect(full - filtered).toBeGreaterThan(500);
|
||||
}
|
||||
});
|
||||
|
||||
it('T + category preserves Markdown structure across adjacent kept blocks (no fence-heading collision)', () => {
|
||||
// Earlier regex consumed surrounding whitespace too greedily, joining
|
||||
// body1's closing ``` directly to body2's heading like ```### Audit...
|
||||
// and breaking both the code fence and the heading rendering. Codex
|
||||
// stop-time review caught it. Guard against re-introducing the
|
||||
// collision by asserting fence-followed-by-heading never appears
|
||||
// anywhere in the output for any (category, difficulty) combo where
|
||||
// the filter could fire.
|
||||
for (const category of ['mobile', 'dashboard', 'landing'] as const) {
|
||||
for (const difficulty of ['obvious', 'composite'] as const) {
|
||||
const built = buildSystemPrompt('T', { difficulty, category });
|
||||
// Closing fence directly followed by a level-3 heading on the
|
||||
// same line is the corruption signature: ``` and ### must be
|
||||
// separated by at least a newline. The buggy regex produced
|
||||
// `\`\`\`### Audit ...` with no separator at all.
|
||||
expect(built.system).not.toMatch(/```###/);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ export interface BuildPromptOpts {
|
|||
* multi-file splits to maintain per domain) and keeps the diff
|
||||
* surgical — adding a tag is two HTML comments, no structural move.
|
||||
*
|
||||
* Block syntax:
|
||||
* Block syntax (each marker on its own line):
|
||||
*
|
||||
* <!-- @domain:mobile -->
|
||||
* ... mobile-only content ...
|
||||
|
|
@ -118,10 +118,17 @@ export interface BuildPromptOpts {
|
|||
* and a block matches if `keep` appears in the list. This is the
|
||||
* common case for tools like calendar_grid that legitimately span
|
||||
* domains.
|
||||
*
|
||||
* Whitespace contract: the regex consumes ONLY the single newlines
|
||||
* adjoining each marker, not surrounding blank lines. That preserves
|
||||
* the blank-line separator between adjacent kept blocks — without
|
||||
* this, the closing ` ``` ` of one recipe would butt up against the
|
||||
* `### ` heading of the next, breaking markdown structure (caught
|
||||
* by Codex stop-time review).
|
||||
*/
|
||||
function stripNonMatchingDomains(text: string, keep: string): string {
|
||||
return text.replace(
|
||||
/<!-- @domain:([a-z,\s]+) -->\s*([\s\S]*?)\s*<!-- \/@domain -->\s*/g,
|
||||
/<!-- @domain:([a-z,\s]+) -->\n([\s\S]*?)\n<!-- \/@domain -->/g,
|
||||
(_, tags: string, body: string) => {
|
||||
const allowed = tags.split(',').map((t) => t.trim());
|
||||
return allowed.includes(keep) ? body : '';
|
||||
|
|
|
|||
Loading…
Reference in a new issue