Repository navigation
fix(cap): epoch 3's bound covers per-block rounding, and the cut's estimate reads its argument - #236
Merged
Conversation
…imate reads its argument, and anima-research#227's entry drops a claim Follow-ups to anima-research#227 from its maintainer review, and from a review of this change. - Epoch 3's predicate asked whether a message's estimate could have passed the cap plus 50 at the clamp's ceiling of 1.8 by scaling the store's estimate at the applied multiplier. The store rounds each top-level block's estimate on its own, so a message of many small blocks could pass the cap plus 50 at a multiplier of 1.8 or under while the scaled estimate stayed under it. 83 one-character blocks estimate at 83 at a multiplier of 1, and 1.8 times that is 149.4, under 150 at a cap of 100, but at 1.75 each rounds to 2, 166 in all, which the old price limited. A store holding such a message kept a multiplier learned where that message was under-priced. The bound now adds half a token a block before reading the estimate back from the applied multiplier, for that estimate's rounding, and half a token a block after, for the rounding at the ceiling, so with the multiplier the store estimates at it is never under the estimate at the ceiling. Where it errs, it errs high, by less than 1 + 1.8/F tokens a block, toward a discard. - The predicate read the applied multiplier as 1 where the view doesn't report it as a positive number, so over a store running below 1 the bound could fall under the estimate at 1.8: 26 blocks of three characters at 0.6 estimate at 26 there and 104 at 1.8, past 100 at a cap of 50, while the bound read at 1 is 83.2. The strategy applies only multipliers from 0.6 to 1.8, so an unreported one is read at 0.6, which keeps the bound above the estimate at 1.8 for whichever it applied. Over a store at 1 that puts the bound at about three times the message's estimate, so such a view's store is counted for a message well under the line. - cappedForSend gave the cut an estimate that ignored its argument, the stored message's cached one. The default cut asks about the content it was handed, the message's own, so nothing changed there. But an override of truncateContent that rewrote the content and passed it on to this class's cut, with the estimate it was given, had the cut decide from the stored message's estimate, so a rewrite past the cap went out whole. The estimate is now the message's cached one for its own content, and the rewrite's otherwise. - anima-research#227's pending changelog entry said every message a cap such as 10,000 cuts sends more than the cap plus 50. Prose cut there estimates at 13,808 at a multiplier of 1 and 9,942 at 0.72, so under about 0.73 it prices under 10,050, and many small blocks, which the store rounds one by one, or a long whitespace block, which ends the cut early, can price under it too. The entry now gives the figures instead: a prose block cut at 10,000 does above a multiplier of about 0.73, and a string tool result cut there does at any the clamp allows. Its epoch bullet says a view that doesn't report its multiplier is read at 0.6. - Tests: the predicate's stub store rounds each block, as MessageStore does; the 83-block case, and one at an applied multiplier of 1.2 that each half of the bound's rounding decides. A sweep over messages of equal text blocks that the cut's test leaves, across block sizes, counts, caps, and applied multipliers from 0.6 to 1.8 in steps of 0.05, asserts that the bound counts every message whose estimate at the ceiling passes the cap plus 50, and none under that line by 1 + 1.8/F tokens a block or more. A view with no getter, or one reporting NaN, 0, -1 or Infinity, is read at 0.6. In each autobiographical selection, an override's rewrite passed on to the cut is cut by its own estimate, whether it adds a block or keeps the count, and a compile under a cap estimates only the stored message objects themselves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Required label not found on this PR. |
1 task done
tel-0s
added a commit
that referenced
this pull request
Oct 19, 2026
… the capped-price epochs What main brings since 075dde4: #242, a body's joined raw run in the middle counted as the shards it joins; #237, the fold-journal layout-delta rounds drawn from a sound generator; #236 and #227, the capped price's epoch-3 bound and the cut's estimate; #183, the cached-input total and the membrane requirement as a breaking entry. No conflicts: src/types/strategy.ts auto-merged. Nothing here touches derive() or the branch-bound views. Build and test on the composed rig: 1962 tests, 1962 pass, 0 fail. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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.
Follows #227. slimepriestess's review of #227 found two places where its code is looser than its text. A review of this change found two more: how epoch 3 reads a multiplier the store's view doesn't report, and a clause of #227's changelog entry.
Problem
cappedForSend's estimate ignores its argument. It passestruncateContent() => this.estimateTextOnlyTokens(msg), the stored message's cached estimate, whatever content the cut asks about. The default cut asks once, about the content it was handed, the message's own, so nothing goes wrong there. An override oftruncateContentthat rewrites the content and passes the rewrite on tosuper.truncateContent(rewritten, maxTokens, estimate)has the cut decide from the stored message's estimate instead: a short message that the override lengthens past the cap goes out whole.Changes
1.8 × (E + n/2) / F + n/2passes the cap plus 50, where it asked whether1.8 × E / Fdid. A view that doesn't report its multiplier as a positive finite number is read at 0.6, where it was read at 1. The cut's own condition, the predicate's other half, is unchanged.cappedForSend's estimate. It gives the message's cached estimate when the cut asks about the message's own content, and an estimate of the content it's given otherwise.truncateContent's doc says an estimate it's given is for the content it's called with.What each part is for
(E + n/2) / Fis at least the blocks' unrounded sum. At 1.8 each block's rounding adds at most half a token more. So, with the multiplier the store estimates at, the bound is never under the estimate at 1.8. That's the largest the old price could have met, since the clamp kept the multiplier at 1.8 or under and a block's rounded estimate only grows with it.main, sets one.MessageStore's reports its multiplier, as the wrappers inmessage-view.tsdo for a view that does.computeTextOnlyTokensthere, which stringifies each tool call's input.What a host notices
mainsince fix(cap): price a capped message as it renders (#223) #227 merged has one. If a release does before this lands, a store it stamped that holds a message fix(cap): price a capped message as it renders (#223) #227's predicate missed can keep a multiplier that runs high, by about that message's few tokens a block as a share of its window. A new epoch would make every store holding capped content recalibrate a second time.truncateContentoverride that passes a rewrite on to this class's cut now has the rewrite cut where it passes the cap. agent-framework's and connectome-host'smaindon't override it.Changelog
No new fragment. This changes only behaviour #227 added, which no release carries yet, and it corrects #227's pending entry as above. The rest of that entry holds for this change. The predicate now counts every store the entry says the epoch discards, and a store with no cap keeps its multiplier. A store the bound counts beyond those, behind a view that reports its multiplier, holds a message within the bound's error of the cap plus 50. The changelog check asks for a new fragment, so the PR takes the
no-changeloglabel.Tests
calibration-band:MessageStoredoes.capped-message-price, in each autobiographical selection:MessageStoreandcapContentgive the figures above. The stub's agree for all three block cases: 83 one-character blocks estimate at 83 at a multiplier of 1, and at 166 at 1.75 and at 1.8. 26 blocks of three characters estimate at 26 at 0.6 and 104 at 1.8. 39 blocks of four estimate at 78 at 1 and at 1.2, and 156 at 1.8. The predicate counts each, at the multiplier its case applies, against the store's own view.88e36668's tree,a6e04679, from a clean checkout, the typecheck and the build are clean andnpm testpasses 1,937 of 1,937.main'sautobiographical.tsand this head's tests:calibration-band, the predicate's test, the sweep and the unreported multiplier's test fail;capped-message-price, the six rewrite tests fail. The three counting tests pass, asmainestimates the message's own content from its cache too.cappedForSend's estimate as fix(cap): price a capped message as it renders (#223) #227 has it: the six rewrite tests;Not verified
— Greta-2425 (Claude Opus 5.5). Weft, for slimepriestess, found the first two in their review of #227, and Duncan-2410 (Claude Opus 5.5) had named the rounding edge reading #227's last round and read this change. A review of this change found the changelog clause and the unreported multiplier. Oscar-1005 (Claude Opus 5.5) agreed the design. Description checked and posted by Fiona-2757 (Claude Opus 5.5) through the shared
nissa-seruaccount.🤖 Written using Anthropic's Claude Opus 5.5 through the Rookery's tooling.