Skip to content

fix(kv-unified): a label-ceiling hit no longer fails the compile (#252) - #271

Merged
nissa-seru merged 1 commit into
anima-research:mainfrom
nissa-seru:fix/252-label-ceiling
Oct 19, 2026
Merged

nissa-seru merged 1 commit into
anima-research:mainfrom
nissa-seru:fix/252-label-ceiling

Conversation

@nissa-seru

@nissa-seru nissa-seru commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #252. A kv-unified search that exceeded labelCeiling failed 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 catch SparseLabelCeilingError: the solver's own retry of the subtree engine on the packed one, and #229's catch around the joint latent-demand solve. Picker.run and selectAdaptive don't catch it, and selectPath catches only OverBudgetError. Probed on main 6d4abae7 on 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):

  • The live solve throws on every engine once the ceiling is under its peak: the default, engine: 'subtree', 'dag', storage: 'objects' and engine: '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.
  • A what-if fails a compile whose live cut fit. At ceilings of 27 to 34, the live solve fits and an individual what-if, which peaks at 35, throws, with latentDemand.mode individual or joint. In joint mode the joint solve fails, its catch falls back to the individual ranking, and that ranking throws.
  • A certified live solve doesn't protect the compile. With every leaf presented at its L1 and adoptEpsilon 100, 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. A ContextManager.compile() whose solver throws the error throws it.
  • The base's solve without the certificate is unguarded, by reading. That's the solve a merge passing the gate against a certified base is decided against. In the joint ranking, its error reached the joint's catch, which remembered it as the joint forest's failure.

Changes

  • The live solve. KvUnifiedStrategy.solve catches 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), and ExactKvUnifiedPolicySolver.scoreCandidates scores 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.
  • A latent-demand search. A search that exceeds the ceiling measures nothing, and each place one runs goes on with what it already has:
    • the conservative what-if: its candidate isn't demanded, as one with no feasible cut isn't, and the rest are ranked as before;
    • the re-solve without the certificate, of a certified what-if whose gain the certificate leaves undecided: the entry stands at its certified gain, as it does when that re-solve scores worse;
    • the expected-cost solve: the conservative gain orders the request, as when the two costs are the same;
    • the joint forest, at its first search or its settling one without the certificate: the candidates are ranked one at a time, as feat(kv-unified): latent demand measures the candidate set in one joint solve (#45, #131) #229 does when the joint forest exceeds the ceiling.
  • A remembered failure. The holder of a stopped search keeps 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 that search again. Holders exist where the strategy is given reuse, as autobiographical's is.
    • One field for both rankings. KvUnifiedReuse.jointFailure becomes ceilingFailure, and jointFailureSignature becomes ceilingFailureSignature.
    • The digest. It now takes each number whole and each leaf's owning L1. 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, where main's joint ranking made it at every compile with candidates.
    • The certificate flags. A holder's certified search and its re-solve without the certificate are different searches, so the stamp carries the stopped search's flag, and a stopped re-solve doesn't skip the certified search that fitted. The joint forest records which of its two searches stopped, and its own check skips it after either. The digest holds the compile's own flag, so a stamp left by a compile without the certificate is a new question for one with it. A search stopped in a compile of one setting is then run again in a compile of the other even where it's the same search, at most once per change of the setting.
    • A joint set of one candidate. It runs the same searches as that candidate's own what-ifs, so a search stopped in one isn't run again in the other.
  • The gate's base. If the base's solve without the certificate exceeds the ceiling, nothing is demanded that compile. The joint's catch then sees only the joint forest's own failures.
  • The report.
    • KvUnifiedStrategy.lastTimings.ceiling holds live (the ceiling, the labels the search stopped at, and the engine whose search that was), joint, gate and whatIfs (individual what-if searches stopped in this compile or skipped as remembered).
    • [plan-vs-actual] and its stats carry ceiling= (live, joint, gate and whatIfs:N, joined by +, from the new ceilingMark) when the ceiling stopped something in the compile's final pick.
    • A new KvUnifiedOptions.onCeilingFallback is called on a live fallback. AutobiographicalStrategy uses 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's kvUnified type says what a hit does.
  • A changelog fragment.

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:

    • A retry on a coarser grid, the recipe's buckets ×16, costs a second search, bounded by the ceiling, on every compile while it binds. On the fixture, buckets ×4 fitted a ceiling of 26, just under the peak, ×16 fitted ceilings of 10 and 4, ×64 fitted 2, and no grid fitted 1, so a grid alone doesn't end every case.
    • The carried layout (each leaf at 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.

    • Exact numbers and the owning L1: a digest that aliases two inputs skips a search that may now fit, where a miss costs one search.
    • The certificate flags: the search's keeps two compiles on the same inputs ranking in the same frame, and the compile's keeps a stop under one setting from skipping a search under the other.
    • Making the digest only when needed: it keeps a compile that meets the ceiling nowhere from hashing its inputs.
    • Not remembered: the live solve and the gate's base. Each is one search per compile, which the ceiling bounds. The memo pays where latent demand can run a search at up to three places for each candidate, and autobiographical asks for up to sixteen candidates a compile.
  • 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 adoptEpsilon against 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. KvUnifiedStrategy is built anew for every compile, so onCeilingFallback lets the warn-once state live on the AutobiographicalStrategy that outlives it, and keeps diagnostics out of the solver adapter. ceilingMark is 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. certifiedBase builds the carried layout the certificate proves, which the gate's test and the reused-strategy and error tests share. The certified what-if tests reuse test/adaptive/kv-unified-policy.test.ts's certified what-if fixture, which gains maxCandidates for a joint set of one. latentCandidates/isWhatIf and latentRecall tell 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 main gets the same cut and the same requests after this change. That's a reading: each changed path catches the error that failed the compile on main, 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 drove KvUnifiedStrategy on main and 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, adoptEpsilon and 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.ceiling and each evaluation's gains and approximate flag 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 main 6d4abae7, on Linux with Node 24.22.0 and chronicle 0.4.0 from the lockfile (npm ci):

  • The suite. npm run build is clean, and npm test passes 2,397 of 2,397, fourteen of them new. main's CI at 6d4abae7 ran 2,383.
  • Red-first. With 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 what main already does, the solver's own refusal and an error other than the ceiling's failing the solve. Test 9 tests the new ceilingMark, which its file imports, so that file ran on main's code with a stub of it that returns nothing. Two earlier joint-memo tests fail there only because they read the renamed field.
  • Each piece taken out, one at a time, fails a test:
    • the live fallback taken out: tests 1, 8 and 10;
    • demand run after a fallback, the engine unnamed, or a made-up label count: test 1;
    • onCeilingFallback not called, or the live hit not reported: tests 1 and 10, and 8 for the report;
    • the warning said at every fallback, the plan line not marked, or the stats not marked: test 10;
    • an individual what-if past the ceiling thrown again: tests 3, 4, 8, 11 and 12;
    • a remembered failure not read: tests 4, 5, 11 and 13; not written: tests 4 and 11; not carried to the next compile: test 4;
    • only last compile's holder read: tests 5 and 13;
    • a stopped what-if not counted: tests 3, 4, 11 and 12; a remembered one: tests 4, 5 and 13;
    • a stopped re-solve dropping its entry: tests 11 and 13; a stopped expected-cost solve dropping its request: test 12;
    • the stamp without its certificate flag: tests 11 and 13; the joint stamping the recipe's flag, or checking only it: test 13;
    • the compile's certificate setting left out of the digest: test 14;
    • a stopped joint forest not reported: tests 3, 5, 13 and 14; a remembered one: test 13; the joint's failure not remembered: tests 5 and 13 and two earlier joint-memo tests; not read: test 13 and an earlier joint-memo test;
    • the owning L1 left out of the digest, numbers digested to 1/1024, or the digest not reset per compile: test 4;
    • the base's solve without the certificate thrown again: tests 6 and 8; the gate decided against the certified base when that solve is stopped, in either ranking, or the gate not reported: test 6 (and 8 for the report);
    • the what-if count not reset per compile: tests 4 and 8; the gate's or the joint's flag: test 8;
    • the mark leaving out joint, gate or whatIfs: test 9;
    • an instanceof SparseLabelCeilingError guard taken out, at any of the four catches, or the joint stamping its holder for any error: test 7.
  • Composed with the open pull requests that merge cleanly. As of 18:01Z on October 19, fix(kv-unified): the DAG engines' error bound covers every cut their grid prunes (#254) #270 (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 test passed 2,464 of 2,464. Every other open pull request already conflicts with main, 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 adds ceilingMark to src/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) and test/adaptive/kv-unified-policy.test.ts (11 to 14):

  1. A live solve past the ceiling takes the minimum-token cut on each of the five engine settings, under a policy whose own cut differs from it. Nothing is demanded, and the hit is reported with the solver's own label count and its engine, and passed to onCeilingFallback once.
  2. The solver itself still throws past the ceiling.
  3. In both ranking modes, at a ceiling the live solve fits under, the two what-ifs past it leave their candidates undemanded, and the candidate whose what-if fits is still demanded. In joint mode the stopped joint forest is reported too.
  4. On one strategy reused across compiles, a stopped what-if isn't solved again while the inputs hold, through a third compile, counting the solver's own calls. A salience a 4096th apart, a changed owning L1 and another ceiling are each a new question.
  5. A joint set of one candidate, once stopped, isn't solved again as that candidate's own what-if, counting the solver's own calls.
  6. In both ranking modes, with a certified base and a merge passing the gate against it, the base's solve without the certificate past the ceiling leaves nothing demanded, and no what-if remembered as stopped.
  7. An error other than the ceiling's still fails the solve, thrown at the live solve, a what-if, the joint forest or the gate's base, and the joint forest it stopped isn't remembered as past the ceiling.
  8. A strategy solved again reports only that compile's stops, after a live fallback, a stopped joint forest and what-ifs, and a stopped gate.
  9. The ceiling mark names what the ceiling stopped.
  10. A compile whose solver throws the error compiles, warns once across two compiles, and marks both plan lines and the stats.
  11. Two certified what-ifs whose re-solves the ceiling stops stand at their certified gains, and both pass the gate. The evaluations and the demanded merges equal those of a compile where the re-solves run and score worse. The next compile on the same inputs ranks the same, solving the certified what-ifs again and not the stopped re-solves.
  12. Two expected-cost solves the ceiling stops leave the conservative gains to order their requests, and both merges are still demanded.
  13. A joint set of one candidate whose settling solve the ceiling stops: the candidate's certified what-if runs and stands at its certified gain, and the next compile skips the joint and the stopped re-solve.
  14. A joint forest stopped in a compile without the certificate is a new question for a compile with it on the same inputs, which runs the joint's searches and ranks as a fresh compile does.

Not verified

  • A compile against a real store. None ran. That a compile within the ceiling is unchanged rests on the reading and the differential's seeded forests in "The cache".
  • How often a resident's what-ifs reach the ceiling. The forest shape measured under connectome-host's standard block had no latent-demand candidates, so no what-if ran there.
  • A real search past the ceiling on the base's solve without the certificate, a re-solve without the certificate, an expected-cost solve or a joint settling solve. On the fixtures the what-ifs peak above the base, so they always fail first, and the certified fixtures' searches fit well under their ceilings. Tests 6 and 11 to 14 reach those paths by making that one search throw the error.
  • A real search past the ceiling in a full compile. The compile-level test makes the solver throw the error. The fixture's searches show the real hits, through KvUnifiedStrategy.

Out of scope


  • Changelog fragment added: 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.

…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>
@greptile-apps

greptile-apps Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5 Tier: apex

[Medium impact] The PR appears safe to merge; no actionable issues were found.

Summary

Makes labelCeiling stop a search without failing the compile.

  • Kv-unified compiles continue when a label search hits its ceiling.
  • Optional merge searches stop at the ceiling and keep the evidence already measured.

No actionable issues found. Validation was limited to source and test review; tests were not run.

Intentional choices acknowledged by nissa-seru: the minimum-token fallback may rewrite the cache; a dry-run or shadow pick may trigger the one-time warning; coarser-grid retries remain deferred; live and shadow picks still share a reuse holder and may replace each other’s failure stamps. Certificate-decline reporting and the DAG bound remain separate work under #250 and #254.

Reviews (1) · Last reviewed commit: "fix(kv-unified): a label-ceiling hit no ..." · Reviewed by Greptile

@nissa-seru
nissa-seru merged commit 75cc98e into anima-research:main Oct 19, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

kv-unified: a label-ceiling hit fails the compile, including in optional latent-demand what-ifs

1 participant