fix(ship): agent-mode pipeline blockers found dogfooding on a real repo - #45
Merged
Merged
Conversation
Seven issues that stopped `forge ship --agent-mode` from certifying a feature
end-to-end on a large Next.js/Supabase repo (2026-09-07):
1. forge clean flagged git-ignored files (~450 .playwright-mcp/*.log, sibling
.claude/worktrees) as "unmanaged scratch" and the ship hygiene gate
hard-failed on them, telling the user to run `forge clean --apply` which
would delete other tools'/sessions' ignored working files. clean now skips
git-ignored paths *outside* .forge/ by default (forge still tidies its own
ignored scratch); `--include-ignored` restores the old behaviour.
2. self-review-gate / spec-completeness / adr-quality / tdd-gate /
security-hygiene resolved the spec dir with slugify(description), ignoring
the --name/-n override that agent-mode always uses — so every gate reported
"spec.md not found / UNVERIFIED" while the artefacts sat in
.forge/specs/<name>/. They now use HookContext.SpecName via ctxSpecSlug().
3. Same gates only looked for the canonical filename; agent-mode writes
test.md / code-plan.md / etc. Added readSpecArtefact() aliases
(arch.md↔adr.md, test.md↔tests.md, code-plan.md↔impl-notes.md).
4. The Code checkpoint reported "N modified file(s)" + status ok by counting
every dirty line in `git status` — unrelated docs, .forge ledgers, another
session's screenshots. Added countChangedSourceFiles() (source extensions,
excludes .forge/ docs/ growth/); a plan with no source change now reports
"warning — implement then rerun", not a green "code written".
5. Test artefacts were always written to <root>/tests, invisible to a runner
whose roots are "src"; the reachability check then swept the whole repo and
flagged the project's pre-existing e2e/staging suites as "unreachable".
pickTestsDir() prefers an existing collected dir (src/test, …);
reachability now checks only the artefacts forge wrote for this slug.
6. ship:test:integration hard-coded "Jest + supertest"; on a repo without
supertest or an HTTP entrypoint the stub could not compile. Prompt now
tells the model to follow the project's own integration-test convention.
7. `forge agent submit --file` failed on a path containing ".." or mixed
separators ("cannot find the path specified") even when the file existed;
the path is now cleaned and resolved against cwd.
Tests: cmdship/cmdclean/cmdagent suites green; two TestCheckCode assertions
updated to the corrected (plan != implementation) contract.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…acts Removing bare "..." from the contains-scan (it hit prose elisions, "P1-01 … P1-09" ranges and code snippets). Unfilled ellipsis placeholders are still caught by a per-line check — a line that is only dots, or a "key: ..." / "= ..." stub — which skips fenced code blocks and does not fire on real content. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
testingPipelineEvidencePath slugified ctx.Description, so on an agent-mode run (which always sets --name/-n) the gate looked for testing-pipeline.md under a truncated description slug and reported it missing even when it existed under .forge/specs/<name>/. Now resolves via ctxSpecSlug(ctx); the path helper also accepts an already-resolved slug. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- tdd-gate now accepts it()/test()/describe() (Jest/Vitest/Jasmine/Mocha) as a test scenario, not only Gherkin or `func Test*`, and reads test-stubs.md in preference to forge's thin test.md summary for the quality check. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Nine issues that stopped
forge ship --agent-modefrom certifying a feature end-to-end on a large Next.js/Supabase repo (found 2026-09-07 driving the pipeline by hand). After these fixes the same feature's pipeline reportsship pipeline ready (all checkpoints validated)— spec/arch/test/breakdown/ship all ✓.forge cleanflagged ~465 git-ignored files (.playwright-mcp/*.log, sibling.claude/worktrees/*) as "unmanaged scratch"; theshiphygiene gate hard-failed and told the user toforge clean --apply, which would delete other tools'/sessions' ignored files.cleannow skips git-ignored paths outside.forge/by default (still tidies forge's own ignored scratch).--include-ignoredrestores the old behaviour.self-review-gate/spec-completeness/adr-quality/tdd-gate/security-hygiene/qa-coverage/manual-test-plan/four-stage-testingresolved the spec dir withslugify(description), ignoring the--name/-noverride agent-mode always sets → every gate reported "artefact not found / UNVERIFIED" while the files sat under.forge/specs/<name>/.HookContext.SpecNamevia newctxSpecSlug(ctx);testingPipelineEvidencePathaccepts a resolved slug.test.md/code-plan.md/ etc.readSpecArtefact()aliases:arch.md↔adr.md,test.md↔tests.md↔test-stubs.md,code-plan.md↔impl-notes.md.strings.Contains(content,"...")inself-review-gateflagged prose elisions,P1-01 … P1-09ranges and{ ... }code as "hedging"."..."; a per-line check still catches a line that is only dots or akey: .../= ...stub, skipping fenced code.tdd-gateonly accepted Gherkin orfunc Test*as a "test scenario".it()/test()/describe()(Jest/Vitest/Jasmine/Mocha); readstest-stubs.mdbefore forge's thintest.md.checkCodereported "N modified file(s)" + statusokby counting every dirtygit statusline (docs,.forgeledgers, another session's screenshots) — the known "✓ Code with zero code" gap.countChangedSourceFiles()counts only source extensions, excluding.forge/ docs/ growth/. A plan with no source change now reportswarning — implement then rerun+ "(N other working-tree change(s) not attributed to this checkpoint)".<root>/tests, invisible to a runner whose roots aresrc; the reachability check then swept the whole repo and flagged the project's pre-existingtests/e2e/*/tests/staging/*suites as "unreachable".pickTestsDir()prefers an existing collected dir (src/test, …);allTestArtifactsExist/missingTestArtifactscheck both; reachability now runs only against the artefacts forge wrote for this slug.ship:test:integrationprompt (and theship-testtemplate) hard-coded "Jest + supertest"; on a repo without supertest / a single HTTP entrypoint the stub couldn't compile.forge agent submit --filefailed on a path with..or mixed separators (FORGE-6900 … cannot find the path specified) even when the file existed.readAnswerfilepath.FromSlash+Cleans the path and resolves a relative one against cwd.Not fixed (noted for follow-up): npm shim resolving a nested
forge.execopy (#1),pending.jsonneeding an explicit UTF-8 read on Windows (#3),-nvs--sessiondesync footgun (#9).Tests:
go test ./internal/...green (76 packages); twoTestCheckCodeassertions updated to the corrected "a plan is not an implementation" contract.🤖 Generated with Claude Code