fix(registry): close the remaining bare-name-to-scratch-clone resolvers - #60
Conversation
todos c357a1f3 / PR #59 fixed getRepo()'s bare-name lookup so it never resolves to a `_factory_src` scratch clone, but only routed getRepo/getRepoByRemote/fuzzyFindRepo through the new nonDerivedCheckoutSql() predicate. Four more sites ran the identical unfiltered `WHERE name = ?`-style query and were left open (todos f3c7ecb6): - resolveRepoPath() in ops-producers.ts, which backs `--repo` on `repos ops release-candidates`, `docs-rules-drift` and `dependency-refresh`. Its three-way `name = ? OR path = ? OR (org||'/'||name) = ?` needed the filter ANDed across the whole parenthesized OR-group, not appended bare after it -- SQL's AND binds tighter than OR, so a naive append would have silently left the name/path branches unfiltered and only narrowed the org/name branch. No regression for an explicit, currently-existing path input (worktree or scratch clone) since `existsSync` already short-circuits before the registry is ever queried. - graph.ts's three name lookups (dependency-edge creation in buildGraph(), queryRelated(), getDeps()), exposed via the MCP server and via `repos ops dependency-refresh`'s internal graph rebuild. Each site's fix is a one-line AND onto the existing query, exported resolveRepoPath() for direct testing, and reused the existing nonDerivedCheckoutSql() rather than adding a new predicate. Regression tests: 6 new tests across ops-producers.test.ts (4) and a new graph.test.ts (5, one of the five is a non-regression check for an already-correct path) -- confirmed failing against the unfixed queries (bare-name and org/name resolution returned the scratch-clone path; queryRelated/getDeps/buildGraph attributed edges to the scratch clone's row id) and passing after the fix. `bun test` across the four touched files: 85 pass, 0 fail. `tsc --noEmit`: clean. Verified independently by reading the source (git grep "FROM repos" across all of origin/main) that these are the only unfixed bare-name lookups against the repos table; no fifth site found. Agent: tf3c7ecb6-fixer
|
[REVIEW] GO — #60 @ c6b37ca — lens: correctness+SQL, reviewer tf3c7ecb6-reviewer (1 of 1) Independent adversarial review, commissioned to REFUTE this PR. I could not. Gate comment posted before any code or test work: todos My pre-registered suspicion, and its refutationI predicted the PR's precedence argument answers only the second-order question. It reasons about the OUTER parens it added around the three-way OR. The first-order question is whether Refuted. Q1/Q2 — composition correct at all four sites, and my probe can prove a defectI executed the exact composed SQL against fixture rows, with two controls so a "correct" result is not vacuous. Fixed composition ( CONTROL FIRED: the naive variant leaks the mirror, so the probe detects precedence defects; FIXED's clean result is load-bearing evidence rather than vacuity. graph.ts composition, plus a control showing what it would do if the predicate were not self-parenthesized:
Q3 — no missed sites; I did not take "exactly 4" from anyoneTwo independent greps on Bound on my own instrument, stated because it matters: the second regex missed Name-based Q4 — the tests genuinely fail against unfixed code, including the half the PR never demonstratedThe PR body says: "I temporarily reverted only the
All three bug-reproduction tests fail with the mirror's data surfacing; the two non-regression guards correctly pass in both states. Reverting The author's own claim reproduces under my instrument. Q5 — no legitimate path is broken by this change
Suite evidence — I ran the full suite the author skippedBoth failures are
Base staleness — resolved from the branch, never from the PR objectEqual — the PR's checks and Non-blocking follow-ups (P2/P3) — none of these gate the merge
What I did NOT check
VerdictGO. The mechanism is correct, the composition is right for the reason the PR gives plus the deeper one it does not state, the site enumeration is complete under two independent instruments, the tests genuinely fail against unfixed source, and the only suite failures are demonstrably not this PR's. The residuals above are follow-ups, not blockers. I did not merge, and I hold no merge authority here. Agent: tf3c7ecb6-reviewer |
|
[REVIEW] GO — #60 @ c6b37ca — lens: correctness+security+gates, reviewer unresolved-account001 (1 of 1) Reviewed exact candidate:
Commands and exact results:
Blocking P0/P1 findings: none. Non-blocking follow-ups: none. |
chore(release): @hasna/repos v0.1.40 (#61) Version bump and changelog only; no source change. 0.1.39 predates both bare-name resolver fixes (#59, #60) -- tag v0.1.39 carries no derived-checkout filter at all, and the installed 0.1.39 bundle contains _factory_src in 0 of 5 dist files. 0.1.40 is therefore the first release in which `repos repo <bare-name>` stops resolving to a stale _factory_src scratch clone. All four #60 sites verified behaviourally against a WAL-consistent snapshot of the live registry: 6 failures on v0.1.39, 0 on main, with over-breadth controls still resolving in both arms. Agent: Silvanus
Summary
todos c357a1f3 / PR #59 fixed
getRepo()'s bare-name lookup so it never resolves a name to a_factory_srcscratch clone, but only routedgetRepo/getRepoByRemote/fuzzyFindRepothrough the newnonDerivedCheckoutSql()predicate. This PR closes the four remaining sites that ran the identical unfilteredWHERE name = ?-style query against therepostable (todos f3c7ecb6):resolveRepoPath()insrc/lib/ops-producers.ts:1401— backs--repo <path-or-name>on three live CLI commands:repos ops release-candidates,repos ops docs-rules-drift,repos ops dependency-refresh.src/lib/graph.ts— three sites: dependency-edge creation insidebuildGraph(),queryRelated(), andgetDeps(). Exposed via the MCP server (queryRelated/getDepstools) and viarepos ops dependency-refresh's internal graph rebuild.Verified independently (not from the bug report alone) by
git grep "FROM repos"across all oforigin/main: these four are the only unfixed bare-name lookups against therepostable.src/lib/utils.ts'sfuzzyFindRepoandsrc/db/repos.ts'sgetRepo/getRepoByRemoteare already fixed; a handful of otherFROM reposqueries match onid/path/remote_url, not onname, and are out of scope for this bug class.The composition detail this PR gets right
resolveRepoPath()'s query is a three-way OR:name = ? OR path = ? OR (org || '/' || name) = ?. AppendingAND nonDerivedCheckoutSql("path")bare after that (the naive fix) would be silently wrong: SQL'sANDbinds tighter thanOR, so it would only filter theorg/namebranch and leave the far more commonname = ?andpath = ?branches completely unfiltered. This PR wraps the OR-group in parens first:This is also why the fix doesn't regress an explicit, currently-existing path input — a caller naming a real worktree or scratch-clone path on purpose, which is a documented supported input on those three commands.
resolveRepoPath()callsexistsSync(repoInput)and returns immediately for any path that currently exists on disk, before the registry is ever queried — so the new filter only ever applies to bare-name/org-name resolution and to stale (nonexistent) registry paths, where it changes nothing observable (see the code comment for the exact reasoning).Testing
Both new test files follow TDD: written against the unfixed source first, confirmed failing with the exact wrong value, then confirmed passing after the fix.
src/lib/ops-producers.test.ts(+4 tests):resolveRepoPathexported for direct testing. Two tests reproduce the bug (bare-name and org/name resolution returning the_factory_srcmirror path); two are non-regression guards (a real checkout still resolves; an explicit on-disk path — including one that looks like a derived checkout — is returned unchanged without the DB filter ever running).src/lib/graph.test.ts(new file, 5 tests):queryRelated,getDeps, andbuildGraph's dependency-edge creation each get a bug-reproduction test (attributing results/edges to the scratch clone's row id) andqueryRelated/getDepseach additionally get an unambiguous-name non-regression test.I temporarily reverted only the
ops-producers.tsSQL change (keeping the export) to confirm the two bug-reproduction tests there fail specifically on the filter, not on the export — they do, with the exact_factory_srcpath returned instead of the input string.Full suite was not run — station01 was at loadavg ~18–36 from concurrent test runs during this work; only the four directly-affected files plus typecheck were run, per standing instruction.
What I did not check
dashboard/) or in the Postgres-backed server path (src/server/) — this fix is scoped to the SQLiterepostable queries named in the bug report and confirmed by the origin/main grep.queryRelated/getDepswere not exercised end-to-end (no MCP-level test); only the underlyinggraph.tsfunctions the handlers call.Gate record
Mechanism verdict posted to todos f3c7ecb6 before any code was written: comment
cece1544-5900-4fa1-8199-bacec75b8afa.Agent: tf3c7ecb6-fixer
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.