diff --git a/get-shit-done/bin/lib/security.cjs b/get-shit-done/bin/lib/security.cjs index f64a5642a..ffef1fc51 100644 --- a/get-shit-done/bin/lib/security.cjs +++ b/get-shit-done/bin/lib/security.cjs @@ -237,7 +237,6 @@ function sanitizeForDisplay(text) { const protocolLeakPatterns = [ /^\s*(?:assistant|user|system)\s+to=[^:\s]+:[^\n]+$/i, - /^\s*(?:assistant|user|system)\s+to=all:[^\n]+$/i, /^\s*<\|(?:assistant|user|system)[^|]*\|>\s*$/i, ]; diff --git a/get-shit-done/bin/lib/uat.cjs b/get-shit-done/bin/lib/uat.cjs index d34a4b683..7a63495e9 100644 --- a/get-shit-done/bin/lib/uat.cjs +++ b/get-shit-done/bin/lib/uat.cjs @@ -135,7 +135,8 @@ function parseCurrentTest(content) { const numberMatch = section.match(/^number:\s*(\d+)\s*$/m); const nameMatch = section.match(/^name:\s*(.+)\s*$/m); - const expectedBlockMatch = section.match(/^expected:\s*\|\n([\s\S]*?)(?=^\w[\w-]*:\s|\Z)/m); + const expectedBlockMatch = section.match(/^expected:\s*\|\n([\s\S]*?)(?=^\w[\w-]*:\s)/m) + || section.match(/^expected:\s*\|\n([\s\S]+)/m); const expectedInlineMatch = section.match(/^expected:\s*(.+)\s*$/m); if (!numberMatch || !nameMatch || (!expectedBlockMatch && !expectedInlineMatch)) { diff --git a/tests/uat.test.cjs b/tests/uat.test.cjs index f708afb0f..40aaec245 100644 --- a/tests/uat.test.cjs +++ b/tests/uat.test.cjs @@ -390,6 +390,51 @@ awaiting: user response assert.ok(result.output.includes('Chinese strings render correctly.')); }); + test('does not truncate expected text containing the letter Z', () => { + fs.writeFileSync(uatPath, `--- +status: testing +phase: 01-test-phase +--- + +## Current Test + +number: 3 +name: Timezone display +expected: | + Timezone abbreviation shows CET. + Zero-offset zones display correctly. +awaiting: user response +`); + + const result = runGsdTools(['uat', 'render-checkpoint', '--file', '.planning/phases/01-test-phase/01-UAT.md', '--raw'], tmpDir); + assert.strictEqual(result.success, true, `render-checkpoint failed: ${result.error}`); + assert.ok(result.output.includes('Timezone abbreviation shows CET.'), + 'Expected text before Z-containing word should be present'); + assert.ok(result.output.includes('Zero-offset zones display correctly.'), + 'Expected text starting with Z should not be truncated by \\Z regex bug'); + }); + + test('parses expected block when it is the last field in the section', () => { + fs.writeFileSync(uatPath, `--- +status: testing +phase: 01-test-phase +--- + +## Current Test + +number: 4 +name: Final field test +expected: | + This block has no trailing YAML key. + It ends at the section boundary. +`); + + const result = runGsdTools(['uat', 'render-checkpoint', '--file', '.planning/phases/01-test-phase/01-UAT.md', '--raw'], tmpDir); + assert.strictEqual(result.success, true, `render-checkpoint failed: ${result.error}`); + assert.ok(result.output.includes('This block has no trailing YAML key.')); + assert.ok(result.output.includes('It ends at the section boundary.')); + }); + test('fails when testing is already complete', () => { fs.writeFileSync(uatPath, `--- status: complete