test(#3149): correct stale tdd_mode assertion and drop a marker-token collision
Two failures from the remote runner on 654b2cc10, both introduced here.
1. tests/mcp-catalog-parity.install.test.cjs greps emitted workflow files
for the bare substring 'gsd:section' and treats its presence in a
composed file as an un-stripped marker. debug.md's new Step 0 prose
documented the field by writing that token literally, so the emitted
file tripped the gate even though the parser correctly ignored it as
prose. Reworded to 'applicability-section markers'. Same class as
DEFECT.PROMPT-INJECTION-SCAN-COLLISION.
2. tests/debug-session-management.test.cjs asserted debug.md contains the
literal 'config-get workflow.tdd_mode'. That call is gone. The
invariant it protected -- tdd_mode comes from the workflow.tdd_mode
key, never a bare top-level one -- is unchanged, and now has a
stronger behavioral home: init-debug.test.cjs row A9 asserts a bare
key is ignored and the canonical key is honored, whatever the read
mechanism.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,7 +28,7 @@ One round-trip carries everything this workflow needs (#3149 — this call repla
|
||||
- `debug_dir` — an absolute path anchored on `project_root` (#2376: `debug_file_path` values handed to the spawned `gsd-debug-session-manager` must resolve regardless of that subagent's own cwd, which may differ from the orchestrator's — build them as `{debug_dir}/{slug}.md`, never a bare `.planning/debug/...` literal).
|
||||
- `debugger_model` — the resolved model for `gsd-debugger` spawns; used as `{debugger_model}` below and governed by the model-omission rule in step 2.
|
||||
- `tdd_mode` — used as `{TDD_MODE}` in the session parameter blocks below.
|
||||
- `section_manifest` — `null` today, because this workflow carries no `<!-- gsd:section -->` markers. **When it is `null`, read this workflow in full.** When it is present, read only the files named in its `read` array. `null` and an empty `included` array are NOT the same: `null` means "no manifest for this workflow", an empty `included` means "nothing applies".
|
||||
- `section_manifest` — `null` today, because this workflow declares no applicability-section markers of its own. **When it is `null`, read this workflow in full.** When it is present, read only the files named in its `read` array. `null` and an empty `included` array are NOT the same: `null` means "no manifest for this workflow", an empty `included` means "nothing applies".
|
||||
|
||||
**If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
|
||||
|
||||
|
||||
@@ -76,13 +76,21 @@ describe('debug session management implementation', () => {
|
||||
path.join(process.cwd(), 'gsd-core/workflows/debug.md'),
|
||||
'utf8'
|
||||
);
|
||||
// #3149: tdd_mode now arrives on the `init.debug` bundle rather than a
|
||||
// `config-get` call in this workflow, so the old literal-call assertion no
|
||||
// longer describes reality. The invariant it protected is unchanged and is
|
||||
// asserted at its new home: `cmdInitDebug` resolves `config.workflow`'s
|
||||
// `tdd_mode`, never a bare top-level key — proven behaviorally in
|
||||
// tests/init-debug.test.cjs ('honors workflow.tdd_mode, ignores a bare
|
||||
// top-level tdd_mode'). What must remain true HERE is only that this
|
||||
// workflow never reintroduces a bare-key read of its own.
|
||||
assert.ok(
|
||||
!content.includes('config-get tdd_mode'),
|
||||
'debug.md must not use bare "tdd_mode" key — use "workflow.tdd_mode" to match every other consumer'
|
||||
);
|
||||
assert.ok(
|
||||
content.includes('config-get workflow.tdd_mode'),
|
||||
'debug.md must read tdd_mode via the "workflow.tdd_mode" key'
|
||||
content.includes('tdd_mode'),
|
||||
'debug.md must still consume tdd_mode (now from the init.debug bundle)'
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"version": 1,
|
||||
"paths": {
|
||||
"debug.md": "#3149 (prerequisite for #3128, ADR-1671 admission gate 2): debug.md gains a dedicated `init.debug` entry point (cmdInitDebug) and its Step 0 collapses THREE separate `gsd_run` round-trips into one. Removed: `gsd_run query state.load` (line 20, replaced in place), the `resolve-model gsd-debugger --pick model` block, and the `config-get workflow.tdd_mode --raw` block — 2 prose lead-ins and 2 fenced code blocks in total. Added: a 6-bullet extraction list documenting the bundle's fields (`commit_docs`, the now TOP-LEVEL `response_language`, `debug_dir`, `debugger_model`, `tdd_mode`, `section_manifest`) plus the `section_manifest: null` -> read-everything rule and the null-vs-empty-included distinction. Net SOURCE growth is +607 bytes (20,555 -> 21,162): the bullets that document one bundle cost more bytes than the two shell round-trips they replace, which is the intended trade — the round-trips cost three subprocess spawns at RUN time on every /gsd:debug invocation. No `<!-- gsd:section -->` marker is added and WHEN_VOCABULARY is unchanged at 29, so the composeWorkflow emission path is byte-identical in shape to before; only this file's own content moved. The `{TDD_MODE}` and `{debugger_model}` placeholders in the session-parameter blocks (lines ~137-145, ~226-234) are deliberately left byte-identical — they now resolve from the init bundle instead of shell variables, and rewording them would ripple into tests/fix-2257-debug-nonterminal-resume.test.cjs and tests/debug-session-manager-commit.test.cjs for no behavioral gain."
|
||||
"debug.md": "#3149 (prerequisite for #3128, ADR-1671 admission gate 2): debug.md gains a dedicated `init.debug` entry point (cmdInitDebug) and its Step 0 collapses THREE separate `gsd_run` round-trips into one. Removed: `gsd_run query state.load` (line 20, replaced in place), the `resolve-model gsd-debugger --pick model` block, and the `config-get workflow.tdd_mode --raw` block — 2 prose lead-ins and 2 fenced code blocks in total. Added: a 6-bullet extraction list documenting the bundle's fields (`commit_docs`, the now TOP-LEVEL `response_language`, `debug_dir`, `debugger_model`, `tdd_mode`, `section_manifest`) plus the `section_manifest: null` -> read-everything rule and the null-vs-empty-included distinction. Net SOURCE growth is +618 bytes (20,555 -> 21,173): the bullets that document one bundle cost more bytes than the two shell round-trips they replace, which is the intended trade — the round-trips cost three subprocess spawns at RUN time on every /gsd:debug invocation. No applicability-section marker is added and WHEN_VOCABULARY is unchanged at 29, so the composeWorkflow emission path is byte-identical in shape to before; only this file's own content moved. The `{TDD_MODE}` and `{debugger_model}` placeholders in the session-parameter blocks (lines ~137-145, ~226-234) are deliberately left byte-identical — they now resolve from the init bundle instead of shell variables, and rewording them would ripple into tests/fix-2257-debug-nonterminal-resume.test.cjs and tests/debug-session-manager-commit.test.cjs for no behavioral gain."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,6 +157,26 @@ describe('init.debug resolves identically to the three calls it replaces (matrix
|
||||
assert.equal(viaInit.tdd_mode, true, 'the root value must be inherited, not lost');
|
||||
assert.equal(String(viaInit.tdd_mode), viaConfigGet.output.trim());
|
||||
});
|
||||
|
||||
test('honors workflow.tdd_mode, ignores a bare top-level tdd_mode (row A9)', () => {
|
||||
// The invariant tests/debug-session-management.test.cjs used to guard by
|
||||
// grepping debug.md for `config-get workflow.tdd_mode`. Asserted here
|
||||
// behaviorally instead, which is strictly stronger: a bare top-level key
|
||||
// must NOT be honored, whatever the read mechanism.
|
||||
writeConfig(tmpDir, { tdd_mode: true });
|
||||
assert.equal(
|
||||
runJson(['init', 'debug'], tmpDir).tdd_mode,
|
||||
false,
|
||||
'a bare top-level tdd_mode key must be ignored — the canonical key is workflow.tdd_mode'
|
||||
);
|
||||
|
||||
writeConfig(tmpDir, { workflow: { tdd_mode: true } });
|
||||
assert.equal(
|
||||
runJson(['init', 'debug'], tmpDir).tdd_mode,
|
||||
true,
|
||||
'the canonical workflow.tdd_mode key must be honored'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// ─── Group B: bundle shape ─────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user