fix: defects that surfaced while building the distribution funnel (expand-tool gate, count_tokens, C-toolchain claim, preset facts) - #161
Conversation
OsherElhadad
left a comment
There was a problem hiding this comment.
Reviewed, built, and ran locally. The engineering is sound and I couldn't break it: all five listed mutations reproduce by hand (revert-and-confirm-FAIL, restore-and-confirm-PASS), and I extended the check into a full matrix over all 14 presets and all 21 registered components — HasOffload() is correct everywhere, no mirror-image gap. The purego claim reproduces end-to-end: CGO_ENABLED=0 CC=/nonexistent-c-compiler go build ./cmd/context-guru-proxy really does produce a static binary that starts and answers /healthz, and I drove the new count_tokens route against the real Anthropic upstream and got its actual 401 relayed verbatim. Both of the two near-misses this PR self-reports catching are genuinely resolved — smartcrush really does implement components.Offload, and proxy/proxy.go against current main is a clean three-hunk superset with #155's effPreset/notePreset fully intact.
What blocks this from merging as-is is that the PR's prose — which is the whole point of a PR themed on "our docs/comments say things that aren't true" — has the same problem in three more places, one of them in shipped code, not just docs.
Merge-blocking
1. proxy/proxy.go:1164's comment repeats the exact mistake this PR says it caught twice already.
It reads: an offloader-free pipeline (\cache`, `off`, `safe`, `mcp`). mcpis not offloader-free — this PR's own test assertswantAdd: truefor it, and forcingHasOffload()to always-false fails on exactlymcpplus the offloader-capable fixture, proving the gate genuinely depends onsmartcrushbeing anOffload`. The self-caught error was fixed in the test and left standing in the comment a future reader will actually trust.
2. Several sites name a preset that doesn't exist on this base. proxy/proxy.go:94, proxy/proxy.go:1164, proxy/proxy_test.go:43, proxy/counttokens_test.go:93, proxy/expandgate_test.go:15 all reference "the cache preset." There's no cache entry in config/config.go's presets map — only an unrelated Cache CacheConfig yaml field. This looks like a copy-paste artifact from the sibling distribution branch (#141), consistent with the admitted wholesale copy of proxy/proxy.go from there. The underlying defect these comments describe is real (proved it independently on off/safe/cachesplit-only) — just the attribution needs to name a preset that's actually on this branch.
3. proxy/counttokens_test.go carries copy-paste artifacts gofmt/vet won't catch. Lines 93-112 are a 20-line orphaned doc comment for TestCachePresetAdvertisesNoExtraTool, a function that doesn't exist here (moved/renamed into expandgate_test.go); it also cites TestCachePresetIsCachesplitAlone, which exists nowhere in the repo. Lines 61-63 duplicate 65-67 verbatim.
Should land, not necessarily blocking
4. docs/reference/config.md:88 and docs/components.md:82-84 still say auto injection fires on exactly two conditions ("Both conditions are properties of the session") — there are now three. In a PR about false doc claims, this is a new one.
5. Items 3 and 4 are incomplete:
docs/get-started/quickstart-proxy.md:6still says a C toolchain is required — andmake build(its own step 1) still does, since the Makefile exportsCGO_ENABLED=1and I confirmed it fails without a C compiler.make build-staticexists but nothing points a reader at it.README.md:88andCLAUDE.md:26are also still unfixed.config/config.go:406,445,docs/components.md:34,docs/how-to/choose-a-preset.md:14,46, anddocs/how-to/use-with-claude-code.md:84still assertcodesmartis the default.choose-a-preset.mdis one of the four docs the orphaned comment in finding 3 names, so it was in view and skipped.
6. docs/setup.md:8-14 overstates its own evidence — claims CI removes the C compiler from PATH (it doesn't; CGO_ENABLED=0 is what does the work, and I confirmed CC is never consulted once cgo is off) and claims cross-compilation across four GOOS/GOARCH targets is asserted, when CI only builds native linux/amd64.
7. ci.yaml:78 names TestCtlGetCampaignAggregatesPredictedAndRealPerTenant as the flake with "see the issue linked below" and no link follows; the PR body separately names a different flake (TestConcurrentCallsDoNotRaceOnTheGateHistogram, #163). One of the two references is wrong — worth a one-line fix.
Not asking for, but noting
HasOffload() itself has no unit test inside ./components, only proxy-level integration coverage — cheap insurance for a method whose whole selling point is not rotting, but not blocking. Also: main has since gained #142, which also touches the preset tables finding 5 needs to fix — rebase before doing that pass so the two don't re-fix or re-break each other's work.
Fail-open holds: the new route forwards verbatim so there's nothing to fail open from, 502-on-unreachable matches every other route, counttokens.go:203-208 deliberately returns a fixed string rather than err.Error() so a *url.Error can't leak the operator's upstream address, and I found no panic path.
Requesting changes for 1-3; happy to see 4-7 as an immediate follow-up if you'd rather land the logic now and the doc pass separately.
None of this is distribution work. Every item is a defect in code or docs that already shipped, found while doing #141, and split out at review request so it can be judged on its own — and so it can land whether or not the funnel does. ## 1. The expand tool was advertised where no marker can exist `expand.Inject` under `auto` gated on "the request declares tools" and "the store persists". Nothing asked whether the pipeline could produce a `<<cg:HASH>>` marker at all, so an offloader-free pipeline declared `context_guru_expand` to the provider — and every call against it must fail, because there is nothing in the Store to resolve. Measured on the real gateway route: tools SENT by client : [Read Bash] tools FORWARDED upstream: [Read Bash context_guru_expand] Affected `safe` and any cachesplit-only configuration, and — the one that matters most — **`off`, the A/B control arm**. A control that carries an extra tool declaration is not a control, and every measurement taken against it was comparing two arms that differed by more than the pipeline. The cost when it fires is a wasted round trip and a step of the user's turn: on a transcript containing marker-shaped text (this repo's own docs contain literal `<<cg:HASH>>`), a model calls the tool and gets "[expand: original for id ... is no longer available]". It was also a code-vs-comment contradiction, which is why nobody noticed: `Options.InjectExpand` documented the gate as requiring "an expandable marker", while `expand/inject.go` says "No marker condition, deliberately" three lines from the code. Both now describe what happens. `components.Pipeline.HasOffload()` answers by TYPE ASSERTION, not a list of component names: a name list is a second copy of "which components are lossy" and drifts the moment somebody adds one. `components.Offload` cannot be implemented by accident — it requires returning cache keys proving the original was stashed. Marker independence is preserved (the property that keeps the tools array byte-stable across a session, and hence the prefix cached): a pipeline does not change turn to turn. **Ten existing tests changed fixture.** Every test of the expand loop hand-seeds the Store to simulate an offload, but built its handler with `pipeline: []` — which cannot offload anything. Harmless while injection ignored the pipeline; now they use `offloadCapablePipeline` (`[linecap]`, which does not act on their short bodies). No assertion was weakened; each fixture now matches its own premise. ## 2. `POST /v1/messages/count_tokens` was not served Absent it, a client asking how big its context is gets a 404 and falls back to working it out with **inference requests** — billed calls, caused by a proxy whose purpose is to reduce them. Cheap to add, and it costs every routed user, not only the funnel. Forwarded verbatim, with no pipeline. Returning the compacted count would be smaller and would be wrong in the dangerous direction: the client budgets its own transcript from this number, and because every component fails open, the next request could forward the full body and take a 400. Over-reporting is recoverable; under-reporting is a failed turn. The cost of that choice is now documented in `docs/reference/routes.md`, where the route was absent entirely — a routed session self-compacts earlier than it needs to (115,933 reported vs 32,802 forwarded on a measured body). The hosted branch has tests, because that branch is the only thing standing between the multi-tenant service and an unmetered open forwarder that would send OUR credential upstream. ## 3. Our own docs said the binary needs a C toolchain `docs/setup.md`, `docs/hosted.md` and `docs/get-started/quickstart-proxy.md` all told evaluators to install one. It is needed for `go test -race` and for the optional `cg_skeleton` tag, not for the binary. setup.md went further and named **bifrost's tokenizer** as a cgo dependency, which it never was — o200k_base is embedded (`internal/tokens/tokens.go`). Asserted rather than re-claimed: a new `purego` CI job builds with `CGO_ENABLED=0` and `CC=/nonexistent-c-compiler`, checks the artifact is statically linked, starts it and probes /healthz. It also runs the packages whose behaviour depends on which components compile in — because `build-test` runs exclusively with `CGO_ENABLED=1` (the race detector needs it), so `TestEveryPresetBuilds` had **never executed in the configuration a user would build**. That guard exists for exactly the `preset: coding` / `unknown component "skeleton"` breakage. ## 4. Preset facts stated outside the guarded files (#143, #145) - The binary defaults to **`house`**; five sites said `codesmart` (README x3, `docs/reference/config.md`, `docs/get-started/quickstart-proxy.md` — the last is step 2 of the first page anyone runs). Anyone running the binary bare while reading those measured a different configuration than the published SWE-bench numbers describe. - README's `codesmart`/`codesafe` pipeline lists and `docs/get-started/connect-ibm-service.md`'s "Default pipeline" were stale — naming `toon`, retired after acting 0 of 5,752 production requests, and omitting components that do run. The IBM page's omission of `toolfilter` matters most: that page is what a prospective hosted tenant reads to decide what the service does to their traffic. All regenerated from the `presets` map. The two tables inside #142's drift guard are untouched here; these are the sites that guard cannot reach. ## Verification Five mutations, each proven to have landed in the source before its result was allowed to count: expand injection ungated -> TestExpandToolIsAdvertisedOnlyWhereMarkersCanExist FAIL on cachesplit-only, `safe`, and `off` HasOffload always false -> same test FAIL on `mcp` and the offloader pipeline: "mints markers but no longer advertises the expand tool, so a model cannot recover what it offloaded" count_tokens route unregistered -> TestCountTokensIsServed FAIL (404) count_tokens rewrites the body -> TestCountTokensIsServed FAIL hosted auth removed -> TestCountTokensHostedRequiresAuth FAIL (502, want 401) The second is the mirror-image check: it proves the gate did not trade one silent defect for another, an offloader whose output nothing can expand. Two things I got wrong on the way, recorded because both were caught by tests rather than by me: - I first asserted `mcp` had no offloader. `smartcrush` implements `components.Offload` (`components/offload/smartcrush.go`), so that pipeline genuinely mints markers and genuinely needs the tool. The case now asserts the opposite, with the reason — and it is the argument for asking the interface rather than keeping a hand-written list. - Copying `proxy/proxy.go` wholesale from the older distribution branch onto current main silently reverted #155's `effPreset`/`notePreset` work. `TestCompactRowNamesThePresetThatRan` — a test I had never read — failed with "the dashboard names a pipeline that did not run". The file was restored from main and the two edits re-applied on top; #155's change is intact. `go build ./...`, `go vet ./...`, `gofmt -l` and the full `go test ./...` are clean. One unrelated flake seen once and not reproduced: `TestConcurrentCallsDoNotRaceOnTheGateHistogram` failed in a full-suite run with "no single-flight follower ran ... the race was never exercised", then passed 8/8 in isolation and in two further full suites, and passes on clean main. Reported separately rather than papered over. Assisted-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: DAVID AMID <DAVIDA@il.ibm.com>
The new job runs `go test` over five package trees, and `go test` starts up to GOMAXPROCS package binaries in parallel. On a 2-core CI runner that added a second heavily-parallel run of the proxy package per PR, and under that contention a timing-sensitive control-plane test from #150 (TestCtlGetCampaignAggregatesPredictedAndRealPerTenant) failed on two unrelated PRs — then passed on a re-run of the same commit, and passes 3/3 whole-package on a 16-core box against both main and the affected branch. Filed as #163. Hunting that flake is not this job's business. Not provoking it is: `-p 1` costs about a minute and removes the contention this job introduced, without dropping any coverage. Assisted-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: DAVID AMID <DAVIDA@il.ibm.com>
Review of #161 found the same defect this PR is themed on — claims that are not true — in seven more places, one of them in shipped code. All seven fixed, plus the `HasOffload` unit test the reviewer raised without asking for. Rebased onto current main first, so #142's preset-table guard and the preset pass below cannot re-fix or re-break each other. ## Merge-blocking **1. `proxy/proxy.go` named `mcp` as offloader-free.** It is not: `smartcrush` implements components.Offload, which this PR's own test asserts (`wantAdd: true`) and its own mirror-image mutation proves. I had corrected the test and left the comment wrong — the copy a future reader actually trusts. The fix deletes the list rather than correcting it. The comment now names the shapes affected (`off`, `safe`, any cachesplit-only configuration) and then says why enumerating presets here is the wrong move: a list in a comment is a second source of truth, and this one was wrong about `mcp` on its first draft. That is the whole argument for gating on the interface. **2. Five sites named the `cache` preset, which does not exist on this base.** It is #141's, and it reached here in the wholesale copy of `proxy/proxy.go` this PR already admits to, then travelled into the test files when they were split out of that branch. Reworded to name configurations that exist here; the underlying defect they describe is unchanged and still reproduces on `off` and `safe`. **3. `proxy/counttokens_test.go` carried copy-paste artifacts vet and gofmt cannot see.** A duplicated 3-line doc comment, and a 20-line orphan documenting a function that lives in `expandgate_test.go` under a different name and citing a test that exists nowhere. Both from the same cause: my splitter took each test's doc comment by scanning back to the previous blank line, which swallowed the FOLLOWING test's comment as a trailing block. A third artifact the review did not list is fixed too — `expandgate_test.go`'s doc comment still described "the preset's promise" and cited `docs/how-to/install-plugin.md` and an install skill, both of which belong to #160. ## The rest **4.** `docs/reference/config.md` and `docs/components.md` said `auto` injection has exactly two conditions. It has three. Both now say so, and say what the third is for. The cache-stability argument those passages make is unaffected — a pipeline does not change turn to turn either — so it gained a member rather than needing a rewrite. **5. `make build` now sets `CGO_ENABLED=0`.** The docs could claim "no C toolchain" all they liked while step 1 of the quickstart was `make build`, which needed one because the Makefile exported `CGO_ENABLED=1` for every target. Pointing readers at `build-static` would have fixed the sentence; making the DEFAULT build pure Go makes the claim true of the command the docs tell people to run. `CGO_ENABLED=1` stays for the test targets, where `-race` requires it, and the comment says exactly that. Verified: `CC=/nonexistent make build` produces a statically linked binary. README, CLAUDE.md and the quickstart no longer require a C toolchain. All five remaining `codesmart`-is-the-default sites are corrected — including two in `config/config.go`, which is how the claim spread to five documents: it sat three lines from the flag that disproves it. **6.** `docs/setup.md` overstated its own evidence, which is the exact sin this PR is about. It claimed CI removes the C compiler from `PATH` (with cgo off the toolchain never consults `CC`; that variable is a tripwire, not the mechanism) and that cross-compilation to four targets is asserted, when CI builds native linux/amd64 only. Now says what CI actually does, and states separately that the other three targets were verified by hand and are asserted at release time. Same overstatement fixed in the `ci.yaml` comment. **7.** `ci.yaml` promised a linked issue and linked nothing, and named a different flake than the PR body did. Both are real; the comment is about the campaign one, and now links #163. ## HasOffload unit tests `./components`: nil-safe, empty pipeline (the A/B control arm), reformatters-only, and an offloader in three positions. Revert-verified both ways — always-true fails the empty and reformatter cases, always-false fails the offloader cases. A registry-walking test was supposed to make it rot-proof, and **it skipped**: registrations happen in `components/all`, so a test inside `components` can neither see them nor import the package that does. A test that skips reads as coverage and is not, so it moved to `components/all`, where it runs — 21 of 21 registered components, 13 implementing Offload. It fails if either count is zero, because an all-false or all-true population would agree with a broken HasOffload. Full `go test ./...`, `go vet ./...` and `gofmt -l` clean; doc link/anchor checker re-run over every document touched. Assisted-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: DAVID AMID <DAVIDA@il.ibm.com>
e943ccb to
62234c3
Compare
|
All seven fixed, plus the Rebased onto current Merge-blocking1. The 2. 3. Should land4. Both sites now say three conditions, and say what the third is for. The cache-stability argument those passages make survives — a pipeline doesn't change turn to turn either — so it gained a member rather than needing a rewrite. 5. Both halves done, and the first one deserves a note because I changed behaviour rather than wording:
6. Corrected, and this one was the most deserved hit in the review — an evidence claim overstating its evidence, in a PR about exactly that. 7. The comment now links #163 (the campaign flake it actually describes). The PR body's #162 is a different test; both are real, the comment was pointing at the wrong one. The one you weren't asking for
I also wrote a registry-walking test to make it rot-proof, and it skipped, because registrations live in Full suite, |
Pulled out of #141 at review request: none of this is distribution work. Every item is a defect in code or docs that already shipped, found while building the funnel, and it can land whether or not the funnel does. #141 now contains only genuine distribution work and stacks on this.
What is here
context_guru_expandadvertised to pipelines that cannot mint a marker — includingoff, the A/B control armPOST /v1/messages/count_tokensnot served, so clients count context with inference requestssetup.mdnamed bifrost's tokenizer as a cgo dep, which it never washouse; five documented sites saidcodesmart. Stale pipeline lists in README and the IBM page (#143, #145)On #1 — the control arm is the part I would look at first.
expand.Injectunderautogated on "declares tools" + "store persists", and nothing asked whether the pipeline contained an Offload. Sooff— the passthrough baseline — forwarded an extra tool declaration, meaning every A/B taken against it compared two arms differing by more than the pipeline. Verified on the wire before fixing:[Read Bash]in,[Read Bash context_guru_expand]out.It survived because the code contradicted its own comment:
Options.InjectExpandclaimed a marker condition three lines fromexpand/inject.go's "No marker condition, deliberately". Both now say what happens. The gate asksPipeline.HasOffload()by type assertion, not a name list — a name list is a second copy of "which components are lossy" and rots on the next component added.Ten existing tests changed fixture, and that deserves a look. Every expand-loop test hand-seeds the Store to simulate an offload but built its handler with
pipeline: [], which cannot offload. Harmless while injection ignored the pipeline. They now useoffloadCapablePipeline([linecap], inert on their short bodies). No assertion weakened — each fixture just now matches its own premise.On #3, the claim is asserted rather than restated: a new
puregoCI job builds withCGO_ENABLED=0andCC=/nonexistent-c-compiler, checks the binary is statically linked, starts it, probes/healthz. It also runs the component-sensitive packages with CGO off, becausebuild-testruns exclusively withCGO_ENABLED=1(the race detector needs it) — soTestEveryPresetBuilds, the guard forunknown component "skeleton", had never run in the configuration a user would actually build.Verification
Five mutations, each proven to have landed in the source before its result counted, each failing the named test and passing when restored — full output in the commit body. The one worth naming is
HasOffloadalways false, which proves the gate did not trade the original defect for its mirror image: an offloader whose output nothing can expand.Two mistakes of mine that tests caught, not me:
mcphad no offloader.smartcrushimplementscomponents.Offload, so that pipeline really does mint markers and really does need the tool. The case now asserts the opposite with the reason attached — and it is the argument for asking the interface rather than maintaining a list.proxy/proxy.gowholesale from the older distribution branch onto currentmainsilently reverted fix(dash): report unpriced components in tokens, state the cache-frozen ceiling, and export the counters that only reached /stats #155'seffPreset/notePresetwork.TestCompactRowNamesThePresetThatRan, a test I had never read, failed with "the dashboard names a pipeline that did not run". I restoredmain's file and re-applied my two edits on top; fix(dash): report unpriced components in tokens, state the cache-frozen ceiling, and export the counters that only reached /stats #155 is intact and verified.One flake, reported not hidden
TestConcurrentCallsDoNotRaceOnTheGateHistogramfailed once in a full-suite run — "no single-flight follower ran ... the race was never exercised" — then passed 8/8 in isolation, in two further full suites here, and in a full suite on cleanmain. Unrelated to this change (nothing here touchesextract_llm), filed separately.Related
cachepreset, --idle-exit, and gateway conformance #141 — the distribution work, stacked on this. Merge this first.🤖 Generated with Claude Code