Skip to content

tech-debt(frontend): a frontend change in a fresh worktree has no local verification at all — not vitest, not vue-tsc #16912

Description

@mrveiss

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:

  • vitest cannot run — no test runner, no negative control, no confirmation the test even executes;
  • vue-tsc cannot run — pre-push says so itself and continues: node_modules missing — skipping vue-tsc;
  • pre-push degrades 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.md and MEASUREMENT_DISCIPLINE.md both turn on it, and half the guards in repo_tests/ carry an explicit control for exactly this reason.

Backend changes get that control locally: pre-push runs 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

PR Frontend change Local verification
#16911 ChatInterface init racing an uncancelled timer none — author flagged the missing negative control explicitly
#16909 TerminalWindow modal-choice branch + 3 tests none
#16907 Knowledge sidebar train, 2 components + 11 locales none
#16902 LlcSidebar entry + a new coverage guard none

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 else branch, nothing in the file sets showLegacyModal to true — it was assigned false at three sites and true at none — so the failing-on-defect claim is analytically certain. #16911's is not: whether a never-settling init plus advanceTimersByTimeAsync(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

  • A shared, worktree-resolvable node_modules — a store outside the codebase that worktrees can resolve, so installing-into-the-repo stays prohibited while the tools still run.
  • A CI job that runs each frontend test against the pre-change tree and reports whether it fails there, turning the negative control into something CI produces rather than something the author must run.
  • Accept it and make it visible: pre-push already 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.

Activity

  1. mrveiss commented on Sep 17, 2026

    @mrveiss
    OwnerAuthor

    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_modules store 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.

  2. mrveiss commented on Sep 20, 2026

    @mrveiss
    OwnerAuthor

    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-tsc on 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-dir outside 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 next gh pr create reads? 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.

  3. mrveiss commented on Sep 20, 2026

    @mrveiss
    OwnerAuthor

    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.

  4. mrveiss commented on Sep 23, 2026

    @mrveiss
    OwnerAuthor

    Closure evidence — verified against merged code in origin/main (f72de7e), not against the PR diff

    This 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/main
    Worktrees could not resolve node_modules scripts/hooks/post-checkout:46 — # 7. Link node_modules into a linked worktree (Issue #16912), listed in the header index at :15
    A skipped frontend check read as a pass tools/git-hooks/pre-push:367 could_not_run "vue-tsc" and :416 could_not_run "vitest" — the repo's own "could not look ≠ found nothing" helper, which sets a non-zero state and names its opt-out
    Changed .spec.ts files were never selected tools/git-hooks/pre-push:379 — `grep -E '.(test
    The vitest reporter could never load autobot-frontend/src/test/dependency-floor-reporter.ts:49 process.stderr.write (no longer importing the browser logger that pulls in .vue SFCs) and :136 export default DependencyFloorReporter (the class, where vitest calls new)
    A directory-only ignore pattern could not match the link autobot-slm-frontend/.gitignore:2 — node_modules

    Proof the cause is actually gone, rather than the code merely being present: the full autobot-frontend suite 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 reports COULD NOT RUN ... this push is NOT verified for both checks and states the 1 selected test file(s) did not run; with it restored, vue-tsc: 0 errors and vitest: all relevant tests pass. The #16919 dependency-floor banner printed for the first time.

    Merged in #17321 (f72de7e); frontend-tests and Unit & Integration Tests both green on the merged head.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions