Repository navigation
tech-debt(frontend): a frontend change in a fresh worktree has no local verification at all — not vitest, not vue-tsc #16912
Description
Activity
The asymmetry this issue describes just demonstrated itself, in both directions, within an hour.
A reviewer verifying #16892 (a backend guard) ran its negative control directly:
Ran the new test file both ways: fails 3/6 against the unpatched filter, passes 6/6 with the fix — a genuine regression test.
That is the whole claim: not "the test passes", but "the test would have caught the defect". It took one command, because the backend's tooling resolves from a worktree.
The same reviewer cannot produce that sentence for any of the four frontend PRs listed above. Not through lack of rigour — the command does not exist to run.
So the gap is not only that an author cannot self-verify a frontend change. A reviewer cannot verify it either. Both roles are reduced to reading the diff and trusting CI's green, which confirms the fixed behaviour and is silent on whether the test discriminates. For backend work the repository has a real answer to "would this have caught it?"; for frontend work it currently has none.
That makes the first direction above — a worktree-resolvable
node_modulesstore outside the codebase — worth more than its cost. It is not a convenience for authors; it is the difference between a review that can check the central claim and one that cannot.Confirming this is a live, current gap, not just a filed observation — every push I made in this session's gui-fixes-2026-09-20 worktree hit exactly this:
[pre-push WARN] node_modules missing — skipping vue-tscon every push touching .ts files, for the same reason this issue names (fresh worktree, no ancestor node_modules, installing into the checkout prohibited). I've been working around it the same way the issue's own "cheapest, weakest" option describes — stating explicitly in each PR's Verification section that vue-tsc/vitest were skipped locally and CI is the first real signal — but doing it by hand, per-PR, is exactly the "whichever author remembers" failure mode the issue is about.Not implementing anything here — all three directions are tooling/CI/infrastructure work (a shared node_modules store, a CI job, or a hook-to-PR-body pipeline), not frontend application code, and this issue's own framing ("Directions, not a decision") already says it needs buy-in before scoping. That puts it outside my current GUI-only mandate rather than something to fold into gui-fixes-2026-09-20.
Recommendation, since asked for directions: #1 (a shared, worktree-resolvable node_modules store) is the actual fix — it removes the gap instead of documenting around it, and is a known pattern (a package manager content-addressable store or a
--modules-diroutside the repo, shared read-only across worktrees). #3 (surface the fact automatically) is worth doing regardless of which bigger direction wins, as a stopgap — but its mechanism ("reach the PR body automatically") isn't specified and choosing one (a state file the nextgh pr createreads? a git note? something else?) is itself a small design decision, not a purely mechanical one.Leaving this open, unlabeled by me for needs-decision since it already carries that framing in its own body.
Removed from umbrella #17151: all three of this issue's own directions are infra/CI tooling (a shared node_modules store, a CI job, or a hook-to-PR-body pipeline), not frontend application code, so it isn't GUI-scoped work this umbrella's owner will actually deliver. Recommendation from the earlier comment stands; this stays open as a standalone tooling issue.
Closure evidence — verified against merged code in
origin/main(f72de7e), not against the PR diffThis issue carried no acceptance-criteria checklist; it was filed as a decision ("Directions, not a decision") with three options. Direction 1 was taken, plus the cheap half of direction 3, and direction 2's CI negative-control job was deliberately not built. Five causes were found, not the one the issue named:
Cause Evidence in origin/mainWorktrees could not resolve node_modulesscripts/hooks/post-checkout:46—# 7. Link node_modules into a linked worktree (Issue #16912), listed in the header index at:15A skipped frontend check read as a pass tools/git-hooks/pre-push:367could_not_run "vue-tsc"and:416could_not_run "vitest"— the repo's own "could not look ≠ found nothing" helper, which sets a non-zero state and names its opt-outChanged .spec.tsfiles were never selectedtools/git-hooks/pre-push:379— `grep -E '.(testThe vitest reporter could never load autobot-frontend/src/test/dependency-floor-reporter.ts:49process.stderr.write(no longer importing the browser logger that pulls in.vueSFCs) and:136export default DependencyFloorReporter(the class, where vitest callsnew)A directory-only ignore pattern could not match the link autobot-slm-frontend/.gitignore:2—node_modulesProof the cause is actually gone, rather than the code merely being present: the full
autobot-frontendsuite now runs inside a worktree — 297 files, 3408 passed, 1 skipped, 0 failed, 149s — and the hook was exercised in both directions: with the link removed it reportsCOULD NOT RUN ... this push is NOT verifiedfor both checks and statesthe 1 selected test file(s) did not run; with it restored,vue-tsc: 0 errorsandvitest: all relevant tests pass. The #16919 dependency-floor banner printed for the first time.Merged in #17321 (f72de7e);
frontend-testsandUnit & Integration Testsboth green on the merged head.- added 4 commits that reference this issue
on Sep 27, 2026
What
A worktree created for a task has no
autobot-frontend/node_modules. The main checkout's copy is not an ancestor of the worktree, so Node cannot resolve it, and installing into the codebase is prohibited by the repository's own rules.So for any frontend change made in a worktree:
pre-pushsays so itself and continues:node_modules missing — skipping vue-tsc;pre-pushdegrades to a warning and pushes anyway.That degradation is the right call for a hook — blocking every frontend push on an unsatisfiable precondition would be worse — but the consequence is that frontend PRs arrive with strictly less local evidence than backend ones, and nothing on the PR says so unless the author writes it by hand.
Why it matters beyond convenience
A test that has never been run against the unfixed code is not yet evidence. It confirms the fixed behaviour when CI goes green; it does not show the test would have failed on the defect. That distinction is the one this repository leans on hardest —
RATCHET_BASELINES.mdandMEASUREMENT_DISCIPLINE.mdboth turn on it, and half the guards inrepo_tests/carry an explicit control for exactly this reason.Backend changes get that control locally:
pre-pushruns pytest and a mutation can be tried in seconds. Frontend changes cannot, so the control is either skipped or deferred to a reviewer's reading.Live instances, today
Four PRs in one day. This is not an occasional gap.
Not all of these are equally exposed, and the difference is worth naming. #16909's negative control is provable by inspection rather than execution: without the added
elsebranch, nothing in the file setsshowLegacyModalto true — it was assignedfalseat three sites andtrueat none — so the failing-on-defect claim is analytically certain. #16911's is not: whether a never-settling init plusadvanceTimersByTimeAsync(11000)reaches the catch block on unpatched code is a runtime question, and its author said so rather than implying otherwise.So the gap bites hardest where the test's behaviour on the defect cannot be read off the source.
Directions, not a decision
node_modules— a store outside the codebase that worktrees can resolve, so installing-into-the-repo stays prohibited while the tools still run.pre-pushalready knows it skipped; have that fact reach the PR body automatically so "no local frontend verification" is stated by the tooling rather than by whichever author remembers.The third is the cheapest and the weakest. The first fixes the cause.
Found by autobot-ai-42 while verifying #16274 (PR #16911); filed here because it affects four PRs across two sessions and is a toolchain property rather than anyone's oversight.