Repository navigation
fix(vibe): symbol-level route rule and the 2026-10-21 lessons - #329
Merged
Merged
Conversation
…s that reach the endpoint routeSpecs followed helper imports at file level, so a route named in a large shared fixture required every spec importing that fixture (62 for batch-move). It now reads each helper's top-level statements and requires a spec only when it imports an export that names the endpoint or references a constant, function or import that does, across re-exports within three files. Namespace, dynamic and indirect default imports, a top-level statement that runs on load, and a file the splitter cannot read fall back to file level, with the reason in the requirement.
…nce lane isRootTest and the e2e evidence lane matched only e2e/, so a repair to a spec under another e2e root was not a test repair and a change there needed no e2e run. Both now use isE2ePath, and the verify worker searches every e2e root for specs covering a touched screen.
…D and shallow history The pull-request evidence gate now needs an import and an e2e by-reference selection for every changed source file and a passing run on the published commit for every selected, required or edited test. The body gate refuses a body missing a heading of the repo's pull request template. A delivered PRD child moves to IN_REVIEW only with its pull request. executed-check.mjs refuses EXECUTED without the production visual-QA flag section checked after the last merge. The restored-removal rule blocks in a shallow clone, where the removal it looks for can be cut off.
Writer, verify, ticket and handoff instructions point at the new gates; fleet-orchestrator gains the QA-then-one-main-merge order, stopping idle helpers, follow-up ticket placement, the executed-PRD flag section, the shallow-clone check, one e2e lock entry per head, the shipped-items rule for prototype matching and the general-lessons rule.
…1021 # Conflicts: # CHANGELOG.md
Removed shipped mounts and strings need a recorded source, the e2e lock takes one entry per worktree, ticket writes are checked for sprint, parent and pull request, the QA-then-one-merge order is a state check, and fleet-orchestrator gains a helper ledger that flags idle helpers and a history lookup that refuses a shallow clone. Prose that these checks now enforce points at them instead.
…n, ticket parents widen Publication main-sync merges fresh main only in final-merge mode (vibe-sessions.mjs touch --main-merge final, set once QA passes), when the branch no longer merges cleanly onto main, or when its last validation failed; otherwise the branch's base stands in as its main and the waiting main is recorded as deferredMain. The dist bundle is rebuilt. The restored-removal rule deepens a shallow clone in steps instead of blocking, and blocks only when a fetch fails. ticket-write-check also refuses a DONE or CANCELED parent.
A conflicting branch is QA'd as it is and a failing check is fixed on the branch's own base, so neither triggers a main merge any more; only final-merge mode, set once QA passes or when the person asks for a merge now, does. A conflicting branch outside final mode is covered by a new test.
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.
Purpose
vibe 1.0.73: one combined lessons PR for vibe and fleet-orchestrator, covering every open entry in the lessons ledger. Wherever a lesson had a checkable shape it got a mechanical check, with prose only where nothing can observe the mistake.
Route rule: symbol-level narrowing
routeSpecsused to follow helper imports at file level. As a result, a route named in one large shared fixture required every spec that imported that fixture. The rule now lives inroute-specs.mjs, andmodule-symbols.mjsgives a text-only read of each helper's top-level statements. A spec is required only when it imports an export that reaches the endpoint. An export reaches it when its declaration names the endpoint, or references a constant, function or import that does. Re-exports (named, aliased andexport *) are followed within the existing three-file hop limit. Type-only imports never count. The rule falls back to file level only for a namespace import, a dynamic import, a default import of a file with no default declaration, a helper whose top level runs on load, or a file the splitter cannot read. Each fallback prints its reason in the requirement.Real tree: symphony-alpha
origin/mainat2dd71fbab2,apps/api/app/artifact-links/batch-move/route.ts, file contents read withgit show.apps/desktop/test/e2e/sessions-list-project-edit.spec.ts: importssessionsListProjectCloudRoutesfromapps/desktop/test/e2e/helpers/sessions-list-project-cloud.tse2e/sessions-linked-entity-columns.spec.ts: importsinstallProjectWriteMocksfrome2e/helpers/sessions-list-fixtures.tsBATCH_MOVE_PATHfeeds onlyinstallProjectWriteMocks; the Desktop helper names it insidesessionsListProjectCloudRoutes). The splitter read all 2,861 e2e and Desktop test files on that tree with no fallback.Failing-first: the brief's case (a helper with two exports, only one naming the endpoint, and a spec importing the other) and the wider case (type, alias, re-export and namespace imports) both fail on
origin/mainand pass here.Publication main-sync waits for QA
Operator ruling: QA the feature-complete head, conflicts included, then merge main once and enqueue. Before this change, vibe's "Main-sync before publication" merged main on every push. Now
prepareMainSync(tools/vibe-workers/src/main-sync.ts, dist rebuilt withnpm run build) still fetches main, but stages the merge only in final-merge mode:vibe-sessions.mjs touch --main-merge final, which is set once QA passes or when the person asks for a main merge now. Otherwise the branch's own merge-base with main stands in as its main, and that includes a branch that conflicts with main or fails a check (it is fixed on that base). The receipt records the waiting main asdeferredMain, and preparation returnsmainMerge: "deferred".Tests:
qa-merge-order.mjschecks the result before enqueue.Shallow clones are deepened, not blocked
When a lookup by the restored-removal rule finds nothing in a shallow clone, the rule deepens the history in steps (
git fetch --deepen=1000, then--deepen=10000, then--unshallow) and reruns until the lookups resolve or the clone is complete. It blocks only when a fetch fails, and it prints git's reason. The test clones with--depth 1: deepening finds the removal commit and leaves the clone complete, and an unreachable remote blocks with the fetch error.Same-class spots #327 listed
isRootTest/ROOT_TEST_PREFIXES(test-files.mjs)isRootTestalso acceptsisE2ePath; the prefixes staye2e-*was not a test repair, and a spec added there for a requested PR was outside the allowed paths, though the same spec undere2e/passed. Only spec and test files are widened; a config under an e2e root is still outside.requiredLanese2elane (pr-facts.mjs)isE2ePathchangee2e/one did.rg... undere2e/" (vibe-verify-worker.md)e2e/that cover a touched screen were never searched.Each spot has a failing-first test (the inventory phase tests and the lane test) except the prose.
Ledger entries
Taken (ledger line, lesson → what changed):
capability-removalrule indiff-rules.mjs.## Test plan→ body gate checks the repo template's headings.e2e-lock.mjsrefuses a second entry from the same worktree.ticket-write-check.mjsand the children gate (awaitingPullRequest).executed-check.mjs, ticket worker, fleet.helpers.mjs statusprints STOP lines (replaces "reuse an idle reviewer").history-origin.mjsrefuses to attribute without full history.qa-merge-order.mjsstate check before enqueue.Skipped:
Rungs
Each lesson takes the highest rung that can catch it (types or architecture, then a script or gate, then a guard test, then prose).
route-specs.mjs,module-symbols.mjs(diffRules.requiredTests)e2e/(#327 spots)isRootTest,requiredLanesuseisE2ePathselectionProblems(blocking.prEvidence)templateHeadingProblems(blocking.prBody)checkChildEvidence(awaitingPullRequest);ticket-write-check.mjs --status IN_REVIEWticket-write-check.mjs(ticket worker create mode, fleet ticket filing)M/D-M/Dname; otherwise proseexecuted-check.mjs(ticket worker merge check, fleet PRD close-out)history-origin.mjsrefusescapability-removalrule: a removed mount or shipped string needsRemoval: <source>e2e-lock.mjsrefuses a second entry from the same worktree (exit 76)helpers.mjs statusprintsSTOPlinesqa-merge-order.mjsbefore enqueuegeneric.test.mjsInstruction length (agents and SKILL files): +56 / -15 lines. The prose for the lock, ticket and helper rules now points at their checks instead of restating them.
Tests
Two prose contract tests changed with the wording they pin (
only the tests selected for each file of the whole branch diff;Every other child ... Never set IN_REVIEW without a pull request). The children-gate fixture now passespullRequest, because the ruling made a delivered child without one stay open.Prevention