feat(router): universal cross-provider router + research-audit gap fixes - #152
Merged
Merged
Conversation
The staged secret scan reads every file with `git diff --text`, and the
entropy leg of hasSecret flagged the XMP packet id W5M0MpCehiHzreSzNTczkc9d
that the XMP packet wrapper carries inside PDFs, JPEGs and PNGs, so
ordinary binary commits were refused.
- A staged file that git reports as binary (`--numstat` prints `-\t-`) AND
whose added bytes contain a NUL (git's own content test) is scanned with
SECRET_RE / CASE_RE only. A `binary` attribute on a text file does not
qualify, so .gitattributes cannot switch the entropy leg off.
- The XMP packet id is a public constant, exempt from the entropy leg like
lockfile integrity digests (whole-token match only).
- hasSecret / redactSecrets take `{ entropy: false }`; defaults unchanged.
The unscanned-file fail-closed path is untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JpQ15QdqdDUJLavNhExwvL
The formal synthesis (§5.3, corrected 2026-09-21) withdrew the claim that running the same check at Stop, pre-commit and CI multiplies catch rates: on the same diff the copies fire together, so they are nested checks and the residual is (1−p)(1−c_max), not (1−p)·∏(1−cⱼ). Rewrites the headers of src/commit_gate.js and src/gate.js, the two ARCHITECTURE.md passages (§5 intro and the commit-boundary gate), and the Mintlify verification-gates intro to the corrected law, and states what the commit rung does add: catches for edits after the turn, hosts or sessions where the Stop hook never ran, and sessions whose one Stop block was spent. The gate.js header no longer calls the gate a cⱼ≈1 layer; its catch rate on real misses is unmeasured. No behaviour change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JpQ15QdqdDUJLavNhExwvL
writeState bounded the snapshot at 150 lines while stateBlock injected only 80 at SessionStart, so rows 81-150 of a valid handoff were silently dropped: the A4/A5 budget mismatch the formal synthesis's T4 correction names, reproduced in lines. - STATE_BUDGET_BYTES (8192, the synthesis's A5 cap) is the single budget, in one unit (UTF-8 bytes of the snapshot body), used by both sides. - selectSnapshot keeps rows in A4 priority order (goal + criteria, next, decisions, gotchas + assumptions, in-progress, done) until the body fits; every header stays, and a cut section ends with "(+N more not kept …)". Sections are written in that order, so even a loader cut of a hand-edited file drops the least important rows first. - stateBlock applies the same budget; a snapshot writeState produced always arrives whole. `maxLines` options are replaced by `budget`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JpQ15QdqdDUJLavNhExwvL
… callers The substrate pre-action check (and through it the ambient prompt hook and the FORGE_ENFORCE gate) and the Stop gate's repair checklist ran the reverse-only walk the empirical refutation measured at recall 0.022, where 94.7% of the misses were sibling files (audit E03). - substrateCheck walks IMPACT_RELATIONS by default (the frozen SIBLING / FORWARD parameters already in atlas.js) and returns impact.relations, impact.fileRelations (file -> strongest relation) and relationCounts. renderSubstrate and the ambient advisory print `path (relation)` with a per-relation count and a one-line legend. - repairReason lists the untouched co-change candidates, tagged. - enforceDecision counts DEPENDENT_RELATIONS (reverse, llm-verified) toward its 25-file block by default and names the other candidates in its reason; `blastRelations` counts more. Counting everything would put 79 of this repo's 98 source files over the threshold (35 today) at precision ~0.09. - impact(): a sibling/forward offer never relabels a reverse dependent, so a wide walk's reverse-tagged set equals the reverse-only answer. New helpers fileRelations, byRelation, relationRank, RELATION_ORDER. - Scope decomposition and lesson matching keep the dependent set; predicted tests are ordered dependents first. - `relations: ["reverse"]` is the explicit reverse-only option; forge impact, predict_impact, imagine and context keep their reverse-only default. - source/substrate.json: impact faculties operational-v1 -> operational-v2-recall with a scoped guarantee; docs updated. Tests use the serializer/deserializer/wire_format fixture for every caller, including the real hook entrypoint. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JpQ15QdqdDUJLavNhExwvL
…mputes ARCHITECTURE.md, docs/GUIDE.md, docs/cognitive-substrate/README.md and the src/preflight.js comment said "Change verifyToken in src/auth.js to require length > 20; update tests" scores ≈ 0.63 (medium risk); the code gives 0.878 (low risk). Re-running the pre-df1c5a3 preflight gives exactly 0.630: the prior was hand-set when the task had one concrete anchor (the filename), and df1c5a3 (2026-09-21) made a named code identifier a second anchor. The docs now show 0.88 and explain the change; the weights are untouched. A test pins 0.23 / 0.88 (0.63 at one anchor) and checks that the two documented example outputs print the computed line. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JpQ15QdqdDUJLavNhExwvL
…odel bin/learn-consolidate.sh sent every learned lesson to Haiku with "DROP anything ... contradicted" and rewrote ~/.claude/skills/learned from the answer: memory pruned by the model's own judgment, which the research rejects (audit A13 / H25). src/learn_consolidate.js makes the default path deterministic: - exact and near-duplicate lessons within a project merge into their first occurrence (MinHash Jaccard >= 0.7, the ledger's clusters() threshold); - a lesson is dropped only when its matching ledger claim (lesson/fact) in the same project is dormant (isDormant), tombstoned, or in the attic; a lesson with no matching claim is kept; - originals are archived first, as before; --dry-run and --json report. The script execs it by default (`--repo <root>` names the ledger, default the cwd). The Haiku rewrite stays behind an explicit `--llm` first argument, with "contradicted" removed from its prompt. Tests stub `claude` on PATH so the suite never calls a model. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JpQ15QdqdDUJLavNhExwvL
… + correlated cascade policy) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JpQ15QdqdDUJLavNhExwvL
…d data in package files Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JpQ15QdqdDUJLavNhExwvL
… clean Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JpQ15QdqdDUJLavNhExwvL
…command table; changelog Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JpQ15QdqdDUJLavNhExwvL
…ale 4) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JpQ15QdqdDUJLavNhExwvL
The router patch series re-serialized package.json and wrote the description's em dash as a — escape. Same string once parsed, but an unrelated diff line; restore the literal character so the only package.json change on this branch is the new "data" entry in "files". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CodeWithJuber
force-pushed
the
feat/universal-router-research-gaps
branch
from
September 22, 2026 12:01
f70ff14 to
d6014b5
Compare
bin/learn-consolidate.sh wrapped `claude -p` in `timeout 180`, a GNU coreutils command stock macOS does not ship. With stderr sent to /dev/null the missing command failed silently, claude never ran, and every --llm run on a Mac ended in "response too short". The stub-claude test added in this branch exposed it: Install smoke (macos-latest) failed reading calls.log. The call now goes through `limited`: `timeout`, else Homebrew's `gtimeout`, else the bare command. Checked in Git Bash with a PATH that has neither (stub called once, exit 1, "originals kept") and with `timeout` present. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CodeWithJuber
added a commit
that referenced
this pull request
Sep 22, 2026
fix: follow-ups to #152 — session learner on macOS, Sonnet 5 price, release npm check
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.
Summary
Adds the opt-in universal router (
forge route universal|outcome|fit|models) and closes seven gaps from a research-to-code audit. It is an 11-patch series applied withgit amonto v1.0.0 (61385b3), plus two small commits.data/models.jsonand.forge/models.json, not in code, and a test enforces that.match-best-single(the default),target:p,value:$orbudget:$.forge route outcomethenforge route fit).forge route(haiku / sonnet / opus / fable) stays as it is.ghp_token inside a binary is still refused.--llm.package.jsonand turned the description's em dash into a JSON unicode escape. The literal character is restored.learn-consolidate.sh --llmwrapped the model call in GNUtimeout, which stock macOS doesn't ship.timeout, elsegtimeout, else runs without a limit. fix: follow-ups to #152 — session learner on macOS, Sonnet 5 price, release npm check #153 replaces that last fallback with a watchdog.What stays the same
forge impact,predict_impact,imagineandcontextstill walk reverse dependencies only by default, as decided in fix: resolve the deep review's findings across impact, guards, memory, routing, primitives and research #151.FORGE_ENFORCEgate still counts only dependents (reverse and llm-verified) toward its 25-file block. Counting all three relations would push 79 of this repo's 98 source files over the limit.Verification
Run locally on Windows (Node 24) before the macOS fix; that fix changed no test count. CI was green on all 12 checks at
f64c540.npm testnpm run lintnpm run typecheckforge docs checkWhy 6 tests skip here:
RUN_INTEGRATIONandFORGE_PLAYWRIGHT.Consolidation script: run by hand in Git Bash, with a stub
claudefirst onPATHand the real CLI kept off it.claude.--llmmade exactly 1, to the stub.timeoutnorgtimeoutonPATH(the stock macOS setup), the original script never called the stub. The fixed one called it once, exited 1 and printed "originals kept", which is what the test asserts.Router smoke test:
forge route universal "Add pagination to the users endpoint"suggests gpt-5-mini, then minimax-m2.5 if a check fails. That gives P(success) 0.86 at an expected $0.040, against the best single model, claude-opus-4.6, at 0.84 and $0.271. The command writes no files.Known limits
target:pis optimistic by 4–6 points.learnedDir()uses node'shomedir(), which readsUSERPROFILEon Windows, while the bash learner writes under$HOME. Fixed in fix: follow-ups to #152 — session learner on macOS, Sonnet 5 price, release npm check #153.claude-fable-5andclaude-opus-4-8are valid ids: Anthropic lists both under "Legacy models (still available)".claude-fable-5-1andclaude-opus-5, at the same prices.claude -pin the build environment. It sent the fixed consolidation prompt plus one heading line; no lesson text and no secrets. The test now puts a stub first onPATH.The router design, benchmark and research audit are from the patch author.
🤖 Generated with Claude Code