Repository navigation
fix(kv-unified): a label-ceiling hit no longer fails the compile (#252) - #271
Merged
Merged
Conversation
…ma-research#252) The label ceiling bounds a search, but nothing between the solver and compile() caught SparseLabelCeilingError, apart from the joint latent-demand solve's own catch, so a search past it failed the turn: the live solve on any engine a recipe names, and on the default once the packed retry exceeded it too, and an optional what-if even where the live cut fit, in individual and joint mode alike (the joint's catch falls back to the individual ranking, which threw). - The live solve: past the ceiling, the compile takes the minimum-token cut, which the solve's feasibility check computes before any search, scored as any cut is, and demands no merge, since demand is gated against the policy's best cut. It fits whenever the wall can be met, and it becomes the carried layout, which the next compile's certificate or search judges as any other. The solver itself still throws: the fallback is the strategy's, for its live solve. - A latent-demand search past the ceiling measures nothing, and each place one runs keeps what's already shown: a conservative what-if's candidate isn't demanded, as one with no feasible cut isn't; a certified what-if whose re-solve without the certificate is stopped stands at its certified gain, as when that re-solve scores worse; a stopped expected-cost solve leaves the conservative gain to order its request; and a stopped joint forest has its candidates ranked one at a time, as before. - A stopped search's holder remembers its failure under a digest of the inputs that decide the label count and the search's certificate flag, so the next compile on the same inputs doesn't run it again; the joint forest records which of its two searches stopped. The joint's field and signature are now one for both (ceilingFailure, ceilingFailureSignature). The digest takes each number whole and each leaf's owning L1, where the joint's kept a number to 1/1024 and left the L1 out, and it's made only when a failure is read or written, where the joint ranking made it at every compile with candidates. A joint set of one candidate runs the same searches as that candidate's own what-ifs, so one stopped in either isn't run again in the other. The digest also holds whether the compile uses the certificate, as the joint's did, so a joint search stopped in a compile without it isn't taken for a settling search's stop by a compile with it. - The base solve without the certificate, which a merge that passes the gate against the certified base is decided against: past the ceiling, no merge is demanded that compile. In the joint ranking its error went to the joint's catch and was remembered as the joint forest's failure; now the joint's catch sees only the joint forest's own. - What the ceiling stopped is reported: KvUnifiedStrategy's lastTimings.ceiling (live hit with ceiling, labels and engine; joint; gate; individual what-ifs stopped or skipped as remembered), `ceiling=` on [plan-vs-actual] and in its stats (ceilingMark), and onCeilingFallback, through which an AutobiographicalStrategy warns of its first fallback, in whichever pick it happens, where the operator reads, naming the ceiling, the labels the search stopped at and the engine ('packed, after subtree' on the default). labelCeiling's config doc says what a hit does. A compile whose searches stay within the ceiling is unchanged: each changed path catches the error that failed the compile before, and the digest isn't made there. Tests: test/adaptive/kv-unified-ceiling.test.ts (the live fallback on each of the five engine settings, with the solver's own label count; the solver still throwing; what-ifs stopped with the rest demanded in both modes; the remembered failure through a third compile on one reused strategy, with a changed salience, owning L1 or ceiling as a new question; a joint set of one; the base re-solve in both modes; an error other than the ceiling's at each catch, with the joint holder left unstamped; a reused strategy's report; the mark), kv-unified-strategy-integration (a compile whose solver throws the ceiling error compiles, warns once across two compiles, and marks both plan lines), and kv-unified-policy (a stopped re-solve's entry stands at its certified gain at every compile, as when it scores worse; a stopped expected-cost solve leaves its request ordered by the conservative gain; a joint settling solve that's stopped is remembered as that search alone; and a joint failure remembered from a compile without the certificate is a new question for one with it; the certified what-if fixture gains maxCandidates). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
[Medium impact] The PR appears safe to merge; no actionable issues were found. SummaryMakes
No actionable issues found. Validation was limited to source and test review; tests were not run. Intentional choices acknowledged by Reviews (1) · Last reviewed commit: "fix(kv-unified): a label-ceiling hit no ..." · Reviewed by Greptile |
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.
Fixes #252. A kv-unified search that exceeded
labelCeilingfailed the compile, on the live solve and on an optional latent-demand search alike. With this change the ceiling bounds the search and the compile goes on. A live solve past it takes the minimum-token cut. A latent-demand search past it measures nothing, and the demand goes on with what the searches that fit showed. When the base's solve without the certificate exceeds it, no merge is demanded that compile. Each is reported, and a host is told of a live fallback. A compile whose searches stay within the ceiling is unchanged.Problem
On the live pick's way to
compile(), only two places catchSparseLabelCeilingError: the solver's own retry of the subtree engine on the packed one, and #229's catch around the joint latent-demand solve.Picker.runandselectAdaptivedon't catch it, andselectPathcatches onlyOverBudgetError. Probed onmain6d4abae7on Linux, under Bun 1.4.3 with chronicle 0.4.0, on six leaves each under its own L1 (the fixture of the joint-failure tests):engine: 'subtree','dag',storage: 'objects'andengine: 'leaf'. The default's retry on the packed engine doesn't help there, because the packed engine peaks at the same 27 labels per state.latentDemand.modeindividualorjoint. In joint mode the joint solve fails, its catch falls back to the individual ranking, and that ranking throws.adoptEpsilon100, the certificate answers the live solve at a ceiling of 1, with no label search. With latent demand on, the what-ifs then search and throw at every ceiling tried up to 60.compile()throws it to its caller. AContextManager.compile()whose solver throws the error throws it.Changes
KvUnifiedStrategy.solvecatches the error from its live solve and takes the minimum-token cut.ParetoKvUnifiedPolicySolver.solve's feasibility check computes that cut before any search (forest.minimumTokens), andExactKvUnifiedPolicySolver.scoreCandidatesscores it as any cut is scored. It fits whenever the wall can be met. No merge is demanded after it, since demand is gated against the policy's best cut. The solver itself still throws, so its direct callers and the subtree engine's tests see what they did.reuse, as autobiographical's is.KvUnifiedReuse.jointFailurebecomesceilingFailure, andjointFailureSignaturebecomesceilingFailureSignature.main's joint signature kept a number to 1/1024, so near inputs shared a digest, and left the L1 out. It's made only when a failure is read or written, wheremain's joint ranking made it at every compile with candidates.KvUnifiedStrategy.lastTimings.ceilingholdslive(the ceiling, the labels the search stopped at, and the engine whose search that was),joint,gateandwhatIfs(individual what-if searches stopped in this compile or skipped as remembered).[plan-vs-actual]and its stats carryceiling=(live,joint,gateandwhatIfs:N, joined by+, from the newceilingMark) when the ceiling stopped something in the compile's final pick.KvUnifiedOptions.onCeilingFallbackis called on a live fallback.AutobiographicalStrategyuses it to warn of its first fallback, in whichever pick it happens, through its diagnostics:[kv-unified] labelCeiling 10000 exceeded at 10001 labels (engine: packed, after subtree); that solve took the minimum-token cut, ….labelCeiling's doc in the recipe'skvUnifiedtype says what a hit does.What each part is for
The minimum-token cut. Something has to stand in for the policy's cut. This one is already computed, always fits when the wall can be met, and needs no new code to build or check. It is the design's guaranteed feasible incumbent (
docs/unified-solve-design.md§4.2), which §4.4 keeps as the hard-budget guarantee while the ceiling is the solver's only bound. Its price is the policy's most-folded cut while the ceiling binds. Its first compile rewrites the cache from the first changed unit. It then becomes the carried layout, which the next compile's certificate or search judges as any other. Two alternatives were priced and left out:currentResolution) changes nothing while it fits the wall. But the forest has no check that given levels form a cut the solver would produce, around pinned holes and summaries made since, and it is the cut the certificate has just declined.Under connectome-host's standard block, a probe of ours measured peaks of 4 to 43 labels per state, on one forest shape, against a ceiling of 100,000. A live hit there means the recipe's ceiling or grid is wrong for its forest, and the warning tells its operator.
No demand after a fallback. A merge's gain would be measured against a cut the policy didn't choose.
What each latent-demand search leaves standing. Each is optional, so the compile goes on without it, and each place keeps what's already shown. Without a conservative what-if there's no gain to demand on. A certified pool is a real layout, so its gain is a floor, and dropping the entry would lose a merge whose floor may already pass the gate. The expected-cost solve only orders requests the gate has passed, so dropping the request would lose a merge for want of its order.
The remembered failure. Without it, each compile on the same inputs would run the search up to the ceiling again for each stopped search. A compile on changed inputs, as after a new message, still pays it. It reuses the joint's signature and field rather than adding a second.
This compile's holder first. One lookup, for a joint set of one candidate, whose searches are the candidate's own.
The gate's base. Without the solve without the certificate, a merge passing against the certified base could be worth less than
adoptEpsilonagainst the best cut, which is why that solve exists. So without it, nothing is demanded.The report and the warning. The timings and the plan line say what each compile went without. The warning is said once per strategy, where an operator reads, since a change of the recipe is the remedy in the operator's hands. A dry run, a production-budget shadow pick or an attempt a retry replaces can be the first to meet the ceiling, so its words name the solve, not the compile.
KvUnifiedStrategyis built anew for every compile, soonCeilingFallbacklets the warn-once state live on theAutobiographicalStrategythat outlives it, and keeps diagnostics out of the solver adapter.ceilingMarkis the mark's one formatter, for the plan line and the stats.The engine's name tells the operator which engine's peak the ceiling met: on the default, the packed retry's, after the subtree engine's.
The tests' fixtures and helpers. The new test file's six leaves are the joint-failure tests' fixture, under a grid and wall where the live solve and the what-ifs peak at known counts, so a ceiling can stop one and not another.
certifiedBasebuilds the carried layout the certificate proves, which the gate's test and the reused-strategy and error tests share. The certified what-if tests reusetest/adaptive/kv-unified-policy.test.ts's certified what-if fixture, which gainsmaxCandidatesfor a joint set of one.latentCandidates/isWhatIfandlatentRecalltell a mocked solve which search it is (the live solve or the base, a what-if, the joint forest, or a what-if at a recall cost), so a test can stop exactly one search, or count the solver's own calls.The fragment says what hosts and operators will notice.
Cut. The coarser grid and the carried layout (above), a separate field for an individual what-if's failure, and a memo for the live solve and the gate's base.
The cache
A compile that succeeds on
maingets the same cut and the same requests after this change. That's a reading: each changed path catches the error that failed the compile onmain, and the probes above show each throw there. The digest is made only where a failure is read or written, so within the ceiling it isn't made at all. A differential run at this head agrees. It droveKvUnifiedStrategyonmainand on this change over 300 seeded forests of 8 to 12 leaves, under a ceiling of 1,000,000, with the pins, presentation, receipt, grid, wall,adoptEpsilonand certificate drawn at random. Each forest ran in individual and joint mode, two compiles each on one reuse holder. In all 1,200 compiles the frontier, the demanded merges,demandSolves,lastTimings.ceilingand each evaluation's gains andapproximateflag were identical. 964 of them ran latent-demand searches, 40 demanded merges, and none reported a ceiling. A compile that would hit the live ceiling now gets the minimum-token cut where it got an error.Tests
At this head on
main6d4abae7, on Linux with Node 24.22.0 and chronicle 0.4.0 from the lockfile (npm ci):npm run buildis clean, andnpm testpasses 2,397 of 2,397, fourteen of them new.main's CI at6d4abae7ran 2,383.main's four changed source files under these tests, tests 1, 3 to 6, 8 and 10 to 14 below fail on the ceiling error itself. Tests 2 and 7 pass there too, as controls: they pin whatmainalready does, the solver's own refusal and an error other than the ceiling's failing the solve. Test 9 tests the newceilingMark, which its file imports, so that file ran onmain's code with a stub of it that returns nothing. Two earlier joint-memo tests fail there only because they read the renamed field.onCeilingFallbacknot called, or the live hit not reported: tests 1 and 10, and 8 for the report;joint,gateorwhatIfs: test 9;instanceof SparseLabelCeilingErrorguard taken out, at any of the four catches, or the joint stamping its holder for any error: test 7.88bb07ca), fix(images): image ceilings for the live window and compression prompts #268 (a0efb9ff), fix(tool-pruning): price replaced tool results and truncated inputs as sent, from one decision over the conversation #249 (ddcf09c6) and chore(deprecate): ContextInjection and compile(injections) #140 (cc1e7e71) merged cleanly with this change and with each other, and with all of them in,npm testpassed 2,464 of 2,464. Every other open pull request already conflicts withmain, and its conflicts are the same with this change in, except fix(kv-unified): hold a level pin at the deepest level its chain supplies until the pinned level exists (#193) #213's. This change addsceilingMarktosrc/strategies/autobiographical.ts's import from../adaptive/strategies/kv-unified.js, and fix(kv-unified): hold a level pin at the deepest level its chain supplies until the pinned level exists (#193) #213 adds an import on the line after it, so the two meet there.The new tests, in
test/adaptive/kv-unified-ceiling.test.ts(1 to 9),test/kv-unified-strategy-integration.test.ts(10) andtest/adaptive/kv-unified-policy.test.ts(11 to 14):onCeilingFallbackonce.Not verified
KvUnifiedStrategy.Out of scope
[plan-vs-actual], the line this change marks withceiling=.docs/unified-solve-design.md§4.4, which that section makes a pilot gate for a ceiling that's routinely reached. Under connectome-host's standard block it isn't, by the peaks above.mainfor the forest and the joint memo. Where both stop on one candidate under different walls, each restamps its holder, so the memo saves nothing between them. It never skips a search wrongly, since the wall is in the digest.changelog.d/252-label-ceiling.fixed.md— Hilda-2580 (Claude Opus 5.5). Oscar-1005 (Claude Opus 5.5) placed the issue with me and chose the live fallback and its warning. Ezra-2423 (Claude Opus 5.5) read the change and wrote and ran the differential. Esther-2584 (Claude Opus 5.5) measured the label peaks under connectome-host's standard block. An internal review read it as well.
Description checked and posted by Fiona-2757 (Claude Opus 5.5).
🤖 Written using Anthropic's Claude Opus 5.5 through the Rookery's tooling.