| Command→agent seam: forward check |
tests/seams/command-agent-input.test.ts |
Every KEY: passed in a caller fence is declared in the op's **Input:** — fixes debug.mds ISSUE: / ISSUE_INPUT: mismatch (AC-0.1) |
Inline corpus with OPERATION: fetch-issue\nISSUE: 42\n → exactly 1 violation naming ISSUE |
| Command→agent seam: reverse check |
tests/seams/command-agent-input.test.ts |
Every required **Input:** value declared by an op is passed by at least one caller fence |
Same inline corpus |
| Command→agent seam: third direction (producer) |
tests/seams/command-agent-input.test.ts |
Every issue_capture_contract() value has a caller-side producer |
Same inline corpus |
resolveAllAgents() ⊇ getAllAgentNames() |
tests/guards/agent-source-resolver.test.ts |
Agent roster completeness — 16 agents (AC-0.7) |
Would fail if an agent is registered in plugins.ts but has no source file |
resolveAgentSource dist-preferred |
tests/guards/agent-source-resolver.test.ts |
When dist/agents/ exists, resolver prefers it over src/assets/agents/ |
Synthetic dist tree with a different content → dist version returned |
resolveAgentSource build hint |
tests/guards/agent-source-resolver.test.ts |
Throws with `/Run \`npm run build\ `` when neither src nor dist file exists |
resolveAgentSource('_nonexistent_agent_') → throws containing the build hint |
extractOpSectionFromCorpus 'sole' mode |
tests/guards/agent-source-resolver.test.ts |
Throws on duplicate anchor across corpus files (DR-18) |
Two-file corpus with duplicate ## Operation: X heading → throws naming both file paths |
extractOpSectionFromCorpus 'union' mode |
tests/guards/agent-source-resolver.test.ts |
Returns all matching sections with a match count (DR-18) |
Same two-file corpus → matchCount = 2, not 1 |
| git-agent golden |
tests/goldens/git-agent-golden.test.ts |
tests/fixtures/golden/git-agent.md is byte-identical to src/assets/agents/git.md |
Fixture absent → throws with regeneration command hint |
| github-status-lines frozen fixture |
tests/goldens/github-status-lines.test.ts |
Frozen fixture byte-identical; test:golden:update refuses to overwrite without --unfreeze |
node scripts/update-golden.js github-status-lines → non-zero exit + §0.2 rule text printed |
| Guard 1: REQUIRED_OPS coverage (17 ops) |
tests/git-agent.test.ts |
All 17 operations exist in git.md including fetch-issue and fetch-issues-batch (AC-0.11) |
Removing either new op from REQUIRED_OPS → test fails naming the missing op |
Guard 2: manage-debt: 60000 bound |
tests/git-agent.test.ts |
manage-debt section contains the 60000-char archive threshold before Phase 2 moves it (AC-0.12) |
Removing the literal → test fails with "missing 60000-char archive threshold" |
INTERNAL_OPS: fetch-issues-batch removed |
tests/registry-integrity.test.ts |
INTERNAL_OPS allowlist is ['learn-conventions'] only — fetch-issues-batch removed with a rationale comment (AC-0.11, SG-11) |
Re-adding fetch-issues-batch without updating the test → reverse-check finds it unlisted in compiled commands |
| DIST_FILES non-vacuity |
tests/build-mds.test.ts §20 |
DIST_FILES.length === 14 (13 compiled hosts + release.md, SG-13) |
Would fail if dist/commands/ is absent (throw) or if release.md is removed from the constant |
compliance_gate() adoption guard |
tests/build-mds.test.ts §20 |
≥6 compiled hosts import the {compliance_gate()} partial (P0-S22) |
hostsScanned >= 6 — fails if all imports are removed |
| gh-issue scope guard |
tests/build-mds.test.ts §21 |
No gh issue invocation or descriptive mention in any DIST_FILE outside a Git spawn fence (AC-0.4) |
Inline corpus OPERATION: fetch-issue\ngh issue view 42\n → violation detected (not inside spawn fence) |
Retired wording: ISSUE_NUMBERS |
tests/guards/retired-wording.test.ts |
ISSUE_NUMBERS (renamed to ISSUE_REFS in Phase 0) is absent from all Phase-0 output files (GAP-32, AC-0.17) |
Synthetic file seeded with ISSUE_NUMBERS → wouldFlag === true |
| Numeric floor manifest |
tests/guards/numeric-floor-manifest.test.ts |
No pinned numeric floor in tests/** decreases vs the committed manifest tests/fixtures/numeric-floors.json (AC-0.17, DR-27a) |
Copy of manifest with one entry decremented → allPatternsExist assertion fails |
| Extended references resolver |
tests/guards/extended-references.test.ts |
Every ## Extended References row in any skill resolves to a real file on disk |
Synthetic skill with a nonexistent reference path → violations array non-empty |
Initial Request
Devflow's command→agent seam for issue handling is untyped and currently broken in five user-visible ways, and the test harness that Phases 1–3 will lean on does not yet exist in a form that survives an agent rename.
/plan #42parses an issue reference and never fetches it;/debug #42passes a key (ISSUE:) that thefetch-issueop does not declare; three command-layer sites still invoke or describegh issue viewdirectly;resolve.mds:378states a D9 thread-resolution rule that contradictsgit.md:96's single authority; andrelease.md:138promises a post-release "close milestone" step that does not exist. Phase 0 fixes those defects and lands the harness — the shared dist-preferred agent-source resolver, the two-sided seam test, the D11 guard-class union, the two goldens, andtest:integrationin CI — against the fixed corpus, so that a red guard in any later phase is unambiguous evidence of a regression rather than of a pre-existing defect.Phase label (honest, verbatim): "no change to the GitHub rendering of any existing traceability artifact."
This label is deliberately narrower than "no behaviour change". Phase 0 is a
fix, not arefactor, precisely because it does change five user-visible behaviours. Claiming otherwise would be the untruthful-traceability-claim defect this phase exists to delete (intent #22).The five user-visible changes (enumerated with before/after in the issue body and
CHANGELOG.md### Fixed, AC-0.15):/plan #Nnow actually fetches the issue (it previously consumed a body it never fetched)./debug's issue path works for the first time (ISSUE:→ISSUE_INPUT:).dynamic-planissue bodies are now wrapped<untrusted-issue-body>at the sink.resolution-summary.md'sTracked = (pending)now names a reason.release.md's untruthful "close milestone" claim is deleted.Execution:
SEQUENTIAL_CODE_AGENTS· context-risk: HIGH · Design artifact:.devflow/docs/design/tracker-phase-0.2026-09-05_1155.md(authoritative; local, gitignored — a 60k-truncated copy is posted as a collapsed comment).Product Requirements
Depends on
none — first phase (branch from
main). Tracking issue: #321.Acceptance criteria
debug.mdsbefore, green after; covers Git and Code fences both directions; excludes Produces/Requires; ≥1 fence scanned per agent typenpm run test:golden:updatedocumented; CI never auto-regenerates/plan #42→OPERATION: fetch-issue;/plan #12 #15 #18→OPERATION: fetch-issues-batchwith≤50pinned,TRUNCATED ({n} not processed)beyond it,## Issues Batch ({n} issues)assertedgh issueinvocation or descriptive mention indist/commands/*.mdoutside a Git spawn fence; the twogh pr viewsites recorded as exceptionsresolve.mdsD9 matchesgit.md:96verbatim, pinned in source anddist/commands/resolve.mdmanage-debtemits DEGRADED andresolution-summary.mdkeepsTracked = (pending)with the reason named at all four sites; everyREQUIRED_OPdoing remote I/O has a D4 linepostingOps.length >= 8fromgit.mdalone and fail on a known-bad samplegithub-status-lines.txtbyte-identical before and after Phase 0<untrusted-issue-body>(non-vacuous, ≥3 ops); no reply/summary template interpolates a remote body fieldfetch-issues-batchdeclaresISSUE_REFSatgit.md:69andgit.md:292;plan.mds:32renamed;fetch-issuekeepsISSUE_INPUT;debug.mdspassesISSUE_INPUT; both ops inREQUIRED_OPS;fetch-issues-batchout ofINTERNAL_OPSwith a rationale comment; noISSUE_NUMBERSliteral remains repo-wide, andISSUE_NUMBER(singular) is untouched at all 14 sitesmanage-debt: 60000before the literal movesrelease.md:138"close milestone" deleted[DR-27a]:tests/guards/numeric-floor-manifest.test.tscompares every pinned numeric floor intests/**against a committed manifest and fails when any entry decreases (new entries allowed, decreases never). If the manifest guard is not landed in P0-S22, AC-0.17 falls back to (process-only — PR checklist) per D-Bnpm run build && npm test && npm run test:integration && npm pack --dry-runare green; (ii) a fresh install from the tarball drives/plan → /implement → /code-review → /resolve → /releaseon a GitHub project with no new prompt and no new file ingit status; (iii) every artifact in the tree has at least one reachable consumer in this phase's end-state — no file, define, list element, frontmatter key or conditional arm exists solely for a later phase (ADR-003); (iv) the frozengithub-status-lines.txtfixture is byte-identical to its Phase-0 capture.git.md; capturing first pins a tree Phase 0 immediately moves past (GAP-06 / B-9). Verified by reviewing the commit list on the PR: exactly four subtask commits in that order, A2's diff limited totests/fixtures/golden/**.Subtasks
src/assets/commands/resolve.mds(:352,:378,:499,:508,:539) ·debug.mds(:17,:24,:46,:51) ·plan.mds(:27,:32, new Git fence inserted at#### Phase 1: Gate 0before:63) ·dynamic-plan.mds:103·dynamic-build.mds:73·_partials/_wave.mds(:4,:9) ·implement.mds:73·release.md:138·src/assets/agents/git.md(:69,:268-284,:288-300,:292,:294-298,:300-318,:379-411,:723,:922) ·src/assets/scripts/hooks/ensure-devflow-init:23git.mdSHA-256 + line count; the list of every line A1 changed ingit.md(so A2's capture is spot-checkable); confirmation no test file was touchedtests/fixtures/golden/git-agent.md· newtests/fixtures/golden/github-status-lines.txttests/helpers.ts· newtests/seams/command-agent-input.test.ts· newtests/goldens/git-agent-golden.test.ts· newtests/goldens/github-status-lines.test.ts· newtests/guards/agent-source-resolver.test.ts· newtests/guards/extended-references.test.ts· newtests/guards/retired-wording.test.ts· newtests/guards/numeric-floor-manifest.test.ts+ its committed manifest[DR-27a]·tests/git-agent.test.ts·tests/registry-integrity.test.ts·tests/agent-name-guards.test.ts·tests/agent-frontmatter.test.ts·tests/skill-references.test.ts·tests/installer-new.test.ts·tests/build-mds.test.ts·tests/shell-hooks.test.ts(gitignore fixture only) ·tests/init-logic.test.ts(gitignore fixture only) ·.github/workflows/ci.yml:23·package.json(test:golden:update)release.md:85conventions read;gh pr viewatcode-review.mds:76-78/bug-analysis.mds:43-45); the mode ('union'/'sole') eachextractOpSectionFromCorpusconsumer names[DR-18]docs/reference/platform-assumptions.md·.devflow/features/dynamic-workflow-engine/KNOWLEDGE.md·CHANGELOG.md· the seven drifted citations in.devflow/features/*/KNOWLEDGE.md· the Phase-0 issue bodyGates
npm run build && npm test— full suite green at the post-A1 tree. No new test exists yet; this proves A1 broke nothing.tests/fixtures/golden/git-agent.mdbyte-equalssrc/assets/agents/git.md(verify withcmp, not by reading);github-status-lines.txtnon-empty and every extracted literal present in the source at the cited line.npm run build && npm test && npm run test:integrationgreen; each new guard demonstrated non-vacuous with a recorded red case (AC-0.13);postingOps.length >= 8satisfied bygit.mdalone (AC-0.8);resolveAllAgents() ⊇ getAllAgentNames()= 16 (AC-0.7).github-status-lines.txtbyte-identical to its A2 capture (AC-0.9) +git status --porcelainempty./implementspawn notesCREATE_PR: falseon A1, A2, and A3 (and A3a when the split is taken);CREATE_PR: trueon A4, the terminal agent, which opens the PR with the complete test-inventory table and the RED proofs from all subtasks (implement.mds:409). A4 must therefore receive every prior handoff.HANDOFF_REQUIRED: trueon every subtask but the last (A1, A2, A3 — and A3a when the split is taken). A4 is terminal and produces no handoff..devflow/docs/handoff-{branch_slug}.mdviaHANDOFF_FILE; each writes its handoff contents (column 7 above) after its own gate passes, never before.git commit -- <owned paths>(PF-020's validated cheap mitigation; per-commit provenance survives the squash-merge).Execution strategy
SEQUENTIAL_CODE_AGENTS— 4 subtasks (A1 → A2 → A3 → A4). Context risk: HIGH.Rationale — three independent forcings (any one sufficient)
git.md; capturing the golden first pins a tree Phase 0 immediately moves past (GAP-06). A single Code agent has no mechanism that guarantees commit ordering inside one run; sequential agents make each ordinal a spawn boundary.Why
PARALLEL_CODE_AGENTSis rejected (feature-wide, PF-020 closure rule)PF-020's 2026-08-30 extension binds — "disjointness has to hold over each agent's READ/EXECUTE closure, not merely its WRITE set." Three facts collapse every candidate partition:
npm run buildisrm -rf dist && …(package.json:20). Every Code agent's verification step deletes and rebuilds the one shareddist/. A sibling agent mid-suite observes a missing dist tree — and Phase 0 deliberately makes every dist-scanning guard fail loud on a missing directory (AC-0.16, R3). Parallel agents therefore manufacture nondeterministic red suites that look exactly like real regressions./implementhas no worktree isolation — grep forworktreeinimplement.mdsreturns zero hits. All Code agents share one worktree, one git index, onedist/, onenode_modules, one vitest run.git.md ∪ dist/commands/*.md ∪ dist/skills/git/references/**— the union of every proposed subtask's outputs. Disjoint write sets, 100% overlapping read closure.This disqualifier is independent of write-set disjointness, so it holds for all four phases. It is a tooling limitation, not a plan limitation
[DR-23, ALREADY-ADDRESSED].PR title
fix(traceability): repair issue-seam defects and land the tracker test harnessImplementation Plan
Design artifact (authoritative):
.devflow/docs/design/tracker-phase-0.2026-09-05_1155.md— local and gitignored. A copy truncated at the 60k comment cap is posted as a collapsed comment: #322 (comment). Run with/implement .devflow/docs/design/tracker-phase-0.2026-09-05_1155.md. Tracking issue: #321.Test Inventory (AC-0.13)
Each new guard landed in Phase 0, named with its file and proven non-vacuous via a known-bad inline sample (mechanic 2, per H10).
tests/seams/command-agent-input.test.tsKEY:passed in a caller fence is declared in the op's**Input:**— fixes debug.mdsISSUE:/ISSUE_INPUT:mismatch (AC-0.1)OPERATION: fetch-issue\nISSUE: 42\n→ exactly 1 violation namingISSUEtests/seams/command-agent-input.test.ts**Input:**value declared by an op is passed by at least one caller fencetests/seams/command-agent-input.test.tsissue_capture_contract()value has a caller-side producerresolveAllAgents() ⊇ getAllAgentNames()tests/guards/agent-source-resolver.test.tsresolveAgentSourcedist-preferredtests/guards/agent-source-resolver.test.tsdist/agents/exists, resolver prefers it oversrc/assets/agents/resolveAgentSourcebuild hinttests/guards/agent-source-resolver.test.ts`/Run \`npm run build\`` when neither src nor dist file existsresolveAgentSource('_nonexistent_agent_')→ throws containing the build hintextractOpSectionFromCorpus'sole'modetests/guards/agent-source-resolver.test.ts## Operation: Xheading → throws naming both file pathsextractOpSectionFromCorpus'union'modetests/guards/agent-source-resolver.test.tsmatchCount = 2, not 1tests/goldens/git-agent-golden.test.tstests/fixtures/golden/git-agent.mdis byte-identical tosrc/assets/agents/git.mdtests/goldens/github-status-lines.test.tstest:golden:updaterefuses to overwrite without--unfreezenode scripts/update-golden.js github-status-lines→ non-zero exit + §0.2 rule text printedtests/git-agent.test.tsgit.mdincludingfetch-issueandfetch-issues-batch(AC-0.11)REQUIRED_OPS→ test fails naming the missing opmanage-debt: 60000boundtests/git-agent.test.tsmanage-debtsection contains the 60000-char archive threshold before Phase 2 moves it (AC-0.12)fetch-issues-batchremovedtests/registry-integrity.test.tsINTERNAL_OPSallowlist is['learn-conventions']only —fetch-issues-batchremoved with a rationale comment (AC-0.11, SG-11)fetch-issues-batchwithout updating the test → reverse-check finds it unlisted in compiled commandstests/build-mds.test.ts §20DIST_FILES.length === 14(13 compiled hosts +release.md, SG-13)dist/commands/is absent (throw) or ifrelease.mdis removed from the constantcompliance_gate()adoption guardtests/build-mds.test.ts §20{compliance_gate()}partial (P0-S22)hostsScanned >= 6— fails if all imports are removedtests/build-mds.test.ts §21gh issueinvocation or descriptive mention in anyDIST_FILEoutside a Git spawn fence (AC-0.4)OPERATION: fetch-issue\ngh issue view 42\n→ violation detected (not inside spawn fence)ISSUE_NUMBERStests/guards/retired-wording.test.tsISSUE_NUMBERS(renamed toISSUE_REFSin Phase 0) is absent from all Phase-0 output files (GAP-32, AC-0.17)ISSUE_NUMBERS→wouldFlag === truetests/guards/numeric-floor-manifest.test.tstests/**decreases vs the committed manifesttests/fixtures/numeric-floors.json(AC-0.17, DR-27a)allPatternsExistassertion failstests/guards/extended-references.test.ts## Extended Referencesrow in any skill resolves to a real file on disk