Changelog
All packages in the fixed group release in lockstep with identical versions; @rulvar/compat is versioned independently. The sections below mirror each package's CHANGELOG.md as written by Changesets.
@rulvar/anthropic
1.252.0
Patch Changes
- Updated dependencies [3ccb6cf]
- Updated dependencies [52d807f]
- Updated dependencies [517ed00]
- Updated dependencies [a7e589d]
- Updated dependencies [76e95eb]
- @rulvar/[email protected]
1.251.0
Patch Changes
- Updated dependencies [e7e829c]
- Updated dependencies [5982be8]
- Updated dependencies [7c58fb2]
- Updated dependencies [b3e465a]
- Updated dependencies [c4e5d6a]
- Updated dependencies [c6fc3da]
- Updated dependencies [c6fc3da]
- Updated dependencies [0ae8b85]
- Updated dependencies [7932936]
- Updated dependencies [7932936]
- Updated dependencies [88da0ed]
- Updated dependencies [06c0e85]
- @rulvar/[email protected]
1.250.0
Patch Changes
- Updated dependencies [0e240b9]
- Updated dependencies [6fe585e]
- Updated dependencies [c5eb19c]
- Updated dependencies [565c13b]
- Updated dependencies [c6d197b]
- Updated dependencies [c9d9729]
- Updated dependencies [fed9db6]
- Updated dependencies [df9ed76]
- Updated dependencies [3020912]
- Updated dependencies [d8d598d]
- @rulvar/[email protected]
1.249.0
Patch Changes
- Updated dependencies [8862133]
- Updated dependencies [0d7a717]
- Updated dependencies [e4428bd]
- Updated dependencies [d6873c1]
- Updated dependencies [4092e8d]
- Updated dependencies [e086590]
- Updated dependencies [1411938]
- Updated dependencies [737d1ee]
- Updated dependencies [634f966]
- Updated dependencies [052cc26]
- Updated dependencies [bbae134]
- @rulvar/[email protected]
1.248.0
Patch Changes
- Updated dependencies [8d0cd69]
- Updated dependencies [81065e4]
- Updated dependencies [8573f20]
- Updated dependencies [95f6a5e]
- @rulvar/[email protected]
1.247.0
Minor Changes
- b698726: The first-party surface attests, and the floor loses its holes (RV4204, the sixth comparison experiment). Before this, only
mcp()and the AI SDK bridge exposeddescribeRegulatedPosture(), sounrecognized >= 1on nearly every real regulated compile and a zero-blind-spot floor was unsatisfiable by construction; and the floor checked toolset attestation only ondefaults.profiles, accepted legacy contract-only pins that pass authority drift silently, and never walked the executors at all. Now:anthropic()andopenai()attest their egress (official, acustom-base-urlwhose ORIGIN enters the hashed posture map, or apreconstructed-clientnamed honestly) plus the caps pagination bound;subprocessExecutor()andcontainerExecutor()attest their ledger, env allowlist, resolved ceilings, and isolation seam;compileRegulatedProfilewalksengine.executorsand the sandbox runner beside adapters and toolsets, wraps attested executors sorun()re-judges the posture at use (the RV4102 seam), refuses a regulated executor without aToolEffectLedgerby field name, refuses legacy contract-only pins (re-record withattestToolset()), and arms the new engine-widedefaults.requireToolsetAttestation, under which a spawn resolving a non-empty toolset with no pin binding it refuses typed at spawn time (the per-call-tools hole the profile pins could not see). The opt-inconstruction: 'require-recognized'compile floor turns the unrecognized count into a typed refusal naming the blind constructions, satisfiable now that the first-party surface attests.
Patch Changes
- Updated dependencies [1933ecc]
- Updated dependencies [db0a5f0]
- Updated dependencies [b698726]
- Updated dependencies [48348d2]
- Updated dependencies [4cfa1cc]
- Updated dependencies [4b7197a]
- Updated dependencies [5ebc842]
- Updated dependencies [16ff6b9]
- Updated dependencies [0c9941d]
- @rulvar/[email protected]
1.246.0
Patch Changes
- Updated dependencies [d165b0c]
- Updated dependencies [d59f4a0]
- Updated dependencies [46907ac]
- Updated dependencies [9929ad3]
- Updated dependencies [1790a6a]
- @rulvar/[email protected]
1.245.0
Patch Changes
- Updated dependencies [b4d47a8]
- Updated dependencies [dee6db4]
- Updated dependencies [b85c113]
- Updated dependencies [bc556e7]
- Updated dependencies [9f11d29]
- Updated dependencies [19bcea0]
- Updated dependencies [60b461c]
- Updated dependencies [61e3a1a]
- Updated dependencies [a156b81]
- Updated dependencies [0bd7045]
- @rulvar/[email protected]
1.244.0
Patch Changes
- Updated dependencies [38d839a]
- Updated dependencies [ce13b0f]
- Updated dependencies [4fa23e3]
- Updated dependencies [6841c69]
- Updated dependencies [f56721d]
- Updated dependencies [c894a43]
- Updated dependencies [f6944a3]
- Updated dependencies [23fd0e0]
- @rulvar/[email protected]
1.243.0
Patch Changes
- Updated dependencies [746d1f4]
- Updated dependencies [009b29c]
- Updated dependencies [1674cbe]
- Updated dependencies [bd096bc]
- @rulvar/[email protected]
1.242.0
Patch Changes
- Updated dependencies [6e3438e]
- Updated dependencies [ba5cf67]
- Updated dependencies [c2d1531]
- @rulvar/[email protected]
1.241.0
Patch Changes
- Updated dependencies [dbcdd24]
- Updated dependencies [7ae7243]
- Updated dependencies [4f832c4]
- Updated dependencies [7452d3d]
- Updated dependencies [a4e22bf]
- Updated dependencies [82df4af]
- @rulvar/[email protected]
1.240.0
Patch Changes
- @rulvar/[email protected]
1.239.0
Patch Changes
- Updated dependencies [74ce99a]
- Updated dependencies [ccd0665]
- Updated dependencies [0c5ce21]
- Updated dependencies [0616934]
- @rulvar/[email protected]
1.238.0
Patch Changes
- Updated dependencies [cf00947]
- Updated dependencies [c7b9382]
- Updated dependencies [88aea96]
- Updated dependencies [6da8d05]
- Updated dependencies [eae5c4c]
- @rulvar/[email protected]
1.237.0
Minor Changes
- 3b987a1: Anthropic model resolution adopts the dated snapshot grammar (RV3303), the posture openai took in the v1.17.0 review P1-1. The old matcher let ANY suffix of a known name inherit the full table row, so an unseen variant like
claude-sonnet-5-previewsilently took the known model's caps and its promotional pricing, exactly the fabricated row the table's unknown model contract forbids; the 2026-08-12 comparison run named this counterexample. Now only the exact name or<exact model>-YYYYMMDDresolves a row; every other suffix falls through to the conservative unpriced caps, surfaces inCostReport.unpriced, and trips the ceiling warning instead of pricing as its neighbor. Dated snapshots of known names (claude-haiku-4-5-20251001) resolve byte identically to before.
Patch Changes
- Updated dependencies [9d6a279]
- Updated dependencies [49a98f6]
- Updated dependencies [a734ca0]
- Updated dependencies [deb406f]
- @rulvar/[email protected]
1.236.0
Patch Changes
- Updated dependencies [26306ea]
- Updated dependencies [709b942]
- @rulvar/[email protected]
1.235.0
Patch Changes
- Updated dependencies [ba4e10d]
- Updated dependencies [172402b]
- Updated dependencies [2ecd787]
- Updated dependencies [e20a5e9]
- Updated dependencies [98c8691]
- Updated dependencies [c70def0]
- @rulvar/[email protected]
1.234.0
Patch Changes
- Updated dependencies [8420c04]
- @rulvar/[email protected]
1.233.0
Patch Changes
- Updated dependencies [48b5200]
- Updated dependencies [73bc32b]
- Updated dependencies [e63b743]
- Updated dependencies [ef45da7]
- @rulvar/[email protected]
1.232.0
Minor Changes
- 6a58120: Bounded
refreshCaps()pagination (RV2904). The ninth comparison run's adversarial audit foundmodels.listthe one pagination in the tree the MCP cycle doctrine (RV1602/RV1808) had not reached: a server echoing or recyclinglast_idspun the sweep forever, comfortably inside every timeout. A cursor echoed back or re-used by the sweep is now refused unconditionally as a typed cycle, and the new opt-incapsMaxPagesfails the refresh typed when more pages are still reported past the bound, in the fail-closed maxTools direction: truncating would clamp output bounds against a silently partial caps table.
Patch Changes
- Updated dependencies [1440410]
- Updated dependencies [6e467f4]
- Updated dependencies [0b14293]
- Updated dependencies [e3bcab2]
- Updated dependencies [b55a0f7]
- @rulvar/[email protected]
1.231.0
Patch Changes
- Updated dependencies [4eb4b56]
- Updated dependencies [bc8f09e]
- Updated dependencies [ff9b8c2]
- @rulvar/[email protected]
1.230.0
Patch Changes
- Updated dependencies [e9bf910]
- Updated dependencies [57bfb38]
- @rulvar/[email protected]
1.229.0
Patch Changes
- Updated dependencies [3370342]
- Updated dependencies [2fb6656]
- Updated dependencies [edce170]
- @rulvar/[email protected]
1.228.0
Patch Changes
- Updated dependencies [4034fac]
- Updated dependencies [a54b085]
- Updated dependencies [9d0a9be]
- Updated dependencies [be9ef28]
- @rulvar/[email protected]
1.227.0
Patch Changes
- Updated dependencies [f262e9f]
- Updated dependencies [f191ff7]
- Updated dependencies [fbbfbe8]
- Updated dependencies [263b5e8]
- Updated dependencies [db4d56d]
- Updated dependencies [41f93a9]
- Updated dependencies [98c8ca9]
- @rulvar/[email protected]
1.226.0
Patch Changes
- @rulvar/[email protected]
1.225.0
Patch Changes
- @rulvar/[email protected]
1.224.0
Patch Changes
- Updated dependencies [4eca1a3]
- @rulvar/[email protected]
1.223.0
Patch Changes
- Updated dependencies [549aabd]
- Updated dependencies [549aabd]
- @rulvar/[email protected]
1.222.0
Patch Changes
- Updated dependencies [8326268]
- @rulvar/[email protected]
1.221.0
Patch Changes
- Updated dependencies [032ce93]
- @rulvar/[email protected]
1.220.0
Patch Changes
- Updated dependencies [0babe70]
- @rulvar/[email protected]
1.219.0
Patch Changes
- Updated dependencies [65a4ce7]
- @rulvar/[email protected]
1.218.0
Patch Changes
- Updated dependencies [088bda6]
- @rulvar/[email protected]
1.217.0
Patch Changes
- Updated dependencies [ab80b97]
- @rulvar/[email protected]
1.216.0
Patch Changes
- Updated dependencies [b357f4a]
- @rulvar/[email protected]
1.215.0
Patch Changes
- Updated dependencies [e1da4c7]
- @rulvar/[email protected]
1.214.0
Patch Changes
- Updated dependencies [c8af0ec]
- @rulvar/[email protected]
1.213.0
Patch Changes
- Updated dependencies [61680df]
- @rulvar/[email protected]
1.212.0
Patch Changes
- Updated dependencies [e6f8516]
- @rulvar/[email protected]
1.211.0
Patch Changes
- Updated dependencies [d5a8a36]
- @rulvar/[email protected]
1.210.0
Patch Changes
- Updated dependencies [c871ddc]
- @rulvar/[email protected]
1.209.0
Patch Changes
- Updated dependencies [514c7bb]
- @rulvar/[email protected]
1.208.0
Minor Changes
- e7d426f: First-class prompt-cache policy (RV2006).
ChatRequest.cacheHintexisted and the Anthropic adapter compiled it intocache_control, but nothing in the core ever populated it: the third parity rerun's workers re-paid the full input rate on every turn of their ~550k-token contexts (cacheReadTokens 0across the run), and the $6 envelope sized on OpenAI's implicit server cache was incomparable on Anthropic. The agent loop now compiles the hint on every tool-cycle turn: breakpoints after tools, after system, and after the deepest message, sliding with the history. Default ON exactly where the adapter declares the newModelCaps.promptCaching: 'explicit'(the Anthropic adapter does); OpenAI declares'implicit'and undeclared adapters get byte-identical requests. Configure withdefaults.cache,AgentProfile.cache, or per-callopts.cache(CachePolicy { mode?: 'auto' | 'off'; ttl?: '5m' | '1h' }), call over profile over engine. Billing note: on cache-capable Anthropic models this changes the wire requests of every loop turn to carry cache breakpoints, typically cutting long-cycle input cost several-fold (cached reads bill at a tenth of the input rate);CostReportcache accounting is unchanged, the hint never enters identity or journals, and@rulvar/testing'srequestHashstrips it so existing cassettes replay byte for byte.
Patch Changes
- Updated dependencies [e7d426f]
- @rulvar/[email protected]
1.207.0
Patch Changes
- Updated dependencies [99beee2]
- @rulvar/[email protected]
1.206.0
Patch Changes
- Updated dependencies [ec8e1f1]
- @rulvar/[email protected]
1.205.0
Patch Changes
- Updated dependencies [6d224da]
- @rulvar/[email protected]
1.204.0
Patch Changes
- Updated dependencies [efaec9b]
- @rulvar/[email protected]
1.203.0
Patch Changes
- Updated dependencies [fb08c10]
- @rulvar/[email protected]
1.202.0
Patch Changes
- @rulvar/[email protected]
1.201.0
Patch Changes
- Updated dependencies [7e01189]
- @rulvar/[email protected]
1.200.0
Patch Changes
- Updated dependencies [e2ddbdf]
- @rulvar/[email protected]
1.199.0
Patch Changes
- Updated dependencies [29891c6]
- @rulvar/[email protected]
1.198.0
Patch Changes
- Updated dependencies [c097c96]
- @rulvar/[email protected]
1.197.0
Patch Changes
- @rulvar/[email protected]
1.196.0
Patch Changes
- Updated dependencies [ec9c3e3]
- @rulvar/[email protected]
1.195.0
Patch Changes
- Updated dependencies [5702a70]
- @rulvar/[email protected]
1.194.0
Patch Changes
- Updated dependencies [360a659]
- @rulvar/[email protected]
1.193.0
Patch Changes
- Updated dependencies [2bca1d1]
- @rulvar/[email protected]
1.192.0
Patch Changes
- Updated dependencies [8757601]
- @rulvar/[email protected]
1.191.0
Patch Changes
- Updated dependencies [745387c]
- @rulvar/[email protected]
1.190.0
Patch Changes
- Updated dependencies [8e02021]
- @rulvar/[email protected]
1.189.0
Patch Changes
- Updated dependencies [6a5cc2d]
- @rulvar/[email protected]
1.188.0
Patch Changes
- @rulvar/[email protected]
1.187.0
Minor Changes
- c9798ef: The absorbed pause_turn wire set survives the error arms (RV1805). The Anthropic adapter published the whole segment set (
wireRequests = { count, responseIds }) only on the successful terminal finish, so an error after absorbed continuations, acreate()failure, a truncated read, the continuation cap, or a pre-wire segment denial, yielded bare and orphaned exactly the paid wires a per-request statement join needs most (the segments' usage already survives through mid-stream reports; the ids and the count did not). Every error arm now rides the COMPLETED absorbed segments' wire set on its error data, the agent loop's provider call record reads it when the finish that would have named the set never came (a single absorbed segment included, since an errored dispatch has no plain responseId to join by), the invoice row keeps the ids and the count, and a first-segment failure stays a bare error with nothing invented.
Patch Changes
- Updated dependencies [c9798ef]
- @rulvar/[email protected]
1.186.0
Patch Changes
- Updated dependencies [242647e]
- @rulvar/[email protected]
1.185.0
Patch Changes
- Updated dependencies [1248623]
- @rulvar/[email protected]
1.184.0
Patch Changes
- Updated dependencies [8a9caca]
- @rulvar/[email protected]
1.183.0
Patch Changes
- Updated dependencies [dd3767c]
- @rulvar/[email protected]
1.182.0
Patch Changes
- Updated dependencies [144d026]
- @rulvar/[email protected]
1.181.0
Patch Changes
- @rulvar/[email protected]
1.180.0
Patch Changes
- Updated dependencies [b124d26]
- @rulvar/[email protected]
1.179.0
Patch Changes
- Updated dependencies [1a5a85a]
- @rulvar/[email protected]
1.178.0
Patch Changes
- @rulvar/[email protected]
1.177.0
Patch Changes
- Updated dependencies [94db8ff]
- @rulvar/[email protected]
1.176.0
Patch Changes
- Updated dependencies [a74304d]
- @rulvar/[email protected]
1.175.0
Patch Changes
- Updated dependencies [1999c5d]
- @rulvar/[email protected]
1.174.0
Patch Changes
- Updated dependencies [aa9a772]
- @rulvar/[email protected]
1.173.0
Patch Changes
- Updated dependencies [67d27ac]
- @rulvar/[email protected]
1.172.0
Patch Changes
- Updated dependencies [0d4770b]
- @rulvar/[email protected]
1.171.0
Patch Changes
- Updated dependencies [f6116b9]
- @rulvar/[email protected]
1.170.0
Patch Changes
- Updated dependencies [86e4c06]
- @rulvar/[email protected]
1.169.0
Patch Changes
- Updated dependencies [623b2ae]
- @rulvar/[email protected]
1.168.0
Patch Changes
- Updated dependencies [ebba79a]
- @rulvar/[email protected]
1.167.0
Patch Changes
- @rulvar/[email protected]
1.166.0
Patch Changes
- Updated dependencies [d8262c3]
- @rulvar/[email protected]
1.165.0
Patch Changes
- Updated dependencies [6391274]
- @rulvar/[email protected]
1.164.0
Patch Changes
- Updated dependencies [9f2dda9]
- @rulvar/[email protected]
1.163.0
Patch Changes
- Updated dependencies [e8d9ada]
- @rulvar/[email protected]
1.162.0
Patch Changes
- Updated dependencies [2031e82]
- @rulvar/[email protected]
1.161.0
Patch Changes
- Updated dependencies [d4547b7]
- @rulvar/[email protected]
1.160.0
Patch Changes
- Updated dependencies [1c6f0d0]
- @rulvar/[email protected]
1.159.0
Patch Changes
- Updated dependencies [e881c8b]
- @rulvar/[email protected]
1.158.0
Patch Changes
- Updated dependencies [a266bc7]
- @rulvar/[email protected]
1.157.0
Patch Changes
- Updated dependencies [1883421]
- @rulvar/[email protected]
1.156.0
Patch Changes
- Updated dependencies [537144e]
- @rulvar/[email protected]
1.155.0
Patch Changes
- Updated dependencies [49b08a7]
- @rulvar/[email protected]
1.154.0
Patch Changes
- Updated dependencies [9259f24]
- @rulvar/[email protected]
1.153.0
Patch Changes
- Updated dependencies [d8bebcb]
- @rulvar/[email protected]
1.152.0
Patch Changes
- Updated dependencies [dd6a616]
- @rulvar/[email protected]
1.151.0
Patch Changes
- Updated dependencies [1de0610]
- @rulvar/[email protected]
1.150.0
Patch Changes
- Updated dependencies [a331211]
- @rulvar/[email protected]
1.149.0
Patch Changes
- Updated dependencies [08b4537]
- @rulvar/[email protected]
1.148.0
Patch Changes
- Updated dependencies [c85dac9]
- @rulvar/[email protected]
1.147.0
Patch Changes
- Updated dependencies [6367231]
- @rulvar/[email protected]
1.146.0
Patch Changes
- Updated dependencies [5d9bbc8]
- @rulvar/[email protected]
1.145.0
Patch Changes
- @rulvar/[email protected]
1.144.0
Patch Changes
- Updated dependencies [c11bcd6]
- @rulvar/[email protected]
1.143.0
Patch Changes
- Updated dependencies [f412169]
- @rulvar/[email protected]
1.142.0
Patch Changes
- @rulvar/[email protected]
1.141.0
Patch Changes
- Updated dependencies [4f12a62]
- @rulvar/[email protected]
1.140.0
Patch Changes
- @rulvar/[email protected]
1.139.0
Patch Changes
- Updated dependencies [03a2141]
- @rulvar/[email protected]
1.138.0
Minor Changes
ed0c4fb: Pre-wire continuation reservation, the self-describing fault kit, and the run-id surface (RV1013 + RV1014, PR VII closing the fourteenth plan)
- Pre-wire continuation admission (RV1013, opt-in). Post-hoc settlement is accounting, not admission: a hard provider RPM cap needs each
pause_turncontinuation reserved BEFORE its egress. Withquota: { reserveContinuations: true }the engine admits every provider-side continuation through the new adapter-sideStreamHooksseam (ProviderAdapter.streamgains an optional third parameter; the Anthropic adapter honors it): under a 2-request window the third wire of one absorbed dispatch never leaves and the denial rides the provider-429 machinery verbatim, the main settlement stops re-adding individually admitted segments (the window is never double-counted), and a granted admission whose wire never left is RELEASED back to the window through the new optionalQuotaLimiter.release(reservationId)(implemented bymemoryQuotaLimiter; a release returns exactly what admission consumed, and unknown or expired ids are no-ops). Adapters unaware of the hook keep the documented post-hoc semantics byte for byte, and the default stays post-hoc. The midstream-versus-finish usage confirmation now fires only when a finish CLAIM exists: an error-terminal absorption (a segment denial, a transport cut) no longer manufactures an invariant violation that shadows the real wire error. - The self-describing kit (RV1014).
runFaultInjectionrefuses an emptyonlyselection typed (a gate that runs zero scenarios used to reportallMatched: true), and the report carriesrequestedandselectedcounts so the gate can never quietly shrink. The audit scenario grows the RV1007 arcs (a page-only long-context tier and aNaNscalar are findings, never silent passes), completing kit coverage of every real defect of the fourteenth plan on its real path. - The run-id boundary surface (
assertSafeRunId,MAX_RUN_ID_LENGTH) is now exported from@rulvar/core, so hosts can pre-validate ids beforeengine.run.
- Pre-wire continuation admission (RV1013, opt-in). Post-hoc settlement is accounting, not admission: a hard provider RPM cap needs each
Patch Changes
- Updated dependencies [ed0c4fb]
- @rulvar/[email protected]
1.137.0
Patch Changes
- Updated dependencies [96f6788]
- @rulvar/[email protected]
1.136.0
Patch Changes
- Updated dependencies [aa6ca71]
- @rulvar/[email protected]
1.135.0
Patch Changes
- Updated dependencies [cf75e22]
- @rulvar/[email protected]
1.134.0
Patch Changes
- @rulvar/[email protected]
1.133.0
Minor Changes
2659f54: A legitimate pause_turn survives the engine end to end, and an invalid continuation cap refuses typed before the first wire (RV1003 + RV1004, PR II of the fourteenth plan)
The fourteenth comparison experiment drove the real Anthropic adapter through the real engine and a legitimate two-segment
pause_turnkilled the run: every segment'smessage_startemitted its own usage mid-stream (5 then 6), the terminal finish carried only the LAST segment's counts, and the engine's midstream-versus-finish invariant read 11 > 6, losing the paid segments from the money. The same experiment fedpauseTurnMaxContinuations: NaNand the cap silently disarmed (continuations > NaNis always false), turning every further continuation into unplanned paid traffic.- The terminal finish now speaks for the WHOLE logical turn (RV1003): the adapter accumulates each absorbed segment's normalized usage (
sumUsage, cache counts and the TTL split included) and the finish carries the sum, so the invariant confirms the per-segment mid-stream reports, the per-call record and the invoice price every paid segment, and the quota window still settles at true wire units. Mid-stream events stay per-segment deltas; a single-segment turn stays byte-identical.TurnMappinggains the segment's ownusage. pauseTurnMaxContinuationsmust be a nonnegative safe integer (RV1004): any other present value (NaN, Infinity, negatives, fractions, strings) refuses with a typedConfigErrorbefore the first wire, instead of silently disarming the continuation bound.runFaultInjection(@rulvar/evals) grows the seventeenth scenario,pause-turn-real-adapter: the two-segment absorption through the REAL adapter and engine must settleokat usage 11/2 with both wire ids on the invoice row and the quota window at 2, and the NaN cap must refuse before any wire. Reverting either fix reportsmatched: falsein the kit.
- The terminal finish now speaks for the WHOLE logical turn (RV1003): the adapter accumulates each absorbed segment's normalized usage (
Patch Changes
- @rulvar/[email protected]
1.132.0
Patch Changes
- Updated dependencies [2bec904]
- @rulvar/[email protected]
1.131.0
Patch Changes
- Updated dependencies [256cae1]
- @rulvar/[email protected]
1.130.0
Patch Changes
- Updated dependencies [d6bec7a]
- @rulvar/[email protected]
1.129.0
Patch Changes
- Updated dependencies [1612439]
- @rulvar/[email protected]
1.128.0
Minor Changes
27c4e38: pause_turn continuations become accounted wire units (RV905, the thirteenth experiment's fifth release risk). The Anthropic adapter absorbs server-side turn pauses by re-sending, making up to six wire requests inside ONE core dispatch; until now the request quota window, the provider call record, and the invoice row all saw one, and a per-request provider statement matched one segment while the rest read statement-only.
The adapter's finish metadata now names the whole segment set (
providerMetadata.anthropic.wireRequests = { count, responseIds }); the provider call record and the invoice row carrywireResponseIds; and the quota reconciliation settles the reservation against the TRUE wire request count. TheQuotaLimiter.reconcileSPI gains an optionalactual.requestsargument, honored by all three reference limiters through one shared arithmetic (quotaActualRequestsDelta), so a window that admitted one request per reservation now reflects what the provider's own RPM meter saw; a settlement only ever adds, never denies retroactively, and implementations written against the two-argument form remain valid.reconcileStatementjoins a multi-wire invoice row by ANY id of its segment set, all-or-nothing: a partially delivered segment set readspartial-coveragewith its delivered segments never counted as statement-only (and neverno-overlapwhen segments touched our data), and provider-reported token counts compare as the SUM over the segments against the dispatch's recorded usage. Single-wire dispatches carry none of the new fields and stay byte-identical, journals and events included.
Patch Changes
- Updated dependencies [27c4e38]
- @rulvar/[email protected]
1.127.0
Minor Changes
b3b1805: Admission before egress for the pre-dispatch token count (RV904, the thirteenth experiment's pre-admission egress probe). ctx.agent calls the adapter's optional
countTokenswith the FULL child prompt to tighten the admission reserve; before this release that network call ran before the budget decided anything, so a spawn the budget could never admit still sent the prompt to the provider, the call honored no abort signal, and nothing observable recorded the egress.The reserve is monotone in the count, so the smallest reserve any count outcome could produce is computable without it: the priced floor at zero input tokens, or the flat fallback the count-failed path admits under. The engine now checks that floor against the budget first, through the exact refusal arithmetic
admitSpawnitself uses (RunBudget.refuseSpawnIfInfeasible, the refusal arm factored out so the two layers can never disagree), and a spawn that could never be admitted (the lifetime spawn cap, a full account, an exhausted ceiling) refuses with zero network calls. The provider SPI'scountTokensgains an options argument with anAbortSignal; the Anthropic adapter threads it into the SDK request, and an abort mid-count cancels the spawn instead of silently falling back to the flat reserve and dispatching behind a cancelled spawn. Every count is now observable: anadmission.countTokensinfo log names the model and the counted tokens, and a failed count warns with the failure the flat reserve then covers. An explicitestCost(per call or per profile) remains the zero-egress path that skips the count entirely, now documented as the posture for hosts whose privacy gates must run before any prompt byte reaches a provider. Spawns on adapters withoutcountTokens, and spawns carryingestCost, behave byte-identically to v1.126.0.
Patch Changes
- Updated dependencies [b3b1805]
- @rulvar/[email protected]
1.126.0
Patch Changes
- @rulvar/[email protected]
1.125.0
Minor Changes
109e9fa: Pricing-table truth: the Anthropic 1h cache-write premium is seeded, the rates audit fails closed on documented rates the seed never declared, and the OpenAI Terra/Luna price cut ships as a versioned revision (RV901, RV902, RV911; the thirteenth experiment's underpricing probes).
@rulvar/anthropicseeds now carry all five published pricing columns:cacheWrite1hUsdPerMToklands on every priced row at the documented 2x base input (Fable 5 $20, Opus 4.8/4.7/4.6 $10, Sonnet 5 $4 under the introductory price, Sonnet 4.6 $6, Haiku 4.5 $2), under the newpricingVersionanthropic-2026-07-31. v1.124.0 taught the wire to fill the canonical 5m/1h split andpriceUsdOfto bill the 1h share at the premium, but the seed never declared the rate, so a million Sonnet 5 1h write tokens priced at the 5m $2.50 instead of the documented $4.00: an underpricing a budget ceiling then failed to bound. A usage with no split still folds the whole write count at the 5m rate, byte for byte as before; the stale caps comment claiming the canonical Usage cannot distinguish 1h writes is retired.scripts/rates-audit.mjs(the weekly documented-rates drift audit) now compares seed and page in BOTH directions: a billable page rate the seed never declared is a finding, not a silent skip. The old one-directional rule rested on the 1h premium being unbillable; that rationale died with the Usage split, and the audit printingmatchfor Sonnet 5 while the page showed a 1h column the seed lacked is exactly how the underpricing hid. The pinning test is flipped to the fail-closed behavior.@rulvar/openaipicks up the provider's 2026-07-30 price cut, docs-verified per model page on 2026-07-31 after the live audit caught the drift: Terra to $2 input / $12 output / $0.20 cached input / $2.50 cache write (0.8x across the board) and Luna to $0.20 / $1.20 / $0.02 / $0.25 (0.2x), both keeping the family's long-context tier, under the newpricingVersionopenai-2026-07-31. Sol is unchanged and additionally remains billing-confirmed by the 2026-07-30 statement reconciliation; the new Terra and Luna rates are docs-verified only until the next reconciliation over a saved export. Runs recorded underopenai-2026-07-18-r2overstated Terra/Luna spend relative to the cut, never under, and a resumed run surfaces the rotation as explicit pricing drift instead of silently reinterpreting recorded spend. Every re-verified row now stampsratesVerifiedAt: '2026-07-31'.
Patch Changes
- @rulvar/[email protected]
1.124.0
Minor Changes
- 37fd1f2: The twelfth plan's closing trio (RV809, RV810, RV811). The tool budget extension gains
coverEvidenceDeficit: with an evidence contract declared, the extension grants at a tool-turn boundary whenever the remaining call budget cannot cover the declared floor's outstanding deficit, under the same money, progress, and maxExtensions gates, so a limited child at 7 of 11 entries converts headroom into the missing evidence BEFORE the cap instead of dumping through the reserved tail; the journaled grant decision carriestrigger: 'evidence-deficit'and the announcement names the exact deficit. Canonical Usage gains the optional cache-write TTL split (cacheWrite5mTokensandcacheWrite1hTokens, invariant: the split sums tocacheWriteTokens);priceUsdOfbills the 1h share atcacheWrite1hUsdPerMTokwith everything unclaimed at the plain write rate (byte-identical arithmetic without a split), sanitize repairs broken splits with 1h priority (never an undercharge), and the Anthropic adapter fills the split from thecache_creationbreakdown when it agrees with the flat total. @rulvar/evals gains the fault-injection kit:runFaultInjectiondrives the never-observed-live fail-closed branches (in-flight-exposure refusal, duplicate quota rule, torn and glued JSONL tails, the settle-boundary crash resume, pricing rotation with an uncovered tail, unknown provider id) on the real engine offline, verifies each documented typed observable fail closed, and leaves experiment-grade artifacts.
Patch Changes
- Updated dependencies [37fd1f2]
- @rulvar/[email protected]
1.123.0
Patch Changes
- Updated dependencies [5c46468]
- @rulvar/[email protected]
1.122.0
Patch Changes
- Updated dependencies [8cf45c5]
- @rulvar/[email protected]
1.121.0
Minor Changes
- 3d67d41: Rate provenance made checkable (RV807, RV813, RV814). The pricing row grows
ratesVerifiedAt(SPI), the ISO date it was last verified against the provider's documented rates or, stronger, its billing categories: the shipped seeds stamp it (the GPT-5.6 family reads2026-07-30, the day the statement reconciliation confirmed those rates against the provider's own per-component billing categories to the cent; the pre-5.6 OpenAI rows keep their2026-07-18docs verification; every Anthropic row was re-verified against the documented table on2026-07-30). The date is surfaced wherever a dollar is consumed:preflightEstimatecopies it onto each spawn report andrulvar preflightrendersratesVerified=<date>with its age on the spawn line; the settle pin journals it with the rest of the applied row so it survives any later table rewrite; andrulvar invoiceprints arates verified:line naming each priced model's date and age, pinned rows first, current table past them; the twelfth run's founder read the invoice doubting the rates and nothing said the seed was 12 days stale. The doctrine ships with the mechanism: seeds bound ceilings conservatively, billing truth is established only byreconcileStatementover saved exports, and a confirmed divergence corrects the seed in its own release with a changeset, never a silent rewrite. Enforcement rides two new gates: a weekly documented-rates audit (scripts/rates-audit.mjsin the live contract workflow) re-fetches exactly the pages the seed comments cite, compares every rate, write premium, and long-context tier, and opens an issue on drift or on a page that stops extracting, and a README release-table gate (scripts/readme-release-shas.mjs, in CI) requires every cited squash SHA to be an ancestor of HEAD, catching the v1.109.0 row that pointed at an object no branch contained for eleven releases (now corrected to the real squash58afdb5).
Patch Changes
- Updated dependencies [3d67d41]
- @rulvar/[email protected]
1.120.0
Patch Changes
- Updated dependencies [d630c9e]
- @rulvar/[email protected]
1.119.0
Patch Changes
- Updated dependencies [1e4ff3c]
- @rulvar/[email protected]
1.118.0
Patch Changes
- Updated dependencies [f8341a3]
- @rulvar/[email protected]
1.117.0
Patch Changes
- @rulvar/[email protected]
1.116.0
Patch Changes
- Updated dependencies [a213878]
- @rulvar/[email protected]
1.115.0
Patch Changes
- Updated dependencies [63642ae]
- @rulvar/[email protected]
1.114.0
Patch Changes
- Updated dependencies [5759731]
- @rulvar/[email protected]
1.113.0
Patch Changes
- Updated dependencies [a60807a]
- @rulvar/[email protected]
1.112.0
Patch Changes
- Updated dependencies [00ae55b]
- @rulvar/[email protected]
1.111.0
Patch Changes
- Updated dependencies [fd25169]
- @rulvar/[email protected]
1.110.0
Patch Changes
- Updated dependencies [58afdb5]
- @rulvar/[email protected]
1.109.0
Patch Changes
- Updated dependencies [85b1d39]
- @rulvar/[email protected]
1.108.0
Patch Changes
- Updated dependencies [affa3d4]
- @rulvar/[email protected]
1.107.0
Patch Changes
- Updated dependencies [9f5f6f6]
- @rulvar/[email protected]
1.106.0
Patch Changes
- Updated dependencies [9a4ce49]
- @rulvar/[email protected]
1.105.0
Patch Changes
- Updated dependencies [531dc88]
- @rulvar/[email protected]
1.104.0
Patch Changes
- @rulvar/[email protected]
1.103.0
Patch Changes
- Updated dependencies [f2b809e]
- @rulvar/[email protected]
1.102.0
Patch Changes
- Updated dependencies [3eb6515]
- @rulvar/[email protected]
1.101.0
Patch Changes
- Updated dependencies [51b215c]
- @rulvar/[email protected]
1.100.0
Patch Changes
- Updated dependencies [9785bea]
- @rulvar/[email protected]
1.99.1
Patch Changes
- Updated dependencies [ef08d73]
- @rulvar/[email protected]
1.99.0
Patch Changes
- Updated dependencies [9e00888]
- @rulvar/[email protected]
1.98.0
Patch Changes
- @rulvar/[email protected]
1.97.0
Patch Changes
- Updated dependencies [5c3b453]
- @rulvar/[email protected]
1.96.0
Patch Changes
- @rulvar/[email protected]
1.95.0
Patch Changes
- @rulvar/[email protected]
1.94.0
Patch Changes
- @rulvar/[email protected]
1.93.0
Patch Changes
- Updated dependencies [c62150a]
- @rulvar/[email protected]
1.92.0
Patch Changes
- Updated dependencies [351d1f5]
- @rulvar/[email protected]
1.91.0
Patch Changes
- @rulvar/[email protected]
1.90.0
Patch Changes
- Updated dependencies [9603940]
- @rulvar/[email protected]
1.89.0
Patch Changes
- Updated dependencies [f18b671]
- Updated dependencies [f18b671]
- @rulvar/[email protected]
1.88.0
Patch Changes
- Updated dependencies [3b339d9]
- @rulvar/[email protected]
1.87.0
Patch Changes
- Updated dependencies [c4c02b1]
- @rulvar/[email protected]
1.86.0
Patch Changes
- Updated dependencies [2f71894]
- @rulvar/[email protected]
1.85.0
Patch Changes
6932a9f: Three fail-closed fixes from the cycle 83 sweep, plus the dependency refresh.
Engine. A typed error thrown out of
ProviderAdapter.stream()now keeps its own class instead of being laundered into a retryable transport fault. AConfigError(a bridged model id that does not match the wrapped model, an unsupported role, a namespaced option contradicting a canonical field) used to be retried through the whole backoff ladder and then trigger transport failover, so a misconfigured primary silently served the run from a fallback model the caller never asked for while the real fault vanished behind a generic message. Typed errors that ARE retryable by class (a lost lease) keep retrying exactly as before, and an untyped throw is still a retryable transport fault.Planner sandbox. The realm scrub replaced
Date.nowandMath.random, which left three ambient sources open: a barenew Date()never consultsDate.now(V8 reads the system clock directly),performance.now()is a second live clock, and WebCrypto (crypto.randomUUID(),crypto.getRandomValues()) is raw entropy. Those are the first idioms a machine-written script reaches for, and each silently produced a run that could not reproduce on replay. All of them now draw from the same seeded stream: zero-argumentnew Date()andDate()take the logical clock,performance.now()is that clock minus the segment base,crypto.randomUUID()is the journaled uuid shim, andcrypto.getRandomValues()fills from the seed. Passing a timestamp or a date string toDatestays a pure conversion.Server. A tracked run whose segment REJECTS instead of settling (the genesis ownership boot refusing a run another process owns, a withheld settlement whose durable write failed) was reported as
runningfor the life of the process, its SSE connections never closed, and neither retention nor the settled cap could release it.GET /runs/:idnow answersstatus: "error"with the typed wire error, connected streams close with a comment naming the failure, a late subscriber gets that comment instead of an empty stream, and the tracked run becomes eligible for retention like any other terminal run.Dependencies.
@anthropic-ai/sdkmoves to^0.115.0(the only shipped floor its caret was blocking); in-range minors refresh across the workspace. The four majors stay held: eslint 10 and@eslint/js10,@types/node26 against the Node 22.12 floor, and TypeScript 7. The tsdown resolution is pinned at 0.22.3 because it generates the frozen.d.tsartifacts, including the published@rulvar/compattarball that must repack byte identical.Updated dependencies [6932a9f]
- @rulvar/[email protected]
1.84.0
Patch Changes
- @rulvar/[email protected]
1.83.0
Patch Changes
- @rulvar/[email protected]
1.82.0
Patch Changes
- Updated dependencies [9cc5d66]
- @rulvar/[email protected]
1.81.2
Patch Changes
- Updated dependencies [296885b]
- @rulvar/[email protected]
1.81.1
Patch Changes
- Updated dependencies [c030982]
- @rulvar/[email protected]
1.81.0
Patch Changes
- Updated dependencies [ce4c392]
- @rulvar/[email protected]
1.80.0
Patch Changes
- Updated dependencies [262e397]
- @rulvar/[email protected]
1.79.0
Patch Changes
- Updated dependencies [85956ab]
- @rulvar/[email protected]
1.78.0
Patch Changes
- Updated dependencies [941b6e1]
- @rulvar/[email protected]
1.77.0
Patch Changes
- Updated dependencies [6aba271]
- @rulvar/[email protected]
1.76.0
Patch Changes
- Updated dependencies [22cba47]
- @rulvar/[email protected]
1.75.1
Patch Changes
- Updated dependencies [82bc0f0]
- @rulvar/[email protected]
1.75.0
Minor Changes
- c486de8: The provider output floor and the finish arguments second chance (the v1.74 comparison review, P0.1 + P1.5).
ModelCaps.minOutputTokensPerTurndeclares the smallest request output cap the provider accepts (OpenAI Responses: 16; absent means one), and the layer-2b budget clamp never dispatches below it: the last-gasp turn goes out AT the floor instead of one token, a remainder that cannot buy the floor is refused as a typedBudgetExhaustedErrorwith zero wire calls, and a configured per-turn cap below the floor is aConfigError;preflightEstimatereports that configuration as the error findingoutput-cap-below-provider-minimum. Tool arguments an adapter delivered as the parse-failure wrapper{__unparsed: raw}now get one deterministic second chance before the schema rejection: a strict re-parse, then one bounded normalization (markdown fence, first balanced object, raw control characters escaped inside string literals); a recovered object that passes the tool schema executes as if it had parsed on the wire, with a warn log naming the pass, and replay or resume recovers identically with nothing journaled. The OpenAI wire re-projects an unparseable call as the ORIGINAL raw arguments string instead of the wrapper JSON, so a model no longer learns to imitate{"__unparsed": ...}from its own rewritten history. Both wires drop unsafe-integerx-ratelimitvalues instead of normalizing 400 digits intoInfinity.FakeAdaptergainscapsOverridesso offline tests can drive caps-declared behavior like the floor.
Patch Changes
- Updated dependencies [c486de8]
- @rulvar/[email protected]
1.74.0
Minor Changes
- d94beab: Quota drift telemetry and the honest zero (the v1.71 experiment review, P0.5 resized + P1.4). The experiment declared 12M TPM over a provider-real 1M, the local limiter went quiet, and seven live 429s followed with nothing recording the mismatch. Now: both wire adapters parse the provider's x-ratelimit headers on every real 429 into normalized per-minute limits (
WireError.data.reportedLimits; the openai wire also gains the raw bucket capture the anthropic wire already had), the loop remembers them per (provider, model) as live telemetry, and the opt-inquota.declaredRules(the SAME rule array preflight takes) makes the engine journal aquota_driftdecision plus a warn log whenever a binding declared cap EXCEEDS the provider-reported one, per invocation and dimension, with anthropic's split input and output windows summed against a combined declared tokensPerMinute. Purely observational, synthetic limiter denials never count, and without declaredRules journals and events stay byte identical. On the invoice, anunconfirmedrow that recorded zero usage on every counter now carriesusageUnknown: true(export-levelusageUnknownRowscount, CLIusage-unknownmarker): the zeros mean "nothing recorded", never "the provider metered nothing"; derived at export time, no journal shape change.
Patch Changes
- Updated dependencies [d94beab]
- @rulvar/[email protected]
1.73.0
Patch Changes
- Updated dependencies [3e95bd1]
- @rulvar/[email protected]
1.72.0
Patch Changes
- Updated dependencies [662e9e0]
- @rulvar/[email protected]
1.71.0
Patch Changes
- Updated dependencies [20d02e0]
- @rulvar/[email protected]
1.70.1
Patch Changes
- @rulvar/[email protected]
1.70.0
Patch Changes
- @rulvar/[email protected]
1.69.0
Patch Changes
- Updated dependencies [b21a681]
- @rulvar/[email protected]
1.68.0
Patch Changes
- Updated dependencies [b227874]
- @rulvar/[email protected]
1.67.0
Patch Changes
- Updated dependencies [8e6006d]
- @rulvar/[email protected]
1.66.0
Patch Changes
- Updated dependencies [1b8987e]
- @rulvar/[email protected]
1.65.0
Patch Changes
- Updated dependencies [0b6b859]
- @rulvar/[email protected]
1.64.0
Patch Changes
- Updated dependencies [991f9b5]
- @rulvar/[email protected]
1.63.0
Patch Changes
- Updated dependencies [8a28aed]
- @rulvar/[email protected]
1.62.0
Patch Changes
- Updated dependencies [fca5fd1]
- @rulvar/[email protected]
1.61.0
Patch Changes
- Updated dependencies [b4c1f1f]
- @rulvar/[email protected]
1.60.0
Patch Changes
- Updated dependencies [59bbeaa]
- @rulvar/[email protected]
1.59.4
Patch Changes
- Updated dependencies [c49d7a1]
- @rulvar/[email protected]
1.59.3
Patch Changes
- Updated dependencies [deaef36]
- @rulvar/[email protected]
1.59.2
Patch Changes
- Updated dependencies [dd0e10f]
- @rulvar/[email protected]
1.59.1
Patch Changes
- Updated dependencies [c127770]
- @rulvar/[email protected]
1.59.0
Patch Changes
- Updated dependencies [615dc90]
- @rulvar/[email protected]
1.58.0
Patch Changes
- Updated dependencies [4fa35ce]
- @rulvar/[email protected]
1.57.0
Patch Changes
- Updated dependencies [5897232]
- @rulvar/[email protected]
1.56.0
Patch Changes
- Updated dependencies [f26dba0]
- @rulvar/[email protected]
1.55.0
Patch Changes
- Updated dependencies [e9b005b]
- @rulvar/[email protected]
1.54.0
Patch Changes
- Updated dependencies [3f6bc03]
- @rulvar/[email protected]
1.53.0
Patch Changes
- Updated dependencies [b821bd1]
- @rulvar/[email protected]
1.52.0
Patch Changes
- Updated dependencies [e138df9]
- @rulvar/[email protected]
1.51.0
Patch Changes
- @rulvar/[email protected]
1.50.0
Patch Changes
- Updated dependencies [e39a885]
- @rulvar/[email protected]
1.49.0
Patch Changes
- Updated dependencies [bab7b2c]
- @rulvar/[email protected]
1.48.0
Patch Changes
- @rulvar/[email protected]
1.47.0
Patch Changes
- Updated dependencies [a3687fe]
- @rulvar/[email protected]
1.46.0
Patch Changes
- Updated dependencies [865e7bf]
- @rulvar/[email protected]
1.45.0
Patch Changes
- Updated dependencies [b96305d]
- @rulvar/[email protected]
1.44.1
Patch Changes
- @rulvar/[email protected]
1.44.0
Patch Changes
- Updated dependencies [299f7d2]
- @rulvar/[email protected]
1.43.0
Patch Changes
- Updated dependencies [71b7181]
- @rulvar/[email protected]
1.42.0
Patch Changes
- Updated dependencies [9b70f27]
- @rulvar/[email protected]
1.41.0
Patch Changes
- Updated dependencies [be589ec]
- @rulvar/[email protected]
1.40.0
Patch Changes
- Updated dependencies [cf33550]
- @rulvar/[email protected]
1.39.0
Patch Changes
- @rulvar/[email protected]
1.38.0
Patch Changes
- @rulvar/[email protected]
1.37.0
Patch Changes
- Updated dependencies [e6b1481]
- Updated dependencies [e6b1481]
- @rulvar/[email protected]
1.36.0
Patch Changes
- Updated dependencies [101795b]
- @rulvar/[email protected]
1.35.0
Patch Changes
- Updated dependencies [d4ac3bf]
- @rulvar/[email protected]
1.34.0
Patch Changes
- Updated dependencies [f1505ec]
- @rulvar/[email protected]
1.33.0
Patch Changes
- @rulvar/[email protected]
1.32.0
Patch Changes
- @rulvar/[email protected]
1.31.0
Patch Changes
- df6b8f8:
Retry-Afteraccepts HTTP optional whitespace padding only. ECMAScripttrim()removed far more than the OWS production (space and horizontal tab), so values padded with newline, carriage return, vertical tab, form feed, or NBSP were honored as delays despite the documented exact delta seconds grammar; a real HTTP transport rejects most of those octets, but an injected SDK client or a mock does not. Both first party adapters now match/^[\t ]*([0-9]+)[\t ]*$/and fall back to the computed policy backoff for every other form.- @rulvar/[email protected]
1.30.0
Patch Changes
- 87ce985: Parse
Retry-Afterunder the exact RFC delta seconds grammar (v1.29.0 review P3). Published 1.29.0 usedNumber(header), which accepted far more than the documented delta seconds form: an empty or whitespace header became a 0 ms delay (an instant retry instead of the policy backoff), and hex (0x10), exponent (1e3), decimal (1.5), and signed (+3) forms were honored as delays. The value must now be a nonempty run of decimal digits after optional whitespace; every other form (the HTTP date included) omitsretryAfterMsso the engine's computed backoff applies, and a huge digit run still clamps to the Node timer maximum. - Updated dependencies [87ce985]
- @rulvar/[email protected]
1.29.0
Minor Changes
621d566: Make the retry and failover backoff interruptible and validate every provider supplied retry delay (v1.28.0 review P1 and P2).
The retry engine now races its backoff wait against the host cancel signal (which the run deadline also drives) and the budget ceiling signal: an abort wakes the wait immediately, settles through the canonical aborted outcome (
cancelledorexhausted, with every already recorded usage kept), and forbids every further dispatch, including the one behind a keyed limiter queue, so an adapter that ignores its signal can no longer be re entered after an abort. Previously a provider suppliedretryAfterMsarmed an uninterruptible sleep: a cancel, a crossed deadline, and a crossed budget ceiling all waited out the full backoff and the adapter was dispatched again. The injectedretry.sleep(ms)test hook keeps its signature; a hook that loses the race is abandoned without an unhandled rejection, and the native timer path clears its timer so an abandoned long backoff never pins the event loop.retryDelayMsis now the defensive boundary the docs promise: only a finite nonnegative providerretryAfterMsreplaces the computed delay, anything else (NaN, Infinity, a negative) is ignored as adapter noise, and every returned delay is a finite nonnegative integer clamped to the Node timer maximum, so a malformed or huge value can never arm an instant or overflowing timer. Both first party adapters stop emitting unvalidatedRetry-Afterparses: an unparsable header (the HTTP date form included) omitsretryAfterMsentirely instead of producing NaN (which also broke theWireError.dataJson invariant by serializing to null), and a huge but finite value is clamped. ThemapAnthropicStreamTSDoc now states precisely how a truncated stream is reported (thefinishedflag on the return value, with the adapter synthesizing the terminal error).Four frozen fixture cassettes are refrozen for this release (the hashVersion-bump refreeze ceremony applies; hashVersion itself is unchanged and existing journals replay identically): in three cap freeze scenarios the main orchestrator entry now honestly settles cancelled at the cap instead of paying one more ordinary turn whose result the forced finish machinery discarded anyway, and one scenario loses a post abort wait suspension that can no longer be dispatched. Entry identities, keys, and every other row are byte identical.
Patch Changes
- Updated dependencies [621d566]
- @rulvar/[email protected]
1.28.0
Minor Changes
- d98eb0b: Enforce the terminal stream contract end to end (v1.27.0 deep E2E review P1 and P2). The runtime now fails closed when an adapter stream drains without a terminal
finishorerrorevent: the partial turn becomes a retryable transport fault that feeds the ordinary retry and failover machinery instead of settling asokwith truncated text, and a requested abort (cancel, budget ceiling, idle severance) remains a clean end with no fabricated provider error. Consumption stops at the first terminal event, so events afterfinishcan no longer mutate the value, revise the authoritative bill, or trigger tool execution. The first party adapters enforce the same contract at the wire: the Chat Completions mapper no longer synthesizesfinish: stopwhen the stream is cut before afinish_reason(usage the provider did report is still forwarded, half assembled tool calls are dropped), the Responses mapper fails closed on EOF without a response terminal event, and the Anthropic adapter surfaces a read cut beforemessage_stopas a retryable transport error and no longer converts a caller requested abort duringmessages.create()into a terminal error.mapResponsesStreamandmapChatCompletionsStreamaccept an optionalsignalso a requested abort keeps ending the stream without a terminal event. The VCRrecordwrapper now commits its cassette row even when the consumer stops reading at the terminal event (the engine always does now); adapter middleware must not rely on being drained past the terminal. The committedcombined-loop-descentcatalog cassette is refrozen because stopping consumption at the terminal shifts the deterministic interleaving of two parallel plan children by one scheduler turn; entry content, keys, and the actualhashVersionare unchanged, journals recorded under earlier versions replay unchanged, and this changeset carries the frozen fixture gate's hashVersion-bump ceremony token only to unlock that refreeze.
Patch Changes
- Updated dependencies [d98eb0b]
- @rulvar/[email protected]
1.27.0
Minor Changes
- 884a433: Types referenced by public signatures are now exported from their package barrels, so the API docs resolve them instead of carrying known incomplete references (v1.26.0 deep E2E review):
BaseAppendfrom@rulvar/core(the fields common to everyReplayerappend),BlockandMappedStopfrom@rulvar/anthropic(the wire level content block alias and the stop reason mapping), andVcrHeaderfrom@rulvar/testing(the first line of every cassette file). The frozen TypeDoc baseline shrinks from eleven entries to the four vendored Standard Schema notices.
Patch Changes
- Updated dependencies [884a433]
- @rulvar/[email protected]
1.26.0
Patch Changes
- Updated dependencies [a4fc757]
- @rulvar/[email protected]
1.25.0
Patch Changes
- @rulvar/[email protected]
1.24.1
Patch Changes
- Updated dependencies [0bb14db]
- @rulvar/[email protected]
1.24.0
Patch Changes
- Updated dependencies [2b033e8]
- @rulvar/[email protected]
1.23.0
Patch Changes
- 1f9c272: The
anthropic()TSDoc no longer describes the SDK's ambient credentials as a precedence chain (v1.22.0 review P3-2).ANTHROPIC_API_KEYandANTHROPIC_AUTH_TOKENare independent credentials: requests carryx-api-keyfor the key, bearerAuthorizationfor the token, and BOTH headers when both are set; the config-file token-provider chain is consulted only when apiKey and authToken are both null. The providers guide already said exactly this; the source doc (and the generated API page built from it) had drifted. - Updated dependencies [1f9c272]
- @rulvar/[email protected]
1.22.0
Patch Changes
- Updated dependencies [77b554f]
- @rulvar/[email protected]
1.21.0
Patch Changes
- 7ee42a0: Declare
usageSemantics: 'anthropic-cache-additive-v1'on the adapter: the additive reading it has always normalized under (the Anthropic wire genuinely excludes cache reads and writes frominput_tokens, so canonicalinputTokensis the sum of all three) now rides usage-bearing journal entries as an auditable policy stamp (v1.20.0 review P1/P2-2). - Updated dependencies [7ee42a0]
- @rulvar/[email protected]
1.20.0
Patch Changes
- Updated dependencies [9367030]
- @rulvar/[email protected]
1.19.0
Patch Changes
- Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- @rulvar/[email protected]
1.18.0
Patch Changes
- Updated dependencies [943962d]
- @rulvar/[email protected]
1.17.0
Patch Changes
- @rulvar/[email protected]
1.16.2
Patch Changes
- 9f07130: Correct five stale rows in the seed capability table: Claude Opus 4.8, Opus 4.7, Opus 4.6, Sonnet 5, and Sonnet 4.6 all carry a 1M context window and 128k max output, verified against the official models table and live
GET /v1/modelson 2026-07-17. Default routing, the compaction threshold, and the wiremax_tokensclamp no longer under-provision runs that never callrefreshCaps()(Sonnet 5 was clamped to 64k output for no reason). Every row is now pinned by a committedcaps-snapshot.json: an offline test fails when the table and the snapshot disagree, and the weekly live contract workflow audits the snapshot against the model list so provider-side drift pages instead of rotting. Pricing rows are untouched.- @rulvar/[email protected]
1.16.1
Patch Changes
- fac1ecc: Treat explicit
apiKey: null/authToken: nullas absent credentials for the structured-auth env suppression, not as chosen ones. The SDK types allowauthToken?: string | null, and on v1.16.0 a typed null besidecredentials,config, orprofiledefeated the=== undefinedsuppression check, so an ambientANTHROPIC_API_KEY(or, withapiKey: null, an ambientANTHROPIC_AUTH_TOKEN) silently authenticated instead of the configured provider and billed a different principal. The suppression now uses nullish checks: any combination of unset and explicitly null keeps the configured provider in charge, while a realapiKey/authTokenstring next to structured auth still forwards verbatim under the SDK's own precedence (which never consults the provider once either is set). The Anthropic credential precedence docs now state the SDK's actual order: a setapiKeyorauthTokendisables token providers entirely; providers run only when both are null; a namedprofileskips both env reads inside the SDK itself.- @rulvar/[email protected]
1.16.0
Minor Changes
- 5f76cf2: Structured auth wins over ambient env (v1.15 review P2-2). The underlying SDK lets any
apiKey, one it read fromANTHROPIC_API_KEYincluded, beat a configuredcredentials/config/profiletoken provider: the provider was called zero times and requests carriedx-api-keyfrom the environment. WhensdkOptionscarries structured auth and noapiKey/authTokenis set anywhere, the adapter now passes explicitapiKey: null, authToken: nullto the SDK, so the configured provider is the one that authenticates regardless of what the environment exports. Setting anapiKeyorauthTokenyourself next to structured auth keeps verbatim forwarding and the SDK's own precedence, which is now documented exactly (apiKey, then token providers, then authToken). Covered by synthetic tests for the provider, an end-to-end file-backedprofile(staticuser_oauthtoken,ANTHROPIC_CONFIG_DIRisolated, 0600 credentials), and the explicit-key-beside-provider case.
Patch Changes
- @rulvar/[email protected]
1.15.0
Minor Changes
- 4aee1f3: Production auth surface (v1.14 review P2-2). New
sdkOptionsonAnthropicAdapterOptionsforwards official SDK construction options verbatim,maxRetriesexcluded from the type (AnthropicSdkOptions) and forced to 0: bearerauthToken, anAccessTokenProviderviacredentials,config(OIDC/workload-identity federation),profile, plusfetch,timeout, anddefaultHeaders. Theclientoption now accepts the officialAnthropicinstance directly under strict TypeScript, no casts, alongside the structuralAnthropicClientLikemock; an injected client with SDK autoretries enabled (maxRetries !== 0) is rejected with a typedConfigError, as areclientcombined with construction options and the same field set both top-level and insdkOptions, all before any network I/O. The implicit SDK credential chain (ANTHROPIC_API_KEY, then bearerANTHROPIC_AUTH_TOKEN, then config files) is now documented and covered by tests.
Patch Changes
- @rulvar/[email protected]
1.14.0
Patch Changes
- @rulvar/[email protected]
1.13.0
Patch Changes
- @rulvar/[email protected]
1.12.0
Patch Changes
- Updated dependencies [46edcc0]
- @rulvar/[email protected]
1.11.0
Patch Changes
- Updated dependencies [0c70c5e]
- @rulvar/[email protected]
1.10.0
Patch Changes
- Updated dependencies [0e8d78e]
- @rulvar/[email protected]
1.9.0
Minor Changes
7577f8e: Correct the Anthropic fallback pricing to the official table and export versioned price tables from both first-party adapters.
The
ANTHROPIC_MODELSseed rows had never been audited against the published price list and overcharged every current Claude model: Fable 5 was seeded at exactly 2x the official rate (20/100 vs 10/50 per MTok, cache rates likewise), Opus 4.8 at 12/60 vs 5/25, Opus 4.7 at 10/50 vs 5/25, and Opus 4.6 at 15/75 vs 5/25. Claude Sonnet 5 now carries its introductory price (2/10, in effect through 2026-08-31); Haiku 4.5 and Sonnet 4.6 were already correct. Cost reports for affected models drop accordingly, and budget ceilings admit roughly twice the work they previously rejected.New exports
ANTHROPIC_PRICING(anthropic-2026-07-16) andOPENAI_PRICING(openai-2026-07-16) publish the seed rows as versionedPriceTables forcreateEngine({ pricing }), so runs journal a concrete pricing version instead ofunpricedand price revisions become explicit table updates.createTestEnginegained apricingpassthrough for testing against a versioned table.
Patch Changes
- Updated dependencies [3a53383]
- @rulvar/[email protected]
1.8.0
Patch Changes
- Updated dependencies [25724b5]
- Updated dependencies [57ea1de]
- Updated dependencies [7884ec5]
- Updated dependencies [52db30d]
- @rulvar/[email protected]
1.7.0
Patch Changes
- Updated dependencies [45285aa]
- Updated dependencies [2f20d1d]
- Updated dependencies [22f65a8]
- Updated dependencies [2ddfa29]
- Updated dependencies [2abd9c2]
- Updated dependencies [1c1175d]
- @rulvar/[email protected]
1.6.0
Minor Changes
df416fc: Correct and extend model pricing: GPT-5.6 entries, long-context tiers, no fabricated prices, no double-charged cache.
Pricinggains optional long-contexttiers(PricingTier): the highest threshold strictly below the full prompt re-prices the entire request, input-side rates (cache included) scaling byinputMultiplierand the output rate byoutputMultiplier. Existing linear rows are untouched.@rulvar/openaiseedsgpt-5.6-soland itsgpt-5.6alias with the official caps and pricing (1,050,000 context, 128,000 max output, $5/$0.50/$30 per MTok, $6.25 cache write, 2x input and 1.5x output above 272K input tokens). Previously the unknown-model fallback silently priced them as gpt-5.4.- Unknown model ids in both first-class adapters keep conservative transport caps but no longer receive a fabricated price row: their usage surfaces in
CostReport.unpricedand a USD ceiling warns that it cannot bound them. Provide a versionedcreateEngine({ pricing })row for hosted models the tables do not know yet. priceUsdOfno longer double-charges cache tokens: under the Usage invariantinputTokensis the full prompt, so the input rate now bills only the uncached remainder while cache reads and writes bill at their own rates (a row without cache rates bills them at the input rate). Cache-heavy runs previously over-attributed cost by the full input rate on every cached token.- Admission reserve estimation routes through the same
priceUsdOf, so estimates and settled costs share one formula, tiers included. - Model id resolution picks the longest matching table prefix, so a dated
gpt-5.5-pro-...snapshot resolves to the pro entry, never the shortergpt-5.5sibling.
886d065: Make the first-class adapters genuinely streaming: every canonical event is yielded AS its provider event is consumed.
Both adapters (and
openaiCompatible) buffered the complete canonical event stream in an internal array and yielded it only after the provider response finished. Consequences fixed by this change:agent:streamwas never live; the stream-idle watchdog saw zero events during healthy generation, so any turn longer thanstreamIdleTimeoutMs(default 120s) was falsely severed as idle and retried; a budget or external abort lost ALL partial usage (the journal recorded zero for tokens the provider billed); and every delta of a long response was retained in memory.mapAnthropicStream,mapResponsesStream, andmapChatCompletionsStreamare now async generators: they yield eachChatEventas the corresponding provider event is consumed, with the consumer's pull as the only pacing (natural backpressure, no queue, no detached work). The Anthropic mapper's return value carries the accumulatedpause_turnstate;TurnMappingno longer has the redundanteventsarray field. Callers of the old callback signatures (emitparameter) must switch to iterating the generator.- Adapter behavior is preserved: canonical id mapping, thinking/reasoning retention,
pause_turncontinuation and its cap (each segment now streams live before the continuation dispatches), tool argument assembly, typed refusals and errors, exactly one canonical terminal event, the degraded Chat Completions path (visible inproviderMetadata.openai.degradedPath), abort propagation, usage normalization, and SDK autoretries disabled. - New regression tests with gated fake SDK clients prove the first
stream().next()resolves before the provider terminal exists, aborts reach the in-flight provider iterable after the first delta, a paused consumer causes zero read-ahead (lock-step pulls),pause_turnsegment deltas arrive before the continuation request, and exactly one terminal event survives.
Patch Changes
- da4dbad: Write the product name as Rulvar in prose: package READMEs, npm descriptions, and the documentation site now capitalize the brand. Identifiers keep their exact casing, so package names, the
rulvarbinary,rulvar.config.mjs, the.rulvarstore directory, therulvar.*OTel attributes, and every URL are unchanged. Documentation and metadata only; no runtime behaviour changes. - Updated dependencies [da4dbad]
- Updated dependencies [487da86]
- Updated dependencies [df416fc]
- Updated dependencies [a737810]
- Updated dependencies [9eb66b4]
- @rulvar/[email protected]
1.5.2
Patch Changes
- Updated dependencies [54936a0]
- @rulvar/[email protected]
1.5.1
Patch Changes
- Updated dependencies [6c6d56f]
- @rulvar/[email protected]
1.5.0
Patch Changes
- Updated dependencies [4fba3c7]
- Updated dependencies [8655c0f]
- @rulvar/[email protected]
1.4.0
Patch Changes
- Updated dependencies [c4f563d]
- @rulvar/[email protected]
1.3.2
Patch Changes
- ddef383: Every published package now ships a README, so its npm page states what the package is, how it installs, and where the documentation lives (npm includes README.md in the tarball regardless of the files allowlist, so no manifest changes are involved; @rulvar/compat gains its README on its own next release). Alongside, the repository-level pages are refreshed to the current project state: the root README is rewritten around the never-pay-twice pitch with a runnable quickstart condensation and the full package table, CONTRIBUTING.md lists the complete PR gate set, the examples README drops retired-spec citations for live docs.rulvar.com links and documents the dogfood journal replay, and the pointer README gets the same treatment.
- Updated dependencies [ddef383]
- @rulvar/[email protected]
1.3.1
Patch Changes
- 7d1552e: Runtime message strings no longer cite the retired internal specification set: error and warning messages, validation issues, and the CLI help text drop the dangling
docs/NN, section ...references, pointing at https://docs.rulvar.com pages where a pointer earns its place (the CLI help header, tool naming, toolset registries, bare resume). The umbrella package description sheds the naming-contingency note: the unscoped alias is published and owned. Three strings embedded in frozen recordings stay byte-identical on purpose (the no-progress abort reason and two testing-internal recorder strings), as does the byte-locked golden-fold fixture. Test-file comments lose their citations too; test titles are unchanged. - Updated dependencies [7d1552e]
- @rulvar/[email protected]
1.3.0
Patch Changes
- Updated dependencies [7d1a287]
- @rulvar/[email protected]
1.2.0
Patch Changes
- 154507b: TSDoc and inline comments no longer cite the retired internal specification set (the pre-docs-site
docs/NN, section ...references). The citations either became links to the public documentation at docs.rulvar.com or were dropped where the comment already carried the rule; traceability markers (DEF-n, XF-nn, FR-nnn, OQ-nn, W-nnn) are untouched. Comment-only change: no runtime behavior, no API shapes, and no runtime message strings were modified; the frozen golden-fold fixture is byte-identical. - Updated dependencies [3bfaec0]
- Updated dependencies [890f42c]
- Updated dependencies [154507b]
- @rulvar/[email protected]
1.1.0
Patch Changes
- f2253cb: The adapter scrubs constrained-decoding-unsupported keywords from the wire copy of strict tool schemas and output format schemas (
minimum,maximum,exclusiveMinimum,exclusiveMaximum,multipleOf,maxItems; measured live, docs/04 section 4.3 as amended). The orchestrator's spawn tools carry integer minimums, so every live orchestrate run died with a pre-first-call 400 ("For 'integer' type, property 'minimum' is not supported") at zero cost, which is what kept criterion 2 of the M12 checkpoint unmeasurable. The engine-side schema stays unscrubbed and still validates tool args and structured output, so the dropped keywords remain enforced; only the model-side hint is lost. - 63b2c01: Two defects the first live M12 checkpoint run surfaced. The Anthropic capability table lacked a Haiku 4.5 entry, so the dated id fell through to the current-generation default and the adapter sent adaptive thinking, which that model rejects with a live 400 (every haiku run died at zero cost):
claude-haiku-4-5(and its dated snapshots by the prefix rule) now resolves to the enabled-budget thinking form with real haiku pricing, meaning the default wire omits thinking entirely. And the checkpoint's criterion 2 could pass vacuously when both arms scored zero at zero cost (zero satisfies "at least equal at no more cost"): the card-informed arm must now win something real (nonzero n and pass rate) before the criterion can hold. - 99dc3ed: The second Haiku 4.5 wire incompatibility (the first live probe after the caps entry): the model also rejects the top-level effort parameter with a 400, so its capability entry now declares empty reasoningEfforts and the router scrubs effort off the wire (the requested effort stays in identity). Verified live: a haiku run completes ok.
- Updated dependencies [d16b04a]
- @rulvar/[email protected]
1.0.0
Patch Changes
- Updated dependencies [0e0b569]
- Updated dependencies [b28b7a3]
- Updated dependencies [b53a89e]
- Updated dependencies [4454175]
- Updated dependencies [6599ca8]
- Updated dependencies [6649e5f]
- Updated dependencies [fd2f83b]
- Updated dependencies [01d6b2d]
- Updated dependencies [9a20dbb]
- Updated dependencies [0fbe7ea]
- Updated dependencies [ebe0abc]
- Updated dependencies [a3079d0]
- Updated dependencies [596a39b]
- Updated dependencies [464ab6e]
- @rulvar/[email protected]
0.9.0
Patch Changes
- Updated dependencies [84f94d4]
- Updated dependencies [65c7b2c]
- Updated dependencies [a2a3243]
- Updated dependencies [ebc8101]
- @rulvar/[email protected]
0.8.0
Patch Changes
- Updated dependencies [85d55cf]
- Updated dependencies [b88c9e3]
- Updated dependencies [f3c4613]
- Updated dependencies [a41c20f]
- Updated dependencies [f4e70be]
- Updated dependencies [75d1646]
- Updated dependencies [0627413]
- Updated dependencies [55c0f87]
- Updated dependencies [fd33871]
- Updated dependencies [e70e7f4]
- Updated dependencies [bc9c903]
- @rulvar/[email protected]
0.7.0
Patch Changes
- Updated dependencies [fd1d06c]
- Updated dependencies [6fcf296]
- Updated dependencies [dcc97a9]
- Updated dependencies [434dc83]
- Updated dependencies [03173c1]
- Updated dependencies [11c0afc]
- @rulvar/[email protected]
0.6.0
Patch Changes
- Updated dependencies [fa05007]
- Updated dependencies [9234dc8]
- Updated dependencies [644512c]
- Updated dependencies [8a41656]
- Updated dependencies [02f7f7a]
- @rulvar/[email protected]
0.5.0
Minor Changes
ac274f4: M4-T01 role protocol completion. The full trigger protocol for the six invocation roles lands in
@rulvar/core(model/roles.ts):- Extract necessity is completed per docs/04 section 8.3: a separate final structured-output invocation fires when a schema is set AND (routing directs extract to a different model OR the loop model's required tier cannot ride a tools-available turn OR finalize is routed). The required-tier rule is new: a
forced-tooltier pins toolChoice toemit_resultand cannot ride while the agent's tools must remain available, so such agents now pay one separate extract call instead of silently losing tool access. Agents without tools keep the M1 single-shot behavior byte for byte. - The finalize role fires for the first time: only when configured in routing and only for tool-bearing agents, as one synthesis invocation with toolChoice
'none'over the full transcript after tools stop. Its text is the output for schema-less calls; with a schema the separate extract runs over the transcript including the synthesis. - A separate extract invocation over a tool-bearing transcript now carries the agent's tool contracts (both providers reject tool-use history without tool definitions) with toolChoice pinned to
'none'or toemit_resultper tier. - Both adapters map
toolChoice: 'none'to the provider's explicit none choice with the tools param present instead of dropping tools from the request. createTestEngineno longer routesfinalizeby default: the routing key is the firing opt-in, and the old default would have summoned a synthesis call for every tool-bearing test agent. Tests that want finalize route it explicitly.
Identity is untouched: extract and finalize resolutions never enter the spawn content key, and existing journals replay unchanged.
- Extract necessity is completed per docs/04 section 8.3: a separate final structured-output invocation fires when a schema is set AND (routing directs extract to a different model OR the loop model's required tier cannot ride a tools-available turn OR finalize is routed). The required-tier rule is new: a
5735d92: M4-T02 HistoryProjector. Cross-provider history projection lands in
@rulvar/core(model/projector.ts) and the retention pipeline that feeds it:projectHistoryprojects the canonical history into a target provider's view: provider-raw parts ride if and only if the target adapter's provider family matches the part's provider; everything else passes through untouched. The agent loop projects EVERY outgoing request (loop turns, finalize, extract), so per-role provider mixing inside one agent yields a valid wire history on each side.- Retention transport: adapters ship a turn's blocks-to-retain in stream order via
finish.providerMetadata[<adapter id>].retainedParts; the runtime lifts them into provider-raw parts at the HEAD of the turn's canonical assistant message.@rulvar/anthropicships thinking and redacted_thinking blocks (signatures intact, pause_turn continuations included);@rulvar/openaiships reasoning items with their encrypted_content. Retained blocks now actually reach the canonical history, survive checkpoints, and echo byte-exact to their own provider on every subsequent turn. ProviderAdaptergains an optionalproviderfield: the provider family for provider-raw matching (default = adapter id). The first-class adapters declare 'anthropic' and 'openai';openaiCompatiblegateways declare 'openai' whatever their custom id, so same-family adapters share retained blocks and projections.
Identity is untouched: projection state never enters content keys, and adapters that ship no retention payload (FakeAdapter included) produce byte-identical histories.
Patch Changes
- Updated dependencies [ac274f4]
- Updated dependencies [5735d92]
- Updated dependencies [46ca98e]
- Updated dependencies [8ae129e]
- Updated dependencies [d1c4525]
- Updated dependencies [b840aba]
- @rulvar/[email protected]
0.4.0
Patch Changes
- Updated dependencies [dfe03b5]
- Updated dependencies [d2089a7]
- Updated dependencies [3f60234]
- Updated dependencies [f668890]
- Updated dependencies [16d7aa6]
- Updated dependencies [6513ce8]
- Updated dependencies [7dad493]
- Updated dependencies [2bbf180]
- @rulvar/[email protected]
0.3.0
Patch Changes
- Updated dependencies [43444f6]
- Updated dependencies [279881b]
- Updated dependencies [9fd0966]
- Updated dependencies [24ebadf]
- Updated dependencies [a1b35d3]
- Updated dependencies [18a5821]
- @rulvar/[email protected]
0.2.0
Minor Changes
- 527c9b4: M1-T12/T13: the two first-class adapters on the July 2026 surfaces. @rulvar/anthropic: adaptive thinking, the output_config umbrella (effort passthrough including max, native json_schema format), strict tools, cache_control compilation from cacheHint (deepest-4 kept), thinking-block retention with provider-granularity projection, pause_turn absorption without synthetic user messages, the full stop-reason table with typed refusal stop details, count_tokens, capabilities-bearing refreshCaps, retry-after/x-ratelimit/529 signaling, SDK autoretries disabled, usage normalization under the Usage invariant. @rulvar/openai: Responses API with manual item replay only (store false, encrypted reasoning echoed verbatim; previous_response_id/Conversations rejected as ConfigError), flattened strict function tools, text.format json_schema, the typed SSE catalog mapped to ChatEvent, the Chat Completions degraded path (visible via providerMetadata), effort mapping with the documented lossy max-to-xhigh downmap and provider none via providerOptions only, usage normalization.
Patch Changes
- Updated dependencies [c24228d]
- Updated dependencies [c50871e]
- Updated dependencies [1af8fb9]
- Updated dependencies [1fe0249]
- Updated dependencies [5c4fc32]
- @rulvar/[email protected]
0.1.0
Minor Changes
- f4e2be9: M0 repo bootstrap (v0.1.0, docs/10-implementation-plan.md section "M0"): monorepo scaffold on the committed toolchain (pnpm 11 workspaces with catalogs, TypeScript 6.0, tsdown, Vitest 4, ESLint 9 flat config, Turborepo 2, changesets fixed mode, npm trusted publishing), the docs/ canon as single source of truth, the L0 contracts skeleton in @rulvar/core, and the vendored dependencies (StandardSchemaV1/StandardJSONSchemaV1 types, the @cfworker/json-schema lineage validator subset, a first-party monotonic ULID). Placeholder scaffolds only: no public API ships in this release.
Patch Changes
- Updated dependencies [f4e2be9]
- @rulvar/[email protected]
@rulvar/bridge-ai-sdk
1.252.0
Patch Changes
- Updated dependencies [3ccb6cf]
- Updated dependencies [52d807f]
- Updated dependencies [517ed00]
- Updated dependencies [a7e589d]
- Updated dependencies [76e95eb]
- @rulvar/[email protected]
1.251.0
Patch Changes
- Updated dependencies [e7e829c]
- Updated dependencies [5982be8]
- Updated dependencies [7c58fb2]
- Updated dependencies [b3e465a]
- Updated dependencies [c4e5d6a]
- Updated dependencies [c6fc3da]
- Updated dependencies [c6fc3da]
- Updated dependencies [0ae8b85]
- Updated dependencies [7932936]
- Updated dependencies [7932936]
- Updated dependencies [88da0ed]
- Updated dependencies [06c0e85]
- @rulvar/[email protected]
1.250.0
Patch Changes
- Updated dependencies [0e240b9]
- Updated dependencies [6fe585e]
- Updated dependencies [c5eb19c]
- Updated dependencies [565c13b]
- Updated dependencies [c6d197b]
- Updated dependencies [c9d9729]
- Updated dependencies [fed9db6]
- Updated dependencies [df9ed76]
- Updated dependencies [3020912]
- Updated dependencies [d8d598d]
- @rulvar/[email protected]
1.249.0
Patch Changes
- Updated dependencies [8862133]
- Updated dependencies [0d7a717]
- Updated dependencies [e4428bd]
- Updated dependencies [d6873c1]
- Updated dependencies [4092e8d]
- Updated dependencies [e086590]
- Updated dependencies [1411938]
- Updated dependencies [737d1ee]
- Updated dependencies [634f966]
- Updated dependencies [052cc26]
- Updated dependencies [bbae134]
- @rulvar/[email protected]
1.248.0
Patch Changes
- Updated dependencies [8d0cd69]
- Updated dependencies [81065e4]
- Updated dependencies [8573f20]
- Updated dependencies [95f6a5e]
- @rulvar/[email protected]
1.247.0
Patch Changes
- Updated dependencies [1933ecc]
- Updated dependencies [db0a5f0]
- Updated dependencies [b698726]
- Updated dependencies [48348d2]
- Updated dependencies [4cfa1cc]
- Updated dependencies [4b7197a]
- Updated dependencies [5ebc842]
- Updated dependencies [16ff6b9]
- Updated dependencies [0c9941d]
- @rulvar/[email protected]
1.246.0
Minor Changes
- d165b0c: The profile hash sees the constructions, and counts what it cannot (RV4101; the debt RV4009 named). The regulated floor binds what flows through options, but the postures that decide whether a tool list can drift beneath a run (an
mcp()source'sdriftand discovery bounds, RV1516/RV1808) or whether a provider executes tools outside the permission chain (the AI SDK bridge'sproviderExecutedToolsseam) live on CONSTRUCTIONS the options never see; RV4009 excluded them from the hash by principle ("a hash must not imply what it cannot verify") and named them in prose. This train makes the verifiable part verified. A risk-bearing construction now exposesdescribeRegulatedPosture(), a PURE snapshot of what was chosen at build time (no wire, no connect):mcp()reports{ drift, bounds },bridgeAiSdk()reports{ providerExecutedTools }, both implemented this release.compileRegulatedProfilewalks every construction its options reach (adapters, named toolsets, profile toolsets, each object once), REFUSES a loosened posture by field name (construction['mcp:http:...'].drift must be 'refuse'; bounds must be declared; the bridge must deny), refuses outright a descriptor of a shape or kind it cannot judge, and folds the sorted descriptors into the hashed posture map underconstruction, beside anunrecognizedcount of the constructions that exposed nothing, so the hash names its own blind spot instead of implying totality.REGULATED_VERSIONbumps to 2 (regulated:2:<hash>): the map's meaning changed, and a v1 fingerprint must never collide with a v2 reading of the same options. Deliberately open, by name: a construction mutated AFTER compile time; the descriptor is a snapshot, not a lease, and the first-use re-assertion is the RV1608 template applied in its own train. Probes pin the drift refusal and the blind-spot count.
Patch Changes
- Updated dependencies [d165b0c]
- Updated dependencies [d59f4a0]
- Updated dependencies [46907ac]
- Updated dependencies [9929ad3]
- Updated dependencies [1790a6a]
- @rulvar/[email protected]
1.245.0
Patch Changes
- Updated dependencies [b4d47a8]
- Updated dependencies [dee6db4]
- Updated dependencies [b85c113]
- Updated dependencies [bc556e7]
- Updated dependencies [9f11d29]
- Updated dependencies [19bcea0]
- Updated dependencies [60b461c]
- Updated dependencies [61e3a1a]
- Updated dependencies [a156b81]
- Updated dependencies [0bd7045]
- @rulvar/[email protected]
1.244.0
Patch Changes
- Updated dependencies [38d839a]
- Updated dependencies [ce13b0f]
- Updated dependencies [4fa23e3]
- Updated dependencies [6841c69]
- Updated dependencies [f56721d]
- Updated dependencies [c894a43]
- Updated dependencies [f6944a3]
- Updated dependencies [23fd0e0]
- @rulvar/[email protected]
1.243.0
Patch Changes
- Updated dependencies [746d1f4]
- Updated dependencies [009b29c]
- Updated dependencies [1674cbe]
- Updated dependencies [bd096bc]
- @rulvar/[email protected]
1.242.0
Patch Changes
- Updated dependencies [6e3438e]
- Updated dependencies [ba5cf67]
- Updated dependencies [c2d1531]
- @rulvar/[email protected]
1.241.0
Patch Changes
- Updated dependencies [dbcdd24]
- Updated dependencies [7ae7243]
- Updated dependencies [4f832c4]
- Updated dependencies [7452d3d]
- Updated dependencies [a4e22bf]
- Updated dependencies [82df4af]
- @rulvar/[email protected]
1.240.0
Patch Changes
- @rulvar/[email protected]
1.239.0
Patch Changes
- Updated dependencies [74ce99a]
- Updated dependencies [ccd0665]
- Updated dependencies [0c5ce21]
- Updated dependencies [0616934]
- @rulvar/[email protected]
1.238.0
Patch Changes
- Updated dependencies [cf00947]
- Updated dependencies [c7b9382]
- Updated dependencies [88aea96]
- Updated dependencies [6da8d05]
- Updated dependencies [eae5c4c]
- @rulvar/[email protected]
1.237.0
Patch Changes
- Updated dependencies [9d6a279]
- Updated dependencies [49a98f6]
- Updated dependencies [a734ca0]
- Updated dependencies [deb406f]
- @rulvar/[email protected]
1.236.0
Patch Changes
- Updated dependencies [26306ea]
- Updated dependencies [709b942]
- @rulvar/[email protected]
1.235.0
Patch Changes
- Updated dependencies [ba4e10d]
- Updated dependencies [172402b]
- Updated dependencies [2ecd787]
- Updated dependencies [e20a5e9]
- Updated dependencies [98c8691]
- Updated dependencies [c70def0]
- @rulvar/[email protected]
1.234.0
Patch Changes
- Updated dependencies [8420c04]
- @rulvar/[email protected]
1.233.0
Patch Changes
- Updated dependencies [48b5200]
- Updated dependencies [73bc32b]
- Updated dependencies [e63b743]
- Updated dependencies [ef45da7]
- @rulvar/[email protected]
1.232.0
Patch Changes
- Updated dependencies [1440410]
- Updated dependencies [6e467f4]
- Updated dependencies [0b14293]
- Updated dependencies [e3bcab2]
- Updated dependencies [b55a0f7]
- @rulvar/[email protected]
1.231.0
Patch Changes
- Updated dependencies [4eb4b56]
- Updated dependencies [bc8f09e]
- Updated dependencies [ff9b8c2]
- @rulvar/[email protected]
1.230.0
Patch Changes
- Updated dependencies [e9bf910]
- Updated dependencies [57bfb38]
- @rulvar/[email protected]
1.229.0
Patch Changes
- Updated dependencies [3370342]
- Updated dependencies [2fb6656]
- Updated dependencies [edce170]
- @rulvar/[email protected]
1.228.0
Patch Changes
- Updated dependencies [4034fac]
- Updated dependencies [a54b085]
- Updated dependencies [9d0a9be]
- Updated dependencies [be9ef28]
- @rulvar/[email protected]
1.227.0
Patch Changes
- Updated dependencies [f262e9f]
- Updated dependencies [f191ff7]
- Updated dependencies [fbbfbe8]
- Updated dependencies [263b5e8]
- Updated dependencies [db4d56d]
- Updated dependencies [41f93a9]
- Updated dependencies [98c8ca9]
- @rulvar/[email protected]
1.226.0
Patch Changes
- @rulvar/[email protected]
1.225.0
Patch Changes
- @rulvar/[email protected]
1.224.0
Patch Changes
- Updated dependencies [4eca1a3]
- @rulvar/[email protected]
1.223.0
Patch Changes
- Updated dependencies [549aabd]
- Updated dependencies [549aabd]
- @rulvar/[email protected]
1.222.0
Patch Changes
- Updated dependencies [8326268]
- @rulvar/[email protected]
1.221.0
Patch Changes
- Updated dependencies [032ce93]
- @rulvar/[email protected]
1.220.0
Patch Changes
- Updated dependencies [0babe70]
- @rulvar/[email protected]
1.219.0
Patch Changes
- Updated dependencies [65a4ce7]
- @rulvar/[email protected]
1.218.0
Patch Changes
- Updated dependencies [088bda6]
- @rulvar/[email protected]
1.217.0
Patch Changes
- Updated dependencies [ab80b97]
- @rulvar/[email protected]
1.216.0
Patch Changes
- Updated dependencies [b357f4a]
- @rulvar/[email protected]
1.215.0
Patch Changes
- Updated dependencies [e1da4c7]
- @rulvar/[email protected]
1.214.0
Patch Changes
- Updated dependencies [c8af0ec]
- @rulvar/[email protected]
1.213.0
Patch Changes
- Updated dependencies [61680df]
- @rulvar/[email protected]
1.212.0
Patch Changes
- Updated dependencies [e6f8516]
- @rulvar/[email protected]
1.211.0
Patch Changes
- Updated dependencies [d5a8a36]
- @rulvar/[email protected]
1.210.0
Patch Changes
- Updated dependencies [c871ddc]
- @rulvar/[email protected]
1.209.0
Patch Changes
- Updated dependencies [514c7bb]
- @rulvar/[email protected]
1.208.0
Patch Changes
- Updated dependencies [e7d426f]
- @rulvar/[email protected]
1.207.0
Patch Changes
- Updated dependencies [99beee2]
- @rulvar/[email protected]
1.206.0
Patch Changes
- Updated dependencies [ec8e1f1]
- @rulvar/[email protected]
1.205.0
Patch Changes
- Updated dependencies [6d224da]
- @rulvar/[email protected]
1.204.0
Patch Changes
- Updated dependencies [efaec9b]
- @rulvar/[email protected]
1.203.0
Patch Changes
- Updated dependencies [fb08c10]
- @rulvar/[email protected]
1.202.0
Patch Changes
- @rulvar/[email protected]
1.201.0
Patch Changes
- Updated dependencies [7e01189]
- @rulvar/[email protected]
1.200.0
Patch Changes
- Updated dependencies [e2ddbdf]
- @rulvar/[email protected]
1.199.0
Patch Changes
- Updated dependencies [29891c6]
- @rulvar/[email protected]
1.198.0
Patch Changes
- Updated dependencies [c097c96]
- @rulvar/[email protected]
1.197.0
Patch Changes
- @rulvar/[email protected]
1.196.0
Patch Changes
- Updated dependencies [ec9c3e3]
- @rulvar/[email protected]
1.195.0
Patch Changes
- Updated dependencies [5702a70]
- @rulvar/[email protected]
1.194.0
Patch Changes
- Updated dependencies [360a659]
- @rulvar/[email protected]
1.193.0
Patch Changes
- Updated dependencies [2bca1d1]
- @rulvar/[email protected]
1.192.0
Patch Changes
- Updated dependencies [8757601]
- @rulvar/[email protected]
1.191.0
Patch Changes
- Updated dependencies [745387c]
- @rulvar/[email protected]
1.190.0
Patch Changes
- Updated dependencies [8e02021]
- @rulvar/[email protected]
1.189.0
Patch Changes
- Updated dependencies [6a5cc2d]
- @rulvar/[email protected]
1.188.0
Minor Changes
- b6d0bc8: Provider-executed tools become a policy surface, denied by default (RV1806). The bridge used to absorb a wrapped provider's server-side tool exchanges (web search, code execution) silently into retention: calls that never pass the engine's
ToolDefregistry, risk classes, ask rules, or approvals, with effects on provider infrastructure no permission chain can see. Under the new defaultproviderExecutedTools: 'deny'the first provider-executed exchange fails the turn with a typed terminal error naming the tool;'allow'opts back into the old retention behavior and additionally names every provider-executed call on the finish metadata (providerExecutedTools: [{ toolName, toolCallId }]), so the journaled record of the turn says what the provider ran. Hosts that relied on the silent absorption must now passbridgeAiSdk(model, { providerExecutedTools: 'allow' }); a malformed value refuses typed at construction.
Patch Changes
- @rulvar/[email protected]
1.187.0
Patch Changes
- Updated dependencies [c9798ef]
- @rulvar/[email protected]
1.186.0
Patch Changes
- Updated dependencies [242647e]
- @rulvar/[email protected]
1.185.0
Patch Changes
- Updated dependencies [1248623]
- @rulvar/[email protected]
1.184.0
Patch Changes
- Updated dependencies [8a9caca]
- @rulvar/[email protected]
1.183.0
Patch Changes
- Updated dependencies [dd3767c]
- @rulvar/[email protected]
1.182.0
Patch Changes
- Updated dependencies [144d026]
- @rulvar/[email protected]
1.181.0
Patch Changes
- @rulvar/[email protected]
1.180.0
Patch Changes
- Updated dependencies [b124d26]
- @rulvar/[email protected]
1.179.0
Patch Changes
- Updated dependencies [1a5a85a]
- @rulvar/[email protected]
1.178.0
Patch Changes
- @rulvar/[email protected]
1.177.0
Patch Changes
- Updated dependencies [94db8ff]
- @rulvar/[email protected]
1.176.0
Patch Changes
- Updated dependencies [a74304d]
- @rulvar/[email protected]
1.175.0
Patch Changes
- Updated dependencies [1999c5d]
- @rulvar/[email protected]
1.174.0
Patch Changes
- Updated dependencies [aa9a772]
- @rulvar/[email protected]
1.173.0
Patch Changes
- Updated dependencies [67d27ac]
- @rulvar/[email protected]
1.172.0
Patch Changes
- Updated dependencies [0d4770b]
- @rulvar/[email protected]
1.171.0
Patch Changes
- Updated dependencies [f6116b9]
- @rulvar/[email protected]
1.170.0
Patch Changes
- Updated dependencies [86e4c06]
- @rulvar/[email protected]
1.169.0
Patch Changes
- Updated dependencies [623b2ae]
- @rulvar/[email protected]
1.168.0
Patch Changes
- Updated dependencies [ebba79a]
- @rulvar/[email protected]
1.167.0
Patch Changes
- @rulvar/[email protected]
1.166.0
Patch Changes
- Updated dependencies [d8262c3]
- @rulvar/[email protected]
1.165.0
Patch Changes
- Updated dependencies [6391274]
- @rulvar/[email protected]
1.164.0
Patch Changes
- Updated dependencies [9f2dda9]
- @rulvar/[email protected]
1.163.0
Patch Changes
- Updated dependencies [e8d9ada]
- @rulvar/[email protected]
1.162.0
Patch Changes
- Updated dependencies [2031e82]
- @rulvar/[email protected]
1.161.0
Patch Changes
- Updated dependencies [d4547b7]
- @rulvar/[email protected]
1.160.0
Patch Changes
- Updated dependencies [1c6f0d0]
- @rulvar/[email protected]
1.159.0
Patch Changes
- Updated dependencies [e881c8b]
- @rulvar/[email protected]
1.158.0
Patch Changes
- Updated dependencies [a266bc7]
- @rulvar/[email protected]
1.157.0
Patch Changes
- Updated dependencies [1883421]
- @rulvar/[email protected]
1.156.0
Patch Changes
- Updated dependencies [537144e]
- @rulvar/[email protected]
1.155.0
Patch Changes
- Updated dependencies [49b08a7]
- @rulvar/[email protected]
1.154.0
Patch Changes
- Updated dependencies [9259f24]
- @rulvar/[email protected]
1.153.0
Patch Changes
- Updated dependencies [d8bebcb]
- @rulvar/[email protected]
1.152.0
Patch Changes
- Updated dependencies [dd6a616]
- @rulvar/[email protected]
1.151.0
Patch Changes
- Updated dependencies [1de0610]
- @rulvar/[email protected]
1.150.0
Patch Changes
- Updated dependencies [a331211]
- @rulvar/[email protected]
1.149.0
Patch Changes
- Updated dependencies [08b4537]
- @rulvar/[email protected]
1.148.0
Patch Changes
- Updated dependencies [c85dac9]
- @rulvar/[email protected]
1.147.0
Patch Changes
- Updated dependencies [6367231]
- @rulvar/[email protected]
1.146.0
Patch Changes
- Updated dependencies [5d9bbc8]
- @rulvar/[email protected]
1.145.0
Patch Changes
- @rulvar/[email protected]
1.144.0
Patch Changes
- Updated dependencies [c11bcd6]
- @rulvar/[email protected]
1.143.0
Patch Changes
- Updated dependencies [f412169]
- @rulvar/[email protected]
1.142.0
Patch Changes
- @rulvar/[email protected]
1.141.0
Patch Changes
- Updated dependencies [4f12a62]
- @rulvar/[email protected]
1.140.0
Patch Changes
- @rulvar/[email protected]
1.139.0
Patch Changes
- Updated dependencies [03a2141]
- @rulvar/[email protected]
1.138.0
Patch Changes
- Updated dependencies [ed0c4fb]
- @rulvar/[email protected]
1.137.0
Patch Changes
- Updated dependencies [96f6788]
- @rulvar/[email protected]
1.136.0
Patch Changes
- Updated dependencies [aa6ca71]
- @rulvar/[email protected]
1.135.0
Patch Changes
- Updated dependencies [cf75e22]
- @rulvar/[email protected]
1.134.0
Patch Changes
- @rulvar/[email protected]
1.133.0
Patch Changes
- @rulvar/[email protected]
1.132.0
Patch Changes
- Updated dependencies [2bec904]
- @rulvar/[email protected]
1.131.0
Patch Changes
- Updated dependencies [256cae1]
- @rulvar/[email protected]
1.130.0
Patch Changes
- Updated dependencies [d6bec7a]
- @rulvar/[email protected]
1.129.0
Patch Changes
- Updated dependencies [1612439]
- @rulvar/[email protected]
1.128.0
Patch Changes
- Updated dependencies [27c4e38]
- @rulvar/[email protected]
1.127.0
Patch Changes
- Updated dependencies [b3b1805]
- @rulvar/[email protected]
1.126.0
Patch Changes
- @rulvar/[email protected]
1.125.0
Patch Changes
- @rulvar/[email protected]
1.124.0
Patch Changes
- Updated dependencies [37fd1f2]
- @rulvar/[email protected]
1.123.0
Patch Changes
- Updated dependencies [5c46468]
- @rulvar/[email protected]
1.122.0
Patch Changes
- Updated dependencies [8cf45c5]
- @rulvar/[email protected]
1.121.0
Patch Changes
- Updated dependencies [3d67d41]
- @rulvar/[email protected]
1.120.0
Patch Changes
- Updated dependencies [d630c9e]
- @rulvar/[email protected]
1.119.0
Patch Changes
- Updated dependencies [1e4ff3c]
- @rulvar/[email protected]
1.118.0
Patch Changes
- Updated dependencies [f8341a3]
- @rulvar/[email protected]
1.117.0
Patch Changes
- @rulvar/[email protected]
1.116.0
Patch Changes
- Updated dependencies [a213878]
- @rulvar/[email protected]
1.115.0
Patch Changes
- Updated dependencies [63642ae]
- @rulvar/[email protected]
1.114.0
Patch Changes
- Updated dependencies [5759731]
- @rulvar/[email protected]
1.113.0
Patch Changes
- Updated dependencies [a60807a]
- @rulvar/[email protected]
1.112.0
Patch Changes
- Updated dependencies [00ae55b]
- @rulvar/[email protected]
1.111.0
Patch Changes
- Updated dependencies [fd25169]
- @rulvar/[email protected]
1.110.0
Patch Changes
- Updated dependencies [58afdb5]
- @rulvar/[email protected]
1.109.0
Patch Changes
- Updated dependencies [85b1d39]
- @rulvar/[email protected]
1.108.0
Patch Changes
- Updated dependencies [affa3d4]
- @rulvar/[email protected]
1.107.0
Patch Changes
- Updated dependencies [9f5f6f6]
- @rulvar/[email protected]
1.106.0
Patch Changes
- Updated dependencies [9a4ce49]
- @rulvar/[email protected]
1.105.0
Patch Changes
- Updated dependencies [531dc88]
- @rulvar/[email protected]
1.104.0
Patch Changes
- @rulvar/[email protected]
1.103.0
Patch Changes
- Updated dependencies [f2b809e]
- @rulvar/[email protected]
1.102.0
Patch Changes
- Updated dependencies [3eb6515]
- @rulvar/[email protected]
1.101.0
Patch Changes
- Updated dependencies [51b215c]
- @rulvar/[email protected]
1.100.0
Patch Changes
- Updated dependencies [9785bea]
- @rulvar/[email protected]
1.99.1
Patch Changes
- Updated dependencies [ef08d73]
- @rulvar/[email protected]
1.99.0
Patch Changes
- Updated dependencies [9e00888]
- @rulvar/[email protected]
1.98.0
Patch Changes
- @rulvar/[email protected]
1.97.0
Patch Changes
- Updated dependencies [5c3b453]
- @rulvar/[email protected]
1.96.0
Patch Changes
- @rulvar/[email protected]
1.95.0
Patch Changes
- @rulvar/[email protected]
1.94.0
Patch Changes
- @rulvar/[email protected]
1.93.0
Patch Changes
- Updated dependencies [c62150a]
- @rulvar/[email protected]
1.92.0
Patch Changes
- Updated dependencies [351d1f5]
- @rulvar/[email protected]
1.91.0
Patch Changes
- @rulvar/[email protected]
1.90.0
Patch Changes
- Updated dependencies [9603940]
- @rulvar/[email protected]
1.89.0
Minor Changes
- f18b671: Provider-id provenance parity across every adapter path (RV401, the eighth comparison experiment). The AI SDK bridge now ships the flat
responseIdthe core reconciliation record reads, beside the nestedresponseobject it always emitted, and an error finish carries the accumulated response metadata and warnings on the error event instead of dropping them (retained parts stay deliberately absent there: a failed turn is discarded, never re-injected). The core agent loop captures provider metadata from error events and falls back to the AI SDK's nestedresponse.idshape when a third-party adapter ships only that, with the flat first-class form winning when both are present. The OpenAI adapter attaches the failed response's id to itsresponse.failederror event, so a billed failure reconciles against the provider statement exactly like an ok row. End-to-end tests pin a bridged engine run whose per-call reconciliation records carry ids on the success, retry, and billed-failure paths alike.
Patch Changes
- Updated dependencies [f18b671]
- Updated dependencies [f18b671]
- @rulvar/[email protected]
1.88.0
Patch Changes
- Updated dependencies [3b339d9]
- @rulvar/[email protected]
1.87.0
Patch Changes
- Updated dependencies [c4c02b1]
- @rulvar/[email protected]
1.86.0
Patch Changes
- Updated dependencies [2f71894]
- @rulvar/[email protected]
1.85.0
Patch Changes
- Updated dependencies [6932a9f]
- @rulvar/[email protected]
1.84.0
Minor Changes
- bc9105f: First-class doctrine parity for the bridge (the cycle 82 deep review). An error finish now ships the provider's usage as a usage event ahead of the terminal error, so a failed stream's paid tokens land on the meter instead of billing zero. Unparseable client tool arguments ship the
{__unparsed: raw}wrapper the engine's deterministic second chance repairs, instead of destroying the whole paid turn with a terminal error, and history projection unwraps the wrapper back to the raw text the model wrote (the openai wire's imitation guard, mirrored). Retention fidelity: a retained errored provider-executed tool result reinserts aserror-jsoninstead of a success, preliminary provider-executed results are no longer retained (only the final result is), and a reasoning segment still open at finish is flushed into retention instead of silently dropped. A stream that drains without a finish part under a requested abort now ends silently (the v1.27.0 posture) instead of minting a fake transport error, and the bridge cancels the wrapped V4 stream on early termination instead of abandoning the provider connection until GC.
Patch Changes
- @rulvar/[email protected]
1.83.0
Patch Changes
- @rulvar/[email protected]
1.82.0
Patch Changes
- Updated dependencies [9cc5d66]
- @rulvar/[email protected]
1.81.2
Patch Changes
- Updated dependencies [296885b]
- @rulvar/[email protected]
1.81.1
Patch Changes
- Updated dependencies [c030982]
- @rulvar/[email protected]
1.81.0
Patch Changes
- Updated dependencies [ce4c392]
- @rulvar/[email protected]
1.80.0
Patch Changes
- Updated dependencies [262e397]
- @rulvar/[email protected]
1.79.0
Patch Changes
- Updated dependencies [85956ab]
- @rulvar/[email protected]
1.78.0
Patch Changes
- Updated dependencies [941b6e1]
- @rulvar/[email protected]
1.77.0
Patch Changes
- Updated dependencies [6aba271]
- @rulvar/[email protected]
1.76.0
Patch Changes
- Updated dependencies [22cba47]
- @rulvar/[email protected]
1.75.1
Patch Changes
- Updated dependencies [82bc0f0]
- @rulvar/[email protected]
1.75.0
Patch Changes
- Updated dependencies [c486de8]
- @rulvar/[email protected]
1.74.0
Patch Changes
- Updated dependencies [d94beab]
- @rulvar/[email protected]
1.73.0
Patch Changes
- Updated dependencies [3e95bd1]
- @rulvar/[email protected]
1.72.0
Patch Changes
- Updated dependencies [662e9e0]
- @rulvar/[email protected]
1.71.0
Patch Changes
- Updated dependencies [20d02e0]
- @rulvar/[email protected]
1.70.1
Patch Changes
- @rulvar/[email protected]
1.70.0
Patch Changes
- @rulvar/[email protected]
1.69.0
Patch Changes
- Updated dependencies [b21a681]
- @rulvar/[email protected]
1.68.0
Patch Changes
- Updated dependencies [b227874]
- @rulvar/[email protected]
1.67.0
Patch Changes
- Updated dependencies [8e6006d]
- @rulvar/[email protected]
1.66.0
Patch Changes
- Updated dependencies [1b8987e]
- @rulvar/[email protected]
1.65.0
Patch Changes
- Updated dependencies [0b6b859]
- @rulvar/[email protected]
1.64.0
Patch Changes
- Updated dependencies [991f9b5]
- @rulvar/[email protected]
1.63.0
Patch Changes
- Updated dependencies [8a28aed]
- @rulvar/[email protected]
1.62.0
Patch Changes
- Updated dependencies [fca5fd1]
- @rulvar/[email protected]
1.61.0
Patch Changes
- Updated dependencies [b4c1f1f]
- @rulvar/[email protected]
1.60.0
Patch Changes
- Updated dependencies [59bbeaa]
- @rulvar/[email protected]
1.59.4
Patch Changes
- Updated dependencies [c49d7a1]
- @rulvar/[email protected]
1.59.3
Patch Changes
- Updated dependencies [deaef36]
- @rulvar/[email protected]
1.59.2
Patch Changes
- Updated dependencies [dd0e10f]
- @rulvar/[email protected]
1.59.1
Patch Changes
- Updated dependencies [c127770]
- @rulvar/[email protected]
1.59.0
Patch Changes
- Updated dependencies [615dc90]
- @rulvar/[email protected]
1.58.0
Patch Changes
- Updated dependencies [4fa35ce]
- @rulvar/[email protected]
1.57.0
Patch Changes
- Updated dependencies [5897232]
- @rulvar/[email protected]
1.56.0
Patch Changes
- Updated dependencies [f26dba0]
- @rulvar/[email protected]
1.55.0
Patch Changes
- Updated dependencies [e9b005b]
- @rulvar/[email protected]
1.54.0
Patch Changes
- Updated dependencies [3f6bc03]
- @rulvar/[email protected]
1.53.0
Patch Changes
- Updated dependencies [b821bd1]
- @rulvar/[email protected]
1.52.0
Patch Changes
- Updated dependencies [e138df9]
- @rulvar/[email protected]
1.51.0
Patch Changes
- @rulvar/[email protected]
1.50.0
Patch Changes
- Updated dependencies [e39a885]
- @rulvar/[email protected]
1.49.0
Patch Changes
- Updated dependencies [bab7b2c]
- @rulvar/[email protected]
1.48.0
Patch Changes
- @rulvar/[email protected]
1.47.0
Patch Changes
- Updated dependencies [a3687fe]
- @rulvar/[email protected]
1.46.0
Patch Changes
- Updated dependencies [865e7bf]
- @rulvar/[email protected]
1.45.0
Patch Changes
- Updated dependencies [b96305d]
- @rulvar/[email protected]
1.44.1
Patch Changes
- @rulvar/[email protected]
1.44.0
Patch Changes
- Updated dependencies [299f7d2]
- @rulvar/[email protected]
1.43.0
Patch Changes
- Updated dependencies [71b7181]
- @rulvar/[email protected]
1.42.0
Patch Changes
- Updated dependencies [9b70f27]
- @rulvar/[email protected]
1.41.0
Patch Changes
- Updated dependencies [be589ec]
- @rulvar/[email protected]
1.40.0
Patch Changes
- Updated dependencies [cf33550]
- @rulvar/[email protected]
1.39.0
Patch Changes
- @rulvar/[email protected]
1.38.0
Patch Changes
- @rulvar/[email protected]
1.37.0
Patch Changes
- Updated dependencies [e6b1481]
- Updated dependencies [e6b1481]
- @rulvar/[email protected]
1.36.0
Patch Changes
- Updated dependencies [101795b]
- @rulvar/[email protected]
1.35.0
Patch Changes
- Updated dependencies [d4ac3bf]
- @rulvar/[email protected]
1.34.0
Patch Changes
- Updated dependencies [f1505ec]
- @rulvar/[email protected]
1.33.0
Patch Changes
- @rulvar/[email protected]
1.32.0
Patch Changes
- @rulvar/[email protected]
1.31.0
Patch Changes
- @rulvar/[email protected]
1.30.0
Patch Changes
- Updated dependencies [87ce985]
- @rulvar/[email protected]
1.29.0
Patch Changes
- Updated dependencies [621d566]
- @rulvar/[email protected]
1.28.0
Patch Changes
- Updated dependencies [d98eb0b]
- @rulvar/[email protected]
1.27.0
Patch Changes
- Updated dependencies [884a433]
- @rulvar/[email protected]
1.26.0
Patch Changes
- Updated dependencies [a4fc757]
- @rulvar/[email protected]
1.25.0
Patch Changes
- @rulvar/[email protected]
1.24.1
Patch Changes
- Updated dependencies [0bb14db]
- @rulvar/[email protected]
1.24.0
Patch Changes
- Updated dependencies [2b033e8]
- @rulvar/[email protected]
1.23.0
Patch Changes
- Updated dependencies [1f9c272]
- @rulvar/[email protected]
1.22.0
Patch Changes
- Updated dependencies [77b554f]
- @rulvar/[email protected]
1.21.0
Patch Changes
- Updated dependencies [7ee42a0]
- @rulvar/[email protected]
1.20.0
Patch Changes
- Updated dependencies [9367030]
- @rulvar/[email protected]
1.19.0
Patch Changes
- Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- @rulvar/[email protected]
1.18.0
Patch Changes
- Updated dependencies [943962d]
- @rulvar/[email protected]
1.17.0
Patch Changes
- @rulvar/[email protected]
1.16.2
Patch Changes
- @rulvar/[email protected]
1.16.1
Patch Changes
- @rulvar/[email protected]
1.16.0
Patch Changes
- @rulvar/[email protected]
1.15.0
Patch Changes
- @rulvar/[email protected]
1.14.0
Patch Changes
- @rulvar/[email protected]
1.13.0
Patch Changes
- @rulvar/[email protected]
1.12.0
Patch Changes
- Updated dependencies [46edcc0]
- @rulvar/[email protected]
1.11.0
Patch Changes
- Updated dependencies [0c70c5e]
- @rulvar/[email protected]
1.10.0
Patch Changes
- Updated dependencies [0e8d78e]
- @rulvar/[email protected]
1.9.0
Patch Changes
- Updated dependencies [3a53383]
- @rulvar/[email protected]
1.8.0
Patch Changes
- Updated dependencies [25724b5]
- Updated dependencies [57ea1de]
- Updated dependencies [7884ec5]
- Updated dependencies [52db30d]
- @rulvar/[email protected]
1.7.0
Patch Changes
- Updated dependencies [45285aa]
- Updated dependencies [2f20d1d]
- Updated dependencies [22f65a8]
- Updated dependencies [2ddfa29]
- Updated dependencies [2abd9c2]
- Updated dependencies [1c1175d]
- @rulvar/[email protected]
1.6.0
Patch Changes
- da4dbad: Write the product name as Rulvar in prose: package READMEs, npm descriptions, and the documentation site now capitalize the brand. Identifiers keep their exact casing, so package names, the
rulvarbinary,rulvar.config.mjs, the.rulvarstore directory, therulvar.*OTel attributes, and every URL are unchanged. Documentation and metadata only; no runtime behaviour changes. - Updated dependencies [da4dbad]
- Updated dependencies [487da86]
- Updated dependencies [df416fc]
- Updated dependencies [a737810]
- Updated dependencies [9eb66b4]
- @rulvar/[email protected]
1.5.2
Patch Changes
- Updated dependencies [54936a0]
- @rulvar/[email protected]
1.5.1
Patch Changes
- Updated dependencies [6c6d56f]
- @rulvar/[email protected]
1.5.0
Patch Changes
- Updated dependencies [4fba3c7]
- Updated dependencies [8655c0f]
- @rulvar/[email protected]
1.4.0
Patch Changes
- Updated dependencies [c4f563d]
- @rulvar/[email protected]
1.3.2
Patch Changes
- ddef383: Every published package now ships a README, so its npm page states what the package is, how it installs, and where the documentation lives (npm includes README.md in the tarball regardless of the files allowlist, so no manifest changes are involved; @rulvar/compat gains its README on its own next release). Alongside, the repository-level pages are refreshed to the current project state: the root README is rewritten around the never-pay-twice pitch with a runnable quickstart condensation and the full package table, CONTRIBUTING.md lists the complete PR gate set, the examples README drops retired-spec citations for live docs.rulvar.com links and documents the dogfood journal replay, and the pointer README gets the same treatment.
- Updated dependencies [ddef383]
- @rulvar/[email protected]
1.3.1
Patch Changes
- 7d1552e: Runtime message strings no longer cite the retired internal specification set: error and warning messages, validation issues, and the CLI help text drop the dangling
docs/NN, section ...references, pointing at https://docs.rulvar.com pages where a pointer earns its place (the CLI help header, tool naming, toolset registries, bare resume). The umbrella package description sheds the naming-contingency note: the unscoped alias is published and owned. Three strings embedded in frozen recordings stay byte-identical on purpose (the no-progress abort reason and two testing-internal recorder strings), as does the byte-locked golden-fold fixture. Test-file comments lose their citations too; test titles are unchanged. - Updated dependencies [7d1552e]
- @rulvar/[email protected]
1.3.0
Patch Changes
- Updated dependencies [7d1a287]
- @rulvar/[email protected]
1.2.0
Patch Changes
- 154507b: TSDoc and inline comments no longer cite the retired internal specification set (the pre-docs-site
docs/NN, section ...references). The citations either became links to the public documentation at docs.rulvar.com or were dropped where the comment already carried the rule; traceability markers (DEF-n, XF-nn, FR-nnn, OQ-nn, W-nnn) are untouched. Comment-only change: no runtime behavior, no API shapes, and no runtime message strings were modified; the frozen golden-fold fixture is byte-identical. - Updated dependencies [3bfaec0]
- Updated dependencies [890f42c]
- Updated dependencies [154507b]
- @rulvar/[email protected]
1.1.0
Patch Changes
- Updated dependencies [d16b04a]
- @rulvar/[email protected]
1.0.0
Minor Changes
b728c48: M9-T01: bridgeAiSdk, the long-tail provider bridge (docs/04 section 7; FR-1xx). First real public surface of @rulvar/bridge-ai-sdk.
bridgeAiSdk(model, options?)wraps any Vercel AI SDK LanguageModelV4 (@ai-sdk/provider^4, catalog-pinned per docs/13 "Dependency baseline pins") as a rulvar ProviderAdapter for the long tail (Google, Bedrock, Vertex). A wrongspecificationVersionfails at construction with a typed ConfigError, so a transitive provider-package major cannot mis-wire silently.- The full ChatEvent vocabulary streams through: text and reasoning deltas, tool-call start/delta/end with engine-minted canonical ids mapped bijectively onto the wrapped provider's wire ids, incremental-free usage normalized under the Usage invariant (inputTokens always covers cache reads and writes), typed finish outcomes (length to max-tokens, content-filter to a typed refusal carrying the raw stop reason), and exactly one terminal event per stream.
- Retention rides
finish.providerMetadata[<id>].retainedParts(docs/04 section 2.3): assembled reasoning parts with their provider signatures, custom blocks, generated files, and provider-executed tool exchanges round-trip to same-family models; response-side providerMetadata reinserts as prompt-side providerOptions. - Conservative caps for a surface that has no introspection (the openaiCompatible posture, except structuredOutput 'native' because V4 responseFormat json is the interface-native mechanism);
options.capsoverrides per model. Canonical effort maps one to one for low/medium/high/xhigh;maxdownmaps toxhighand the downmap is recorded in providerMetadata. cacheHint is ignored silently per docs/04 section 1.7. - Errors:
aiSdkErrorToWireprojects thrown APICallErrors as typed WireErrors (429 as retryable rate-limit with retryAfterMs from the retry-after header; 5xx and status-less network failures retryable transport; other statuses terminal). Documented as the highest-churn package in the set; its provider-major bumps ride BREAKING releases, never minors.
Patch Changes
- Updated dependencies [0e0b569]
- Updated dependencies [b28b7a3]
- Updated dependencies [b53a89e]
- Updated dependencies [4454175]
- Updated dependencies [6599ca8]
- Updated dependencies [6649e5f]
- Updated dependencies [fd2f83b]
- Updated dependencies [01d6b2d]
- Updated dependencies [9a20dbb]
- Updated dependencies [0fbe7ea]
- Updated dependencies [ebe0abc]
- Updated dependencies [a3079d0]
- Updated dependencies [596a39b]
- Updated dependencies [464ab6e]
- @rulvar/[email protected]
0.9.0
Patch Changes
- Updated dependencies [84f94d4]
- Updated dependencies [65c7b2c]
- Updated dependencies [a2a3243]
- Updated dependencies [ebc8101]
- @rulvar/[email protected]
0.8.0
Patch Changes
- Updated dependencies [85d55cf]
- Updated dependencies [b88c9e3]
- Updated dependencies [f3c4613]
- Updated dependencies [a41c20f]
- Updated dependencies [f4e70be]
- Updated dependencies [75d1646]
- Updated dependencies [0627413]
- Updated dependencies [55c0f87]
- Updated dependencies [fd33871]
- Updated dependencies [e70e7f4]
- Updated dependencies [bc9c903]
- @rulvar/[email protected]
0.7.0
Patch Changes
- Updated dependencies [fd1d06c]
- Updated dependencies [6fcf296]
- Updated dependencies [dcc97a9]
- Updated dependencies [434dc83]
- Updated dependencies [03173c1]
- Updated dependencies [11c0afc]
- @rulvar/[email protected]
0.6.0
Patch Changes
- Updated dependencies [fa05007]
- Updated dependencies [9234dc8]
- Updated dependencies [644512c]
- Updated dependencies [8a41656]
- Updated dependencies [02f7f7a]
- @rulvar/[email protected]
0.5.0
Patch Changes
- Updated dependencies [ac274f4]
- Updated dependencies [5735d92]
- Updated dependencies [46ca98e]
- Updated dependencies [8ae129e]
- Updated dependencies [d1c4525]
- Updated dependencies [b840aba]
- @rulvar/[email protected]
0.4.0
Patch Changes
- Updated dependencies [dfe03b5]
- Updated dependencies [d2089a7]
- Updated dependencies [3f60234]
- Updated dependencies [f668890]
- Updated dependencies [16d7aa6]
- Updated dependencies [6513ce8]
- Updated dependencies [7dad493]
- Updated dependencies [2bbf180]
- @rulvar/[email protected]
0.3.0
Patch Changes
- Updated dependencies [43444f6]
- Updated dependencies [279881b]
- Updated dependencies [9fd0966]
- Updated dependencies [24ebadf]
- Updated dependencies [a1b35d3]
- Updated dependencies [18a5821]
- @rulvar/[email protected]
0.2.0
Patch Changes
- Updated dependencies [c24228d]
- Updated dependencies [c50871e]
- Updated dependencies [1af8fb9]
- Updated dependencies [1fe0249]
- Updated dependencies [5c4fc32]
- @rulvar/[email protected]
0.1.0
Minor Changes
- f4e2be9: M0 repo bootstrap (v0.1.0, docs/10-implementation-plan.md section "M0"): monorepo scaffold on the committed toolchain (pnpm 11 workspaces with catalogs, TypeScript 6.0, tsdown, Vitest 4, ESLint 9 flat config, Turborepo 2, changesets fixed mode, npm trusted publishing), the docs/ canon as single source of truth, the L0 contracts skeleton in @rulvar/core, and the vendored dependencies (StandardSchemaV1/StandardJSONSchemaV1 types, the @cfworker/json-schema lineage validator subset, a first-party monotonic ULID). Placeholder scaffolds only: no public API ships in this release.
Patch Changes
- Updated dependencies [f4e2be9]
- @rulvar/[email protected]
@rulvar/cli
1.252.0
Minor Changes
- 517ed00: The host surface hardens on two seams (RV4803, RV4805). The price table is now SNAPSHOTTED at
createEngine: pricing resolution used to read the caller's live object on every debit, so a host mutating its table mid-run silently changed what wires cost after the strict gates had judged the original; the clone severs the alias (a rates update is a new engine with a bumpedpricingVersion), and a table the structured clone cannot take refuses typed at construction. The HTTP shell'sPOST /runsbody gains the regulated posture subset ofRunOptions(budgetPolicy,maxInFlightExposureUsd,configFingerprint,scope,scopePolicy), so a remote caller can start a run under the immutable lifetime ceiling and the bounded execution scope; authentication, price tables, adapters, stores, and secrets stay with the host process by doctrine and never enter the body.
Patch Changes
- Updated dependencies [3ccb6cf]
- Updated dependencies [52d807f]
- Updated dependencies [517ed00]
- Updated dependencies [a7e589d]
- Updated dependencies [76e95eb]
- @rulvar/[email protected]
1.251.0
Minor Changes
- 7c58fb2: The portable replay descriptor (RV4602, the seventh comparison experiment's P1.2 remainder). A programmatic run records its workflow NAME in the journal, but the workflow VALUE lives in no
rulvar.config.mjs, so the seventh experiment'sreplay --assert-no-liverefused from a clean checkout.rulvar resumeandrulvar replaynow accept--registry FILE, an ordinary module whose named exports (workflows,engineOptions, and the newconfigFingerprint) merge over the config for that one command, so a run travels as a three part descriptor: the journal, the args, and the registry module naming the workflow under its recorded name; a module exporting a singleworkflowvalue serves the recorded name too. TheconfigFingerprintexport closes the drift loop the engine already enforces:rulvar runrecords it at genesis (from the workflow module or the config), and a resume or replay that supplies one is verified against the genesis record strictly before ownership, meta writes, or any provider call, refusing typed on drift instead of replaying under changed policy; the CLI never supplied it before, so every fingerprinted run degraded to the one sided warning. In core, a refused resume now rejects itsresultalone: eachon()subscription of the deferred resume facade used to derive its own unhandled rejection from the refusal, and the CLI progress renderer subscribes fourteen event types. Probes pin the genesis recording, the resume verification, the replay registry load, and the quiet refusal.
Patch Changes
- b3e465a: Precise hash and counter namespaces (RV4604, the seventh comparison experiment's P2.2 remainder). Every hash on the lineage and provenance surfaces is one recipe, sha256 over the JCS canonical value, and the seventh experiment's provenance script had to rediscover that by trial because the bare names said nothing; the invoice's 16 logical calls beside 109 wire fetches were reconciled by hand for the same reason. The precise names now ride beside the bare ones, same hex, additive everywhere:
judgedJcsSha256on the claim meta,auditedJcsSha256on the audit meta, andjudgedDocumentJcsSha256on the semantic terminal verdict, whose barefinalHashcollides withdraftToFinal.finalHashwhile meaning the judged document. On the counter sidelogicalRunTelemetrynow carriesadapterFetches, the sum of every provider call decision's absorbedwireRequests(absent reads one) beside the decision countlogicalWireRequests, plusperSegment[].adapterFetchesnaming which segment actually paid for them (a pure replay segment reads 0);rulvar inspectprints both counters by name on the logical wires line. Probes pin the absorption sum, both meta twins, and the verdict's referent naming. - Updated dependencies [e7e829c]
- Updated dependencies [5982be8]
- Updated dependencies [7c58fb2]
- Updated dependencies [b3e465a]
- Updated dependencies [c4e5d6a]
- Updated dependencies [c6fc3da]
- Updated dependencies [c6fc3da]
- Updated dependencies [0ae8b85]
- Updated dependencies [7932936]
- Updated dependencies [7932936]
- Updated dependencies [88da0ed]
- Updated dependencies [06c0e85]
- @rulvar/[email protected]
1.250.0
Minor Changes
- 1b39e62: The effects family in the CLI and the effect lane guide (RV4506, plan 45):
rulvar effects ls <runId>prints the fold report (the epoch and its restore posture, every machine's effective state, budgets consumed, standalone records;--jsonfor the machine-readable form),rulvar effects show <runId> <intentSeq>prints one machine in full (budgets, attempts with outcomes, receipts with duplicate classification, journaled probes, incidents, dispositions, the closer), andrulvar effects sweep <runId>runs the quarantine-only reconciler sweep through the@rulvar/effectscompanion (loaded dynamically per command, the planner precedent), demanding the explicit--single-processacknowledgment over the non-leasable default store, exactly the writer's doctrine. The guide page docs/guide/effects.md documents the shipped protocol end to end, the production host dossier's effects rows flip from design to shipped, and rfcs/effects.md records the implemented status with its deviations.
Patch Changes
- Updated dependencies [0e240b9]
- Updated dependencies [6fe585e]
- Updated dependencies [c5eb19c]
- Updated dependencies [565c13b]
- Updated dependencies [c6d197b]
- Updated dependencies [c9d9729]
- Updated dependencies [fed9db6]
- Updated dependencies [df9ed76]
- Updated dependencies [3020912]
- Updated dependencies [d8d598d]
- @rulvar/[email protected]
1.249.0
Minor Changes
e4428bd: RV4403: the terminal has five axes (terminal status, execution completion, child acceptance, deliverable acceptance, semantic verdict), and none substitutes for another on any surface, live or restarted. The seventh comparison experiment settled
exhaustedwith both judge metas and the ten-unsupported count only insideerror.data: the outcome's top level read nothing, the settle recorded nothing, a restarted production gate answered 'not-judged' about a failure whose own message counted the findings, andrulvar inspectprintedacceptance: accepted (completion complete; gate on the status and completion PAIR)over a rejected deliverable. Now: every typed semantic failure stamps the one-word verdict beside its metas (folded by the same RV4209 function the acceptance path uses, without a waiver or draft-bridge input, because a failing run has no standing acceptance to license); the engine lifts the semantic facts (claimConsistencyMeta, newcitationAuditMeta,semanticTerminalVerdict) on EVERY terminal path including typed failures without a completion literal, mirrors them onto the outcome, therun:endevent and the terminal envelope, and records them in the journaled settle;lastRunSettleand the persisted terminal envelope read them back defensively (a foreign or partial shape reads NOT RECORDED, never a verdict), so live and restart agree field for field. The CLI production gate reads the outcome's typed verdict field first, so it refuses with the recorded 'findings' instead of a false 'not-judged'.rulvar inspectprints the axes side by side (axes: terminal exhausted | execution complete | children accepted | deliverable rejected | semantic findings) with the semantic counts and the citation audit numbers, and the child roster verdict is labeledchildren:, one axis of five; the bareacceptance:label and the "gate on the status and completion PAIR" advice are gone.d6873c1: RV4404: budget honesty, three opt-in answers to the seventh comparison experiment's death. The intake gate had verified the acceptance tail against DECLARED estimates and the run passed
fits: truehonestly; the workers then overshot their declared estimate 2.8x, and the refusal came only where the armed round could not dispatch, after the composition and both judges were already paid.budget.acceptanceReserve: 'checkpoint'is 'require' plus a runtime re-check of the same arithmetic before each paid acceptance-tail dispatch (the first composition, each judge pass): every ceiling on the chain up to the run root judges its spend plus its dedicated tail reserves plus the worst case still ahead, and the run refuses typed BEFORE paying the stage, journaling anacceptance_checkpoint_refuseddecision naming the account, the stage, and every term. In the seventh trajectory the first checkpoint fires right after the workers, saving the composition and both judge passes. Dispatch-projection holds stay out of the arithmetic: they release on settle and the tail terms already price those futures.budget.estIsCeiling: trueturns declared spawn estimates into the fan-out's own hard allowance ceiling: tool-spawned children share the orchestrator's child scope, so the enforced bound is the AGGREGATE of the admitted estimates (RunBudget.raiseChildAllowancewidens it per admitted child), exactly the number the acceptance-tail arithmetic trusted; a fan-out that overshoots its declarations refuses at ITS ceiling instead of silently eating the tail. With both opt-ins, a preflightfits: truebecomes a dispatch guarantee for the declared tail.The pair ceiling stops laundering itself as a document defect: a declared
semanticAcceptance(claimCoverage 'full') derives coverage target 1 when none is set, so the pass runs coverage-first instead of the historical first-maxselection, and a truncation under a DECLARED target grades'coverage-capped'(a newClaimCoverageGradeliteral) instead of a silent 'partial'. The strict-final and waiver-forbid refusals then name the knob: the pair ceilingmax, and how many citing sentences it left uncovered. The seventh run declared full coverage, folded its pairs truncated, and reported 23 uncovered citing sentences as if the text were the problem.--strictrefuses 'coverage-capped' (a capped pass breaks the contract the declaration states; plain 'partial' deliberately stays exit 0), and the semantic terminal verdict folds it into the partial bucket.634f966: RV4409: the logical run's telemetry is native. The seventh comparison experiment measured its resumed run's active and calendar walls, the operator gap between segments, and the 109-wire logical count by external script over the raw journal, and reconciled "16 versus 109" by hand because the two counter families shared a vocabulary.
logicalRunTelemetrynow folds, from the stamps and decisions the journal already carries:activeMs(each segment's own append window, summed),calendarMs(first to last append),gapMs(their difference, the operator time),perSegment(status, entries, active wall, andreplayed: trueon a pure-replay segment, so a resumed run's walls read as the original segments' work instead of a 0.0 s rerun), andlogicalWireRequests(provider-call decisions across the WHOLE journal, the invoice's cardinality). Absent stamps keep the time fields absent: not recorded, never zero.rulvar inspectprints the logical run block (both time conventions, per-segment walls, the replayed marker) and the wire count under its own name, with the label spelling out that a segment's adapter fetches are a different, smaller counter by design.052cc26: RV4410: opt-in coordination checkpoints. With
coordinationCheckpoints: true, every settled await round appends a compactcoordination_checkpointdecision (the round ordinal, the settled handles, the spend at the checkpoint), so a timeout or kill terminal shows how far coordination durably got, and a resumed run's journal visibly continues from round N+1 instead of an opaque prefix. The seventh comparison experiment's genesis segment died on a timeout mid-coordination and the post-mortem priced the re-coordination by hand; the checkpoint makes the durable progress a journal fact. An await round the kill interrupted journals NOTHING, honestly: coordination got no farther than the journal says. Opt-in because the decisions are journal bytes; without the flag every journal stays byte identical, and the replay machinery never re-pays journaled coordination either way.rulvar inspectprints the last checkpoint (round, settled children, spend) when one exists.
Patch Changes
- Updated dependencies [8862133]
- Updated dependencies [0d7a717]
- Updated dependencies [e4428bd]
- Updated dependencies [d6873c1]
- Updated dependencies [4092e8d]
- Updated dependencies [e086590]
- Updated dependencies [1411938]
- Updated dependencies [737d1ee]
- Updated dependencies [634f966]
- Updated dependencies [052cc26]
- Updated dependencies [bbae134]
- @rulvar/[email protected]
1.248.0
Patch Changes
- Updated dependencies [8d0cd69]
- Updated dependencies [81065e4]
- Updated dependencies [8573f20]
- Updated dependencies [95f6a5e]
- @rulvar/[email protected]
1.247.0
Minor Changes
- 4b7197a: The candidate chain reads by hash, and absent bytes say why (RV4207, the sixth comparison experiment).
finishValidation.candidatePersistence: 'transcript' | 'hash-only'supersedesretainRejectedCandidates(declaring both refuses typed): under a declared policy every finish-validation decision carries the candidate identity, the ACCEPTED verdict included (the hash names the resolved document, deterministic patch or sectional splice applied, on the same recipe the semantic judges bind),'transcript'retains rejected bytes exactly as the boolean did, and'hash-only'retains none on purpose, stampingbytesUnavailableReason: 'hash-only-persistence'on the decision, the fold, and the terminal row (a declared retention the store refused stamps'store-write-failed'), so an auditor finding no blob reads a policy or a fault by name. The hash recipe is exported and documented:candidateHashOf(sha256 over the JCS canonical value; a string document hashes as its JSON encoding, and a file export with a trailing newline changes the file's sha while this hash holds) withverifyCandidateBytes(bytes, hash)as the audit predicate.rulvar inspect <runId> --candidatesrenders the chain (verdict, hash, chars, window, wires, money, byte address or the named reason) and--candidate-bytes <hash>recovers a retained document to stdout, verified against the journaled hash, in one command; the experiment's auditor recovered the rejected 37,645 character composition by digging messages[3] out of a binary transcript blob and re-deriving the recipe from source. Undeclared configs keep every byte: identity on non-accepted verdicts only, exactly RV2507. - 16ff6b9: One word answers the production question, on every surface (RV4209, the sixth comparison experiment). The acceptance envelope now carries
semanticTerminalVerdictwhenever claim or citation machinery is configured:'clean' | 'findings' | 'partial' | 'vacuous' | 'waived' | 'not-judged'with the final hash, the counts (contradictions, unsupported and partial citations, repair rounds), the standing waiver, and the judge-failure codes, folded ONCE at the orchestrator settle (semanticTerminalVerdictOf, exported) with fail-closed precedence: a failed or declined judge, and a draft-stage grade the synthesis rewrote (RV3207), readnot-judged; findings outrank the waiver; the waiver is never clean. The verdict is lifted onto the outcome, mirrored onto the terminal envelope (and through it therun:endevent and the HTTP response), so every consumer reads the SAME derivation instead of re-deriving it from four fields.productionAcceptableis the exported fail-closed gate (only'clean'passes; absence readsnot-judged), andrulvar run --acceptance-policy production(also onresume) applies it after--strict's mechanical checks, refusing suspended runs asunsettled, with ONE stable JSON reason line on stderr per refusal.--strictitself stays byte identical, documented exits included: the experiment's run settled ok under a standing waiver with three unsupported citations, and the pipeline reading strict's exit shipped it.
Patch Changes
- Updated dependencies [1933ecc]
- Updated dependencies [db0a5f0]
- Updated dependencies [b698726]
- Updated dependencies [48348d2]
- Updated dependencies [4cfa1cc]
- Updated dependencies [4b7197a]
- Updated dependencies [5ebc842]
- Updated dependencies [16ff6b9]
- Updated dependencies [0c9941d]
- @rulvar/[email protected]
1.246.0
Patch Changes
- Updated dependencies [d165b0c]
- Updated dependencies [d59f4a0]
- Updated dependencies [46907ac]
- Updated dependencies [9929ad3]
- Updated dependencies [1790a6a]
- @rulvar/[email protected]
1.245.0
Minor Changes
- dee6db4: The workflow answers for its own repairs (RV4002, the fifth comparison experiment). The run paid for exactly one repair (a coordination draft rejected by three validators, healed by a sectional resubmission, one more wire at $0.186) and every terminal aggregate answered truthfully for its own stage while no surface answered for the workflow: the independent judge rebuilt the count from the raw transcript and the repair wire's money drowned in 'coordination'. The exported
repairLedgerFromJournalfolds the workflow-wide ledger ({ draft, composition, semantic, total }plus one row per granted repair with its stage, verdict seq, failed validators, spliced sections, and the repair wire's ref and price when the billing lane covered it); the acceptance envelope carriesrepairscomputed by the same fold over the run's own snapshot, so live and post-hoc agree by construction. The draft gate journals its voice (orchestrator_draft_gateon rejection and on the healing sectional acceptance), finish-validation decisions carry theirstageand spliced markers, and the granted repair turn's own wire is stampedphase: 'repair'(ProviderCallRecord.phase), which all three byPhase folds split out of the hosting dispatch's bucket.rulvar cost-auditprints the ledger when the journal proves one, byte parity otherwise; pre-RV4002 journals fold withunstagedVerdictsnamed, a floor, never a guess; clean runs keep every byte (all 61 frozen fixtures verify unchanged). Kit:coordination-draft-repairpins the experiment's exact shape ({ draft: 1, composition: 0, semantic: 0, total: 1 }, the gate decisions, the stamped wire) andsectional-repair-roundpins the semantic round's ledger; four mutation probes pin the wire stamp, the gate's journal voice, the round count, and the CLI line. journal-shape-revision: the wire-levelphasestamp is an additive journal evolution, and the frozen cassettes whose flows contain a refused finish exchange are re-recorded under it. - 19bcea0: The pre-wire provider intent (RV4006, the fifth comparison experiment's P0.5). Receipts journal after a wire settles, so the wire most exposed at a crash is exactly the one being paid for: between dispatch and receipt, a death leaves money the journal never heard about.
defaults.billingReceipts: 'intent'journals aprovider-intentdecision before every dispatched wire attempt (awaited, the executor ledger's intent-before-effect rule: a failed intent append refuses the dispatch), keyed by dispatch seq, ordinal, and attempt, carrying the serving model, role, and a sha256 request fingerprint; receipts stay awaited as under'awaited'. An intent with neither a receipt row nor a settled terminal covering it is a wire with UNKNOWN outcome: the exportedopenWireIntentsOffold names them, the invoice carries theopenIntentslane (no invented dollars),rulvar cost-auditprints it, and a resume that finds one refuses the blind retry typed untilResumeOptions.acknowledgeOpenWireIntents: trueis passed, which the new segment journals asopen_wire_intents_acknowledged. Dispatch stays at-least-once with attempt binding; the default'async'and'awaited'postures keep every byte. Kit:wire-intent-unknown-outcomedrives the reconstructed crash window through both resume arms; probes pin the quota-arm intent, the resume gate, and the receipt closure.
Patch Changes
- Updated dependencies [b4d47a8]
- Updated dependencies [dee6db4]
- Updated dependencies [b85c113]
- Updated dependencies [bc556e7]
- Updated dependencies [9f11d29]
- Updated dependencies [19bcea0]
- Updated dependencies [60b461c]
- Updated dependencies [61e3a1a]
- Updated dependencies [a156b81]
- Updated dependencies [0bd7045]
- @rulvar/[email protected]
1.244.0
Minor Changes
- f56721d:
InvoiceRow.agentType?andInvoiceRow.label?(RV3906, the fourth comparison experiment): in dynamic runs the scope grammar nests every orchestrator spawn under oneagent:<seq>bucket, sobyScopelegitimately reads two buckets and per-child money used to require a join through the journal. Every row of an attributed terminal (record rows, unattributed slice rows, and remainder rows alike) now carries the spawn'sagentTypeand the dispatchlabelfrom the terminal's cost attribution; the empty agentType folds as absent (the root's honest non-type), and rows of journals recorded before attribution shipped stay byte for byte.rulvar cost-auditprints the same cut as aby agentType:line and carries it asinvoice.byAgentTypein the JSON form, both absent on pre-attribution journals. Cardinality pins unchanged; one mutation probe pins the threading.
Patch Changes
- Updated dependencies [38d839a]
- Updated dependencies [ce13b0f]
- Updated dependencies [4fa23e3]
- Updated dependencies [6841c69]
- Updated dependencies [f56721d]
- Updated dependencies [c894a43]
- Updated dependencies [f6944a3]
- Updated dependencies [23fd0e0]
- @rulvar/[email protected]
1.243.0
Patch Changes
- Updated dependencies [746d1f4]
- Updated dependencies [009b29c]
- Updated dependencies [1674cbe]
- Updated dependencies [bd096bc]
- @rulvar/[email protected]
1.242.0
Patch Changes
- Updated dependencies [6e3438e]
- Updated dependencies [ba5cf67]
- Updated dependencies [c2d1531]
- @rulvar/[email protected]
1.241.0
Patch Changes
- Updated dependencies [dbcdd24]
- Updated dependencies [7ae7243]
- Updated dependencies [4f832c4]
- Updated dependencies [7452d3d]
- Updated dependencies [a4e22bf]
- Updated dependencies [82df4af]
- @rulvar/[email protected]
1.240.0
Minor Changes
- b2cf668:
cost-auditsurfaces the invoice's orphaned receipt lane on every output form (RV3501). When a journal carries the RV3405 crash shape (a receipt row the settled terminal's record set does not cover), the single run text prints the lane totals plus one line per receipt, both JSON shapes carry the lane verbatim underinvoice, and the catalog sweep appends an orphaned suffix to the carrying run's row and a carrying count to its header. The lane never moves the verdict or the exit code: an orphaned receipt is the honest double payment window of a resume, not a divergence, and before this surface such a journal passed all six checks while the money stayed invisible in every printed figure. Journals without the lane render byte for byte as before.
Patch Changes
- @rulvar/[email protected]
1.239.0
Patch Changes
- Updated dependencies [74ce99a]
- Updated dependencies [ccd0665]
- Updated dependencies [0c5ce21]
- Updated dependencies [0616934]
- @rulvar/[email protected]
1.238.0
Patch Changes
- Updated dependencies [cf00947]
- Updated dependencies [c7b9382]
- Updated dependencies [88aea96]
- Updated dependencies [6da8d05]
- Updated dependencies [eae5c4c]
- @rulvar/[email protected]
1.237.0
Patch Changes
- Updated dependencies [9d6a279]
- Updated dependencies [49a98f6]
- Updated dependencies [a734ca0]
- Updated dependencies [deb406f]
- @rulvar/[email protected]
1.236.0
Minor Changes
- 4701bfe:
--strictbinds the semantic verdict to the shipped document (RV3207). A claim-coverage grade rendered overjudgedStage: 'draft'while the envelope'sdraftToFinal.rewrittenreports the synthesis replaced that draft now exits nonzero, naming the remedy (claimConsistency.stage: 'final'or'both'), because nothing semantically judged the artifact the run settled on: the 2026-08-11 experiment run shipped a repaired composition under a draft-stagepartialgrade and read green. An unchanged draft, a final-stage verdict, an absent claim meta, or an absent bridge all keep their existing exits byte for byte.
Patch Changes
- Updated dependencies [26306ea]
- Updated dependencies [709b942]
- @rulvar/[email protected]
1.235.0
Patch Changes
- Updated dependencies [ba4e10d]
- Updated dependencies [172402b]
- Updated dependencies [2ecd787]
- Updated dependencies [e20a5e9]
- Updated dependencies [98c8691]
- Updated dependencies [c70def0]
- @rulvar/[email protected]
1.234.0
Minor Changes
- 04c86d6:
rulvar inspectprints the observed tool-budget calibration beside the child roster (RV3103): the RV3003 fold in operator output. The aggregate line (observed tool calls per recorded evidence entry:with the rate, the executed-call and entry sums, and the paired-dispatch count) exists only when at least one terminal carries both the RV806 evidence verdict and the RV3002 executed-call counter; unpaired sides are named instead of zeroed (declared contracts with no journaled counter, the pre-RV3002 journal shape, and counters with no declared contract); a journal carrying neither side prints nothing at all, so absence stays NOT RECORDED in operator output too.
Patch Changes
- Updated dependencies [8420c04]
- @rulvar/[email protected]
1.233.0
Patch Changes
- Updated dependencies [48b5200]
- Updated dependencies [73bc32b]
- Updated dependencies [e63b743]
- Updated dependencies [ef45da7]
- @rulvar/[email protected]
1.232.0
Patch Changes
- Updated dependencies [1440410]
- Updated dependencies [6e467f4]
- Updated dependencies [0b14293]
- Updated dependencies [e3bcab2]
- Updated dependencies [b55a0f7]
- @rulvar/[email protected]
1.231.0
Minor Changes
ff9b8c2: The offline child roster names the children the run ABANDONED (RV2804).
childRostersFromJournalpresented a child on a discarded branch exactly like a child whose work the run kept, so a post-mortem reading "four children settled ok" was counting branches the orchestration had thrown away. The money layer has refused that conflation since RV1904:grossUsdkeeps abandoned spend because the provider billed it,totalUsddoes not because the run kept none of it. The roster now says the same thing.JournaledChild.abandonedis present and true exactly when the first-wins abandon projection covers that child's dispatch, subtree coverage included, and absent otherwise, never false (RV1209). It needs nothing that was not already written down: the fold reads the same projection the replayer disposes by, over the same journal, and a child'shandleis the very seq an abandon entry targets, so journals from every prior version answer.rulvar inspectprints the discarded children under the roster it already prints, named by their handles.
Patch Changes
- Updated dependencies [4eb4b56]
- Updated dependencies [bc8f09e]
- Updated dependencies [ff9b8c2]
- @rulvar/[email protected]
1.230.0
Minor Changes
abe9c09: The human report says what the terminal CLAIMS, not only what it transported (RV2703).
rulvar runprinted the transport status, the value, the error, the drops, the suspensions and the money, and not one semantic field. So a run accepted with degradation, a run whose declared finish contract refused every candidate it was handed, and a clean run all printedstatus: okwith nothing between them.--stricthas read those fields since RV2604, but strict is the machine gate: a person who does not pass the flag was left with exactly the blindness the last two releases went into curing.The report now names
completion:with the degraded reasons behind it,deliverable:(accepted or REFUSED by the declared contract, and whether the terminal carries an artifact at all), the count of rejected finish candidates with the distinct documents among them, andchildren at failure:for a run that died before any policy judged its roster (RV2602), which is the only account of work that was already paid for.rulvar inspectgains the offline half: thecompletionits ownlastRunSettleread has been available since the persisted-terminal tail, while inspect printed the acceptance DECISION only, which exists only where a verdict was rendered. A run that died before acceptance, or one resumed past it, showed a reader nothing.Absence prints nothing, everywhere (RV1209): a host that declares no contract is its own judge, and a workflow that makes no completion claim is not an incomplete run. A run with none of these fields prints exactly what it printed before.
57bfb38: The child roster of a run that died before acceptance is readable OFFLINE (RV2702).
childrenAtFailure(RV2602) answers "what had the children produced" for a consumer watching the run, and it dies with the process that held it. The settle persists the completion lift and nothing else, so a post-mortem over a journal, which is all a paid run leaves behind, had no way to ask the question at all: not for a run that crossed its ceiling mid-roster, and not for any run in an archive written before the field existed.childRostersFromJournal(entries)is the fold, and it reads what resume reads. Aspawn-admissiondecision names every child the controller judged, with its ordinal, its profile, its verdict and the scope its dispatch pins to; the dispatch and terminalagententries under that scope are the child itself, and the RV806 evidence verdict rides the terminal. Nothing new is written, nothing is re-derived and no validator runs again, so a journal from any prior version reads exactly as well as today's.rulvar inspectprints it: how many children were admitted, how many settled and with what statuses, how many were refused admission, and the ones that settled ok below a declared evidence floor, named by the dispatch seq the orchestrator's own turns used as their handle.Two things it does not claim. It is not the live roster: this reading happens after the RV1903 exit barrier settled the stragglers, so a child the live field called unsettled usually has a terminal here, and an absent status means the journal truly ends mid-flight rather than a child that failed. And it counts CHILDREN: the coordination loop, the synthesis and the judge dispatch through the same
ctx.agent, and only a child carries the spawn admission that pins it to the child scope.
Patch Changes
- Updated dependencies [e9bf910]
- Updated dependencies [57bfb38]
- @rulvar/[email protected]
1.229.0
Minor Changes
7ce0be2:
--strictreads the deliverable verdict (RV2604). The flag has always refused a partial acceptance and, since RV1702, a coverage grade that verified nothing. It never asked the one question RV2506 shipped a field for: did the declared finish contract accept the artifact this run settled on. Completion answers for the CHILDREN, and the twenty-fifth comparison run is the row that gap leaves open, with four accepted children, three syntheses the contract refused, a run that settled on unvalidated output, and a scoring harness readingstatus: 'ok'.deliverableAccepted: falsenow exits nonzero even undercompletion: 'complete', naming the contract and, when the terminal carries no artifact at all, saying so in the same line. The check precedes every coverage grade deliberately: a semantic grade over an artifact the contract rejected answers a question nobody should still be asking, and the refusal that names the contract is what a reader needs.An ABSENT verdict is left alone. The check is
=== false, not!== true, because absence means nofinishValidationwas declared, nothing judged anything, and a host that declares no contract is its own judge. That is the same line the normative consumer predicate draws in the observability guide.edce170:
rulvar inspectreports the logical run and what the contract refused (RV2605). Two surfaces shipped in v1.228.0 had no consumer in the tool people actually read a run with:inspectprintedentries: N, which over a resumed run is one undifferentiated heap with no boundaries in it, and said nothing at all about finish candidates the declared contract rejected.segments:islogicalRunTelemetry(RV2510) printed: how many segments ran, how each settled, how many entries each appended, and the count of entries that continued PAST the last settle (RV1407) when there are any, because the last settled status is then not the run's last word.rejected finish candidates:lists the RV2507 rows with verdict, size, hash prefix, failing validators, and the blob ref when the bytes were retained, and counts DISTINCT documents beside the row count, so three rows sharing one hash reads as the model serving one text three times rather than as three genuine attempts.lastRunSettlegainsrejectedFinishCandidates. The settle already persists the whole completion lift, so this is a read of what is recorded, not a re-fold and not a validator re-run, and every row is parsed defensively: any malformed row drops the WHOLE list, the same posture the live lift takes, because a partial history read as complete under-reports exactly the runs that misbehaved most, and offline is where nobody can check. A journal that records nothing of the kind reads as NOT RECORDED and both lines stay absent.
Patch Changes
- Updated dependencies [3370342]
- Updated dependencies [2fb6656]
- Updated dependencies [edce170]
- @rulvar/[email protected]
1.228.0
Patch Changes
- Updated dependencies [4034fac]
- Updated dependencies [a54b085]
- Updated dependencies [9d0a9be]
- Updated dependencies [be9ef28]
- @rulvar/[email protected]
1.227.0
Minor Changes
41f93a9: The claim-coverage grade sees a declined judge and a zero denominator (RV2508).
claimCoverageOfnever readjudgeDeclined, the RV2106 degradation where the claim judge is refused ADMISSION and never dispatched, so a pass that judged nothing was graded by the counts of a pass that did not happen; over a draft carrying no citing sentence it graded'full', the strongest word in the vocabulary. The vacuous'full'at a zero denominator was the same failure at its extreme: RV1702 exists to stop a consumer inferring semantic health from emptiness, and an empty set graded stronger than a bounded subset.ClaimCoverageGradegains two words.'judge-declined'ranks with'judge-failed'and above everything the counts could say, below it only because a failure at least had an invocation to fail and the two causes are worth telling apart.'vacuous'sits below'partial': no subset was chosen because there was no set.ClaimCoverageInputgainsjudgeDeclined?: true; the orchestrator already spreads that flag into the meta it grades, so no call site changes and every existing meta grades the same unless it carried one of the two states. The CLI's--strictexits nonzero on'judge-declined'exactly as on'judge-failed'(nothing was judged either way) and prints'vacuous'to stderr while keeping the exit, because citing nothing breaks no contract the pass declares.Consumers with an exhaustive
switchoverClaimCoverageGradewill see a type error until they handle the two new members. That is the intended shape of the change: both states existed before and were silently folded into words that did not describe them.
Patch Changes
- Updated dependencies [f262e9f]
- Updated dependencies [f191ff7]
- Updated dependencies [fbbfbe8]
- Updated dependencies [263b5e8]
- Updated dependencies [db4d56d]
- Updated dependencies [41f93a9]
- Updated dependencies [98c8ca9]
- @rulvar/[email protected]
1.226.0
Patch Changes
- @rulvar/[email protected]
1.225.0
Minor Changes
- a2770e6: The cost-audit catalog sweep (RV2209). The parity sessions verified the one-denominator contract seven journals at a time, one
rulvar cost-audit <runId>invocation each; a catalog posture check should cost one command.rulvar cost-audit --all --store <dir>runs the same six checks (roster closed, settle recorded, settle is the billing boundary, fold matches invoice, wires match, incremental rows match) over EVERY run the store lists, in run-id order whatever the store returns, one summary row each naming the verdict, the passed-of-total checks with the failing names, the gross, and the wire count, and exits 1 when ANY run diverges;--jsoncarries the same per-run shapes underrunswith the sweep verdict on top. The single-run form is unchanged byte for byte and stays the deep view; a runId beside--all(or neither) refuses typed. Under the hood the grammar grows optional positionals (rendered bracketed on every usage surface, arity admits required through required plus optional), and the six checks are extracted into one audit function both forms share.
Patch Changes
- @rulvar/[email protected]
1.224.0
Patch Changes
- Updated dependencies [4eca1a3]
- @rulvar/[email protected]
1.223.0
Patch Changes
- Updated dependencies [549aabd]
- Updated dependencies [549aabd]
- @rulvar/[email protected]
1.222.0
Patch Changes
- Updated dependencies [8326268]
- @rulvar/[email protected]
1.221.0
Patch Changes
- Updated dependencies [032ce93]
- @rulvar/[email protected]
1.220.0
Patch Changes
- Updated dependencies [0babe70]
- @rulvar/[email protected]
1.219.0
Patch Changes
- Updated dependencies [65a4ce7]
- @rulvar/[email protected]
1.218.0
Patch Changes
- Updated dependencies [088bda6]
- @rulvar/[email protected]
1.217.0
Patch Changes
- Updated dependencies [ab80b97]
- @rulvar/[email protected]
1.216.0
Patch Changes
- Updated dependencies [b357f4a]
- @rulvar/[email protected]
1.215.0
Patch Changes
- Updated dependencies [e1da4c7]
- @rulvar/[email protected]
1.214.0
Patch Changes
- Updated dependencies [c8af0ec]
- @rulvar/[email protected]
1.213.0
Patch Changes
- Updated dependencies [61680df]
- @rulvar/[email protected]
1.212.0
Patch Changes
- Updated dependencies [e6f8516]
- @rulvar/[email protected]
1.211.0
Patch Changes
- Updated dependencies [d5a8a36]
- @rulvar/[email protected]
1.210.0
Minor Changes
- c871ddc: Incremental billing journaling (RV2008). ProviderCallRecords rode ONLY the terminal agent entry, so when the third parity rerun's process died with the root still running, ~$0.99 of its dispatches existed nowhere durable: the live ledger read $4.467 while the journal folded $3.478. Every record now journals the moment its wire call settles, as a
provider-calldecision row keyed by the dispatch seq and the record ordinal in the invocation's own scope; the terminal entry still carries the canonical set, replayed segments append no duplicates, and the crash window shrinks from the invocation's whole history to the one in-flight turn.invoiceFromJournalgains the additiveunsettledlane: dispatches of agents still running at the journal's edge, priced from the incremental rows and kept OUTSIDE the settled totals (run_settle stays the billing boundary).rulvar cost-auditgrows a sixth check,incremental-rows-match: every settled agent's terminal dispatch set must equal its incremental rows, count and per-ordinal usage alike; agents with no rows (pre-RV2008 journals, replayed invocations) pass vacuously. The frozen cassette catalog is re-recorded for the additive rows (journal-shape-revision, policy not identity: existing entries byte-identical, no hashVersion change).
Patch Changes
- Updated dependencies [c871ddc]
- @rulvar/[email protected]
1.209.0
Patch Changes
- Updated dependencies [514c7bb]
- @rulvar/[email protected]
1.208.0
Patch Changes
- Updated dependencies [e7d426f]
- @rulvar/[email protected]
1.207.0
Patch Changes
- Updated dependencies [99beee2]
- @rulvar/[email protected]
1.206.0
Patch Changes
- Updated dependencies [ec8e1f1]
- @rulvar/[email protected]
1.205.0
Patch Changes
- Updated dependencies [6d224da]
- @rulvar/[email protected]
1.204.0
Patch Changes
- Updated dependencies [efaec9b]
- @rulvar/[email protected]
1.203.0
Patch Changes
- Updated dependencies [fb08c10]
- @rulvar/[email protected]
1.202.0
Minor Changes
- 08c1247:
rulvar cost-audit <runId>verifies the one-denominator contract on a concrete stored run (RV1910). The four-role benchmark's recovery run produced four mutually inconsistent cost views, and the judge reconciled them by hand; the lifecycle now admits one, and the audit checks it instead of trusting the doctrine: the roster is closed (every agent entry has a terminal),run_settleis recorded and is the billing boundary (no agent entry follows it), and the settled fold, the invoice totals and the wire cardinality agree. Text and--jsonforms, exit 1 with the failing checks named when any diverge, which is exactly what a pre-RV1904 journal, the benchmark's own, reports.
Patch Changes
- @rulvar/[email protected]
1.201.0
Patch Changes
- Updated dependencies [7e01189]
- @rulvar/[email protected]
1.200.0
Patch Changes
- Updated dependencies [e2ddbdf]
- @rulvar/[email protected]
1.199.0
Patch Changes
- Updated dependencies [29891c6]
- @rulvar/[email protected]
1.198.0
Patch Changes
- Updated dependencies [c097c96]
- @rulvar/[email protected]
1.197.0
Patch Changes
- @rulvar/[email protected]
1.196.0
Patch Changes
- Updated dependencies [ec9c3e3]
- @rulvar/[email protected]
1.195.0
Patch Changes
- Updated dependencies [5702a70]
- @rulvar/[email protected]
1.194.0
Patch Changes
- Updated dependencies [360a659]
- @rulvar/[email protected]
1.193.0
Patch Changes
- Updated dependencies [2bca1d1]
- @rulvar/[email protected]
1.192.0
Patch Changes
- Updated dependencies [8757601]
- @rulvar/[email protected]
1.191.0
Minor Changes
- 745387c: Enforceable coverage floors and two new corpus classes (RV1809). The claim pass graded itself honestly (RV1702) but nothing could enforce a floor:
claimConsistency.minimumCoverageRatioandrunFactCoverageRatio(each in(0, 1]) now declare the minimums,onLowCoverage: 'report'(default) stamps the machine-readablelowCoverageblock on the meta with each ratio beside its floor,'fail'fails the run typed BEFORE the judge dispatch exactly likeonUncoveredCritical, the meta additionally carriesrunFactCandidates(the uncapped matched count, so both ratios are computable from the meta alone, live or persisted), and--strictexits nonzero on a stamped block with the ratios printed. The adversarial corpus grows two classes from the nineteenth benchmark:modality-overclaim(a mitigation stated as an unconditional guarantee: the attestation "stops any tool drift" beside the pool reading naming the contract-hash boundary) andscope-ambiguity(child-only totals printed as whole-workflow figures), both forming pairs through the same pure folds.
Patch Changes
- Updated dependencies [745387c]
- @rulvar/[email protected]
1.190.0
Patch Changes
- Updated dependencies [8e02021]
- @rulvar/[email protected]
1.189.0
Patch Changes
- Updated dependencies [6a5cc2d]
- @rulvar/[email protected]
1.188.0
Patch Changes
- @rulvar/[email protected]
1.187.0
Patch Changes
- Updated dependencies [c9798ef]
- @rulvar/[email protected]
1.186.0
Patch Changes
- Updated dependencies [242647e]
- @rulvar/[email protected]
1.185.0
Patch Changes
- Updated dependencies [1248623]
- @rulvar/[email protected]
1.184.0
Patch Changes
- Updated dependencies [8a9caca]
- @rulvar/[email protected]
1.183.0
Patch Changes
- Updated dependencies [dd3767c]
- @rulvar/[email protected]
1.182.0
Patch Changes
- Updated dependencies [144d026]
- @rulvar/[email protected]
1.181.0
Patch Changes
- @rulvar/[email protected]
1.180.0
Patch Changes
- Updated dependencies [b124d26]
- @rulvar/[email protected]
1.179.0
Minor Changes
1a5a85a: The claim-coverage grade rides the acceptance envelope, and strict reads it (RV1702). The eighteenth comparison benchmark's run reported
completion: 'complete'withcontradictions: []while the judge had seen 40 of 144 citing sentences, and three material falsehoods rode that gap; the counts that told the truth (RV1603) still had to be interpreted. The claim-consistency meta now carriescoverage, one closed vocabulary a consumer reads instead of inferring semantic health from an empty findings array:'full'(every citing sentence had a judged pair, nothing cut, no declared critical anchor missed, the judge settled ok; zero citing sentences grade full vacuously),'partial'(a bound cut the fold or citing sentences went unjudged),'critical-uncovered'(declared critical anchors got no judged pair),'judge-failed'(nothing was judged at all), precedence strongest last. The pureclaimCoverageOfhelper derives the identical grade from any persisted meta, including metas written before the field shipped, so old envelopes grade without re-running. The CLI's--strictnow reads the grade beside the completion contract:'judge-failed'and'critical-uncovered'exit nonzero, both states that previously slipped through strict as green, while'partial'prints its counts to stderr and keeps the exit, because the bounded pass is the documented default and declaring critical anchors is the opt-in that makes the subset enforceable.Journal: the orchestrate acceptance envelope's
claimConsistencyMetagains the requiredcoveragefield on newly settled runs; persisted metas from older engines stay readable and grade throughclaimCoverageOf.
Patch Changes
- Updated dependencies [1a5a85a]
- @rulvar/[email protected]
1.178.0
Patch Changes
- @rulvar/[email protected]
1.177.0
Patch Changes
- Updated dependencies [94db8ff]
- @rulvar/[email protected]
1.176.0
Patch Changes
- Updated dependencies [a74304d]
- @rulvar/[email protected]
1.175.0
Patch Changes
- Updated dependencies [1999c5d]
- @rulvar/[email protected]
1.174.0
Patch Changes
- Updated dependencies [aa9a772]
- @rulvar/[email protected]
1.173.0
Patch Changes
- Updated dependencies [67d27ac]
- @rulvar/[email protected]
1.172.0
Patch Changes
- Updated dependencies [0d4770b]
- @rulvar/[email protected]
1.171.0
Patch Changes
- Updated dependencies [f6116b9]
- @rulvar/[email protected]
1.170.0
Patch Changes
- Updated dependencies [86e4c06]
- @rulvar/[email protected]
1.169.0
Patch Changes
- Updated dependencies [623b2ae]
- @rulvar/[email protected]
1.168.0
Patch Changes
- Updated dependencies [ebba79a]
- @rulvar/[email protected]
1.167.0
Minor Changes
59765b1: Answer the SSE capability machine-readably on every run status body (the P1 tail).
Events are process-local telemetry:
GET /runs/:id/eventsstreams a run's events only from the process that holds it live, and a run served from the store answers an immediately closing comment stream. That association lived in documentation prose, so a client discovered it by connecting. EveryGET /runs/:idbody now carriescapabilities: { events: boolean }besidelive:trueexactly when this process holds the run and the events endpoint would stream,falseon the persisted path. The cli guide's endpoint notes are updated, including the stale claim that a rebuilt envelope never carriescompletion(recoverable since the settle records the semantic lift).
Patch Changes
- @rulvar/[email protected]
1.166.0
Patch Changes
- Updated dependencies [d8262c3]
- @rulvar/[email protected]
1.165.0
Patch Changes
- Updated dependencies [6391274]
- @rulvar/[email protected]
1.164.0
Patch Changes
- Updated dependencies [9f2dda9]
- @rulvar/[email protected]
1.163.0
Minor Changes
e8d9ada: Report the import bundle's reference closure, serve verify-only journal reads, and close the documentation gaps the benchmark named (RV1511, RV1512, RV1513). The sixth and final PR of the eighteenth plan.
The import closure report (RV1511). The intake validated shapes, namespaces, and the runId, but nothing held the ENTRIES' own references against the blobs the bundle carries: a torn bundle imported whole and the missing transcript surfaced only when something later read it.
importRunnow returns{ unresolvedRefs }, every transcript, checkpoint, artifact, and workflow-source ref the entries (and meta) name that no bundle blob resolves; the default stays permissive (retention and checkpoint pruning legitimately drop blobs their entries still name) and the report makes the gap visible, whilerequireClosure: truerefuses typed BEFORE any write. A duplicate blob ref refuses always: last-write-wins over transcript bytes is a torn or edited bundle, never a valid export.The verify-only load (RV1512). The A1 salvage model repairs a torn trailing line ON LOAD, which is right for an owner about to append and wrong for an auditor: a verification read that rewrites the artifact it verifies destroys the evidence of the tear.
JsonlFileStore({ repairOnLoad: false })serves the salvageable records without touching the file, andrulvar runs audit --no-load-repairopens the default store that way (contradicting--repairis refused typed).The documentation debts (RV1513). The README package count now matches its own table (seventeen names, the unscoped pointer included);
@rulvar/executorships a README and LICENSE like every sibling; the package reference names the eval framework's real dependencies; and the isolated-executor guide gains "What the ledger is NOT", the explicit denial list (not an outbox, not authorization, not exactly-once, not always on) for exactly the facts the seventeenth comparison run's dossier inverted while citing the sources that state them.
Patch Changes
- Updated dependencies [e8d9ada]
- @rulvar/[email protected]
1.162.0
Patch Changes
- Updated dependencies [2031e82]
- @rulvar/[email protected]
1.161.0
Patch Changes
- Updated dependencies [d4547b7]
- @rulvar/[email protected]
1.160.0
Patch Changes
- Updated dependencies [1c6f0d0]
- @rulvar/[email protected]
1.159.0
Patch Changes
- Updated dependencies [e881c8b]
- @rulvar/[email protected]
1.158.0
Patch Changes
- Updated dependencies [a266bc7]
- @rulvar/[email protected]
1.157.0
Patch Changes
- Updated dependencies [1883421]
- @rulvar/[email protected]
1.156.0
Patch Changes
- Updated dependencies [537144e]
- @rulvar/[email protected]
1.155.0
Minor Changes
- 49b08a7: Make the persisted terminal tail-aware and give offline authorities the engine's own resolution validator (RV1407, RV1408). The persisted terminal (RV1209) served the journaled settle even when the journal had CONTINUED past it, so a restarted reader could hold yesterday's envelope over a run that a detached resolution had already destined to resume, or that a successor segment was actively working, while
auditRunderived a non-terminal status from exactly that evidence.persistedTerminalEnvelopenow refusesnot-terminalwhenever entries follow the last settle, with a message naming the continuation (count and settle seq), so the persisted surface and the audit read one journal one way; the conformance table pins the new refusal (settled-then-continued) beside the five terminal paths. And the CLI server's offline resolution used a lookalike validator that demanded the plain{ decision }from EVERY kind-'approval' suspension: a legitimateEscalationDecisionfor a flavor B escalation was refused, and a wrong-shaped plain approval payload was waved into the journal. The new exportvalidateDetachedResolutionis the engine's own detached validation (the RV1203 flavor classifier, both payload arms, the pinned schema) as one function; the engine's detached path and the CLI offline path now call the same bytes, so an escalation resolves offline with its OWN payload exactly as detached-live, and an invalid one is refused typed before anything is journaled.
Patch Changes
- Updated dependencies [49b08a7]
- @rulvar/[email protected]
1.154.0
Patch Changes
- Updated dependencies [9259f24]
- @rulvar/[email protected]
1.153.0
Patch Changes
- Updated dependencies [d8bebcb]
- @rulvar/[email protected]
1.152.0
Patch Changes
- Updated dependencies [dd6a616]
- @rulvar/[email protected]
1.151.0
Patch Changes
- Updated dependencies [1de0610]
- @rulvar/[email protected]
1.150.0
Patch Changes
- Updated dependencies [a331211]
- @rulvar/[email protected]
1.149.0
Patch Changes
- Updated dependencies [08b4537]
- @rulvar/[email protected]
1.148.0
Minor Changes
c85dac9: The terminal envelope survives the process that produced it, and the invoice states how many provider requests its rows represent (RV1209, RV1210).
A run this server never held used to answer
GET /runs/:idwith a bare status projection while a live consumer read the wholeTerminalEnvelope, so the durability story stopped one surface short of the one a host reads after a restart. The non-live response now carriesenvelopetoo, rebuilt from the journal through the same producer and markedprovenance: 'journal': the verdict comes from the journaled run settle (the authority, not the meta projection), the money from the same composed settle-pin foldGET /runs/:id/costruns, and the usage andagentsSpawnedfrom the same ledger fold the resume budget seed uses. Two fields are deliberately absent on a rebuilt envelope and the marker is what makes their absence honest:completion(the workflow's semantic claim rides its result value, and only that value's digest is journaled) anderror(the run's terminal wire error is never journaled as the run's own), so absence there means NOT RECORDED, never "the workflow claimed nothing" or "the run did not fail". A live envelope carries noprovenanceat all and keeps its original byte contract. Where nothing durable records a terminal, the body carries a typedterminalUnavailable: { reason, message }(unsettled,not-terminal, orunknown-workflow) instead of an envelope; it is its own field, nevererror, becauseerroron that body means the run failed.persistedTerminalEnvelopeis exported, and the terminal-envelope conformance table now drives every row through a restarted server as its final surface.The invoice declares the dispatch-versus-wire cardinality (
cardinality: { dispatchRows, wireRequests, multiWireRows, wireIdsMissing }). One row is one logical dispatch, and a dispatch that absorbed provider-side continuations is billed as several HTTP requests, so a per-request statement has more lines than the export has rows by construction: reconcile a statement line count againstwireRequests, neverrows.length. The per-rowwireRequestsbehind it comes from the count the adapter reported rather than the length ofwireResponseIds, because a provider that leaves an absorbed segment unnamed still billed it, and counting ids alone made the invoice contradict the quota window that settles on the same count. Single-wire dispatches carry neither field and stay byte-identical.Two limiter fixes ride with it. An abort landing inside an awaited quota reservation now stops the wire: a limiter that queues can hold
reservepast the dispatch's own abort check, and the engine rechecks the host and budget signals when the reservation resolves, releasing the granted admission rather than reconciling it, because a settlement only ever adds while that call provably never happened. And the unused-continuation release is fail closed on the wire count: only a finish that names its wire set proves which pre-wire grants went unused, so a finish carrying no count releases nothing, instead of reading the absence as one flown wire and handing a hook-granting adapter back exactly the capacity it had consumed.
Patch Changes
- Updated dependencies [c85dac9]
- @rulvar/[email protected]
1.147.0
Patch Changes
- Updated dependencies [6367231]
- @rulvar/[email protected]
1.146.0
Patch Changes
- Updated dependencies [5d9bbc8]
- @rulvar/[email protected]
1.145.0
Patch Changes
- @rulvar/[email protected]
1.144.0
Patch Changes
- Updated dependencies [c11bcd6]
- @rulvar/[email protected]
1.143.0
Patch Changes
- Updated dependencies [f412169]
- @rulvar/[email protected]
1.142.0
Minor Changes
- 473981a: The terminal envelope conformance table (RV1106): every terminal path (ok, error, exhausted, cancelled, superseded) drives the real engine, and the envelope is checked fact for fact across the resolved outcome, the run:end event, the HTTP run status body, the SSE replay, and the OTel run span, in one truth table with the surface honesty rules pinned. The red-first fix the table found:
toOtelnow completes its export over every terminal path, the rejecting ones included; a rejectingresultnever fails an export the stream already completed, it only marks a leftover span with the refusal instead of green.
Patch Changes
- @rulvar/[email protected]
1.141.0
Minor Changes
- 4f12a62: The unified terminal envelope (RV1105, the P1-5 arc): every terminal fact of a run travels in ONE exported shape,
TerminalEnvelope(run identity, status, the typed error, the completion claim,settled+settledReason,totalUsd/grossUsdwith the detached per-model split, the usage aggregate,usageApproxnormalized to a boolean, andagentsSpawned), assembled once at the settlement chokepoint by the exportedterminalEnvelopeOfafter the settlement verdict is known. Every surface carries that object: the resolved outcome (outcome.envelope, alwayssettled: true, because an unsettled terminal rejects typed instead of resolving), therun:endevent (event.envelope, where thesettled: falseenvelopes live with the superseded reason inside), the server'sGET /runs/:idresponse, and the OTel exporter (rulvar.run.total_usd,rulvar.run.agents_spawnedbeside the existing settled attributes; a persisted stream from an older engine still closes its span). Nothing pre-existing was renamed or removed: the envelope is an assembly over fields that all remain.
Patch Changes
- Updated dependencies [4f12a62]
- @rulvar/[email protected]
1.140.0
Patch Changes
- @rulvar/[email protected]
1.139.0
Patch Changes
- Updated dependencies [03a2141]
- @rulvar/[email protected]
1.138.0
Patch Changes
- Updated dependencies [ed0c4fb]
- @rulvar/[email protected]
1.137.0
Patch Changes
- Updated dependencies [96f6788]
- @rulvar/[email protected]
1.136.0
Minor Changes
aa6ca71: A superseded segment refuses green everywhere: typed SupersededError, the distinct settledReason on run:end, and exactly one authoritative successor (RV1009, PR V of the fourteenth plan)
The fencing design swallowed a superseded segment's
LeaseHeldErroron both settlement writes, so a stale segment whose settle bounced off the successor's fence resolvedokwith an unmarkedrun:end: a green terminal that no durable store wrote, exactly the split view the RV907 doctrine forbids.- The stale segment now rejects
handle.resultwith the typedSupersededError(codesuperseded, not retryable,data { runId, runStatus }, cause the fencing rejection): the successor owns settlement, and the authoritative outcome is its settle or the store's run meta, never the stale computation. The meta write is skipped instead of re-proving the fence. run:endrefuses green withsettled: falseand the distinctsettledReason: 'superseded'(an l0-compatible extension), so an event-only consumer can tell a superseded segment from a settlement write failure; the settlement-failure path and every ordinary terminal keep their exact bytes.- A meta-only lease bounce over an already durable settle stays swallowed: the journal records the outcome, and only the projection belongs to the current holder (the takeover no-op contract is unchanged).
- The CLI progress line renders
settled=false (superseded; the successor owns settlement)instead of the resume hint, and the OTel exporter stampsrulvar.run.settled_reasonbeside the refused span status. runFaultInjection(@rulvar/evals) grows the nineteenth scenario,superseded-terminal-honesty: the fenced-out segment must reject typed with the distinct reason and zero settle entries, and the successor must settleokby replay with exactly one settle entry and no second paid call.
- The stale segment now rejects
Patch Changes
- Updated dependencies [aa6ca71]
- @rulvar/[email protected]
1.135.0
Patch Changes
- Updated dependencies [cf75e22]
- @rulvar/[email protected]
1.134.0
Patch Changes
- @rulvar/[email protected]
1.133.0
Patch Changes
- @rulvar/[email protected]
1.132.0
Patch Changes
- Updated dependencies [2bec904]
- @rulvar/[email protected]
1.131.0
Patch Changes
- Updated dependencies [256cae1]
- @rulvar/[email protected]
1.130.0
Minor Changes
d6bec7a: Every tool event names its call (RV908, the thirteenth experiment's OTel attribution risk).
tool:startandtool:endgaintoolCallId, the model-minted id the journal's messages and tool-result parts have always carried: present on every live event and on every replayed reconstruction (the id rides the checkpoint's tool-result parts, so even journals written before this release name their calls on resume), absent only on streams recorded before RV908 or written by foreign emitters.The OTel exporter pairs tool spans EXACTLY by the id (stamped as
rulvar.tool.call_id), so concurrent same-name calls that finish out of order keep their own durations and outcomes instead of FIFO-swapping attribution. Streams without the field keep the historical FIFO pairing byte for byte, an id-bearingtool:endwhose start carried no id falls back to the same FIFO (mixed streams pair no worse than before), and the orphan tolerance (a closer with no open start attaches as a span event) is unchanged.
Patch Changes
- Updated dependencies [d6bec7a]
- @rulvar/[email protected]
1.129.0
Minor Changes
1612439: Honest terminals (RV906 + RV907, the thirteenth experiment's release risks six and seven): a forced finish names itself partial, and a failed settlement is never a green event.
RV906: under the default
budget.atCap: 'finish-with-partial', the capped terminal's value becomes the completion envelope{ result, completion }, and the literal is'partial'unless the finalizer's finish provably passed the FULL declared contract: the declared finish validators now BIND the reserved finalizer (on capped runs synthesis never runs, so that finish is the final output they must judge; a finish they reject never becomes the run value and the deterministic fallback settles the run), while a declared acceptance policy is still never judged at the cap, so with one declared the terminal stays'partial'. The finalize fallback's synthesized partial carries the samecompletion: 'partial'claim on itsexhaustedoutcome. The engine lifts the literal ontorun:endand the outcome mirror, so a consumer reading onlystatuscan no longer execute a truncated plan as a full success. The journaled finalize effects also roll forward on resume: a settled capped run reuses its recorded finalize terminal (or fallback decision) instead of re-deriving the prompt from the drifted live digest, which used to mint a fresh agent identity and re-pay the reserve on every resume of an already settled capped run.RV907:
run:endgainssettled: false, present ONLY when a settlement write failed (therun_settlejournal append or the terminalRunMetaprojection): the status stays true as computation, but nothing durable records it andhandle.resultrejects with the typedSettlementError, so an event-only consumer is refused the green terminal exactly like the rejected promise. The CLI progress line appendssettled=false (outcome withheld; resume re-settles), and the OTel exporter stampsrulvar.run.settled: falseand refuses the OK span status. The order stays warn, then the markedrun:end, then the throw; a healed resume re-settles by replay with zero paid calls and its terminal carries no field, byte for byte like every ordinary run.
Patch Changes
- Updated dependencies [1612439]
- @rulvar/[email protected]
1.128.0
Patch Changes
- Updated dependencies [27c4e38]
- @rulvar/[email protected]
1.127.0
Patch Changes
- Updated dependencies [b3b1805]
- @rulvar/[email protected]
1.126.0
Patch Changes
- @rulvar/[email protected]
1.125.0
Patch Changes
- @rulvar/[email protected]
1.124.0
Patch Changes
- Updated dependencies [37fd1f2]
- @rulvar/[email protected]
1.123.0
Patch Changes
- Updated dependencies [5c46468]
- @rulvar/[email protected]
1.122.0
Patch Changes
- Updated dependencies [8cf45c5]
- @rulvar/[email protected]
1.121.0
Minor Changes
- 3d67d41: Rate provenance made checkable (RV807, RV813, RV814). The pricing row grows
ratesVerifiedAt(SPI), the ISO date it was last verified against the provider's documented rates or, stronger, its billing categories: the shipped seeds stamp it (the GPT-5.6 family reads2026-07-30, the day the statement reconciliation confirmed those rates against the provider's own per-component billing categories to the cent; the pre-5.6 OpenAI rows keep their2026-07-18docs verification; every Anthropic row was re-verified against the documented table on2026-07-30). The date is surfaced wherever a dollar is consumed:preflightEstimatecopies it onto each spawn report andrulvar preflightrendersratesVerified=<date>with its age on the spawn line; the settle pin journals it with the rest of the applied row so it survives any later table rewrite; andrulvar invoiceprints arates verified:line naming each priced model's date and age, pinned rows first, current table past them; the twelfth run's founder read the invoice doubting the rates and nothing said the seed was 12 days stale. The doctrine ships with the mechanism: seeds bound ceilings conservatively, billing truth is established only byreconcileStatementover saved exports, and a confirmed divergence corrects the seed in its own release with a changeset, never a silent rewrite. Enforcement rides two new gates: a weekly documented-rates audit (scripts/rates-audit.mjsin the live contract workflow) re-fetches exactly the pages the seed comments cite, compares every rate, write premium, and long-context tier, and opens an issue on drift or on a page that stops extracting, and a README release-table gate (scripts/readme-release-shas.mjs, in CI) requires every cited squash SHA to be an ancestor of HEAD, catching the v1.109.0 row that pointed at an object no branch contained for eleven releases (now corrected to the real squash58afdb5).
Patch Changes
- Updated dependencies [3d67d41]
- @rulvar/[email protected]
1.120.0
Minor Changes
- d630c9e: The partial fan-out contract and the per-child acceptance roster (RV805, RV806).
parallel_agentsadmits children sequentially in submission order, and a mid-loop admission refusal is now part of the TYPED tool result instead of a throw: the model keeps every started handle (awaitable and cancellable), andrefusednames the failed index, the typed error code, and the reason; a thrown refusal used to swallow the whole call while the started children kept spending invisibly, inviting a duplicate wave. The clean-wave result stays byte for byte{ handles }. The acceptance fold now journals a per-child machine roster inside its single decision and carries it asacceptanceChildrenon the envelope, theRunOutcome, andrun:end(same lift and malformed-drops-silently posture as the salvage lists, mirrored to OTel asrulvar.run.acceptanceChildren): each spawned child with its settled status, the salvage arm that accepted it, and, where the child declared an evidence contract, the evidence verdict{ recordedEntries, minEntries, met }withwaivedBySalvage: trueon a below-floor child a salvage arm accepted anyway; the twelfth comparison run accepted two below-floor children through salvage and nothing machine-readable said so. Behind it, a declared evidence contract now stamps EVERY settledAgentResultwithevidence(the same window-derived count as the enforce-refuse floor), absent without a contract so those results stay byte-identical.rulvar inspectprints the acceptance verdict with the completion, the salvage lists, and the per-child evidence verdicts from the journaled decision, plus journaledquota_driftdecisions labeled per-minute window, not cumulative. The guides now state the gating rule outright: gate on the (status,completion) pair, never onstatusalone.
Patch Changes
- Updated dependencies [d630c9e]
- @rulvar/[email protected]
1.119.0
Patch Changes
- Updated dependencies [1e4ff3c]
- @rulvar/[email protected]
1.118.0
Patch Changes
- Updated dependencies [f8341a3]
- @rulvar/[email protected]
1.117.0
Minor Changes
- c15b83a: Tool executions become real OTel child spans and the agent span survives to its end (RV802, the twelfth experiment's P0 #2). Tool events ride the agent's
spanIdand carry no per-call id, sotoOtelpreviously swallowed everytool:startas a duplicate opener of the agent span and let the FIRSTtool:endclose the agent span itself:agent:endthen attached usage, cost, and the exploration counters to nothing, later tool events reopened and reclosed agent-keyed spans, and in the twelfth comparison run all 569 tool events of the live stream produced zero tool spans while every agent span carried a tool's duration and outcome. The exporter now pairs eachtool:startwith itstool:endunder a synthetic FIFO key per(agent span, tool name)and starts atool <name>child span of the agent span: the agent span closes only atagent:endwith the whole dispatch's usage, cost,rulvar.retry_count, andrulvar.exploration.*; a denied call closes its own span withrulvar.status: 'denied'and therulvar.tool.guardmarker on the tool span; concurrent same-name calls keep exact counts, parentage, and durations (attribution may swap among identically named spans, the best the id-less vocabulary allows); and atool:endwith no matching start, the foreign or truncated stream shape, attaches as a span event instead of closing anything.
Patch Changes
- @rulvar/[email protected]
1.116.0
Patch Changes
- Updated dependencies [a213878]
- @rulvar/[email protected]
1.115.0
Patch Changes
- Updated dependencies [63642ae]
- @rulvar/[email protected]
1.114.0
Patch Changes
- Updated dependencies [5759731]
- @rulvar/[email protected]
1.113.0
Minor Changes
- a60807a: The pricing composition's second half names itself, and the effect-ledger quarantine is byte-true (RV706, RV707).
InvoicePricingProvenancegains optionalcurrentPricingVersion: on composed exports it is the version of the caller's current table, the one that priced everything pastpinnedThroughSeq(on current-table exports, the whole fold), so an invoice folded across a rotation now names both halves of the composition where the pinned segments already declared theirs;rulvar invoiceandrulvar inspectfill it from the configured table and extend their text suffix topins composed with the current table (v-a, v-b; current v-live), byte for byte unchanged when the config declares no version. The executor ledger's torn-tail quarantine row now carriesbytesBase64andsha256of the exact torn bytes alongside the lossybytesstring kept for old readers (two different byte tails used to collapse into one indistinguishable row), and the repair's parseable decision is made on the bytes, strict UTF-8 beforeJSON.parse: the lossy decode could make a fragment with invalid bytes inside a string literal parse, and the repair then terminated a line of invalid bytes in place, manufacturing exactly the corruption the fail-closed scan refuses.
Patch Changes
- Updated dependencies [a60807a]
- @rulvar/[email protected]
1.112.0
Patch Changes
- Updated dependencies [00ae55b]
- @rulvar/[email protected]
1.111.0
Patch Changes
- Updated dependencies [fd25169]
- @rulvar/[email protected]
1.110.0
Patch Changes
- Updated dependencies [58afdb5]
- @rulvar/[email protected]
1.109.0
Patch Changes
- Updated dependencies [85b1d39]
- @rulvar/[email protected]
1.108.0
Minor Changes
affa3d4: Stored consumers compose the pricing pins exactly like the engine, and the invoice provenance declares every pinned version (RV611).
JournalPricingSnapshotexports the composition the engine's outcome mirror applies at settle:composedPriceUsd(current)prices pin-covered rows at the rates their own settle recorded and everything past the last pin (a segment journaled but never settled) at the caller's current table. The engine now consumes the same method, and the three stored consumers (rulvar inspect,rulvar invoice, the server's stored-run cost endpoint) fold through it instead of passing the raw snapshot, which silently priced the tail at the last pin's rates and folded never-pinned models as unpriced even when the current table knows them. Two fallbacks stay deliberate and documented: a covered model its covering pin missed back-reprices at the last pin when that pin names it, and a model no pin resolves falls to the current table.The snapshot also carries
segments(every pin's seq boundaries,pricingVersion, and rows in journal order), andInvoicePricingProvenancegains the'composed'source plussegmentsandpinnedThroughSeq, so an invoice folded across a price-table rotation names every version that priced it instead of hiding the rotation behind the last one. The CLI exports that priced through a pin now declaresource: 'composed'(previously'snapshot'), and thepricing rates:/pricing:text lines name the composition and every pinned version.
Patch Changes
- Updated dependencies [affa3d4]
- @rulvar/[email protected]
1.107.0
Patch Changes
- Updated dependencies [9f5f6f6]
- @rulvar/[email protected]
1.106.0
Patch Changes
- Updated dependencies [9a4ce49]
- @rulvar/[email protected]
1.105.0
Patch Changes
- Updated dependencies [531dc88]
- @rulvar/[email protected]
1.104.0
Patch Changes
- @rulvar/[email protected]
1.103.0
Patch Changes
- Updated dependencies [f2b809e]
- @rulvar/[email protected]
1.102.0
Patch Changes
- Updated dependencies [3eb6515]
- @rulvar/[email protected]
1.101.0
Patch Changes
- Updated dependencies [51b215c]
- @rulvar/[email protected]
1.100.0
Patch Changes
- Updated dependencies [9785bea]
- @rulvar/[email protected]
1.99.1
Patch Changes
- ef08d73: Guarantee matrix and exactly-once claim hygiene (RV508); no runtime behavior changes. The isolated-executor guide now carries the guarantee matrix stating flatly who provides what: the library's layers give at-least-once execution with attempt binding and intent-before-effect, exactly-once effect execution is promised by NO library layer, and what IS exactly-once is pay and replay (the never-pay-twice invariant). The two claims the ninth comparison experiment's judge caught are rewritten to the precise statements ("each ran once" became attempt counting under a stable idempotency key; the approvals guide now says continuation is a run-level guarantee, not an effect-level one, with the at-least-once window named);
ctx.stepdocs state the same window for effectful steps; aResolutionBynote says the field records a channel, never a verified principal (identity, signatures, and separation of duties are host IAM). The worker header now points at the shippedSqliteQuotaLimiterandPostgresQuotaLimiterinstead of denying that cross-process limiters exist. A new docs-lint sentinel forbids "exactly once" claims in the hand-written docs and in package source comments outside a vetted (file, heading anchor) allowlist (the durability pay doctrine and the guarantee matrix), and every remaining occurrence in doc prose and source comments was rewritten to the precise wording; string literals are deliberately out of scope (tool descriptions enter the toolset hash). - Updated dependencies [ef08d73]
- @rulvar/[email protected]
1.99.0
Patch Changes
- Updated dependencies [9e00888]
- @rulvar/[email protected]
1.98.0
Patch Changes
- @rulvar/[email protected]
1.97.0
Minor Changes
5c3b453: Per-request cost accounting and per-segment pricing pins (RV504/RV505/RV511, the ninth-experiment accounting P1s).
RV504: when a terminal entry's per-dispatch
providerCallsexactly cover its usage,costReportFromJournalandinvoiceFromJournalnow price each provider call individually, so a nonlinear long-context tier fires per REQUEST, which is the pricing contract's stated semantics. An aggregate that crossed a threshold no single request crossed no longer re-prices the whole entry: the ninth comparison experiment's settled report ran 52.4% above the live budget's per-dispatch debits for exactly this reason, and the two figures now converge. Entries without records, or with records that do not cover their usage, fold exactly as before (the per-model aggregate), and the invoice says so:rowUsdNonAdditiveis now a computed boolean (false exactly when every contributing entry is fully attributed, so the per-call rows sum to the total;allocatedUsdremains the column that sums exactly in every case). The shared fold is public:priceEntryBillingwithEntryBillingUnit/EntryBillingFoldbesidepriceEntryUsage.RV505:
journalPricingSnapshotnow composes the run-settle pricing pins by their settle seq, with no journal shape change: a seq-aware fold prices each row under the pin of ITS OWN segment (the rates its live debits actually used), so a suspend/resume across a price-table rotation no longer re-prices settled history under the new table. Seq-less callers keep the historical last-pin behavior.priceUsdcallbacks across the accounting folds accept an optional thirdseqargument (existing two-argument implementations are unaffected), the snapshot exposespinnedThroughSeq, and the engine's settled-outcome cost mirror composes pinned history with the live table for the segment being settled.RV511: the CLI invoice text output now states the pricing basis honestly per export: additive per-request rows, or the aggregate basis with the reason (a remainder or legacy entry in the fold).
Patch Changes
- Updated dependencies [5c3b453]
- @rulvar/[email protected]
1.96.0
Patch Changes
- @rulvar/[email protected]
1.95.0
Patch Changes
- @rulvar/[email protected]
1.94.0
Minor Changes
- 426e57d: The SSE replay buffer of
createServeris finite by default (RV409): an absentmaxBufferedEventsPerRunnow resolves to the exportedDEFAULT_MAX_BUFFERED_EVENTS_PER_RUN(50,000 events per run) instead of unbounded, with the already established drop semantics past the bound (oldest events dropped in chunks, the retained window never below seven eighths of the bound, replays carryingx-rulvar-events-droppedand a leading SSE comment naming the first retained seq; the journal remains the durable record). Migration: a deployment that relied on the historical unbounded buffer sets an explicit huge bound, for exampleNumber.MAX_SAFE_INTEGER; nothing changes for servers that already configured the option, and the option's domain (a positive safe integer, typedConfigErrorotherwise) is unchanged.
Patch Changes
- @rulvar/[email protected]
1.93.0
Patch Changes
- Updated dependencies [c62150a]
- @rulvar/[email protected]
1.92.0
Minor Changes
- 351d1f5: Historically stable invoices via the applied-pricing pin (RV407, the eighth-experiment review). The invoice and cost folds price at fold time, so a live price-table update used to silently re-price history. When
createEngine({ pricing })is configured, the settling segment now pins what it actually applied, the resolved pricing row of every model the journal used plus the table'spricingVersion, additively inside the existing run-settle decision value (theoutputHashprecedent: no journal shape change). The pin is gated on the configured table deliberately: caps-fallback pricing arrives ambiently from adapters and a setting the user never enabled must not change the journal, so table-less runs settle byte for byte as before; rates the fold would refuse anyway, non-finite or negative, are never pinned. NewjournalPricingSnapshot(entries)reads the pin back and rebuilds apriceUsdover exactly the pinned rows (absent models fold as unpriced, never a silent zero);invoiceFromJournalaccepts a declared provenance and the export carriespricing: { source: 'snapshot' | 'current-table', pricingVersion?, rows? }.rulvar invoice,rulvar inspect, and the server's stored-run cost endpoint prefer the pin, so a repeated fold after the table changes reproduces the original numbers; journals settled before the pin keep the current-table fold and say so. Live pricing, budget admission, and journaled spend debits are untouched.
Patch Changes
- Updated dependencies [351d1f5]
- @rulvar/[email protected]
1.91.0
Patch Changes
- @rulvar/[email protected]
1.90.0
Patch Changes
- Updated dependencies [9603940]
- @rulvar/[email protected]
1.89.0
Patch Changes
- Updated dependencies [f18b671]
- Updated dependencies [f18b671]
- @rulvar/[email protected]
1.88.0
Patch Changes
- Updated dependencies [3b339d9]
- @rulvar/[email protected]
1.87.0
Patch Changes
- Updated dependencies [c4c02b1]
- @rulvar/[email protected]
1.86.0
Patch Changes
- Updated dependencies [2f71894]
- @rulvar/[email protected]
1.85.0
Minor Changes
6932a9f: Three fail-closed fixes from the cycle 83 sweep, plus the dependency refresh.
Engine. A typed error thrown out of
ProviderAdapter.stream()now keeps its own class instead of being laundered into a retryable transport fault. AConfigError(a bridged model id that does not match the wrapped model, an unsupported role, a namespaced option contradicting a canonical field) used to be retried through the whole backoff ladder and then trigger transport failover, so a misconfigured primary silently served the run from a fallback model the caller never asked for while the real fault vanished behind a generic message. Typed errors that ARE retryable by class (a lost lease) keep retrying exactly as before, and an untyped throw is still a retryable transport fault.Planner sandbox. The realm scrub replaced
Date.nowandMath.random, which left three ambient sources open: a barenew Date()never consultsDate.now(V8 reads the system clock directly),performance.now()is a second live clock, and WebCrypto (crypto.randomUUID(),crypto.getRandomValues()) is raw entropy. Those are the first idioms a machine-written script reaches for, and each silently produced a run that could not reproduce on replay. All of them now draw from the same seeded stream: zero-argumentnew Date()andDate()take the logical clock,performance.now()is that clock minus the segment base,crypto.randomUUID()is the journaled uuid shim, andcrypto.getRandomValues()fills from the seed. Passing a timestamp or a date string toDatestays a pure conversion.Server. A tracked run whose segment REJECTS instead of settling (the genesis ownership boot refusing a run another process owns, a withheld settlement whose durable write failed) was reported as
runningfor the life of the process, its SSE connections never closed, and neither retention nor the settled cap could release it.GET /runs/:idnow answersstatus: "error"with the typed wire error, connected streams close with a comment naming the failure, a late subscriber gets that comment instead of an empty stream, and the tracked run becomes eligible for retention like any other terminal run.Dependencies.
@anthropic-ai/sdkmoves to^0.115.0(the only shipped floor its caret was blocking); in-range minors refresh across the workspace. The four majors stay held: eslint 10 and@eslint/js10,@types/node26 against the Node 22.12 floor, and TypeScript 7. The tsdown resolution is pinned at 0.22.3 because it generates the frozen.d.tsartifacts, including the published@rulvar/compattarball that must repack byte identical.
Patch Changes
- Updated dependencies [6932a9f]
- @rulvar/[email protected]
1.84.0
Patch Changes
- @rulvar/[email protected]
1.83.0
Patch Changes
- @rulvar/[email protected]
1.82.0
Patch Changes
- 9cc5d66: The free-cleanup harvest (cycle 80).
leasableStoreConformancegains theexpiryoption: the mandatory lease checks follow the suite's no-wall-clock convention, so the harness now hands them a store whose ttl no scheduler stall can cross, and only the wall-clock expiry check keeps a short-ttl store of its own; the legacy single-ttlMspairing let one CI stall past 150 ms expire a just-acquired lease inside a fencing check (the flake observed on Node 22). All three shipped harnesses move to the split pairing, and the store-authors guide stops recommending the flaky shape. In@rulvar/cli, worker retention is no longer slot-bound: a worker whose every concurrency slot is busy still applies retention over settled runs during its sweeps instead of starving until idle. In@rulvar/core, concurrent coldtools()calls on an MCP source share one in-flighttools/listfetch instead of each sweeping the list, andAdmissionController'smaxTotalSpawnsTSDoc now tells the truth: it is the controller-lifetime cap on admitted spawns for hosts driving the controller directly (pinned by a test), while engine runs cap totals throughbudgetDefaults.lifetimeSpawnCap; the old comment claimed it was the per-orchestratemaxSpawns. - Updated dependencies [9cc5d66]
- @rulvar/[email protected]
1.81.2
Patch Changes
- 296885b: Three defects from a deep review of the MCP bus and the queue worker (cycle 79). In
@rulvar/cli,createWorker().stop()now waits out a sweep that is still scanning the store before taking its cancel snapshot, and a sweep observes the stop before every lease: previously a stop() racing an in-flight sweep could resolve while that sweep went on to lease and drive a new run, leaving a live run and a held lease behind a "stopped" worker. In@rulvar/core, the MCP tool source no longer loses alistChangednotification that races the in-flighttools/listfetch (the fetched list is served but never pinned as the session cache, so the next snapshot refetches), and cursor pagination treats an emptynextCursoras exhaustion instead of spinning the import loop forever on a server that echoes it. A regression test also pins the SDK-level rejection of a declaredoutputSchemawith nostructuredContent, guarding the planned SDK v2 migration. - Updated dependencies [296885b]
- @rulvar/[email protected]
1.81.1
Patch Changes
- Updated dependencies [c030982]
- @rulvar/[email protected]
1.81.0
Patch Changes
- Updated dependencies [ce4c392]
- @rulvar/[email protected]
1.80.0
Patch Changes
- Updated dependencies [262e397]
- @rulvar/[email protected]
1.79.0
Minor Changes
85956ab: Terminal admission at an exhausted tool budget, the two harness-shape preflight findings, and the degradation mirror (the fifth comparison experiment).
The fifth experiment lost a complete 3984 word answer to terminal tool starvation: the harness set the synthesis tool cap to the child count, the mandatory
get_child_resultreads spent the whole budget, and the readyfinishwas cut BEFORE the terminal interception, so the validators never ran, the funded repair reserve never armed, and the run failed closed with the candidate stranded in the transcript.- The terminal tool is now exempt from the tool budget in both directions: it never consumed
maxToolCallsortoolUnitsbelow the cap, and an exhausted budget no longer starves it either. An admitted finish validates and, on rejection, feeds the repair grants exactly as below the cap; non-terminal calls beside it are answered with typed skipped results so the continued exchange keeps a well formed history; a batch with only non-terminal calls past the cap settleslimitbyte identically to before. - New preflight warning
synthesis-terminal-tool-headroom:synthesis.exposeChildResultToolswith asynthesis.limits.maxToolCallsbelow one read per possible child (orchestrator.maxSpawns) loses evidence access to the reads themselves. - New preflight warning
draft-gate-below-contract: adraftPolicy.minWordsbelow the contract's own word minimum admits drafts the final validators must reject, so the paid synthesis starts from an underlength base. The preflight input mirrorsfinishValidation.draftPolicyfor it. - The completion lift now mirrors the degradation facts the acceptance envelope already emits:
degradedReasons,salvagedPartialChildren, andsalvagedTerminalOutputChildrenriderun:endand theRunOutcomeunder the same shape validation ascompletionandchildStatusCounts, and the OTel exporter maps them torulvar.run.*attributes. An empty array is the workflow's claim of zero degradation; absence means no claim.
- The terminal tool is now exempt from the tool budget in both directions: it never consumed
Patch Changes
- Updated dependencies [85956ab]
- @rulvar/[email protected]
1.78.0
Patch Changes
- Updated dependencies [941b6e1]
- @rulvar/[email protected]
1.77.0
Patch Changes
- Updated dependencies [6aba271]
- @rulvar/[email protected]
1.76.0
Patch Changes
- Updated dependencies [22cba47]
- @rulvar/[email protected]
1.75.1
Patch Changes
- Updated dependencies [82bc0f0]
- @rulvar/[email protected]
1.75.0
Patch Changes
- Updated dependencies [c486de8]
- @rulvar/[email protected]
1.74.0
Minor Changes
- d94beab: Quota drift telemetry and the honest zero (the v1.71 experiment review, P0.5 resized + P1.4). The experiment declared 12M TPM over a provider-real 1M, the local limiter went quiet, and seven live 429s followed with nothing recording the mismatch. Now: both wire adapters parse the provider's x-ratelimit headers on every real 429 into normalized per-minute limits (
WireError.data.reportedLimits; the openai wire also gains the raw bucket capture the anthropic wire already had), the loop remembers them per (provider, model) as live telemetry, and the opt-inquota.declaredRules(the SAME rule array preflight takes) makes the engine journal aquota_driftdecision plus a warn log whenever a binding declared cap EXCEEDS the provider-reported one, per invocation and dimension, with anthropic's split input and output windows summed against a combined declared tokensPerMinute. Purely observational, synthetic limiter denials never count, and without declaredRules journals and events stay byte identical. On the invoice, anunconfirmedrow that recorded zero usage on every counter now carriesusageUnknown: true(export-levelusageUnknownRowscount, CLIusage-unknownmarker): the zeros mean "nothing recorded", never "the provider metered nothing"; derived at export time, no journal shape change.
Patch Changes
- Updated dependencies [d94beab]
- @rulvar/[email protected]
1.73.0
Minor Changes
- 3e95bd1: The synthesis repair envelope (the v1.71 experiment review, P0.4/P0.8/P1.7):
finishValidation.repairTurnReservegrants bounded EXTRA turns to the invocation the validators bind, one per rejected finish exchange (schema-invalid finish arguments and host validation rejections alike), derived from the message window itself so resumes recount identically and nothing new journals; the deliberately-deferred RV-204 reserve, now that the experiment showed one malformed finish plus one validator rejection killing a whole run inside maxTurns 3. Every typed synthesis failure now carries the acceptance snapshot (completion,childStatusCounts, lifted onto the error outcome by the completion mirror, so an errored run still reports "the fan-out work is complete") and the verdict-derived repair taxonomy (repairsUsed,maxRepairs,rejectedValidators) read from journaled decisions.preflightEstimatemodels the separate synthesis invocation (orchestrator.synthesis: limits, model, estInputTokens; echoed atbudget.orchestrator.synthesis, priced intoexposure.runCeiling, the gap the experiment's projection stopped short of) and folds a declaredfinishValidation.repairTurnReserveinto the projected turns of the bound invocation; the CLI prints the synthesis projection line. Zero reserve and no synthesis declaration keep every ceiling, journal, and report byte identical.
Patch Changes
- Updated dependencies [3e95bd1]
- @rulvar/[email protected]
1.72.0
Patch Changes
- Updated dependencies [662e9e0]
- @rulvar/[email protected]
1.71.0
Minor Changes
- 20d02e0: The preflight quota planner follows the run past the first wave (the second experiment report, rec 9). Every declared spawn now reports
projectedProviderTurns, the provider-call ceiling of its whole loop (maxTurnsbounded by the executed-call ceiling plus the final no-tool turn, plus the finalization summary turn when a tool budget limiter arms it), and the orchestrator echoes its own.exposure.runCeilingtotals the declared wave run to those ceilings at the declared estimates: provider calls as fan-out times per-spawn turns, and cumulative tokens with the context regrowing every turn (turn k re-sends the declared prompt plus the k-1 prior output bounds, so a K-turn loop costs K x est + outputBound x K(K+1)/2). Three findings compare that projection against the declaredquotaRuleswhen the first-wave checks stay silent:quota-requests-below-run(the loops project more wire requests thanrequestsPerMinuteadmits; the message names about how many windows the run needs at best),quota-tokens-below-run(the regrowth cumulative exceedstokensPerMinute), and the spawn-attributedquota-turn-never-fits(by turn k the single context-grown reservation exceeds the whole token window, which the limiter denies withretryAfterMs 0and no wait helps). The first-wave checks are byte-identical, and a run whose ceiling fits its windows produces exactly the findings it did before.rulvar preflightprints the new turn ceiling per spawn and the run ceiling on the exposure line;--jsoncarries the fields verbatim. The experiment run behind the recommendation had zero preflight quota findings and eleven live limiter denials; this projection is what would have said so before the first dispatch.
Patch Changes
- Updated dependencies [20d02e0]
- @rulvar/[email protected]
1.70.1
Patch Changes
- @rulvar/[email protected]
1.70.0
Patch Changes
- @rulvar/[email protected]
1.69.0
Patch Changes
- Updated dependencies [b21a681]
- @rulvar/[email protected]
1.68.0
Patch Changes
- Updated dependencies [b227874]
- @rulvar/[email protected]
1.67.0
Minor Changes
- 8e6006d: The honest invoice (the experiment review, items 11.2/11.3, recommendations P1.2/P1.3/P1.4). The reconciliation verdict now names exactly what it asserts: the value
matchedis renamed toprovider-id-present, because the library never sees provider billing data and the old term read as a statement match it cannot make (deeper reconciliation tiers are host-side joins keyed onresponseId). Consumers comparingrow.reconciliation === 'matched'must switch to'provider-id-present';reconciliationFailureskeeps its meaning (rows without a provider id).InvoiceExportis now self-describing about pricing:pricingBasis: 'per-call'declares that per-rowusdprices each call individually at current rates, androwUsdNonAdditive: truewarns that those values need not sum tototalUsdunder a nonlinear price table (long-context tiers price a split differently from its sum). For consumers whose rows must sum, everyInvoiceRowgains the additiveallocatedUsdcolumn: each (entry, serving model) slice of the same gross fold the totals run is distributed across its rows in proportion to per-rowusd(token weights when every row priced to zero), one row absorbs the IEEE rounding dust, and the flat sum overrowsreproducestotalUsdexactly.rulvar invoiceprints the declared basis in the text form and passes the new fields through--jsonunchanged.
Patch Changes
- Updated dependencies [8e6006d]
- @rulvar/[email protected]
1.66.0
Patch Changes
- Updated dependencies [1b8987e]
- @rulvar/[email protected]
1.65.0
Patch Changes
- Updated dependencies [0b6b859]
- @rulvar/[email protected]
1.64.0
Patch Changes
- Updated dependencies [991f9b5]
- @rulvar/[email protected]
1.63.0
Patch Changes
- Updated dependencies [8a28aed]
- @rulvar/[email protected]
1.62.0
Minor Changes
fca5fd1: Ship the preflight effective-limits estimator and effective-config linter (the experiment-review P2.2): everything the engine derives from a configuration, computed before any provider dispatch, machine readable, with zero paid requests by construction.
Core exports
preflightEstimate(input): a pure function over the same optionscreateEngineandengine.runreceive plus a declared spawn wave, returning the JSON-serializablePreflightReport. The estimate cannot drift from the engine because it reuses the runtime's own arithmetic:mergeUsageLimitsfor the effective per-spawn limit merge (call over profile over engine defaults),admissionReserveUsdfor the layer-1 reserve formula arm for arm (estCost, profile estCost, the priced estimate fromestInputTokens, the flat default, and the unpriced-model zero), the settlement price resolution, and the shared-quota dimension match. The report carries the admission projection over the declared wave mirroringadmitSpawnexactly (which spawns admit, which are denied and by what: budget, spawn cap, orchestrator maxSpawns, or an orchestrator cap its own reserve cannot fit), the per-tool and weighted-unit executed-call ceilings with the first bottleneck named, the orchestrator effective cap and finalize reserve echo, the concurrency and per-provider exposure floors with the one-more-turn overshoot floor, and the linter findings with stable kebab-case codes (errors:unrouted-role,unknown-profile,nothing-admitted,orchestrator-cap-below-reserve; warnings:partial-admission,weighted-units-bind-first,tool-unaffordable,unpriced-under-ceiling,inert-finalization-reserve,inert-tool-budget-notices,orchestrator-cap-fraction-bound, the quota-window comparisons; infos:overshoot-exposure,no-usd-ceiling,no-quota,per-tool-cap-unreachable).The CLI gains
rulvar preflight <file|name> [--budget-usd N] [--profile NAME] [--spawns JSON] [--json]: it assembles exactly the optionsrulvar runwould (config, module exports, run profile) but constructs no engine, opens no store, and dispatches nothing. The declared wave comes from the newpreflightexport of the config or workflow module ({ spawns?, orchestrator?, quotaRules? }),--spawnsoverrides it,--jsonemits the machine-readable report, and the exit code is the linter contract: 1 when any finding has severity error.
Patch Changes
- Updated dependencies [fca5fd1]
- @rulvar/[email protected]
1.61.0
Minor Changes
b4c1f1f: Durable provider reconciliation (the experiment-review P1.3): every live provider dispatch now mints a
ProviderCallRecordon the terminal entry'sproviderCallsledger, the CostReport splits gross from net, andinvoiceFromJournalplusrulvar invoiceexport the rows.- The per-dispatch ledger. Every wire call the engine actually makes, successful or not, records
{ ordinal, role, servedBy, attempt, outcome, responseId?, usage, usageApprox?, errorCode?, aborted? }, minted at the single dispatch chokepoint from the same sanitized usage the phase slices accumulate. Failed and retried attempts keep their billed usage attributable instead of dissolving into the aggregate; quota denials and abort short circuits that never reached the adapter mint nothing. The providerresponseIdboth shipped adapters already surface on every finish is now persisted. The ledger rides every checkpoint boundary (kill-and-resume keeps pre-kill calls attributable, ordinals continuing) and restores verbatim on replay with zero live calls. - Gross versus net.
CostReport.totalUsdstays the net ledger it always was (abandoned subtrees contribute zero). New required fields make the provider's view first class:grossUsd(net plus abandoned, the figure an invoice reconciles against; abandoning a branch never shrinks it) andabandoned: { usd, unpriced, usageApprox? }.rulvar inspectprints the gross line whenever a run abandoned paid work. - The invoice export.
invoiceFromJournal(entries, priceUsd)returns one row per billable call with a reconciliation verdict per row:matched(response id present),missing-provider-id(a finished call without one),unconfirmed(a failed or severed call without one),unattributed(pre-ledger entries and restored remainders; the spend surfaces instead of vanishing). Totals are the same slice fold the CostReport runs, sototalUsd === CostReport.grossUsdexactly.rulvar invoice <runId> [--json]is the CLI form.
The frozen cassette catalog is re-recorded for the additive
providerCallsfield on terminal agent entries (journal-shape-revision, policy not identity: no hashVersion change, no matching impact).- The per-dispatch ledger. Every wire call the engine actually makes, successful or not, records
Patch Changes
- Updated dependencies [b4c1f1f]
- @rulvar/[email protected]
1.60.0
Patch Changes
- Updated dependencies [59bbeaa]
- @rulvar/[email protected]
1.59.4
Patch Changes
- Updated dependencies [c49d7a1]
- @rulvar/[email protected]
1.59.3
Patch Changes
- Updated dependencies [deaef36]
- @rulvar/[email protected]
1.59.2
Patch Changes
- Updated dependencies [dd0e10f]
- @rulvar/[email protected]
1.59.1
Patch Changes
- Updated dependencies [c127770]
- @rulvar/[email protected]
1.59.0
Patch Changes
- Updated dependencies [615dc90]
- @rulvar/[email protected]
1.58.0
Minor Changes
- 4fa35ce: RV-217: data protection hooks, the full close. The plan's gate ("PII never persists or emits in plaintext under policy") now holds end to end. (1) ENVELOPE ENCRYPTION on the serialization seam:
createEnvelopeEncryption({provider, historicalWrappedKeys?, plaintextReads?})returns aSerializationHookthat AES-256-GCM encrypts every persisted byte (journal payloads, transcript blobs, checkpoints) with entry identity as associated data (a ciphertext moved between entries or refs fails authentication), keeping only the kernel-pinned ordering/identity fields plus spanId and timestamps plaintext;DataKeyProvideris the KMS seam (the exact shape of GenerateDataKey/Decrypt, called only in the async factory so the sync hooks run on in-memory data keys, and every envelope carries its wrapped key so reads need no live KMS); the shippedlocalKeyProviderderives KEKs via HKDF-SHA256 with aninfopartition for tenant-scoped keys (a different tenant's provider cannot unwrap, pinned by tests); reads of non-enveloped data fail closed by default withplaintextReads: 'passthrough'as the explicit migration mode;fromStored(toStored(e))reproduces entries exactly, so replay, resume, and recovery are untouched and a run over real files greps to ZERO plaintext PII whileEngine.storesreads plaintext through the one policy point. (2) REDACTION POLICY:redaction.patternsadds host-defined patterns (RegExp or strings, compiled once, typed ConfigError on an invalid one) on top of the default credential set for every emitted event, via the new exportedcompileSecretMasker; the OTel exporter accepts the samepatternsfor trace parity. (3) EXPORT/IMPORT:engine.exportRun(runId)produces the portable bundle (meta, entries, blobs) read through the policy point, so encrypted deployments export plaintext for subject-access requests;engine.importRun(bundle)writes through the target's stores (re-encrypting under its policy), keeps the original runId, and refuses an existing run typed; together with the existingdeleteRun/pruneRunthis completes the retention/deletion/export surface. (4) SALTED METADATA DIGESTS:security.argsHashSaltswitchesRunMeta.argsHashto HMAC-SHA256 under a deployment salt (equal args stop correlating across deployments; low-entropy args stop being recoverable from the digest),hashRunArgsgains the optional salt, and the CLI resume args gate picks the salt up fromengineOptions.securityautomatically. (5) AUDIT TRAIL:reduceAuditTrail(entries)folds a journal into the typed, ordered sequence of authority events (suspensions with deadlines, resolutions with who and what, abandons with reasons, engine decisions, termination denials, run settles), tolerant across journal vintages. New guide page: https://docs.rulvar.com/guide/data-protection.
Patch Changes
- Updated dependencies [4fa35ce]
- @rulvar/[email protected]
1.57.0
Patch Changes
- Updated dependencies [5897232]
- @rulvar/[email protected]
1.56.0
Patch Changes
- Updated dependencies [f26dba0]
- @rulvar/[email protected]
1.55.0
Patch Changes
- Updated dependencies [e9b005b]
- @rulvar/[email protected]
1.54.0
Minor Changes
3f6bc03: Three improvement-plan remainders: the
run:endsemantic completion lift (RV-207 tail), the standard repository research toolset (RV-210), and incremental synthesis with pre-model claim deduplication (RV-211).The completion lift. Transport status and semantic completeness are different claims, and
run:endnow carries both: a workflow that returns an object result with a validcompletionliteral ('complete' | 'partial' | 'rejected') and optionally achildStatusCountsrecord, or throws a typed error whosedatacarries them, gets both lifted onto therun:endevent. The orchestrator acceptance path emits the envelope on every terminal, including the typed rejection (itsFailRunErrordata now carriescompletion: 'rejected'). Malformed shapes stay silently absent, replay recomputes identical fields, the CLI progress line renderscompletion=..., and the OTel exporter mapsrulvar.run.completionandrulvar.run.childStatusCounts.The repository research toolset.
repositoryResearchToolset({ root })ships fiverisk: 'read'tools over a confined directory root:list_files,search_files, andread_filewith deterministic byte ordering and STABLE keyset cursors (a page boundary never shifts when unrelated entries appear; every cursor embeds its query identity), plusrecord_evidence, which verifies citations at collection time (the file must exist under the root,linesmust be a valid 1-based range inside it,quotemust appear verbatim), andlist_evidence. Pages are canonical: byte-identical however addressed, which is exactly what the exploration guards measure, somaxRepeatedToolSignatureandmaxNoNewEvidenceCallscompose with the kit instead of being defeated by marker fields. Absolute paths,..escapes, and symlink escapes are typed error results; the host reads collected evidence viakit.evidence().Incremental synthesis and claim dedup.
synthesis.mode: 'incremental'dispatches one boundedsynthesize-role NOTE invocation per settled child the moment it settles (defaultnoteLimits{ maxTurns: 2 }), overlapping the still-running fan-out, and the final result is a DETERMINISTIC reconciliation envelope (IncrementalSynthesisResult), never another model call; a dead note falls back to that child's raw digest summary under a journaled per-childorchestrator_synthesis_note_fallbackdecision, replay reproduces the envelope with zero paid calls, andfinishValidationplus incremental mode is aConfigErrorat intake because the reconciliation has no model-composed finish to validate.synthesis.dedupeClaims: truededuplicates repeated claim lines across children BEFORE any model call (whitespace-collapsed exact matching via the exported purededupeRepeatedClaims, never fuzzy): in single mode the digest keeps first occurrences with aREPEATED CLAIMSindex riding the prompt, in incremental mode the envelope carriesrepeatedClaims. Both options default off and the synthesis prompt stays byte-identical when unset.
Patch Changes
- Updated dependencies [3f6bc03]
- @rulvar/[email protected]
1.53.0
Patch Changes
- Updated dependencies [b821bd1]
- @rulvar/[email protected]
1.52.0
Minor Changes
- e138df9: Ship the RV-210 exploration guards (first slice): three opt-in
UsageLimitsfields that make an oscillating tool loop visible and boundable.toolBudgetNoticessurfaces soft 50%/80% thresholds overmaxToolCallsto the model as a plain user message with the exact remaining count (once per threshold, checkpoint-safe, inert with a loud warning withoutmaxToolCalls).maxRepeatedToolSignaturecaps executions of the byte-identical call (tool name plus RFC 8785 canonical args): the excess call is never dispatched, the model receives a typed error result naming the count, the denial does not consume the tool budget, andtool:endcarriesoutcome: 'denied'withguard: 'repeated-signature'.maxNoNewEvidenceCallsaborts the invocation as statuslimitwith the newabortClass: 'exploration'when N consecutive successful executions return only already-seen result digests; the executed work is kept, the terminal memoizes, and the structuredExplorationSummary(toolCallsUsed,distinctSignatures,repeatedCalls,duplicateResultCalls,deniedRepeats,byTool) journals beside the abort class so a replayed consumer sees the same typed evidence with zero live calls. Whenever any guard field is configured the summary also rides the fullAgentResultand the liveagent:endevent (live-only for non-abort terminals, liketransportRetries); values JCS cannot serialize fail open (unique signatures, fresh evidence); on resume the guard rebuilds from the restored checkpoint messages. The CLI TUI renders the guard marker on denied tool lines and the OTel exporter maps the counters torulvar.exploration.*andrulvar.tool.guardattributes. Unconfigured invocations are byte-identical to before. Demonstrated against published 1.51.0 first: the identical call executed six of six times with zero signal, the model never saw a remaining count, duplicate pages never flagged, and the terminal was a barelimitindistinguishable from honest work.
Patch Changes
- Updated dependencies [e138df9]
- @rulvar/[email protected]
1.51.0
Patch Changes
- @rulvar/[email protected]
1.50.0
Minor Changes
e39a885: The structured determinism contract (RV-209): bare-nondeterminism detection is engine-owned, classified, localized, and enforceable, and replay verification is a first-class CLI gate.
- New
determinism:warningevent on the run stream: a bareDate.now()orMath.random()call observed inside an in-process workflow body emitscategory,provenance(workflow|allowlisted), the callingframe, and the parsedfile/line/column, at most once per (category, provenance) per execution segment. Installed dependencies (node_modules) and Node runtime frames are classified exempt and stay silent, so an SDK's internal randomness never brands the run nondeterministic. Never journaled; because replay re-executes the body, a violation still in the code fires again on every replay organically. CreateEngineOptions.determinism:mode: 'off' | 'warn' | 'error'(warn stays the default and the pre-RV-209 dev-only behavior; the process warnings now name the callsite),allowlist(substring or RegExp patterns for confirmed-safe frames, classifiedallowlisted, never rejected), andredact(applied to frames and file paths before they leave in events, warnings, and errors). Config is validated loudly atcreateEngine.mode: 'error'detects in every environment including production and rejects the run: the offending call throws a typedDeterminismError(new error codedeterminism, localization indata) at the call site, and a workflow that swallows it is re-thrown at settle, so the run ends'error'instead of recording a value replay cannot reproduce.- The journaled run-settle decision now records
outputHash(canonical JCS sha256 of the settling segment's result; absent for undefined or non-serializable values). Pure replays append no settle, so a divergent replayed result can never overwrite the live baseline.hashRunOutputand the extendedlastRunSettleare exported. - New
rulvar replay <runId> [--args JSON] [--store PATH] [--assert-no-live] [--compare-output-hash]: a dry-run resume (zero journal or meta writes, zero adapter calls) that reports replay accounting, every localized determinism warning, and the digest comparison;--assert-no-liveexits 1 unless the replay is pure,--compare-output-hashexits 1 unless the replayed result's digest equals the journaled one. Deliberately no--allow-args-change: verifying a different logical run proves nothing. - The TUI renders
determinism:warninglines, and the OTel exporter attaches the event to its span withrulvar.determinism.*pluscode.filepath/code.linenoattributes. - The frozen cassette catalog is re-recorded for the additive
outputHashfield on run-settle decisions (journal-shape-revision, policy not identity: no hashVersion change, no matching impact).
- New
Patch Changes
- Updated dependencies [e39a885]
- @rulvar/[email protected]
1.49.0
Minor Changes
bab7b2c: Make the agent event model unambiguous (RV-207): one
agent:start/agent:endpair per logical agent span, a pairedagent:phase:start/agent:phase:endper model invocation phase, an official reducer, and the OTel exporter leak the old shape caused is closed.Before this release one spanId emitted an extra unpaired
agent:startfor every phase of the dispatch (loop, thensummarizeper compaction,finalize,extract) with a singleagent:end, so durations and attempts were underivable without heuristics: a consumer pairing starts with the end read the LAST phase's duration as the agent's, a starts-minus-ends gauge leaked one running agent per phase, and the shippedtoOtelexporter (reproduced on the published 1.48.0) leaked a never-ended OTel span per multi-phase agent while the span it did close measured only the last phase. The replayed stream had a different shape than the live one (one start), so the same consumer built different tables live and on replay.Now every phase activation emits
agent:phase:start/agent:phase:endkeyed(spanId, invocation)(a 1-based activation ordinal; a summarize that fires three times gets three pairs), carrying the phase's role, the serving model,durationMs, the usage delta the activation added to its(role, model)slice (the pairs sum exactly toagent:endand to the journaledusageByModelsplit),costUsdpriced at each serving model's own rate, a binaryoutcome, andretries(transport retries inside the activation).agent:endgainsretryCount. The retry facts are live telemetry only, never journaled: replayed events omit them, and replayed phase pairs are reconstructed from the terminal entry's recorded slices withdurationMs0, so a live stream and its replay reduce to IDENTICAL usage and cost tables.reduceInvocationTable(new in@rulvar/core) is the official no-heuristics reducer: per-agent per-phase rows plus a per-role aggregate that matchesCostReport.byRole; truncated streams stay honest (open: true), never guessed at.@rulvar/cli:toOtelmaps each phase pair to aninvocation <role>child span of its agent span withgen_ai.usage.*,rulvar.cost_usd, andrulvar.retriesattributes, closes the agent span with the whole dispatch's totals andrulvar.retry_count, and an opener for an already-open span never duplicates it, so even a stream from a pre-RV-207 core cannot overwrite the tracked agent span and leak it unended. The progress renderer prints the phase lines (agent w extract phase on model, then the settle line with per-phase cost, tokens, duration, and retries). Journal bytes, cassettes, and toolset hashes are untouched: events are telemetry, never identity.
Patch Changes
- Updated dependencies [bab7b2c]
- @rulvar/[email protected]
1.48.0
Patch Changes
- @rulvar/[email protected]
1.47.0
Minor Changes
- a3687fe: Ship phase 3 of the fenced run state RFC, reconcile and recover. The engine now journals every run settle whose segment did durable work (or changed the recorded status) as a
run_settledecision entry ordered BEFORE the meta write, so the run's outcome is part of the journal andRunMetais a rebuildable projection; the write-on-change rule keeps pure replay byte stable, so a resume that only replays appends nothing. On top of it,auditRunnames the divergences a worker sweep can never see,auditRunssweeps the catalog, andreconcileRunMetarewrites the sound cases from the journal with zero model calls and no workflow:meta-behind(the crash residue between the journal flush and the meta write, or a stale write contradicted by a journaled settle) takes the journaled status, andstranded(a terminal meta over live journal work, the F1 residue an unfenced store admits, demonstrated against the published 1.46.0 first) becomes sweepable again; ambiguous residues are reported assuspectand never rewritten. The CLI gainsrulvar runs audit [--repair], the operator probe: it lists every divergence, repairs under a brief per-run lease on a leasable store (a live owner is skipped, never raced), and exits 0 only when the catalog ends consistent.ResolutionOutcomeadditionally carrieswoke: trueexactly when a resolution settled a live in-process waiter, and the HTTP server uses it to close a quiesce-window race: a resolve that applied through the fold while the segment was closing now awaits the imminent settle and continues the run in place instead of answeringresumed: falseon timing grounds and stranding it suspended. The committed cassette catalog is re-frozen for the additive settle entry under the journal-shape-revision lane of the fixtures lock: an additive journal evolution that revises no identity (the hashVersion stays 2; entry identity, adapter requests, and the frozen v1 resume fixtures are untouched byte for byte).
Patch Changes
- Updated dependencies [a3687fe]
- @rulvar/[email protected]
1.46.0
Patch Changes
- Updated dependencies [865e7bf]
- @rulvar/[email protected]
1.45.0
Minor Changes
- b96305d: The fenced writes capability (the fenced run state RFC, phase 2).
JournalStore.putMetaanddeleteandTranscriptStore.putanddeleteaccept the same optional trailing lease thatappendalways took, and a store declares enforcement with thefencedWrites: truemarker: a mutation carrying a lease that is not the current holder for the mutated run rejects with the typedLeaseHeldError, atomically and leaving nothing changed, including a live lease for a different run. The engine threads the segment's lease into every durable mutation of a leased resume (meta writes, checkpoints, compaction summaries, worktree patches, workflow sources), so over a declaring store a superseded worker can no longer overwrite the successor's meta at its late settle and strand the run from worker sweeps, and its very first refused meta write now fails the stale segment typed at boot with zero paid calls.SqliteStoredeclares the marker and enforces it onputMeta,delete, andappend(with the run-match rule as defense in depth); the conformance kit gainsfencedWritesConformanceas the capability's executable definition; the queue worker's retention sweep passes its brief lease through the new optional second argument ofengine.deleteRun(pruneRuntakes the same); andhasFencedWritesplusassertFencedWriteslet a host assert the full fence at deployment time. Stores written before the capability are untouched: without the marker the extra argument is ignored and the journal-append fence works exactly as before.
Patch Changes
- Updated dependencies [b96305d]
- @rulvar/[email protected]
1.44.1
Patch Changes
- @rulvar/[email protected]
1.44.0
Patch Changes
- Updated dependencies [299f7d2]
- @rulvar/[email protected]
1.43.0
Patch Changes
- Updated dependencies [71b7181]
- @rulvar/[email protected]
1.42.0
Patch Changes
- Updated dependencies [9b70f27]
- @rulvar/[email protected]
1.41.0
Minor Changes
be589ec: Add the orchestrate acceptance policy and the CLI --strict flag (the v1.40.0 improvement plan's completion contract)
Run status ok proves that finish validated, and nothing more: the model may call finish after any mix of child outcomes, so ok alone never proves the children succeeded. The new opt in OrchestrateOptions.acceptance turns that into a checked contract. childPolicy 'all-ok' requires every spawned child to have settled ok when finish validates (a child still running counts against it); { minSuccessful: N } tolerates failures beyond the first N successes. The verdict is journaled as one decision entry, so a resume rolls the same verdict forward, immune to drift of the live options. An accepted result becomes the acceptance envelope { result, completion, childStatusCounts, degradedReasons }; a violated policy fails the run with the typed FailRunError (code fail_run, data.source 'orchestrator_acceptance') instead of settling ok. Without acceptance nothing changes: the result value stays the raw finish payload and no new journal entry is written.
The CLI pairs with the envelope: rulvar run --strict and rulvar resume --strict exit nonzero when a settled ok value reports completion 'partial', printing the degraded reasons (strictExitCode is exported for hosts). The guides also now state the adjacent contracts plainly: await_any and await_all return truncated TaskDigests rather than full child reports, cost totals are price registry estimates with usageApprox marking estimated usage, the fencing epoch covers journal appends while RunMeta and transcript blobs stay advisory projections, and data protection at rest is owned by the host.
Patch Changes
- Updated dependencies [be589ec]
- @rulvar/[email protected]
1.40.0
Minor Changes
cf33550: Fence the offline resolution append and surface approximate usage (v1.39.0 review)
The CLI server's offline resolution path acquired a store lease but never threaded it into the Replayer, so the resolution append ran unfenced: if the process stalled past its lease ttl and a queue worker took the run over, the stale append could land alongside the new owner's writes. The append now carries the acquired lease, so a superseded owner is rejected with LeaseHeldError (HTTP 409) instead of racing the current owner.
Approximate usage is now visible where the run is reported. usageApprox rides the agent:end and run:end events and the CostReport, and the CLI cost line marks an estimated total, so a total that includes usage estimated after a transport cut, a ceiling that severed a stream, or an abort is never shown as though it were the exact provider charge. The field is present only when true, so every exact usage report and event is byte for byte unchanged.
Patch Changes
- Updated dependencies [cf33550]
- @rulvar/[email protected]
1.39.0
Patch Changes
- @rulvar/[email protected]
1.38.0
Patch Changes
- @rulvar/[email protected]
1.37.0
Patch Changes
- Updated dependencies [e6b1481]
- Updated dependencies [e6b1481]
- @rulvar/[email protected]
1.36.0
Minor Changes
- 101795b: Validate
createWorkertimers and make the TTL match promise executable (v1.35.0 review P2).ttlMsandpollMsmust be integers between 1 and 2147483647 ms, refused typed at construction (an overflow or non finite cadence collapsed to the 1 ms interval floor and stormed the store). A store exposing the optionalleaseTtlMscapability is verified against the worker ttl, a mismatch is aConfigError, and an omittedttlMsadopts the store's value.
Patch Changes
- Updated dependencies [101795b]
- @rulvar/[email protected]
1.35.0
Patch Changes
- Updated dependencies [d4ac3bf]
- @rulvar/[email protected]
1.34.0
Patch Changes
- Updated dependencies [f1505ec]
- @rulvar/[email protected]
1.33.0
Patch Changes
- @rulvar/[email protected]
1.32.0
Patch Changes
- @rulvar/[email protected]
1.31.0
Patch Changes
- @rulvar/[email protected]
1.30.0
Patch Changes
- Updated dependencies [87ce985]
- @rulvar/[email protected]
1.29.0
Patch Changes
- Updated dependencies [621d566]
- @rulvar/[email protected]
1.28.0
Minor Changes
- d98eb0b: The documented spaced syntax of numeric flags now reaches the canonical validation for negative values:
rulvar run wf --budget-usd -1reports--budget-usd must be a positive numberinstead of the generic parseArgs ambiguity error (v1.27.0 review P3). The fold applies only to strictly numeric negative tokens after a numeric flag (--budget-usd,--planning-budget-usd); unknown option, duplicate flag, and missing value diagnostics are unchanged.
Patch Changes
- Updated dependencies [d98eb0b]
- @rulvar/[email protected]
1.27.0
Minor Changes
- 884a433: The HTTP shell's SSE delivery is now complete and bounded per connection (v1.26.0 deep E2E review). A terminal settle closes connected streams only AFTER the segment's event pump has drained, so a client that keeps reading receives the full tail including the terminal
run:endinstead of a clean close that silently swallowed the backlog; when the pump itself failed, the close is preceded by an SSE comment saying the stream may be incomplete. NewmaxPendingEventsPerClientoption (default 10000) bounds what any single SSE connection can accumulate unread, independently of the replay buffer: a consumer that stopped reading is unhooked at the bound and closed with an SSE comment naming it, the frames already queued stay readable, and the standardLast-Event-IDreconnect resumes strictly after the last frame the client consumed; a replay longer than the bound is delivered the same way, in bounded chunks across reconnects, so pending memory per connection is O(bound) while delivery stays at least once.createServernow validates its numeric caps at construction with a typedConfigError(maxTrackedRunsaccepts non negative safe integers,maxBufferedEventsPerRunandmaxPendingEventsPerClientaccept positive safe integers):NaNused to silently mean unbounded,Infinitylooked like a cap without capping, and negative or fractional values produced policies nobody asked for. The barrel additionally exportsDEFAULT_MAX_PENDING_EVENTS_PER_CLIENTand the referenced typesKbSweepCliConfig,LoadedWorkflowModule, andOtelContextApi, so every public signature resolves in the API docs.
Patch Changes
- Updated dependencies [884a433]
- @rulvar/[email protected]
1.26.0
Minor Changes
- a4fc757: The HTTP shell decouples process memory from durable retention (v1.25.0 scale review): new
memoryRetentionpredicate andmaxTrackedRunscap release a settled run's tracked state (args, outcome, handle, SSE buffer) while the journal and transcripts stay, and newmaxBufferedEventsPerRunbounds each run's SSE replay buffer (oldest events dropped in chunks and counted; a replay that lost events carries anx-rulvar-events-droppedheader, and a client whose cursor predates the retained window gets a leading SSE comment naming the first retained seq). TheLast-Event-IDcursor is now a binary search over the seq ordered buffer and the replay streams by index (no buffer copy); a cursor seq the buffer does not hold replays everything strictly after it instead of re-flooding the whole buffer, which remains at least once. The queue worker sweeps candidates only (listRuns({ statuses: ['running', 'suspended'] }), widened to the full catalog only when durableretentionneeds terminal metas), never overlaps sweeps, keys its suspended skip cache and its poison set to the run's generation (RunMeta.genesis) so adeleteRunand recreate of the same runId is picked instead of skipped, and drops skip and poison entries for runIds that left the candidate set. Point lookups inresume,inspect, the kb gate, and the server status path go through the store's exact lookup capability when present.
Patch Changes
- Updated dependencies [a4fc757]
- @rulvar/[email protected]
1.25.0
Patch Changes
- 74851ed: CLI diagnostics stop echoing
--argsvalues and sanitize every dynamic value they embed. The invalid-JSON and non-canonical-JSON refusals now name the failure class and the way out without repeating the supplied value (workflow args may carry private data, and stderr routinely lands in CI logs). Every typed CLI error prints through one site that strips terminal control sequences, and the plain-output run renderers (outcome reports, dry-run previews, suspension prompts, resume warnings, plan lint diagnostics) sanitize untrusted text the same way the live TUI already does, so a hostile runId, suspension key, provider error message, or model ref cannot recolor, retitle, or rewrite the terminal. Exit semantics are unchanged.- @rulvar/[email protected]
1.24.1
Patch Changes
- 0bb14db: Close a resume args-gate bypass through JSON numeric overflow (v1.24.0 review P2-1). A
--argsvalue that overflowed JavaScript's finite range (1e400parses toInfinity) could not be canonicalized, so genesis recorded the args binding withargsProvidedbut no hash, and a laterresumesupplying entirely different args slipped past the gate with only a warning, silently changing the logical run and re-paying every args-dependent call.rulvar runandrulvar resumenow reject non-finite (non-JCS)--argsat parse time, before any config, store, or adapter loads. Independently, when a run recordedargsProvidedwithout a verifiable hash (an in-process host that started it with genuinely non-JCS args), aresumesupplying args is now a typed refusal unless you pass--allow-args-change, instead of the previous soft warning. Core engine policy is unchanged: in-process hosts may still pass non-JCS args and record presence without a hash. - Updated dependencies [0bb14db]
- @rulvar/[email protected]
1.24.0
Minor Changes
- 2b033e8: Make
rulvar resumesafe against forgotten or changed args and add a--dry-runpreview (the v1.23.0 review: a resume without--argssilently changed the logical run and paid again). The resume grammar gains--dry-runand--allow-args-change. Before the engine starts, the CLI verifies the supplied args against the genesis binding recorded inRunMeta: forgetting--argson a run started with them, adding them to a run started without them, or supplying a different value is a typed refusal naming--allow-args-changeas the deliberate override; runs recorded before v1.24.0 carry no binding and demand explicit--argsor the override.--dry-runpasses the engine's replay-strict mode through and prints the resume preview (hits, misses, reruns, skipped, orphaned effect roots, invalid resolutions) plus what the run would settle as, with zero journal or meta writes and zero adapter calls; a preview that reaches work needing a live call reports the stopping point and exits 0.rulvar inspectnow prints the args binding.
Patch Changes
- Updated dependencies [2b033e8]
- @rulvar/[email protected]
1.23.0
Patch Changes
1f9c272: The renderers' remaining unsanitized paths and the malformed-event gaps (v1.22.0 review P2-2, P2-3).
progress(): the error text surfaced when the SOURCE fails (a rejectedRunHandle.result, a rejectedPromise<RunHandle>, a throwing iterable) went to the sink raw; a crafted rejection could inject ANSI, forge lines, and leak a key-shaped fragment. Every catch path now routes through one helper that secret-masks FIRST (the thrown value never crossed the event masking boundary) and terminal-sanitizes second; lines mode prints the notice as its own sanitized line instead of dropping it.- Malformed recognized events from a raw iterable can no longer stop a view: every dynamic field in the
progress()reducer, its lines formatter,renderProgress, and the CLIrenderEventLineis read through typed guards (a hostile object with a throwingtoStringincluded), a backstop catch skips a bad event with a bounded diagnostic carrying no untrusted data, and the stream continues. The v1.22.0 claim of full defensive reads was narrower in reality (agent:streamwithoutdeltaorphase:startwithoutphasestopped the raw-iterable view); it is true now and pinned by a table-driven test over every consumed type. posIntOptionwording: a below-minimum value CLAMPS to the minimum (only non-finite values fall back to the default); the JSDoc said "falls back" for both.@rulvar/clibuild config migrates the deprecated tsdownexternaloption todeps.neverBundle; the packed dist keeps the companion specifiers external, byte-for-same behavior.
Updated dependencies [1f9c272]
- @rulvar/[email protected]
1.22.0
Patch Changes
- 77b554f: Sanitize the CLI event line renderer (
renderEventLine, used byattachProgress): every composed line passes through the sharedsanitizeTerminalTextbefore it reaches the terminal, so an untrusted provider/tool/log string in an event can no longer inject a control sequence or a second physical line into CLI output (v1.21.0 review P2-1). Clean lines stay byte-identical. - Updated dependencies [77b554f]
- @rulvar/[email protected]
1.21.0
Patch Changes
- Updated dependencies [7ee42a0]
- @rulvar/[email protected]
1.20.0
Patch Changes
- Updated dependencies [9367030]
- @rulvar/[email protected]
1.19.0
Patch Changes
- Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- @rulvar/[email protected]
1.18.0
Minor Changes
943962d: Sweep and suite reports are now monotone: paid evidence survives every budget refusal. Previously
runSweepMatrixcaught the envelope'sSweepBudgetErroraround a whole cell and replaced it with an emptyenvelopeExhaustedrow, erasing already completed targets and their cost; a judge refused by the envelope erased the paid successful target the same way; and a judge run that hit its own per-run ceiling threwEvalJudgeErrorout of the entire matrix, losing every accumulated cell.Now:
runEvalSuitereturns partial results withplannedN,completedN, and a typedrefusalmarker instead of throwing when the envelope refuses a target; a judge budget event (per-run ceiling exhaustion or envelope refusal) normalizes into the owningEvalCaseResultasincomplete: { reason: 'judge-exhausted' | 'judge-refused' }with the failing judge run's actual cost counted, while non-budget grader errors still throw;SweepCellReportgainsplannedN,judgeIncompleteRuns,incompleteReason, andrefusedRunLabel, and any incomplete cell (n < plannedN, exhausted targets, unfinished judges, or an envelope refusal) emits no claim;runCanaryrecords an envelope-refused probe asstatus: 'refused'and keeps walking, so completed probe evidence survives andallOkstays the drift-flip gate;EvalJudgeErrorcarriescostUsd. Thekb sweephuman renderer prints incomplete cells explicitly (INCOMPLETE: envelope refused ... after N of M case(s), unfinished-judge counts, refused-probe counts) instead of pretending nothing ran.Migration:
runSweepMatrixandrunEvalSuiteno longer throwSweepBudgetErrorfor refused targets or judges; readEvalSuiteResult.refusal,EvalCaseResult.incomplete, and the new cell fields instead. Cells now always carryplannedN.
Patch Changes
- Updated dependencies [943962d]
- @rulvar/[email protected]
1.17.0
Minor Changes
7909b6b: Every paid CLI surface is now budget-bounded, and the grammar ignores nothing (the v1.16.2 review P1-1, P1-2, P2-1, P3-1).
rulvar plangained separate immutable ceilings for its two paid runs:--planning-budget-usd Nfreezes as the planning run's B0 at its journal's genesis (PlanOptions.run.budgetUsd) and--budget-usd Ncaps the execution run exactly likerulvar run. A machine-written workflow never runs unbounded silently: missing ceilings fail loudly unless--allow-unboundedwaives them explicitly, and--dry-runbeside--budget-usdis a contradiction, not an ignorable leftover.rulvar kb sweeprequireskbSweep.budgets({ targetUsd, judgeUsd, canaryUsd, maxTotalUsd }) or an explicitkbSweep.allowUnbounded: true: every target, judge, and canary run carries an immutable per-run ceiling, the whole sweep authorizes against the debit-onlymaxTotalUsdenvelope (falsification pool growth included), the worst-case authorized spend prints before the first provider call, and envelope-refused or ceiling-exhausted cells report honestly and emit no claim. Canary drift flips claims stale only when every probe settledok, so a budget-starved or transiently failing probe can never blame the model.- The canonical grammar is one data structure now:
--help, every per-command usage error, and the documented grammar block render from it and are locked together by tests. Nothing accepted is ignored:resumerejects--budget-usdand--profileat parse time (the ceiling is immutable from genesis by the documented budget invariant), every command enforces exact positional arity, duplicate value flags fail, and unknown options report as ConfigError usage lines instead of raw parseArgs stack traces. All rejections happen before any config, store, or adapter loads, with zero provider calls and byte-identical journals.
Patch Changes
- @rulvar/[email protected]
1.16.2
Patch Changes
- 9f07130: The published CLI now actually loads its command-local optional companions. The build had been inlining
@rulvar/planner,@rulvar/plan, and@rulvar/evalsinto local chunks, so the packedrulvar planfailed with a false "install @rulvar/planner" even with the planner installed (the inlined eslint broke at load time and a bare catch reported it as missing), whilerulvar kb inboxran without@rulvar/planinstalled, against the documented dependency contract. The three companions are external again (dist keeps the realimport("@rulvar/...")specifiers, the planner's worker sandbox loads from the installed package, and the CLI dist shrinks from megabytes to about 82 kB), and import failures are classified: only a genuine module-not-found for the requested companion produces the install hint, while an installed companion that fails to initialize surfaces its own error with the cause preserved. A packed-consumer E2E matrix (scripts/cli-smoke.mjs) now gates releases on exactly this behavior.- @rulvar/[email protected]
1.16.1
Patch Changes
- fac1ecc: Mark eslint's optional TypeScript-config loader
jitias external in the CLI bundle. The bundled eslint (pulled in through @rulvar/planner's programmaticLinter) lazily importsjitionly on its config-file loading path, which the CLI never executes; the import now stays an import instead of producing UNRESOLVED_IMPORT build warnings. No runtime behavior change.- @rulvar/[email protected]
1.16.0
Patch Changes
- @rulvar/[email protected]
1.15.0
Patch Changes
- @rulvar/[email protected]
1.14.0
Patch Changes
- @rulvar/[email protected]
1.13.0
Patch Changes
- @rulvar/[email protected]
1.12.0
Patch Changes
- Updated dependencies [46edcc0]
- @rulvar/[email protected]
1.11.0
Patch Changes
- Updated dependencies [0c70c5e]
- @rulvar/[email protected]
1.10.0
Patch Changes
- Updated dependencies [0e8d78e]
- @rulvar/[email protected]
1.9.0
Patch Changes
- Updated dependencies [3a53383]
- @rulvar/[email protected]
1.8.0
Patch Changes
- Updated dependencies [25724b5]
- Updated dependencies [57ea1de]
- Updated dependencies [7884ec5]
- Updated dependencies [52db30d]
- @rulvar/[email protected]
1.7.0
Patch Changes
- Updated dependencies [45285aa]
- Updated dependencies [2f20d1d]
- Updated dependencies [22f65a8]
- Updated dependencies [2ddfa29]
- Updated dependencies [2abd9c2]
- Updated dependencies [1c1175d]
- @rulvar/[email protected]
1.6.0
Patch Changes
- da4dbad: Write the product name as Rulvar in prose: package READMEs, npm descriptions, and the documentation site now capitalize the brand. Identifiers keep their exact casing, so package names, the
rulvarbinary,rulvar.config.mjs, the.rulvarstore directory, therulvar.*OTel attributes, and every URL are unchanged. Documentation and metadata only; no runtime behaviour changes. - Updated dependencies [da4dbad]
- Updated dependencies [487da86]
- Updated dependencies [df416fc]
- Updated dependencies [a737810]
- Updated dependencies [9eb66b4]
- @rulvar/[email protected]
1.5.2
Patch Changes
- Updated dependencies [54936a0]
- @rulvar/[email protected]
1.5.1
Patch Changes
- Updated dependencies [6c6d56f]
- @rulvar/[email protected]
1.5.0
Patch Changes
- Updated dependencies [4fba3c7]
- Updated dependencies [8655c0f]
- @rulvar/[email protected]
1.4.0
Minor Changes
c4f563d: Production readiness fixes from the July 2026 full audit.
The
budgetUsdceiling now survives resume: the engine records it inRunMeta.budgetUsdand restores it on every resume, so the replayed spend counts against the original invocation's bound andResumeOptionsstill exposes no way to raise it. Journals written before the field existed (or read through a store that drops optionalRunMetafields) resume uncapped, exactly as before; the conformance kit gains a round-trip check so custom stores cannot drop the field silently.spawn:rejectedandresolution:applied/resolution:supersededare now emitted: live admission rejections carry the rejectioncode,agentType, and the journaled decisionentryRef(absent only for pre-admission config gates), and live resolution attempts report winning or losing the first-closing-wins fold.spawn:admittednow carries the decisionentryRefand the admittingverdictarm. Theorchestrator:budgetunion member now types the two payload shapes actually emitted;journal:compatstays declared but unemitted (the scan runs before a run's event stream exists) and its TSDoc says so.toOtelimplements real parent-child span nesting whencontextApiandsetSpanare passed; without them spans stay flat but attributed.'readonly'isolation now compiles a deny rule for tools declaring riskwriteordestructiveinto the spawn's permission chain, exactly as the tools guide documents; read tools and other isolation modes are unaffected.VCR
replay()refuses a cassette recorded outside the engine's hashVersion support window ([CURRENT-1, CURRENT]) with a typedConfigErrorinstead of silently drifting; in-window cassettes replay as before.InMemoryStoreaccepts{ quiet: true }to opt out of the durability warning, and the warning text now states the precise truth: nothing survives a process exit and cross-process resume is impossible (same-process resume of a kept instance works).createTestEngineconstructs its store quietly, so the blessed offline tier no longer prints a misleading warning.The bare
Date.now()/Math.random()development warnings no longer blame workflow code for calls that originate in library internals (the engine's own retry jitter, provider SDKs): the retry jitter uses a natively capturedMath.random, and the in-process guard skips callers that live undernode_modules.rulvar run --profilenow applies the profile's per-role effort hints: entries indefaults.routingthat carry no effort are seeded fromRunProfile.effortByRole(an explicit host effort always wins; ladder entries and unrouted roles stay untouched).rulvar --helpdocuments the shippedkb inboxandkb gatesubcommands.The unscoped
rulvarpointer package ships TypeScript declarations (index.d.tswith atypesexport condition), so strict TypeScript projects can import the bare name; the install smoke gate now packs and checks the pointer alongside the umbrella.
Patch Changes
- Updated dependencies [c4f563d]
- @rulvar/[email protected]
1.3.2
Patch Changes
- ddef383: Every published package now ships a README, so its npm page states what the package is, how it installs, and where the documentation lives (npm includes README.md in the tarball regardless of the files allowlist, so no manifest changes are involved; @rulvar/compat gains its README on its own next release). Alongside, the repository-level pages are refreshed to the current project state: the root README is rewritten around the never-pay-twice pitch with a runnable quickstart condensation and the full package table, CONTRIBUTING.md lists the complete PR gate set, the examples README drops retired-spec citations for live docs.rulvar.com links and documents the dogfood journal replay, and the pointer README gets the same treatment.
- Updated dependencies [ddef383]
- @rulvar/[email protected]
1.3.1
Patch Changes
- 7d1552e: Runtime message strings no longer cite the retired internal specification set: error and warning messages, validation issues, and the CLI help text drop the dangling
docs/NN, section ...references, pointing at https://docs.rulvar.com pages where a pointer earns its place (the CLI help header, tool naming, toolset registries, bare resume). The umbrella package description sheds the naming-contingency note: the unscoped alias is published and owned. Three strings embedded in frozen recordings stay byte-identical on purpose (the no-progress abort reason and two testing-internal recorder strings), as does the byte-locked golden-fold fixture. Test-file comments lose their citations too; test titles are unchanged. - Updated dependencies [7d1552e]
- @rulvar/[email protected]
1.3.0
Minor Changes
- 969974f: rulvar kb inbox (M12-T03): aggregates kb_propose-born proposals from finished runs through the RunLedger fold behind the LedgerExport seam. Matching (subject, taskClass, polarity) triples group for display ONLY (the command writes nothing, authorizes no spend and schedules no sweeps); each proposal renders with full provenance (initiating run identity, proposal entryRef, lineage, tier, trigger, evidence refs) plus the typed template statement a gated claim would carry; proposals of runs finished more than fourteen days ago expire out of the view. This is the human review surface, so the quarantined note and concrete model names render here verbatim, exactly like kb list.
- 64aff88: rulvar kb gate (M12-T04, the closing task of ModelKnowledge phase 3): the human gate flow turning one inbox proposal into a human-editorial claim. The attribution attestation is mandatory by construction (without --ruled-out over the closed checklist the GateRecord does not assemble and nothing is written; contrast evidence rides --contrast-run or --contrast-eval); the born claim carries the typed template statement (never the quarantined note), origin provenance back to the proposing run and entry, evidence resolving into that run's journal, and the editorial TTL. The commit is CAS against the per-project rulvar.models.json, whose git review is the authenticating gate. Non-proposal entries, expired proposals (fourteen days from the run's terminal updatedAt), running runs and already-gated proposals reject with typed errors.
Patch Changes
- Updated dependencies [7d1a287]
- @rulvar/[email protected]
1.2.0
Patch Changes
- 154507b: TSDoc and inline comments no longer cite the retired internal specification set (the pre-docs-site
docs/NN, section ...references). The citations either became links to the public documentation at docs.rulvar.com or were dropped where the comment already carried the rule; traceability markers (DEF-n, XF-nn, FR-nnn, OQ-nn, W-nnn) are untouched. Comment-only change: no runtime behavior, no API shapes, and no runtime message strings were modified; the frozen golden-fold fixture is byte-identical. - Updated dependencies [3bfaec0]
- Updated dependencies [890f42c]
- Updated dependencies [154507b]
- @rulvar/[email protected]
1.1.0
Patch Changes
- Updated dependencies [d16b04a]
- @rulvar/[email protected]
1.0.0
Minor Changes
93eae2c: M10-T04:
rulvar kb list(docs/05, section "Read path"; docs/06, section 10.5). The second consumption path: claims of the per-project store (./rulvar.models.json) render with full provenance for the humans who author ladders, floors, and profiles: author and gate identity, evidence refs (journal seqs and eval reports), metrics when present, supersede chains, proposal origin, and the TTL state (holds or EXPIRED) per the docs/05 decay table. No run and no pin are involved, so the maintenance view names models verbatim; only in-run cards are nameless. The grammar memberskb inbox(phase 3, M12) andkb sweep(phase 2, M11) fail loudly naming their phases until they ship.fef6263: M11-T05:
rulvar kb sweep(docs/05, section "Grounding and decay"). Falsification sweeps run manually, from CI, or from a user cron, never engine-scheduled, configured by thekbSweepsection of rulvar.config.mjs (committerId, the FIXED model pool, taskClass-tagged eval cases, optional thresholds and canary probes; @rulvar/evals loads dynamically like @rulvar/planner does for plan).- The falsification guarantee: the matrix is the configured pool UNIONED with every model carrying an active, unexpired negative claim, plus the re-measurement queue (expired active eval claims); the pool renders with each member's origin.
- With canary probes configured, every pool member fingerprints BEFORE measurement and drift flips its eval claims to stale in place; the sweep then re-measures and commits threshold-crossing claims through the eval-committer identity, reporting cells, emitted claims, and the committed store version.
Patch Changes
- Updated dependencies [0e0b569]
- Updated dependencies [b28b7a3]
- Updated dependencies [b53a89e]
- Updated dependencies [4454175]
- Updated dependencies [6599ca8]
- Updated dependencies [6649e5f]
- Updated dependencies [fd2f83b]
- Updated dependencies [01d6b2d]
- Updated dependencies [9a20dbb]
- Updated dependencies [0fbe7ea]
- Updated dependencies [ebe0abc]
- Updated dependencies [a3079d0]
- Updated dependencies [596a39b]
- Updated dependencies [464ab6e]
- @rulvar/[email protected]
0.9.0
Minor Changes
65c7b2c: M8-T01: createServer, the HTTP shell (docs/02 section 8.2; FR-702), plus the Engine.stores seam it stands on (docs/06 10.2, M8 entry amendment).
@rulvar/cli:createServer({ engine, workflows })returns{ fetch(req: Request): Promise<Response> }with the five canonical routes: POST /runs (start a registered workflow), GET /runs/:id (status and outcome), GET /runs/:id/events (SSE; Last-Event-ID maps to the event seq, replay is at-least-once and consumers deduplicate onreplayed), POST /runs/:id/external/:key (programmatic resolution,by: 'external'; a run that settled suspended in-process auto-resumes; a run not live in this process gets the documented offline append under a lease where the store is leasable, and resumes on a worker), GET /runs/:id/cost (the settled in-process CostReport, or the pure journal fold priced by the optionalpriceUsd). Authentication stays host middleware (docs/14, OQ-16).@rulvar/core: the Engine interface gains the readonlystoresaccessor exposing the configured journal and transcript stores; exactly the instances createEngine received (or defaulted), no store contract widens.@rulvar/testing:createTestEngineforwards the newstoresaccessor.
a2a3243: M8-T02: createWorker, the queue shell (docs/02 section 8.3; FR-703), plus the two queue seams it stands on (docs/06 10.2 and docs/03 12.3, M8 entry amendment).
@rulvar/cli:createWorker(engine, { store: LeasableStore, concurrency? })leases resumable and suspended runs via acquire/renew/release with fencing epochs (renew cadence ttl/3; Appendix A reference ttl 60000 ms; concurrency default 1). A store without lease capability is a typed ConfigError at start, never a silent split-brain; leasing a store other thanengine.stores.journalis equally a ConfigError. DEF-6 repeats at acquire: a journal outside the hashVersion window releases the lease and poisons the run for this worker. Stateless workers call bareengine.resumewith the lease; unchanged suspended runs are skipped until their journal grows; queue semantics stay honestly at-least-once with deduplication by the journal. The OQ-21 residual (original in-process args are not journaled) is bridged by the optionalargsForhook.@rulvar/core:ResumeOptions.leasecarries the worker's lease through the kernel's single append site, so a stale writer's appends are rejected by the fencing epoch and never become visible (lease theft impossible by construction); bareengine.resume(runId)now falls back from the persisted CompiledWorkflow source todefaults.workflows[workflowName](the registry the queue worker resolves through, docs/06 10.4); the Replayer accepts the lease option.
f920013: M8-T03: the multi-process seam soak and the queue-failover-during-forced-finish cassette (the DEF-7 final cassette; docs/09 sections 6.9 and 6.10; docs/10 section 3.9 exit criteria).
@rulvar/plan: the publicrunQueueFailoverDuringForcedFinishcassette runner: worker A loses its lease strictly between the cap decision and the final wake; worker B reclaims with a bumped fencing epoch and rolls the forced finish forward. The stale writer's appends are rejected and invisible, exactly one cap decision exists, finalization is paid once. The LeasableStore is injected (QueueFailoverDeps.makeStore) so the package stays core-only; the replay test and the record script supply the reference SqliteStore.@rulvar/cli: the multi-process-fencing-soak harness: two workers over one SqliteStore file with kill/failover across the suspension, plan-revision, and forced-finish boundaries; every round asserts zero split-brain and zero double pay. Worker hardening: a failed renew now frees the concurrency slot immediately (a stale run whose landings all reject may never settle; fencing, not the stale process's cooperation, protects the journal).- Repo:
cassettes/queue-failover-during-forced-finish.jsonrecorded and frozen (double-run agreement;scripts/record-m8-cassettes.mjs); the queue-mode limitation stays documented (no distributed cross-process rate limiter, EXC-14/OQ-17).
ebc8101: M8-T04: the redaction and retention interim rules executed (docs/14 OQ-20 and OQ-22; docs/09 section 8 rewritten to the executed state; docs/03 12.4 and 12.8; docs/06 10.1 and 10.2 amendments).
@rulvar/core: the L0 SerializationHook (createEngine({ serialization })): redact/encrypt at the append/put boundaries, symmetric on load/get, applied by wrapping the stores soEngine.storesexposes the one policy point; kernel ordering fields are drift-checked with a loud ConfigError. Default key masking at the telemetry boundary: every emitted WorkflowEvent passesmaskSecrets(provider keys, PATs, bearer tokens, JWTs, private-key blocks become[masked-secret]); opt out viaredaction: { maskEvents: false }; never touches the journal. Retention:TranscriptStore.delete(ref)joins the SPI (missing ref is a no-op; InMemory and File stores implement it),Engine.deleteRun(runId)cascades blob deletion before the journal (no orphan transcripts), andEngine.pruneRun(runId)deletes checkpoint blobs of ok-terminal attempts that nothing else references (parked, cancelled, escalated, and hanging attempts keep theirs).@rulvar/cli:createServerandcreateWorkertake the opt-inretentionpredicate over RunMeta (the server applies it at terminal settles, the worker during sweeps under a brief lease); the OTel exporter masks string span attributes with the same policy, defense in depth over the already conservative attribute content policy.@rulvar/testing:createTestEngineforwardsdeleteRun/pruneRun.
Patch Changes
- Updated dependencies [84f94d4]
- Updated dependencies [65c7b2c]
- Updated dependencies [a2a3243]
- Updated dependencies [ebc8101]
- @rulvar/[email protected]
0.8.0
Patch Changes
- Updated dependencies [85d55cf]
- Updated dependencies [b88c9e3]
- Updated dependencies [f3c4613]
- Updated dependencies [a41c20f]
- Updated dependencies [f4e70be]
- Updated dependencies [75d1646]
- Updated dependencies [0627413]
- Updated dependencies [55c0f87]
- Updated dependencies [fd33871]
- Updated dependencies [e70e7f4]
- Updated dependencies [bc9c903]
- @rulvar/[email protected]
0.7.0
Minor Changes
- 10b45f1: M6-T11: the rulvar plan command and the M6 gating cassettes.
rulvar plan "<goal>" [--dry-run](the canonical grammar) loads @rulvar/planner DYNAMICALLY (the CLI's static dependency stays @rulvar/core; a missing install is a clear error), plans against the host-config engine, prints the accepted script plus its advisory diagnostics, and runs it in the worker sandbox unless --dry-run. The three docs/09 6.10 gating cassettes are recorded on the FakeAdapter and committed under the frozen-fixture lock with exported scenario builders shared by the recorder script and the replay tests: sandbox-determinism (two fresh runs of one CompiledWorkflow produce byte-identical normalized journals matching the cassette), planner-self-repair (the failing draft round-trips through the JSON-diagnostics repair, re-planning from the committed journal is free, and the accepted script executes deterministically in the sandbox), and orchestrator-crash-resume (the committed pre-crash journal plus boundary checkpoints resume with zero re-paid spawns, no duplicate spawn decisions, and byte-stable handles).
Patch Changes
- 9f000a7: Drop the @rulvar/planner peer declaration from the CLI: the plan command loads the planner DYNAMICALLY and reports a clear error when it is not installed, and a workspace peer dependency would major-cascade the whole fixed group on every planner bump under the changesets peer-dependents rule (0.6.0 would have released as 1.0.0 instead of 0.7.0).
- Updated dependencies [fd1d06c]
- Updated dependencies [6fcf296]
- Updated dependencies [dcc97a9]
- Updated dependencies [434dc83]
- Updated dependencies [03173c1]
- Updated dependencies [11c0afc]
- @rulvar/[email protected]
0.6.0
Minor Changes
fa05007: M5-T01 workflow registry and the @rulvar/cli base.
@rulvar/coregains the per-engineWorkflowRegistrytype anddefaults.workflowson createEngine (docs/06 section 10.4): an explicit first-class value, no module-level registry; shells resolve by-name runs against it (ctx.workflow's string form arrives M6, the queue worker M8).- Spec-conformance fix: the M4-T09 quality floors option moves from the createEngine top level to its canonical home
defaults.roleFloors(docs/06 section 10.1). UpdatecreateEngine({ floors })call sites tocreateEngine({ defaults: { roleFloors } }). @rulvar/cliships its first real surface: the canonical grammarrulvar run <file|name> [--args JSON] [--store PATH] [--budget-usd N],rulvar resume <runId> [--args JSON] [--store PATH],rulvar runs ls [--store PATH],rulvar inspect <runId> [--store PATH](no aliases), a line-oriented TUI progress renderer over the event stream, and interactive resolution of suspended approvals and externals (EOF leaves the run suspended, never errors). Engine assembly follows the host-config convention:rulvar.config.mjsdefault-exports{ engineOptions?, workflows? }, a workflow module may exportworkflow/engineOptions/workflows, and --store selects the JsonlFileStore directory (default.rulvar), so the CLI itself depends only on @rulvar/core. Therulvarbin is included; the resume/inspect grammar amendment (--args re-supply, --store symmetry) is recorded in docs/06 section 10.5.
9234dc8: M5-T03 cost reports. The CostReport builder moves to its own module (
engine/cost-report.ts) and report totals become the LEDGER FOLD totals at settle: RunOutcome.usage and cost.totalUsd are computed from the journal's terminal entries (the same summation the kernel budget seed uses), so report totals equal ledger fold totals exactly, live and across resume, by construction. The newcostReportFromJournal(entries, priceUsd)is the pure fold for STORED runs: byModel and totals from terminal servedBy with abandoned subtrees contributing zero; phase, agentType, and role attribution are live-run facts that entries do not carry (byRole and the orchestrator block complete in M7 per DEF-7). Unpriced models keep surfacing, never as silent zeros.rulvar inspectgains the cost view (total, byModel, unpriced) over the config-assembled price function (table wins over caps.pricing), and live run output prints the byModel/byPhase buckets.8a41656: M5-T07 RunProfile presets and M5-T08 OTel exporter.
engine/run-profiles.ts:RUN_PROFILES(fast/standard/deep/ultra) andrunProfile(name)ship the presets as pure DATA, bundles of per-role effort hints, per-run concurrency, budget, permission preset, and spawn limits, with no functions and no named model strings (named strong defaults stay in the umbrella). They are never engine semantics: a source-scan test asserts the engine has zero branches keyed on profile names.rulvar run --profile <name>applies the chosen profile UNDER the host's own engine options (host always wins; the engine then sees only ordinary options), compiling the profile's permission preset into the engine deny/ask layers as data.@rulvar/cligainstoOtel(run, tracer): it maps a settled run's spanId tree 1:1 onto OpenTelemetry spans (run > phase > agent > tool > child), with rulvar.* and gen_ai.* attributes, start/end timestamps from the lifecycle events, and payload-only events attached as span events. Prompts, completions, and tool payloads are NEVER exported; replayed events never create duplicate spans.@opentelemetry/api^1.9 is an optional peer dependency and the exporter is typed against a minimal structural TracerLike, so an absent OTel package never breaks the CLI.
Patch Changes
- 5c8865d: M5 exit criterion coverage: prove the CLI works end to end against SqliteStore, not only JsonlFileStore (docs/10, section 3.6). A host config that supplies a SqliteStore as
engineOptions.stores.journalis honored by the CLI's engine assembly (JsonlFileStore is only the default fallback), so run/suspend, runs ls, resume, and inspect all round-trip against sqlite through the same command paths. Added as a CLI e2e test. - Updated dependencies [fa05007]
- Updated dependencies [9234dc8]
- Updated dependencies [644512c]
- Updated dependencies [8a41656]
- Updated dependencies [02f7f7a]
- @rulvar/[email protected]
0.5.0
Patch Changes
- Updated dependencies [ac274f4]
- Updated dependencies [5735d92]
- Updated dependencies [46ca98e]
- Updated dependencies [8ae129e]
- Updated dependencies [d1c4525]
- Updated dependencies [b840aba]
- @rulvar/[email protected]
0.4.0
Patch Changes
- Updated dependencies [dfe03b5]
- Updated dependencies [d2089a7]
- Updated dependencies [3f60234]
- Updated dependencies [f668890]
- Updated dependencies [16d7aa6]
- Updated dependencies [6513ce8]
- Updated dependencies [7dad493]
- Updated dependencies [2bbf180]
- @rulvar/[email protected]
0.3.0
Patch Changes
- Updated dependencies [43444f6]
- Updated dependencies [279881b]
- Updated dependencies [9fd0966]
- Updated dependencies [24ebadf]
- Updated dependencies [a1b35d3]
- Updated dependencies [18a5821]
- @rulvar/[email protected]
0.2.0
Patch Changes
- Updated dependencies [c24228d]
- Updated dependencies [c50871e]
- Updated dependencies [1af8fb9]
- Updated dependencies [1fe0249]
- Updated dependencies [5c4fc32]
- @rulvar/[email protected]
0.1.0
Minor Changes
- f4e2be9: M0 repo bootstrap (v0.1.0, docs/10-implementation-plan.md section "M0"): monorepo scaffold on the committed toolchain (pnpm 11 workspaces with catalogs, TypeScript 6.0, tsdown, Vitest 4, ESLint 9 flat config, Turborepo 2, changesets fixed mode, npm trusted publishing), the docs/ canon as single source of truth, the L0 contracts skeleton in @rulvar/core, and the vendored dependencies (StandardSchemaV1/StandardJSONSchemaV1 types, the @cfworker/json-schema lineage validator subset, a first-party monotonic ULID). Placeholder scaffolds only: no public API ships in this release.
Patch Changes
- Updated dependencies [f4e2be9]
- @rulvar/[email protected]
@rulvar/compat
Independently versioned (docs/12, section "Exemptions"): releases are deliberate manual events, never lockstep bumps; this changelog is maintained by hand.
0.1.1
- Packaging only: the published artifact now ships a README (purpose, install,
extraDeriversusage, documentation links).distis byte-identical to 0.1.0; no profile, export, or contract changed. The immutability manifest re-freezes on 0.1.1 after publish (node scripts/compat-immutability.mjs --update).
0.1.0
- M2-T05: extraDerivers plumbing plus the synthetic hashVersion 0 deriver for the reject-version-too-old cassette. No real profile has aged out of the support window yet.
@rulvar/core
1.252.0
Minor Changes
- 52d807f: The direct dispatch records what it committed, and announces it (RV4802, RV4806). The dispatch entry's value part now carries
reserveUsd, the committed clamp of its admission, and a journaled rerun re-admits that RECORDED number instead of re-pricing history: the budgets doctrine (reserves are recovered, never re-estimated) extended to the directctx.agentpath, with the recompute kept as the fallback for journals from before the field. Plain direct dispatches now emitspawn:admitted(entryRef is the dispatch entry, additivereserveUsd, the recovered re-admission markedreplayed) and a budget refusal emitsspawn:rejected, closing the observability asymmetry the ninth experiment surfaced; dispatches tracked by an orchestrating layer (spawn tools, the extension seam, the coordinator) or by a lineage decision keep their single existing announcement.spawn:admittedevents gain optionalreserveUsd(thectx.workflowpath reports its verdict reserve) andlogicalTaskIdbecomes optional (absent on direct budget admissions). The cassette corpus is re-recorded and the frozen-fixture lock refreshed through its ceremony (hashVersion-bump): the dispatch VALUE grew one recorded field while the identity profile and every hash rule stay untouched, so replay identity is unchanged and the re-recorded fixtures are the same scenarios with the committed reserve visible on their dispatch rows. - a7e589d: The durable admission bracket hardens on every seam the ninth experiment named (RV4804). The queued wait honors a verdict's
retryAfterMsverbatim for its next sleep (pollMsstays the fallback cadence) and ends with the RUN: the run's cancel signal rides into the wait, so host abort and the deadline stop the polling, cancel the ticket best effort, and hand the run to its own cancellation machinery, where before a cancelled run camped in the queue forever. Renew failures are announced, never fatal: the first failure warns, a verify recover that no longer answersgrantedemits the newadmission:lease-lostevent once (the scheduler expired the grant and may re-admit the capacity while the holder is alive), and the run continues, because the wire quota still gates every dispatch and the settle release is idempotent. The postgres scheduler takes its schema-scoped advisory lock under alock_timeoutbound (lockTimeoutMs, default 10 seconds, validated typed): a holder that hangs mid-transaction used to block every lifecycle call of the whole fleet forever; past the bound the call refuses with the typed retryableLeaseHeldErrorinstead of camping. - 76e95eb: The await digest carries the child's tool budget pressure (RV4807). The ninth experiment's durability specialist starved at 30 of 30 tool calls and the coordinator could not see it: the aggregate reached only the synthesis policy facts, so nothing respawned the specialist or accepted the degradation knowingly.
TaskDigestnow folds the REPLAY-STABLE subset of the child'stoolBudget(usedandcap, the pair the terminal journals; the derivedcapHit, present and true when the executed-call cap was reached, whatever the status says;extensionsGrantedandfinalizationWindowEnteredfrom their decision entries); the live-only fidelity fields stay out so a digest folds byte-identically live and resumed, and a child without a tool budget folds byte for byte as before.
Patch Changes
- 3ccb6cf: The direct dispatch reserve bracket (RV4801, the ninth experiment P0). Admission of a direct
ctx.agentcommits the allowance clamped reserve, but the settle released the RAW estimate; the chain release floors at zero per account, so one clamped child's settle erased SIBLING reservations on shared ancestor accounts, and projected admission then admitted new spawns against money already promised to live children. The settle now releases exactly the committed clamp, and the release rides a finally spanning admission to settle, so a throw between them (the worktree acquire, the dispatch append, the loop itself) returns the reserve instead of parking it for the rest of the run. Regression tests pin the sibling survival, the throw path, the journaled rerun, and the ledger arithmetic; two mutation probes hold the released amount and the finally placement. - 517ed00: The host surface hardens on two seams (RV4803, RV4805). The price table is now SNAPSHOTTED at
createEngine: pricing resolution used to read the caller's live object on every debit, so a host mutating its table mid-run silently changed what wires cost after the strict gates had judged the original; the clone severs the alias (a rates update is a new engine with a bumpedpricingVersion), and a table the structured clone cannot take refuses typed at construction. The HTTP shell'sPOST /runsbody gains the regulated posture subset ofRunOptions(budgetPolicy,maxInFlightExposureUsd,configFingerprint,scope,scopePolicy), so a remote caller can start a run under the immutable lifetime ceiling and the bounded execution scope; authentication, price tables, adapters, stores, and secrets stay with the host process by doctrine and never enter the body.
1.251.0
Minor Changes
- 5982be8: The anchor grounding lint and the grounding windows (RV4601, the seventh comparison experiment's P1.3 remainder).
anchorGroundingValidatoris a zero cost finish validator that catches physically valid citations pointing at the WRONG LINE, the class both of the seventh candidate's audited defects lived in:pointer/package.json:10(the exports block) cited for a caret dependency at line 23, andpackages/rulvar/package.json:2(the name line) cited for dependencies at lines 32..34; both resolved, neither sentence asserted an inline code value, socitationTargetsValidatorandcitedValueValidatorwere structurally blind. The lint extracts the claim's identifier vocabulary (inline code spans, scoped packages, dotted, snake and camel identifiers, the caret and tilde written as words), resolves each anchor to its logical unit (citationUnitExcerptOfwith a grace tail below; a.jsonanchor takes its structural brace block instead, because the generous paragraph unit would swallow the very lines the citation should have named), lints compound sentences per anchor against the nearest claim clause and then once as a whole, and refuses only when a deciding token is absent from the resolved window yet present elsewhere in the cited file, naming the exact lines that carry it. Plain words, identity spans, path tokens, and tokens absent from the whole file never flag; on the seventh corpus the shipped heuristic flags exactly the two wrong anchors with their exact line suggestions and nothing else.anchorGroundingFindingsOfexports the engine for harnesses. Beside it, a'repair'round undercitationAudit.resolver: 2now carries theCITATION GROUNDING:block (citationGroundingLines, capped at 6 anchors and 4800 characters): the resolved unit of each judged anchor, recomputed from the pure snapshot resolver at prompt build, so the composer repairs a citation against the bytes the judge actually read instead of moving anchors blind, and a resumed round rebuilds byte identical windows with nothing new persisted. Probes pin that words never decide, that a flag needs somewhere to point, the structural json block, the grounding budget, and the resolver 2 gate. - b3e465a: Precise hash and counter namespaces (RV4604, the seventh comparison experiment's P2.2 remainder). Every hash on the lineage and provenance surfaces is one recipe, sha256 over the JCS canonical value, and the seventh experiment's provenance script had to rediscover that by trial because the bare names said nothing; the invoice's 16 logical calls beside 109 wire fetches were reconciled by hand for the same reason. The precise names now ride beside the bare ones, same hex, additive everywhere:
judgedJcsSha256on the claim meta,auditedJcsSha256on the audit meta, andjudgedDocumentJcsSha256on the semantic terminal verdict, whose barefinalHashcollides withdraftToFinal.finalHashwhile meaning the judged document. On the counter sidelogicalRunTelemetrynow carriesadapterFetches, the sum of every provider call decision's absorbedwireRequests(absent reads one) beside the decision countlogicalWireRequests, plusperSegment[].adapterFetchesnaming which segment actually paid for them (a pure replay segment reads 0);rulvar inspectprints both counters by name on the logical wires line. Probes pin the absorption sum, both meta twins, and the verdict's referent naming. - c4e5d6a: The preflight honesty pair (RV4702, RV4701; the eighth comparison experiment's first run). RV4702, the child-ceiling feasibility line: under
budget.estIsCeilingthe spawn's declared estimate is the child's hard ceiling (the explicit spawn budget wins), and that run's 1.35 ceiling deterministically starved its child's finalize dispatch after an honest loop; preflight admitted the plan without a word and the death cost 6.74 USD. Each spawn's report now carriesestCeiling({ ceilingUsd, requiredFloorUsd, fits }), the floor being the cheapest honest reading of the declared posture: the loop's input floor across its projected turns (cache-aware unless the policy is off) plus ONE tail turn at the declared floor, the finalize-shaped dispatch that run died on. A ceiling below the floor is the ERROR findingchild-ceiling-below-loop-floorwith every number named, because the starvation is deterministic at the declared prices, not a headroom taste; the run-1 config fails the line and the rerun's 2.40 passes it, exactly the two points the experiment paid to learn. RV4701:preflightEstimateacceptsbudget.acceptanceReserve: 'checkpoint', the posture the runtime has accepted since RV4404, instead of refusing it typed while the engine runs it (the eighth driver had to estimate its genesis arithmetic under a substituted 'require'). Checkpoint estimates with require's genesis arithmetic, the echo carries the declared literal, and an unfit tail is the same error with its own remedy line: the first paid acceptance-tail dispatch re-checks this exact sum at the money actually spent and would refuse it already at the genesis numbers. Probes pin the feasibility refusal and the widened vocabulary. - c6fc3da: The child's death reason survives every surface it used to die on (RV4703, the eighth comparison experiment's first run). That run's child spent under its ceiling through the whole loop and died on a synchronous budget refusal of the FINALIZE dispatch (one millisecond, zero tokens): the journaled terminal named the crossed account, but
agent:endsaid status 'error' and nothing else, the acceptance decision said "child X settled 'error'" and nothing else, and the stage was recovered from phase forensics. Three carries close the gap.AgentError.stagenames WHICH dispatch a budget refusal killed ('loop', 'summarize', 'reserve-summary', 'finalize', 'extract'): every budget gate of the agent loop stamps it, the wire projection carries it in data, and the reader restores it typed. Theagent:endevent carries the terminal's typederrorverbatim from the journaled entry, so the live stream and the replayed stream say WHY without a journal dig, byte for byte the same value. The acceptance fold carries the reason forward: the degraded note reads "settled 'error' (budget at the finalize dispatch: ...)" with the message bounded at 200 characters, and the machine roster row (AcceptanceChildSummary) gains a typederrorfield with the kind, the stage when stamped, and the bounded message. Children without an error keep every byte. Probes pin the event carry, the acceptance carry, and the finalize stamp. - c6fc3da: An empty terminal is not validated output on limit (RV4704, the eighth comparison experiment's first run). That run's acceptance promoted a limit child as degraded-with-output on a 16-token finalize summary that carried no answer, and the decision read "validated terminal output" over bytes nobody could use. The salvage arm now holds a character floor: a limit child's STRING terminal output must clear
acceptance.minTerminalOutputChars(defaultDEFAULT_TERMINAL_OUTPUT_FLOOR_CHARS, 80) after trim beforeacceptValidatedTerminalOutputOnLimitmay accept it. A below-floor string is a limit WITHOUT acceptance: it counts against the policy like any unsalvageable limit child, and its degraded note names the character counts ("N of M characters after trim: not accepted as validated output"). ONE shared function judges the floor for the acceptance fold and the finish-validation salvage marker, so the validator's cited pool and the verdict can never disagree about the same child; structured (schema-validated) outputs pass by their validation exactly as before, and the coordination prompt line states the floor the fold holds. 0 restores the previous acceptance byte for byte. A probe pins the guard. - 0ae8b85: The scoped semantic repair reserve (RV4705, the eighth comparison experiment's rerun). That run declared
maxTotalRepairRounds: 1for the question contract's "exactly one bounded repair" and the pool spent it on a MECHANICAL composition repair before the judges ruled: the anchor grounding lint fired at the draft, the finish-validation grant consumed the pool's only token to clean it, and the post-judge semantic round was refused over 38 standing census findings, one contradiction, and 24 uncovered sentences; the contract meant the post-judge round, the config could not say so.maxSemanticRepairRoundsnow reserves rounds inside the pool for the semantic stage: it is BOTH a reserve and a cap. Mechanical finish-validation grants admit only while the pool holds them plus the UNSPENT reserve on top (a refusal namesmaxSemanticRepairRoundsandsemanticReserveHeldbesiderunRepairPoolExhaustedon the verdict decision, so a reader sees "the pool has room, but not for mechanics"), and the semantic round is bounded by the reserve beside the total pool it still shares, refusing with its own name (the semantic repair bound is spent) instead of masquerading as a spent pool. A reserve greater than the pool refuses typed at construction; declared without a total pool it is the round's own cap alone; absent keeps every decision and refusal byte identical, the RV4406 covenant. Therepair_pool_consumedecision carries the semantic counters exactly when the reserve is declared. The static surfaces reflect the split:preflightEstimateaccepts both bounds, echoes them with the mechanical allowance underbudget.orchestrator.repairPool, warnsrepair-pool-starves-semantic-roundon the rerun's exact shape (an armed round over an undivided pool the mechanical grants can drain), warnsfinish-repairs-exceed-repair-poolwhen the stage bound promises more grants than the mechanics' share, and mirrors the contradiction as therepair-pool-refused-at-intakeerror;wireCapacityEstimateaccepts both keys and reportsrepairWiresCeiling, the pool-bounded worst case of every repair wire, with the capacity sheet carrying it as a derived row. Probes pin that the reserve shields the round from the mechanics and that the scoped cap binds its own round. - 7932936: The census fits its own verdicts, or the judge never dispatches (RV4706). A census (
auditScope: 'all') carries the whole document's rows in ONE citation-judge dispatch, and the { row, verdict, reason } bijection over them must fit the judge's declared output allowance or the reply truncates mid-array: the census rejudges of the seventh and eighth comparison experiments (145 and 215 rows) both overflowed the seventh's 9000-token cap and raised it to 32000 by hand, an arithmetic nobody enforced. Before the citation judge dispatches, a DECLAREDjudge.limits.maxOutputTokensPerTurnis now checked against the bijection floor (CITATION_VERDICT_EST_TOKENS_PER_ROW, 70, per judged row plusCITATION_VERDICT_EST_BASE_TOKENS, 500): a cap below it refuses typed BEFORE the provider call under the defaultjudgeOutputCapGuard: 'fail'(data.source'orchestrator_citation_audit', with the cap, the row count, and the estimate all named), or logs the same numbers and dispatches under a declared'warn'. A 215-row census against 9000 refuses with zero provider calls; against 32000 it dispatches once, exactly the two configurations the experiments paid to learn. An undeclared cap keeps every byte: the guard cannot judge a resolution it does not see. A probe pins the pre-wire refusal. - 7932936: Truncated units reach the judge whole (RV4707, the seventh candidate's census rejudge). Rows 81 and 105 of that census carried honest support 3..7 lines past the 20-line unit clip (a paragraph ending at L839 with the support at 842; a comment-declaration ending at L25 with the support at 32), and the judge honestly ruled unsupported over the incomplete windows: the verdict blamed the composer for the resolver's clipping.
citationUnitExcerptOfnow takes optional bounds (caps: { maxLines?, maxChars? }, positive integers, refused typed otherwise; absent keeps the default caps byte for byte), and the orchestrator's judge-side row mapping re-resolves a unit the DEFAULT cap clipped atCITATION_UNIT_JUDGE_EXTENSION_FACTOR(2) times the line and char bounds, still bounded, stampingextended: trueon the unit so the prompt says which cap produced the excerpt; a unit still clipping at the extended cap keeps itstruncatedflag beside it. Judge side only: the anchor grounding lint keeps the default unit with its own grace tail, and untruncated units keep every byte. A probe pins the extension. - 88da0ed: Distinctive window coverage and composite-name conviction in the anchor grounding lint (RV4708, the seventh candidate's census row 27). Coverage counted any camel part of five or more characters, so
requireBoundscited at a docstring about page caps was silenced by the word "bounds" while the real declaration lived at lines 87 and 95 of the same file, and the true wrong line stayed silent. Coverage now silences by the LONGEST camel part (the benefit of the doubt stays with the anchor: a window discussing 'execution' plausibly grounds ExecutionScope), never by a generic short half. The suggestion channel tightened symmetrically into a CONVICTION channel, because a flag needs somewhere to point and that somewhere must carry the identifier itself: the whole token; the 6+ prefix rule for single-segment tokens only (for a camel compound, a word crossing the segment boundary by one letter is indistinguishable from a plural coincidence: 'executions' is byte-for-byte a prefix of ExecutionScope the way 'postgres' is of PostgreSQL); or a camel part spelled inside a COMPOSITE identifier, marked by glue or a case seam ('telemetry' inside '@acme/telemetry' places OpenTelemetry, the pinned RV4601 case; anexecution_scopedecision places ExecutionScope), never a freestanding prose word or its bare plural. Validated over the eighth experiment's corpora: the rerun candidate's 215 anchors stay at zero findings, and the codex hand's document keeps its true findings while the prose-part convictions of honestly cited negative claims die. Probes pin the distinctive coverage and the composite conviction. - 06c0e85:
handle.previewsettles on a refused resume (RV4710, the RV4602 wave's observed tail). A pre-run refusal (a configFingerprint mismatch, a binding mismatch, an unknown workflow) rejected the resume's handlePromise before any inner handle existed, andhandle.previewpended FOREVER: a caller awaiting the preview on a refused resume hung instead of reading the refusal. The preview now settles with the SAME terminalresultreports: a pre-run refusal rejects it typed, a run that dies before its settle path rejects it with that death, and the ordinary settle keeps resolving it first (a reject on a settled promise is a no-op). The RV4602 posture holds byte for byte: a pre-attached catch keeps the refusal result's alone to REPORT, so an unobserved preview never sprays an unhandled rejection of its own. Beside it,rfcs/sibling-anchor-fold.md(RV4709) records the design question the seventh census's row 24 raised, an unsupported anchor whose clause carries a supported sibling, with the lean toward the byte-additive meta marker; code follows review, not this changeset.
Patch Changes
- e7e829c: The negative scenario citation convention (plan 47 B1..B3): a hypothetical is never a line fact. The orchestration guide gains a section with the paste-ready composer block (cite the DEFENSE the scenario attacks, mark the scenario as inference), the profiles guide carries the census evidence the mandate question waited for (sample buys honesty, census buys completeness; the floor still does not require the census), the audit section documents its own surface (
auditScopecensus, the RV4706 output cap guard, the RV4707 truncated unit extension), and regression fixtures pin what the convention buys from the deterministic layers: the genre form is lint silent by design, the convention form lints clean, a moved defense line convicts with line suggestions, and the contract audit lexer keeps every count over the rewrite. No runtime change. - 7c58fb2: The portable replay descriptor (RV4602, the seventh comparison experiment's P1.2 remainder). A programmatic run records its workflow NAME in the journal, but the workflow VALUE lives in no
rulvar.config.mjs, so the seventh experiment'sreplay --assert-no-liverefused from a clean checkout.rulvar resumeandrulvar replaynow accept--registry FILE, an ordinary module whose named exports (workflows,engineOptions, and the newconfigFingerprint) merge over the config for that one command, so a run travels as a three part descriptor: the journal, the args, and the registry module naming the workflow under its recorded name; a module exporting a singleworkflowvalue serves the recorded name too. TheconfigFingerprintexport closes the drift loop the engine already enforces:rulvar runrecords it at genesis (from the workflow module or the config), and a resume or replay that supplies one is verified against the genesis record strictly before ownership, meta writes, or any provider call, refusing typed on drift instead of replaying under changed policy; the CLI never supplied it before, so every fingerprinted run degraded to the one sided warning. In core, a refused resume now rejects itsresultalone: eachon()subscription of the deferred resume facade used to derive its own unhandled rejection from the refusal, and the CLI progress renderer subscribes fourteen event types. Probes pin the genesis recording, the resume verification, the replay registry load, and the quiet refusal.
1.250.0
Minor Changes
- 0e240b9: The effect lane fold (RV4501, plan 45, rfcs/effects.md):
EffectLaneFoldis the pure journal semantics of the effect intent protocol. Effect lane facts ride kind-'decision' entries with typed payloads (effect_epoch,effect_declared,effect_intent,effect_attempt,effect_outcome,effect_receipt,effect_terminal,effect_incident,effect_disposition, plus theapproval_expiredclock fact), a recorded deviation from the RFC's entry-kind wording: the kinds registry is versioned as part of the hashVersion 2 identity profile, so the lane mints no new kind and stores stay dumb byte stores. The fold decides consumption over the strict prefix (allow before the intent position, no prior revocation or expiry decision, latest epoch, the approval's own licensed key, one canonical intent per logical key per epoch), treats same-opId replays as the same transition, closes machines first-terminal-wins with post-terminal facts as linked incidents, disables re-dispatch on every capability row from a revocation or expiry position on, validates terminal legality (confirmed demands a verified receipt; cancelled-before-dispatch demands zero attempts), classifies duplicate receipts benign against conflicting, and derives the compensated disposition as an overlay (effectiveEffectState) because terminals are immutable. - 6fe585e: The effect lane writer and the admission predicate (RV4502, plan 45, rfcs/effects.md):
consumeApprovalAndRecordIntentis ONE append contended through the store's (runId, seq) uniqueness, with the universal recovery rule on every lane append: an uncertain result reloads and searches for its own operation id before any retry, a loser re-verdicts at the new tail (the fold itself is the verdict authority, evaluated over the prefix plus the hypothetical candidate), and a give-up appends a durable standalone refused record. The writer re-folds before opening each attempt (a revocation with zero attempts cancels cleanly; with history it refuses reconcile-only on every capability row), refuses attempts past the recorded budget, requires a deadline on every effect approval at intake, materializes a crossed grant expiry as an appendedapproval_expireddecision before refusing, and honors the newEffectLaneStorerestoration generation (a restored store comes up with dispatch disabled until a fresh epoch cites the bumped generation). Production mode requires a leasable store withfencedWrites;singleProcess: trueis the explicit conformance posture for the in-memory store.effectLaneAdmissibleevaluates the five conjuncts of RFC section 5 over a terminal envelope, fail closed, naming the first conjunct that refused. New typed errorEffectLaneRefusedError(codeeffect_refused) carries the stable protocol rule that refused. - c5eb19c: The restoration generation (RV4503, plan 45, rfcs/effects.md section 4.5, item 3): SqliteStore and PostgresStore implement the
EffectLaneStorecapability, carrying a restoration generation OUTSIDE the journal bytes (a one-row table beside the leases). The restore runbook is one rule: after a point-in-time restore, callbumpRestorationGeneration()BEFORE the restored database becomes reachable to any worker, so the effect lane comes up with dispatch disabled by construction until an operator appends a fresheffect_epochciting the bumped generation. The neweffectLaneStoreConformancesuite in @rulvar/store-conformance is the executable definition: generation starts at 0 and bumps monotonically (ELS1, ELS2), a bumped generation refuses every lane append until the fresh epoch (ELS3, the kill point 25 window, driven through the real writer over the real store), and a lane append under a non-current lease dies on the store's fence with nothing consumed (ELS4, the kill point 16 shape). - 565c13b: The @rulvar/effects package is born (RV4504, plan 45, rfcs/effects.md sections 4.4, 6, 8, 11): the effect adapter seam that cannot send without an attempt record (dispatch receives the seq of the attempt appended BEFORE the call), the provider capability matrix types, and the crash-window dispatcher whose recovery is licensed exclusively by provider-side fencing: the idempotency-key row re-dispatches under the same key and lets the provider dedupe, the conditional-create row leans on the unique natural key, the acceptance-closing row closes the ambiguous ATTEMPT identity (so the fresh attempt stays legal while the stale one is refused at the provider), and the 'neither' row quarantines every ambiguous window with the possible late stale send named in the record. From a revocation or expiry position recovery is reconcile-only on every row: a found receipt confirms (a revocation then opens the compensation decision path as a linked incident; an expiry opens none, because it bounds the grant, not the past), a closed negative cancels with the proof on the record, and anything unresolvable quarantines. Provider fakes enforce exactly the fencing their row claims, including the deliberately stalled predecessor of kill point 17, where elapsed time licenses nothing. In core, the
cancelled-before-dispatchlegality widens per RFC section 4.7 row 2 (every attempt provably failed also proves no effect) and the writer gainsrefresh(). Kill points 4, 5, 6, 7, 8, 14, 15, 17, 27, 28, 29 are pinned by tests. - c6d197b: The reconciler, the trust envelope, and the whole kill point kit (RV4505, plan 45, rfcs/effects.md sections 3.1, 7, 8, 9). The sweep makes "every intent deterministically reaches confirmed, compensated, or quarantined" true: crossing
reconcileByquarantines whatever state with the state recorded, receipt waits and attempt budgets quarantine on exhaustion, lookups are bounded SEPARATELY through journaledeffect_proberows (countable from the journal alone, crash-proof), pre-terminal conflicting receipts quarantine, and effect authorizations past their deadline refuse durably instead of waiting forever. Receipt verification runs a declared trust envelope: issuer identity, per-class content bindings, key validity windows, revocation from its time forward, and the host's signature check; every failure classifies unverified, which routes to unknown. The post-restore reconciliation (kill 25) quarantines provider effects the journal cannot reconstruct by name (or the whole range without authoritative enumeration), and a restoration epoch stays undispatchable until the neweffect_reconciliation_completedecision cites it. Section 9 telemetry folds effective dispositions (the compensated overlay included), pressure, duplicate classification, and open incidents. The kit exports all thirtyeffects.kill.*rows as named conformance checks parameterized by a store factory (ambiguous acks and restoration generations injected through delegating proxies, so any store qualifies), registered over the in-memory reference store in single-process posture and over the REAL sqlite and postgres stores in their own packages. - c9d9729: The durable admission SPI and the pure scheduler core (RV4507, plan 45, rfcs/admission.md):
AdmissionSchedulerinl0/spi/admission.tsis the seam that answers "when may this work START, and in what order relative to competing tenants", deliberately split from QuotaLimiter (a counter has no queue; the two seams degrade independently, and a granted ticket never exempts a wire from quota). Enqueue is a conditional create under the caller-minted (unitId, generation) identity; every lifecycle call is idempotent by its operation id;deniedis a terminal infeasibility verdict that never camps at the head; of racing release, expiry, and cancel exactly one wins; and the run journal never records scheduler state. The pure algorithms are exact and replica-deterministic: hierarchical start-time fair queuing with cost = reserved wires over weight, V advancing to granted start tags monotonically and capping idle hoarding, arrival seq breaking ties; the sliding window ring that bounds the epoch boundary burst to one sub-window allowance; the token bucket; and the three JCS-canonical level projections (resolved tenant, tenant plus providerAccount, the full scope).MemoryAdmissionScheduleris the single-process reference: all-levels-or-nothing consumption, the emergency reserve, lease-fenced covers with the conservative expiry refund (reservation minus the covered high water), release refunds with bucket debt that never denies retroactively, the level-2 concurrency semaphore, and typed refusal of a conflicting tenant pair outsidetenantFrom: 'scope'. - fed9db6: Durable admission over sqlite and postgres (RV4508, plan 45, rfcs/admission.md section 9):
SqliteAdmissionSchedulerandPostgresAdmissionSchedulerpersist the scheduler's WHOLE state as one plain-JSON document (AdmissionState, now exported withsnapshot()and hydration on the reference core), committed atomically per lifecycle call inside a BEGIN IMMEDIATE transaction (sqlite) or an advisory-lock-serialized transaction (postgres). This is the RFC's first shipped durable shape, recorded as a deliberate decision: a single scheduler over durable state with deterministic ordering, where "state moved AND buckets moved" holds trivially because the whole document commits or none of it does; per-row schemas are an optimization the SPI does not require. A queued ticket survives its holder with position and arrival identity intact, re-enqueueing the same (unitId, generation) returns the SAME ticket, and settlement operation ids replay as durable no-ops across holders (a late-settlement debt entry lands exactly once). - df9ed76: The admission conformance matrix, all twelve rows (RV4509, plan 45, rfcs/admission.md section 7):
admissionConformanceruns the RFC's named acceptance surface over any scheduler factory, registered over the in-memory reference (snapshot/hydrate plays the crash reopen), the sqlite document, and the postgres document. The fairness rows measure GRANTED RAW SERVICE, the property itself: sixty equal tenants each receive their exact share with every consecutive sixty-grant window containing every tenant, and weights 1/2/4 grant exactly 1:2:4 in the first virtual-time cycle with weight 1 never starving (the tenant plugs that assemble the queue first carry weight equal to their cost, a uniform one-unit tag shift that preserves the burst's relative order bit for bit). The remaining rows: the minute-boundary burst bound, queued-ticket crash survival with arrival identity intact, the conservative fenced-cover expiry settlement with late debt, the denied-versus-queued state distinction, region loss without double grants, hundred-percent repair amplification held inside caps through debt, fail-closed foreign scope, multi-level all-or-nothing, the atomic failover rebind (newrebindon the SPI: the target slot acquires before the source releases, and a failed transfer changes nothing), and tenant resolution parity. The reference pump's scan is now bucket-blocking: a refused ticket blocks ITS bucket for the pass, so no later ticket of the same bucket overtakes it (the no-starvation guarantee), while independent buckets proceed;releaseno longer grants implicitly, making every grant an observablepumpevent. - 3020912: The engine's durable admission bracket (RV4510, plan 45, rfcs/admission.md section 5):
createEngine({ admission: { scheduler, reservation?, pollMs?, tenant?, tenantFrom? } })brackets every non-preview run as one unit of work under the run's own identity (runId, genesis). A resumed segment RECOVERS its ticket by that identity before ever enqueueing; a queued run waits for its grant (polling with the scheduler's pump, honoring retryAfterMs); the terminal denied verdict refuses typed (AdmissionRejectedError) before any store mutation or provider dispatch; the full reservation checkpoints as the maximally conservative cover at grant; the lease renews on a timer; and the release is part of settlement ordering (a caller that observed the outcome can observe the released ticket). The effective tenant resolves exactly like the limiter's (engine-configured, or the scope's under tenantFrom 'scope'; the admission config carries its own tenant fields for limiter-less deployments, with quota's taking precedence so the two seams debit the SAME identity). A settled unit re-admits on resume as a fresh ticket under the same identity;deniedstays terminal. Admission is an environmental fact: nothing is journaled, replay never consults it, and the wire-level QuotaLimiter keeps being consulted per dispatch, unchanged. First-shape actuals equal the reservation and the cover is the whole reservation, both recorded as deliberate first shapes in the bracket's doc.
Patch Changes
- d8d598d: Plan 45 closes in the documentation (RV4511): the model-routing page records the limiter/admission split as load bearing (the limiter answers "may this wire fly right now", the durable admission seam answers "when may this work START and in what order", a granted ticket never exempts a wire from quota), the durability page documents the run bracket's crash model (recover by unit identity, re-admission of settled units, conservative expiry settlement through fenced covers, nothing journaled), and rfcs/admission.md records the implemented status with its deviations and first shapes named one by one, mirroring rfcs/effects.md. Both RFCs now read as shipped protocol references rather than promises.
1.249.0
Minor Changes
8862133: RV4401: the resolver v2 excerpt tells the truth about the block the cited line belongs to. This is a bugfix of resolver 2's DOCUMENTED semantics, not a third resolver: replay of existing journals is untouched (judge prompts read from the journal), only new runs change. The seventh comparison experiment's built-in citation judge returned 10 unsupported of 24 sampled, and seven of the ten were excerpt artifacts: docstring body lines start with
*, which also spells a markdown list marker, so the list rule matched first and every JSDoc anchor excerpted as a ONE-LINE list item with its support hidden 3..9 lines away. Comment context now decides before any markdown rule: a star-led line is a comment only when a bounded upward scan finds the/*opener (bare markdown* itemchains keep their list semantics byte for byte), a//,#or--line is a comment only beside a same-family neighbor (a lone# headingstays a heading), and inside a comment the line classifies by its prefix-stripped text, so a stripped list item excerpts the item with its continuations and anything else carries the comment block plus the declaration it documents. A table HEADER anchor (delimiter row directly below) now carries the delimiter and body rows, because citing the header cites the table. Resolver v2 excerpts get their own bounds sized for real docstrings and guide sections,MAX_CITATION_UNIT_EXCERPT_LINES20 andMAX_CITATION_UNIT_EXCERPT_CHARS1600 with thetruncatedflag preserved; resolver v1 keeps its own smaller bounds byte for byte. The ten findings' file geometries are frozen as a test corpus: the artifact excerpts now contain their supporting lines, and the genuinely wrong citations stay exactly as damning as the judge read them.0d7a717: RV4402: the semantic terminal verdict is fail closed about the metas it trusts, and the citation judge's row set is a bijection. The seventh comparison experiment's re-audit found
semanticTerminalVerdictOf({claimConsistencyMeta: {}})folding to 'clean': every malformed field read as absent, every absent counter read as 0, and an empty or foreign meta laundered itself into the one word production gates on, the exact opposite of the fold's own docstring. Now a meta that carries NO evidence anything judged (nojudgedHash/auditedHash, nojudgeInvoked, no judge failure flag, nojudgedStage) folds 'not-judged' with a stable trust code (claim-meta-unjudged/citation-meta-unjudged), and a counter that is PRESENT but not a count taints its meta the same way (claim-meta-malformed/citation-meta-malformed); an absent field still reads absent, because absence is honest and garbage is not.parseCitationVerdictsnow refuses a row outside the judged set: a judge inventing rows is a failed parse, never surplus information.productionAcceptabledistinguishes the two refusal shapes a reader used to conflate: an absent verdict readsnot-recorded: ...(nothing was configured, or the run predates the fold), while a recorded 'not-judged' verdict lists its judge failure codes.e4428bd: RV4403: the terminal has five axes (terminal status, execution completion, child acceptance, deliverable acceptance, semantic verdict), and none substitutes for another on any surface, live or restarted. The seventh comparison experiment settled
exhaustedwith both judge metas and the ten-unsupported count only insideerror.data: the outcome's top level read nothing, the settle recorded nothing, a restarted production gate answered 'not-judged' about a failure whose own message counted the findings, andrulvar inspectprintedacceptance: accepted (completion complete; gate on the status and completion PAIR)over a rejected deliverable. Now: every typed semantic failure stamps the one-word verdict beside its metas (folded by the same RV4209 function the acceptance path uses, without a waiver or draft-bridge input, because a failing run has no standing acceptance to license); the engine lifts the semantic facts (claimConsistencyMeta, newcitationAuditMeta,semanticTerminalVerdict) on EVERY terminal path including typed failures without a completion literal, mirrors them onto the outcome, therun:endevent and the terminal envelope, and records them in the journaled settle;lastRunSettleand the persisted terminal envelope read them back defensively (a foreign or partial shape reads NOT RECORDED, never a verdict), so live and restart agree field for field. The CLI production gate reads the outcome's typed verdict field first, so it refuses with the recorded 'findings' instead of a false 'not-judged'.rulvar inspectprints the axes side by side (axes: terminal exhausted | execution complete | children accepted | deliverable rejected | semantic findings) with the semantic counts and the citation audit numbers, and the child roster verdict is labeledchildren:, one axis of five; the bareacceptance:label and the "gate on the status and completion PAIR" advice are gone.d6873c1: RV4404: budget honesty, three opt-in answers to the seventh comparison experiment's death. The intake gate had verified the acceptance tail against DECLARED estimates and the run passed
fits: truehonestly; the workers then overshot their declared estimate 2.8x, and the refusal came only where the armed round could not dispatch, after the composition and both judges were already paid.budget.acceptanceReserve: 'checkpoint'is 'require' plus a runtime re-check of the same arithmetic before each paid acceptance-tail dispatch (the first composition, each judge pass): every ceiling on the chain up to the run root judges its spend plus its dedicated tail reserves plus the worst case still ahead, and the run refuses typed BEFORE paying the stage, journaling anacceptance_checkpoint_refuseddecision naming the account, the stage, and every term. In the seventh trajectory the first checkpoint fires right after the workers, saving the composition and both judge passes. Dispatch-projection holds stay out of the arithmetic: they release on settle and the tail terms already price those futures.budget.estIsCeiling: trueturns declared spawn estimates into the fan-out's own hard allowance ceiling: tool-spawned children share the orchestrator's child scope, so the enforced bound is the AGGREGATE of the admitted estimates (RunBudget.raiseChildAllowancewidens it per admitted child), exactly the number the acceptance-tail arithmetic trusted; a fan-out that overshoots its declarations refuses at ITS ceiling instead of silently eating the tail. With both opt-ins, a preflightfits: truebecomes a dispatch guarantee for the declared tail.The pair ceiling stops laundering itself as a document defect: a declared
semanticAcceptance(claimCoverage 'full') derives coverage target 1 when none is set, so the pass runs coverage-first instead of the historical first-maxselection, and a truncation under a DECLARED target grades'coverage-capped'(a newClaimCoverageGradeliteral) instead of a silent 'partial'. The strict-final and waiver-forbid refusals then name the knob: the pair ceilingmax, and how many citing sentences it left uncovered. The seventh run declared full coverage, folded its pairs truncated, and reported 23 uncovered citing sentences as if the text were the problem.--strictrefuses 'coverage-capped' (a capped pass breaks the contract the declaration states; plain 'partial' deliberately stays exit 0), and the semantic terminal verdict folds it into the partial bucket.4092e8d: RV4405: the parallel judge pair extends to the merged arming and the post-round rejudges. RV4210 dispatched the final claim pass and the audit's first pass concurrently only when NO repair round was armed; the seventh comparison experiment ran the exact posture the exclusion kept sequential (both
onFound: 'repair'), and its judge wall was pure wait. With BOTH repair postures armed, no single-class round can rewrite the document between the two first passes (the one merged round fires strictly after both), so both passes read the same immutable bytes and now dispatch together, verdicts still processed in the historical order (the claim pass's typed throws first). The two post-round re-passes judge the SAME repaired bytes, so they dispatch together under the same discipline. A SINGLE armed round keeps the strict sequence byte for byte: its round rewrites the document between the passes, and the audit must read what ships. The honest cost is unchanged and documented: under a refusing posture both judges are already paid when one refuses, the price of the saved wall; the acceptance tail funded both passes either way.e086590: RV4406: one run-wide repair pool.
maxTotalRepairRoundsbounds every provider-dispatching repair grant across the whole run, whatever gate granted it: finish-validation repair turns and the bounded semantic round consume from the same pool, and per-stage bounds (finishValidation.maxRepairs, the one semantic round) NARROW it, never widen it. The tokens are durable by construction: a finish-validation 'repair' verdict IS its consumption (the decision lands before the repair turn dispatches), and the semantic round journals a keyedrepair_pool_consumedecision strictly BEFORE its dispatch, so a crash between the decision and the dispatch resumes without a double consume, and the counter is folded from the journal at every consultation so live, replayed, and resumed segments read the same number. A spent pool turns a finish-validation grant into 'rejected' withrunRepairPoolExhausted: trueon the decision, and refuses the semantic round inside the honest could-not-dispatch envelope, naming the bound and the tokens consumed. The draft-gate pre-pass dispatches no provider work and spends nothing, by design. Absent keeps every decision and refusal byte identical.1411938: RV4407: the citation audit's scope becomes a declared mode.
citationAudit.auditScope: 'sample' | 'all': 'sample' (the default) keeps the deterministic stratified sample byte for byte; 'all' judges EVERY anchor row of the document, a census instead of a sample, with no per-section pick and nomaxSampledceiling. The census requires resolver 2 (it enumerates every anchor of every citing sentence, the v2 row semantics) and refuses typed at intake otherwise. One judge invocation still carries all rows (two under an armed round, exactly the sample's worst case): the cost scales through the prompt, sojudge.estCostshould be sized for the whole document; the declared estimate enters the acceptance tail unchanged, one term per pass. The meta stampsauditScope: 'all'under the census so a consumer knows whethersampledcounts a sample or the document; every sample-mode meta keeps its bytes. The production profiles guide RECOMMENDS the census for critical document classes with the cost arithmetic spelled out; the regulated floor does not require it yet, because after the RV4401 excerpt fix sample sensitivity is expected to drop and the floor moves on evidence.737d1ee: RV4408:
sponsorjoins the composite execution scope. The seventh comparison experiment's benchmark domain (a clinical trial adjudication network) runs work on behalf of a study sponsor who is neither the owning tenant nor the billing account, and the scope vocabulary could not say so.ExecutionScope.sponsoris the seventh named dimension (the RV4205providerAccountprecedent): host-defined vocabulary, carried without loss through RunMeta, the genesisexecution_scopedecision, the canonicalscopeDigest, the invoice header, the export bundle, and the resume assertion, entering the regulated posture hash automatically through the same closed table.scopePolicy: { unknown: 'reject' }accepts it as vocabulary; aQuotaRulecan pinsponsorbeside the other dimensions, matching only reservations whose scope carries the same value, with dimension-less rules keeping their storage bucket keys byte identical. The durability and production-profiles guides name the new dimension.634f966: RV4409: the logical run's telemetry is native. The seventh comparison experiment measured its resumed run's active and calendar walls, the operator gap between segments, and the 109-wire logical count by external script over the raw journal, and reconciled "16 versus 109" by hand because the two counter families shared a vocabulary.
logicalRunTelemetrynow folds, from the stamps and decisions the journal already carries:activeMs(each segment's own append window, summed),calendarMs(first to last append),gapMs(their difference, the operator time),perSegment(status, entries, active wall, andreplayed: trueon a pure-replay segment, so a resumed run's walls read as the original segments' work instead of a 0.0 s rerun), andlogicalWireRequests(provider-call decisions across the WHOLE journal, the invoice's cardinality). Absent stamps keep the time fields absent: not recorded, never zero.rulvar inspectprints the logical run block (both time conventions, per-segment walls, the replayed marker) and the wire count under its own name, with the label spelling out that a segment's adapter fetches are a different, smaller counter by design.052cc26: RV4410: opt-in coordination checkpoints. With
coordinationCheckpoints: true, every settled await round appends a compactcoordination_checkpointdecision (the round ordinal, the settled handles, the spend at the checkpoint), so a timeout or kill terminal shows how far coordination durably got, and a resumed run's journal visibly continues from round N+1 instead of an opaque prefix. The seventh comparison experiment's genesis segment died on a timeout mid-coordination and the post-mortem priced the re-coordination by hand; the checkpoint makes the durable progress a journal fact. An await round the kill interrupted journals NOTHING, honestly: coordination got no farther than the journal says. Opt-in because the decisions are journal bytes; without the flag every journal stays byte identical, and the replay machinery never re-pays journaled coordination either way.rulvar inspectprints the last checkpoint (round, settled children, spend) when one exists.
Patch Changes
- bbae134: RV4411: plan hygiene. The docs and RFCs that said "plan 44 scope" about the effects/admission runtime now name the dedicated effects plan (plan 45): plan 44 answered the seventh comparison experiment instead, and a published scope pointer must follow the plan it points at. A pnpm pin guard (
scripts/assert-pnpm-pin.mjs,pnpm run guard:pnpm-pin) runs before every CI Turbo fan-out: one loud line naming the running pnpm, the packageManager pin, and the launch path, instead of the per-child version-mismatch death the RV4306 bootstrap job documents; the RV4306 behavioral gates stay the authority, and the un-enabled Corepack path stays the documented trap this guard names rather than adopts. The release contract gate keeps its documented consumption (the one-time legacy green line was spent by v1.248.0; the next release reads a fresh classification artifact from the always-recording contract-tests workflow).
1.248.0
Minor Changes
- 8d0cd69: Capacity stops being a constant and becomes an artifact (RV4304, plan 43; P2.2 of the sixth comparison experiment's improvement plan).
wireCapacityEstimatetakes the SAME four posture declarations the acceptance tail prices (claimStage,claimOnFound,citationOnFound,claimConfigured), and both derive their arming from one new exported function,semanticRoundArming, the dispatchProjectionReserveUsd precedent: money and wires cannot disagree about which rounds a declared posture arms. With the posture declared, the judge wire counts are COMPUTED from it (a hand-declaredjudgeWires/citationJudgeWiresmust agree or refuses typed with the childWires-contradiction hint, because a hand-widened count double-books the rejudges the delta already prices), andrepairRoundDeltaWiresis derived: 0 with nothing armed, 2 for a lone claim or citation round, 3 for the merged round or a citation round that rejudges a configured claim pass, the case the sixth run's constant 2 could not express. With no posture declared the historical bytes hold exactly: the delta is the documented legacy constant 2. And the newcapacitySheet(spec)plusrenderCapacitySheetMarkdownturn the estimate into a structured artifact with EVERY figure labeledgiven,derived,assumption, orobserved: an undeclared coordination term is a NAMED assumption instead of a silent zero, throughput derives only when concurrency AND service time are both given (wire counts alone bound nothing per unit time), the worst-case envelope calls itself a shaped bound and never a percentile, and observed run measurements (the invoice's 122 physical wires) render in their own section with their source on every row, never folded into the declared arithmetic, so a reader who quotes any single line quotes its provenance with it. - 81065e4: The composition declares its claims, and structure is all the machine judges (RV4305, plan 43; P2.1 of the sixth comparison experiment's improvement plan). Under the opt-in
synthesis.claimMap: truethe synthesis invocation's finish REQUIRES a typedclaimMapbeside the result: one row per material claim, atomic, each with a unique id, its evidentiary grade (source,inference,assumption,live-observed), and the source anchors it rests on; the finish tool's schema and description move BY DESIGN under the opt-in (the sectional precedent), and the reserved finalizer carries the same contract so a capped run is never schema-blocked from complying. The layer split is the design: deterministic validation is STRUCTURAL only, every document anchor covered by the map and every map anchor present in the document (both directions), at most one non-source row per anchor (a row count, never a semantic verdict), the inference bridge required on inference rows (premises and reasoning; the grade never replaces it), run evidence required on live-observed rows, unanchored claims forced to declareassumption, unique ids, and schema-carried bounds; a structural failure rejects like any host validator and spends the ordinary finish repair bound. Semantic truth stays with the judges: the accepted map journals as anorchestrator_claim_mapdecision beside the accepted candidate, linked by the exactcandidateHashOfrecipe the claim judge'sjudgedHashbinds, and the claim judge's prompt gains the map from the JOURNAL (never live state, so live and resumed passes render identical bytes) under this same opt-in; no new judge, no new rounds, no wire growth. The sectional machinery is refused beside the opt-in (a splice would move the document out from under its map), and an armed repair round resubmits the full document with a full map instead of arming the sectional shortcut. Absent, every byte holds: prompt, toolset hash, journal, envelope. - 8573f20: REGULATED_VERSION 4: the floor requires the deliverable contract and absorbs the plan 42 knobs (RV4303, plan 43). The v3 floor never required
finishValidation, so a regulated orchestration could compile with no deliverable verdict, no candidate chain, and nothing for a lineage policy to attach to, a loosening deeper than any field the floor already refused. The v4 compile refuses its omission by name (the RV4103 doctrine: the validators are the host's own acceptance criteria, and a floor that invents them invents the contract), fillscandidatePersistence: 'hash-only'inside the declared contract (the auditability minimum;'transcript'is the legal richer declaration, and the two compile to different profileHashes), and refuses the legacyretainRejectedCandidatesboolean at BOTH values, the fail-closed migration: a silent canonical rewrite would compile a lineage posture the host never wrote. The citation audit's resolver generation is pinned the same way:citationAudit.resolverfills2(the bounded logical-unit resolver) and an explicit1refuses, because the fixed four-line window is the diagnostic resolver whose truncation manufactured the sixth comparison run's false negatives. The hashed map gains the resolver generation, the persistence mode, and the required-contract fact; the fingerprint prefix moves toregulated:4:, a v3 hash never collides with a v4 reading, and the map bytes are now pinned by a golden-hash test so any movement of the hashed posture is a conscious edit beside a version thought. The newclaimMap(RV4305) is deliberately NOT absorbed: the knob matures a cycle first, a candidate for v5. - 95f6a5e: The scope identity gains a declarative value normalization table, and the journal is its authority (RV4302, plan 43).
scopePolicy.normalizeis a versioned table over a closed vocabulary (trim,lowercase,nfc, applied per dimension in declared order), deliberately data and not a callback: a host function is not replay stable, not journalable, and free to read locale or time. The table applies innormalizeExecutionScopestrictly AFTER the existing input validation, the result re-validates by the same rule (an all-whitespace value that trims to empty refuses typed instead of recording an identity that asserts nothing), and the canonical values exist BEFORE any digest does, so' EU-West 'and'eu-west'stop splitting one tenant's quota buckets and FinOps joins across two identities. The table is journaled in the genesisexecution_scopedecision beside the scope and digest it shaped, mirrored inRunMeta.scopeNormalize(stores must round-trip it; the conformance kit checks), and on resume the RECORDED table is what normalizes the supplied scope before any comparison, so a host that re-supplies the raw values it started with asserts true; a conflicting re-supplied table refuses typed (the args-binding rule), and a table supplied over a run that recorded none warns and is never applied.compileRegulatedProfilepreserves a declared table under its pinnedunknown: 'reject'and hashes it into the posture, so two compiles over the same canonical values with different declared tables carry different profileHashes; absence keeps every undeclared config byte for byte, hash included. Beside the code,rfcs/admission.mdrecords the accepted design for the durable fairness and admission SPI (P1.4): the split from the live-onlyQuotaLimiter, hierarchical buckets over the resolved effective tenant, start time fair queuing with reserved wires as the one scheduler unit, conditional-create tickets with lease-fenced consumption covers, and the conformance matrix, hardened by adversarial review to the final verdict closed.
1.247.0
Minor Changes
- 1933ecc: The atomic production posture, and the one bounded round every defect class can ride (RV4201, RV4202; the sixth comparison experiment). The experiment's run was configured knob by knob into "observe and ship anyway": report postures, a standing waiver, no repair round, every choice individually legal, their sum a run that settled accepted over a partial coverage grade, a judged contradiction and five unsupported citations. RV4201:
semanticAcceptanceis the one declaration that says the opposite in full (judgedStage: 'final',claimCoverage: 'full', contradictions/citations'repair-once-then-fail' | 'fail',unresolved: 'fail',waiver: 'forbid' | { judgedHash }); intake fills nothing and refuses every underlying field that contradicts it,'forbid'refuses typed even over a journaled waive decision (a config/journal mismatch is not an authority), the pinned form licenses exactly one reviewed document by its claimjudgedHash, and the terminal invariant asserts that the claim and audit verdicts describe the shipped bytes.compileRegulatedProfileenforces it:onFound'report'/'carry'refuse,'fail'fills, an armed'repair'gainscoverageRepair: true, acoverageTargetbelow 1 refuses as unsatisfiable, a standing waiver refuses outright, and the declaration is written from the enforced postures when absent. RV4202: coverage joins the bounded round (claimConsistency.coverageRepair: a non-'full' FINAL grade arms the same one round, the uncovered citing sentences ride its prompt as the UNCOVERED CLAIMS block, the repaired document is re-graded from its new hash, and a persistent non-'full' meets the strict gate with the spent round named), and arming BOTH the claim and citation repairs is legal now: the pair grants the SAME one merged round, fired after the first audit pass with both defect lists on board, both judges re-rule on the new hash, survivors of either class fail typed, and the acceptance tail prices exactly one round composition and two passes per armed judge. The repair ledger's semantic rows gain the'coverage'and'combined'triggers. - db0a5f0: The posture map tells postures apart (RV4203, the sixth comparison experiment's headline finding).
compileRegulatedProfilehashed NONE of the semantic postures: a run configuredreportfindings beside a standing waiver and a run configured fail closed carried the identicalprofileHashandconfigFingerprint, so the attestation machinery could not distinguish a diagnostic posture from a production one, which is the exact blind spot the sixth experiment ran through. The v3 posture map (REGULATED_VERSION 3, fingerprint prefixregulated:3:) hashes the findings postures of all three passes (claimConsistency.onFound,citationAudit.onFound,contradictions.onFoundwhen declared), the coverage arm and target, the waiver mode with its declared terms, the citation audit's sampling and judge parameters (samplePerSection,maxSampled,window,pattern, judge model and effort), the claim judge's model and effort, thesemanticAcceptancedeclaration in full, and the declared toolset attestation pins (contract and authority hashes), so upgrading a contract-only pin to an authority-bearing one moves the fingerprint. A v2 hash can never collide with a v3 reading of the same options. - b698726: The first-party surface attests, and the floor loses its holes (RV4204, the sixth comparison experiment). Before this, only
mcp()and the AI SDK bridge exposeddescribeRegulatedPosture(), sounrecognized >= 1on nearly every real regulated compile and a zero-blind-spot floor was unsatisfiable by construction; and the floor checked toolset attestation only ondefaults.profiles, accepted legacy contract-only pins that pass authority drift silently, and never walked the executors at all. Now:anthropic()andopenai()attest their egress (official, acustom-base-urlwhose ORIGIN enters the hashed posture map, or apreconstructed-clientnamed honestly) plus the caps pagination bound;subprocessExecutor()andcontainerExecutor()attest their ledger, env allowlist, resolved ceilings, and isolation seam;compileRegulatedProfilewalksengine.executorsand the sandbox runner beside adapters and toolsets, wraps attested executors sorun()re-judges the posture at use (the RV4102 seam), refuses a regulated executor without aToolEffectLedgerby field name, refuses legacy contract-only pins (re-record withattestToolset()), and arms the new engine-widedefaults.requireToolsetAttestation, under which a spawn resolving a non-empty toolset with no pin binding it refuses typed at spawn time (the per-call-tools hole the profile pins could not see). The opt-inconstruction: 'require-recognized'compile floor turns the unrecognized count into a typed refusal naming the blind constructions, satisfiable now that the first-party surface attests. - 48348d2: Scope dimensions v2, and the quota binds to the scope (RV4205, the sixth comparison experiment's P0.2).
ExecutionScopegains the three named host dimensions (legalDomain,region,providerAccount) beside the tenant/account/project trio; the genesisexecution_scopedecision and the invoice header carry the canonicalscopeDigest(sha256 over the normalized JCS bytes, a fixed-length join column for FinOps pipelines);RunOptions.scopePolicy: { unknown: 'reject' }turns the silent unknown-field drop into a typed refusal by name (the drop default is pinned byte for byte, andcompileRegulatedProfileenforces the refusal plus hashes the policy). The quota seam binds to the scope:quota.tenantFrom: 'scope'debits each run's reservations to the tenant its own scope declared instead of the engine-wide name (a scopeless run reserves tenant-less), every reservation carries the run's scope dimensions, and aQuotaRulecan pinaccount,project,legalDomain,region, orproviderAccountbeside provider/model/tenant, matching only reservations whose scope carries the same value. Dimension-less rules keep their storage bucket keys byte identical, so keyed-store windows survive the upgrade. - 4cfa1cc: The telemetry names every judge, and the capacity intake closes (RV4206, the sixth comparison experiment). Both critical-path reducers now classify every synthesize span through one exported
synthesizeSpanClassOf: the citation entailment audit judge gets its owncitationJudgeMsbucket (plus span counter) on the live fold, the journal fold, and both post-fan-in itemizations, instead of folding intofinalCompositionMs(the run under audit read 368889 ms of "composition" that was 214870 against 154019, withcompositionSpansfaking a repair round's signature andlastCandidateMsovershooting the settled candidate by the verdict tail); a PRESENT synthesize label the classifier does not know lands inunclassifiedSynthesisMswith a nonzero span counter instead of silently reading as composition, and the candidate milestones anchor to composition spans only.CostReport.byAgentTypegets the RV3905 vacuum fill: the orchestrator's own dispatches attribute asorchestrator,synthesizer,claim-judge, andcitation-judge(attribution policy only; explicit agent types and spawned profiles always win, events and journal identity untouched). AndwireCapacityEstimatecloses its intake: unknown keys refuse typed (they were silently zero), the fan-out can be declared structurally aschildrentimesturnsPerChildwith a typed hint when a contradictingchildWirespasses a child count where the wire total belongs, the citation audit judge's wires get theircitationJudgeWireskey, and the output stampsbasis: 'declared-estimate'. - 4b7197a: The candidate chain reads by hash, and absent bytes say why (RV4207, the sixth comparison experiment).
finishValidation.candidatePersistence: 'transcript' | 'hash-only'supersedesretainRejectedCandidates(declaring both refuses typed): under a declared policy every finish-validation decision carries the candidate identity, the ACCEPTED verdict included (the hash names the resolved document, deterministic patch or sectional splice applied, on the same recipe the semantic judges bind),'transcript'retains rejected bytes exactly as the boolean did, and'hash-only'retains none on purpose, stampingbytesUnavailableReason: 'hash-only-persistence'on the decision, the fold, and the terminal row (a declared retention the store refused stamps'store-write-failed'), so an auditor finding no blob reads a policy or a fault by name. The hash recipe is exported and documented:candidateHashOf(sha256 over the JCS canonical value; a string document hashes as its JSON encoding, and a file export with a trailing newline changes the file's sha while this hash holds) withverifyCandidateBytes(bytes, hash)as the audit predicate.rulvar inspect <runId> --candidatesrenders the chain (verdict, hash, chars, window, wires, money, byte address or the named reason) and--candidate-bytes <hash>recovers a retained document to stdout, verified against the journaled hash, in one command; the experiment's auditor recovered the rejected 37,645 character composition by digging messages[3] out of a binary transcript blob and re-deriving the recipe from source. Undeclared configs keep every byte: identity on non-accepted verdicts only, exactly RV2507. - 5ebc842: The citation excerpt reads the logical unit, and every anchor gets its row (RV4208, the sixth comparison experiment). The declared
citationAudit.resolver: 2(default 1, byte identical for every existing config) excerpts the bounded LOGICAL UNIT the cited line belongs to instead of the fixed downward window: a heading brings its whole section to the next heading, a list item its continuation lines, a table row its header pair, a code comment its block plus the declaration it documents, anything else its paragraph expanded both ways; all capped at the existing 12 lines and 800 chars with atruncatedflag and the unit type on the row (citationUnitExcerptOf, exported). Under the same opt-in the sampler audits EVERY anchor of a compound sentence as its own row (anchorOrdinal) against its nearest claim clause (clauseAround, on the row and in the judge prompt), and the audit meta stampsresolverVersion: 2. The experiment's confirmed false negatives were exactly window artifacts (a section heading whose support lives below the window; only a sentence's first anchor ever sampled), and its two GENUINE unsupported citations survive v2 untouched: the 24-row gold corpus pins both directions at 24/24. Explicitpath:start-endranges keep range semantics under either resolver. - 16ff6b9: One word answers the production question, on every surface (RV4209, the sixth comparison experiment). The acceptance envelope now carries
semanticTerminalVerdictwhenever claim or citation machinery is configured:'clean' | 'findings' | 'partial' | 'vacuous' | 'waived' | 'not-judged'with the final hash, the counts (contradictions, unsupported and partial citations, repair rounds), the standing waiver, and the judge-failure codes, folded ONCE at the orchestrator settle (semanticTerminalVerdictOf, exported) with fail-closed precedence: a failed or declined judge, and a draft-stage grade the synthesis rewrote (RV3207), readnot-judged; findings outrank the waiver; the waiver is never clean. The verdict is lifted onto the outcome, mirrored onto the terminal envelope (and through it therun:endevent and the HTTP response), so every consumer reads the SAME derivation instead of re-deriving it from four fields.productionAcceptableis the exported fail-closed gate (only'clean'passes; absence readsnot-judged), andrulvar run --acceptance-policy production(also onresume) applies it after--strict's mechanical checks, refusing suspended runs asunsettled, with ONE stable JSON reason line on stderr per refusal.--strictitself stays byte identical, documented exits included: the experiment's run settled ok under a standing waiver with three unsupported citations, and the pipeline reading strict's exit shipped it. - 0c9941d: The judge pair rules together, and the draft becomes a map (RV4210, the sixth comparison experiment). With NO round armed anywhere, the final claim pass and the citation audit's first pass now dispatch CONCURRENTLY on the same immutable document, with the verdicts processed in the historical order (the claim pass's typed refusals fire first), so every decision, meta stamp, and refusal reads exactly as the sequential path wrote it; the run under audit spent 100.8 seconds of its tail waiting for the claim judge before the citation judge could start, on two verdicts that read nothing of each other. Any armed round (claim repair, coverage arm, audit repair, merged) keeps the strict sequence byte for byte, because a round rewrites the document and the audit must read what ships; wire counts are unchanged, and the acceptance tail already funded both passes. And
finishValidation.draftPolicy: 'digest'joins'contract': for configurations that do not useskipWhenDraftValid, the coordination prompt asks up front for a compact structural evidence map (one list row per planned section naming its claims and evidence) and the gate enforces the inversion deterministically, at least one list row and at mostDIGEST_DRAFT_MAX_WORDS(400) words, so the draft can neither stay prose nor decay back into it (the run's contract-policy draft cost 344.8 seconds of model output and was rewritten whole by the composition). A digest is never a shippable candidate:skipWhenDraftValidandfallbackToValidDraftrefuse typed beside it.
1.246.0
Minor Changes
- d165b0c: The profile hash sees the constructions, and counts what it cannot (RV4101; the debt RV4009 named). The regulated floor binds what flows through options, but the postures that decide whether a tool list can drift beneath a run (an
mcp()source'sdriftand discovery bounds, RV1516/RV1808) or whether a provider executes tools outside the permission chain (the AI SDK bridge'sproviderExecutedToolsseam) live on CONSTRUCTIONS the options never see; RV4009 excluded them from the hash by principle ("a hash must not imply what it cannot verify") and named them in prose. This train makes the verifiable part verified. A risk-bearing construction now exposesdescribeRegulatedPosture(), a PURE snapshot of what was chosen at build time (no wire, no connect):mcp()reports{ drift, bounds },bridgeAiSdk()reports{ providerExecutedTools }, both implemented this release.compileRegulatedProfilewalks every construction its options reach (adapters, named toolsets, profile toolsets, each object once), REFUSES a loosened posture by field name (construction['mcp:http:...'].drift must be 'refuse'; bounds must be declared; the bridge must deny), refuses outright a descriptor of a shape or kind it cannot judge, and folds the sorted descriptors into the hashed posture map underconstruction, beside anunrecognizedcount of the constructions that exposed nothing, so the hash names its own blind spot instead of implying totality.REGULATED_VERSIONbumps to 2 (regulated:2:<hash>): the map's meaning changed, and a v1 fingerprint must never collide with a v2 reading of the same options. Deliberately open, by name: a construction mutated AFTER compile time; the descriptor is a snapshot, not a lease, and the first-use re-assertion is the RV1608 template applied in its own train. Probes pin the drift refusal and the blind-spot count. - d59f4a0: The construction posture holds at the seam (RV4102, the RV1608 template; closes the window RV4101 named). The descriptor is a snapshot, and the window between
compileRegulatedProfileand the run is where an in-process mutation could walk a moved posture beneath the hash that licensed a different one. The compiled options now carry each attested construction wrapped: every use of its risk seam (tools()on a tool source,stream()on an adapter) re-readsdescribeRegulatedPosture()and re-judges it with the same judge the compile used, so a posture loosened after compile refuses with the identical field-named error (construction['mcp:...'].drift must be 'refuse'), and any other movement (a rename, a changed bound, a vanished descriptor) refuses naming the drift and the remedy: recompile deliberately instead of mutating beneath the profile. Everything else passes through untouched,close(),caps(), and identity fields included, and a profile with no attested constructions compiles to byte-identical options with no wrapper at all. The cross-process half of the window never needed one: a mutated construction compiles to a different profile hash, and the RV3210 resume assertion refuses it. The realmcp()case is pinned end to end: a config object whosedriftflips to 'rekey' after compile refuses at the nexttools()before any wire. A probe collapses the use-time comparison and requires the moved-posture test to go red. - 46907ac: The regulated floor requires the claim machinery, and the journaled waiver is the authority on resume (RV4103, RV4104; plan 41's audit of the plan-40 surfaces). Two asymmetries, both on the floor's own doctrine. First:
compileRegulatedProfilerefused a loosenedclaimConsistencyfield but admitted an orchestration that omitted the block entirely, and absence is the loosest claim posture there is: no claim pass, no coverage grade, no strict-final gate, exactly the unarmed shape the third comparison defeat ran. The floor now refuses the omission typed (orchestrate.claimConsistency must be declared with stage 'final' or 'both'), symmetric withcitationAudit; it deliberately does not autofill, because the pass needs a judge model and an estimated cost the floor would have to invent. Second: thestrict-finalwaiver's expiry was re-read from the live clock on every finalize execution, while the waiver's own TSDoc had promised since RV4003 that the verdict is "evaluated once at the enforcement point and journaled". A run that waived its gap, crashed before the terminal, and outlivedexpiresAtre-rendered the exception on resume and became unfinishable with its exception already on the record. The enforcement point now reads the journaledclaim_coverage_waiveddecision first: a recorded waive licenses the replayed acceptance verbatim (principal, reason, expiry, waived grade), bound like the RV603 synthesis skip to thejudgedHashit licensed, with pre-field entries staying reusable so journals in flight roll forward. The consumption recheck contrast (RV4008) stands deliberately: an approval's effect has not happened yet at recheck time, a waived acceptance's decision already has. Probes pin both: the absence refusal must not compile away, and the collapsed journal lookup must fail the crash-and-outlive replay. - 9929ad3: Semantic repair rounds own their ledger rows, and a repair wire never walks past a nearer verdict (RV4105; plan 41's audit of the RV4002 ledger). Two defects, one lane. First: the dispatched claim round (RV3307) and citation round (RV4004) counted into a bare
semantictally with no row, so a reader ofsemantic: 2could not tell which machinery asked without cross-reading two metas, and the rounds' own wires had no home. Each dispatched round now folds into its own row:stage: 'semantic', the dispatch entry'sseq, and atrigger('claim'or'citation') read from the newcostAttribution.repairTriggerstamped at dispatch beside the RV3905 phase; journals written before the stamp fold the row with the trigger honestly absent (NOT RECORDED, RV1209). Second: the wire pairing scan attached aphase: 'repair'billing row to the nearest earlier same-scope row WITHOUT a wire yet, which let a wire walk PAST an already-claimed or rowless neighbor onto an older repair's row; concretely, a semantic round following a composition repair whose own billing row never landed (the RV2008 async posture allows exactly that) signed the round's money onto the composition's row, and itscostUsdnamed another repair's price. The window now closes at the next row of the scope: the first wire in a window claims the row (wireRefstays "the first incremental billing row after this verdict"), and a later wire stays unattached rather than misattached, absence over a guess. Probes pin both: the collapsed row push and the reopened scan window each fail the misattribution regressions. - 1790a6a: The pair is primary over the coordination bucket, and the compile floor judges its own intake edges (RV4106, RV4107; the tail of plan 41's audit). RV4106: the RV4010 coordination bucket checked the dispatch ROLE before the evidence/counter pair, so a synthesize (or orchestrate) dispatch that carried BOTH a declared evidence contract and an executed-call counter was swallowed by the bucket and its declared contract fell out of calibration entirely, where before RV4010 it had been an observed row. The pair is primary now: a coordination-side dispatch carrying both sides folds as an observed row like any worker, and the bucket takes the contract-less rest. RV4107, three edges of
compileRegulatedProfile:budgetUsdmust be a positive finite ceiling (a baretypeofcheck let NaN and Infinity compile into the posture map as a ceiling that bounds nothing); the hashedscopeis the NORMALIZED copy (the engine drops junk fields downstream, so a junk field moved the hash while the effective posture stood still; the samenormalizeExecutionScopecall now refuses an empty or malformed scope at compile time, and the copy rides the compiled run so later host mutation of the passed object cannot move what genesis records); andcitationAudit.resolveis judged a function at compile time instead of orchestrate intake, because a declared audit that cannot resolve a single anchor is a posture in name only. Probes pin the pair primacy, the finite ceiling, and the normalized-scope hash.
1.245.0
Minor Changes
- b4d47a8: One acceptance-tail formula for the runtime gate and preflight (RV4001, the fifth comparison experiment). The RV3907 boot gate shipped with its own inline arithmetic and preflight kept another on different terms: the experiment's plan passed preflight green at a $4.54 cap and the runtime refused it typed at $4.82 before the first wire, and the gate's own copy additionally undercounted
stage: 'both'at one worst-case judge pass where the posture dispatches two (three with an armed repair round). The exportedacceptanceTailRequiredUsd(withacceptanceJudgePassesandformatAcceptanceTailTerms, thedispatchProjectionReserveUsdprecedent) now serves both callers term for term. Preflight mirrors the missing declarations (orchestrator.synthesis.estCost,finishValidation.estRepairCostUsd), reportsbudget.orchestrator.acceptanceReserve({ declared, requiredUsd, effectiveCapUsd, fits, terms }; exact fill fits, exactly the gate) whenever the posture is declared, and surfaces an unfit tail as theacceptance-reserve-unfitfinding: an ERROR under declared'require'(the run would refuse to start, and the experiment's harness gated on error findings only) and a warning under'warn'. A differential grid pins runtime and preflight to the same number and the same printed arithmetic; three mutation probes pin the summed terms, the'both'pass count, and the error severity. - dee6db4: The workflow answers for its own repairs (RV4002, the fifth comparison experiment). The run paid for exactly one repair (a coordination draft rejected by three validators, healed by a sectional resubmission, one more wire at $0.186) and every terminal aggregate answered truthfully for its own stage while no surface answered for the workflow: the independent judge rebuilt the count from the raw transcript and the repair wire's money drowned in 'coordination'. The exported
repairLedgerFromJournalfolds the workflow-wide ledger ({ draft, composition, semantic, total }plus one row per granted repair with its stage, verdict seq, failed validators, spliced sections, and the repair wire's ref and price when the billing lane covered it); the acceptance envelope carriesrepairscomputed by the same fold over the run's own snapshot, so live and post-hoc agree by construction. The draft gate journals its voice (orchestrator_draft_gateon rejection and on the healing sectional acceptance), finish-validation decisions carry theirstageand spliced markers, and the granted repair turn's own wire is stampedphase: 'repair'(ProviderCallRecord.phase), which all three byPhase folds split out of the hosting dispatch's bucket.rulvar cost-auditprints the ledger when the journal proves one, byte parity otherwise; pre-RV4002 journals fold withunstagedVerdictsnamed, a floor, never a guess; clean runs keep every byte (all 61 frozen fixtures verify unchanged). Kit:coordination-draft-repairpins the experiment's exact shape ({ draft: 1, composition: 0, semantic: 0, total: 1 }, the gate decisions, the stamped wire) andsectional-repair-roundpins the semantic round's ledger; four mutation probes pin the wire stamp, the gate's journal voice, the round count, and the CLI line. journal-shape-revision: the wire-levelphasestamp is an additive journal evolution, and the frozen cassettes whose flows contain a refused finish exchange are re-recorded under it. - b85c113: The coverage grade becomes a gate under a declared policy (RV4003, the fifth comparison experiment). The run's claim pass covered 54 of 74 citing sentences, graded itself 'partial' honestly, MET its own declared 0.72 coverage target at 0.7297, and the run still shipped three unsupported citations inside exactly the uncovered fraction: every ratio floor held and none of them binds the grade.
claimConsistency.coveragePolicy: 'strict-final'refuses acceptance typed when the FINAL pass's grade is anything but 'full' (partial, vacuous, critical-uncovered, judge-declined, judge-failed alike), unless the declaredwaiver { principal, reason, expiresAt? }stands: the waived acceptance journals aclaim_coverage_waiveddecision and carriesclaimCoverageWaiveron the envelope verbatim beside the meta, so a non-full grade on a strict run always names who accepted it and why; an expired waiver refuses exactly like none. The default 'observed' keeps every existing byte; the policy requires stage 'final' or 'both', and a waiver without the policy is a ConfigError. Kit:strict-coverage-policydrives both arms (the typed refusal and the journaled waiver); probes pin the gate and the expiry; the orchestration guide names the doctrine ("0 findings" was never "semantically verified" without its denominator) and the doctrine-pin gate now requires it. - bc556e7: The citation entailment audit (RV4004, the fifth comparison experiment): the independent judge's method, internalized. The run's built-in verification judged VALUES (cited-value), TARGETS (citation-targets), and CONSISTENCY (the claim pass, child readings against draft claims), and the shipped answer still carried three citations whose cited lines do not entail the sentences citing them, every one mechanically valid, value-clean, and invisible to a pool that held no reading of those files (20 of 74 citing sentences had no candidates at all; child-against-final pairing can never cover them).
citationAuditruns over the FINAL document: a deterministic stratified sample (per H2 section, seeded from the audited document's own hash, replay-stable, capped), excerpts read through the host's pure snapshot resolver (thecitedValueValidatorchannel; a citation whose first cited line does not resolve is unsupported mechanically), one bounded judge invocation rulingsupported | partial | unsupportedper sampled citation. The envelope carriescitationAuditMetaandcitationFindings;onFound: 'report' | 'fail' | 'repair'decides the consequence, with'repair'riding the RV3307 bounded round (one more composition carrying the findings, a fresh audit from the repaired document's new hash, a configured claim pass rejudging the rewritten document, survivors failing typed; arming it beside the claim round is a ConfigError, one bounded round per run). The declaredjudge.estCostenters the RV4001 acceptance-tail formula on both the runtime gate and preflight (citationAuditmirror on the preflight orchestrator spec), one pass or two, with the round composition and the claim rejudge priced. Kit:citation-entailment-auditdrives the flagship shape (the unsupported citation caught, the supported control clean, the armed fail typed); three probes pin the mechanical unresolved verdict, the fail gate, and the round's re-audit. - 9f11d29: The wire capacity of a plan has one exported source (RV4005, the fifth comparison experiment). The run's own terminal answer modeled this runtime's repair round as one extra wire (34 to 35) and multiplied retry share by
1 + r, losing the decisive correctness point to arithmetic the codebase already states: a triggered round is TWO wires past the plan (its composition PLUS the rejudge, RV3307) andrretries over a base ofBwires multiply totals by1 + r/B.wireCapacityEstimateprices a declared plan (child, coordination, synthesis, judge, extract wires) into{ baseWires, repairRoundDeltaWires: 2, mechanicalRepairDeltaWires: 1, wiresWithRound, roundOverheadShare }, andretryWireMultiplieris the retry share formula; golden tests pin the healthy 34/36/5.88-percent example. The budgets guide gains the worked example and two REQUIRED doctrine pins hold the two-invoice round cost and the retry formula on their pages. - 19bcea0: The pre-wire provider intent (RV4006, the fifth comparison experiment's P0.5). Receipts journal after a wire settles, so the wire most exposed at a crash is exactly the one being paid for: between dispatch and receipt, a death leaves money the journal never heard about.
defaults.billingReceipts: 'intent'journals aprovider-intentdecision before every dispatched wire attempt (awaited, the executor ledger's intent-before-effect rule: a failed intent append refuses the dispatch), keyed by dispatch seq, ordinal, and attempt, carrying the serving model, role, and a sha256 request fingerprint; receipts stay awaited as under'awaited'. An intent with neither a receipt row nor a settled terminal covering it is a wire with UNKNOWN outcome: the exportedopenWireIntentsOffold names them, the invoice carries theopenIntentslane (no invented dollars),rulvar cost-auditprints it, and a resume that finds one refuses the blind retry typed untilResumeOptions.acknowledgeOpenWireIntents: trueis passed, which the new segment journals asopen_wire_intents_acknowledged. Dispatch stays at-least-once with attempt binding; the default'async'and'awaited'postures keep every byte. Kit:wire-intent-unknown-outcomedrives the reconstructed crash window through both resume arms; probes pin the quota-arm intent, the resume gate, and the receipt closure. - 60b461c: The bounded execution scope (RV4007, the fifth comparison experiment's P0.4). Who a run executes for, as the host names it, carried WITHOUT LOSS and never interpreted:
RunOptions.scope({ tenant?, account?, project? }, own properties, non-empty strings, at least one field, copied at intake so later mutation moves nothing) records at genesis into RunMeta and a journaledexecution_scopedecision, is immutable for the run's life (no resume door), rides the invoice header asexecutionScope(a pure fold from the entries, so a FinOps pipeline reads the owner off the money document), travels in the export bundle via its meta, andResumeOptions.scopeasserts it back (mismatch refuses typed before ownership; a supplied scope over a run that recorded none warns). On the provider side,ProviderAdapter.scopeKeynames the ACCOUNT within a family: the retention transport then keys provider-raw blocks by(family, scopeKey)instead of family alone, so cache handles and thinking blocks minted under one account never ride a request served by another; undeclared adapters keep the family-wide sharing byte for byte, and routing, pricing, and quota keys are untouched. The store conformance kit pins the RunMeta round-trip; probes pin the genesis decision and the retention separation. Attribution envelope, not IAM: tenancy semantics stay host decisions. - 61e3a1a: A grant can be taken back (RV4008, the fifth comparison experiment's P0.6 revocation half). An allow is a recorded fact history cannot unwrite, so
handle.revokeApproval(key, { principal, reason })makes revocation its own journaled truth: a still-open approval is denied through the ordinary first-closing-wins arbitration (races stay deterministic by the journal), and a RECORDED allow gains anapproval_revokeddecision that beats it at the CONSUMPTION recheck, the moment the allow is about to license the effect, live or re-matched on resume, so an allow granted, crashed over, and revoked never dispatches its tool; the typed deny names the principal and the reason. The grant is boundable too: an allow resolution may carryexpiresAt(validated at the registry; the recheck fails CLOSED on an unparsable expiry recorded past it), and an expired grant denies exactly like a revocation.ApprovalDecisiongainsentryRefandexpiresAt(additive). Revocation gates dispatch and never chases it: an executing or executed tool is outside its reach, the documented at-least-once window. Probes pin the recheck and the fail-closed expiry. - a156b81: The regulated floor is one call (RV4009, the fifth comparison experiment's harness lesson, previously gated behind its own word and confirmed with plan 40). Every assurance posture this library grew is an opt-in knob, which is correct for a library and hazardous for an unreviewed config: the compared runs armed gates to observe because assembling the posture by hand was the only path.
compileRegulatedProfile({ engine, run, orchestrate? })composes the floor in one place:strictApprovalsarmed (the RV1507 monotonic mode),billingReceipts: 'intent'(RV4006),determinism: { mode: 'error' },strictPricingwith a requiredbudgetUsdunderbudgetPolicy: 'immutable-lifetime'(RV3902), a required executionscope(RV4007), and, when orchestrate options ride along,acceptanceReserve: 'require'(RV3907/RV4001), a declaredcitationAudit(RV4004), andcoveragePolicy: 'strict-final'(RV4003); a profile that declares tools must carry its toolset attestation (RV1607). A field that loosens the floor REFUSES typed, naming the field, never a silent overwrite. The returnedprofileHash(sha256 over the enforced posture map) ridesrun.configFingerprintasregulated:1:<hash>, so genesis records it and a mismatched resume refuses through the existing RV3210 machinery: no new meta surface, no engine branch, the compiled options are data. The hash deliberately excludes construction-side postures the options never see (MCPdrift: 'refuse'and bounds, the AI SDK bridge'sproviderExecutedTools: 'deny'); the production profiles guide names them beside the call, because a hash must not imply what it cannot verify. Probes pin the refusal (a loosening must throw, not compile away) and the hash's coverage of the ceiling. - 0bd7045: The calibration fold names the coordination side's own executed tool calls (RV4010, the fifth comparison experiment).
toolCalibrationFromJournalgainscoordination({ dispatches, toolCallsUsed }): terminal dispatches whose role isorchestrateorsynthesizewith the RV3002 counter journaled, the spawn/await/finish exchanges no evidence contract ever binds. The experiment's telemetry counted 407 tool starts against 390 worker calls and the 17-call coordination remainder had to be explained by hand because those counters drowned inbudgetOnlyas if declared contracts had lost their pairs; workers' counters plus this bucket now account for a dynamic run's executed tool calls. Absent when no counted coordination dispatch exists, so those reports keep their bytes; a probe pins the bucket.
1.244.0
Minor Changes
38d839a:
RunOptions.budgetPolicy: 'segment' | 'immutable-lifetime'(RV3902, the fourth comparison experiment): the regulated posture the docs used to promise by accident is now a real, opt-in invariant. Default'segment'is today's behavior byte for byte. Under'immutable-lifetime'the posture is recorded inRunMetaat genesis (only the non-default is written; the store conformance kit holds stores to the round-trip) and restored on every resume, and a resume carrying ANY applyingResumeOptions.runoverride refuses with a typedConfigErrorbefore ownership, meta writes, or any append, raising and lowering alike; the emptyrun: {}object stays the documented no-op, a bare resume stays a pure replay, and a store that drops the field degrades to'segment'(the door works again), never to an invented refusal. The fault kit gains thebudget-policy-immutablescenario (typed refusal, zero wires, zero durable mutations, bare replay intact); two mutation probes pin the refusal gate and the genesis recording. The source TSDoc sweep retires the lastimmutable after startcomments (engine, budget, termination, orchestrate, plan), and the docs doctrine pins now scandocs/apitoo.ce13b0f:
parseTerminalEnvelope(RV3903): a runtime contract gate over the terminal envelope, exported beside the type. The one producer is a compile-time promise, and the fourth comparison experiment probed the built dist straight past it: the typed copy acceptedstatus: 'green', NaN dollars, and negative counters without a sound. The gate validates the contract fields (enumstatus/completion, finite nonnegative money withtotalUsd <= grossUsd, usage and counters,settledReasononly besidesettled: false, thecostBasis/provenanceliterals, the typed error shape) and refuses with aConfigErrornaming the field and the defect; unknown top-level fields pass through, because the contract evolves additively.persistedTerminalEnvelopenow runs every journal-rebuilt envelope through the gate under one catch with the fold's own overflow guard, refusing as the new typed reason'malformed-envelope'instead of serving a green envelope or throwing bare at a serving surface; the server's non-live responses inherit the gate by construction. Four mutation probes pin the enum check, the money guard, the settledReason coherence, and the persisted wiring.4fa23e3: The verdict lineage on the acceptance envelope (RV3904, the fourth comparison experiment): the run's terminal read
findings: 0over a lineage whose first judge pass had caught a real contradiction, and only the journal could say so. Under the armed claim repair round,claimConsistencyMetanow carriespasses,firstPassFindings(when passes exceeds 1), andsemanticRepairRounds, so a repaired verdict is distinguishable from a clean first one on the envelope; absent fields mean NOT RECORDED (no round armed, or an older journal), and the mechanicalrepairsUsedkeeps its byte contract untouched. Beside it, the acceptance envelope gainsdeterministicPatches(the RV3801 machine-patch aggregate: accepted decisions, total patches, the last patch's canonical before/after hashes), derived from the same journaled finish decisions the patches live on, so live and resumed envelopes agree by construction. The sectional and deterministic-patch kit scenarios pin the lineage and the aggregate; two mutation probes pin the pass count and the envelope block; the observability guide documents what zero findings does and does not mean.6841c69: Dynamic stage phases (RV3905): the fourth comparison run's
cost.byPhaseread 100%unknownover stages the journal held plainly apart, because the fold readscostAttribution.phaseand the dynamic orchestrator never stamped one. Each engine-owned dispatch now names its stage on the dispatch scope state:fan-out(children),coordination(the loop and the forced-finish wake),composition(the synthesis invocation and incremental notes),judge(the claim passes),repair(the bounded claim repair round). The stamp is policy, never identity: journal keys and resumed runs are untouched, live and journal folds read the same field by construction, and an explicit hostctx.phasearound the orchestration wins, so the stage names fill only the vacuum (phase-wrapped hosts also stop losing their bucket on spawned children, which never inherited the calling phase before). Two mutation probes pin the fan-out and judge stamps.journal-shape-revision: dynamic dispatches now journal
costAttribution.phase(an additive policy field; old journals replay unchanged and fold the absent field underunknownexactly as before), so the committed plan cassettes are re-recorded with the stamped stage names.f56721d:
InvoiceRow.agentType?andInvoiceRow.label?(RV3906, the fourth comparison experiment): in dynamic runs the scope grammar nests every orchestrator spawn under oneagent:<seq>bucket, sobyScopelegitimately reads two buckets and per-child money used to require a join through the journal. Every row of an attributed terminal (record rows, unattributed slice rows, and remainder rows alike) now carries the spawn'sagentTypeand the dispatchlabelfrom the terminal's cost attribution; the empty agentType folds as absent (the root's honest non-type), and rows of journals recorded before attribution shipped stay byte for byte.rulvar cost-auditprints the same cut as aby agentType:line and carries it asinvoice.byAgentTypein the JSON form, both absent on pre-attribution journals. Cardinality pins unchanged; one mutation probe pins the threading.c894a43:
budget.acceptanceReserve: 'warn' | 'require'(RV3907, the fourth comparison experiment): preflight has long priced the acceptance tail and warned (reserve-line-headroom,orchestrator-working-room), and the experiment's run started anyway with both warnings on record. Under'require'the declared acceptance tail (the heldsynthesisReserveUsd, the claim judge'sestCosttimes one plus the armed semantic repair round, the declaredfinishValidation.estRepairCostUsd, and the armed round's declaredsynthesis.estCostcomposition floor) plus one coordination turn floor must fit the effective cap at exact fill or better, or the run refuses with a typedOrchestratorCapConfigErrorBEFORE the first wire, journaling anacceptance_reserve_refuseddecision that names every term. Undeclared estimates contribute zero, so the gate binds exactly what the host declared; the default'warn'keeps today's behavior byte for byte. The fault kit gainsacceptance-reserve-refusal(typed refusal, zero dispatches, term-by-term decision); boundary tests pin exact fill as admission; one mutation probe pins the gate.f6944a3: The judge wire economy (RV3908, the fourth comparison experiment): every final claim judge paid TWO wires, and the extract wire re-sent the whole conversation at the full input rate with zero cache read; the run's extract role cost $0.28, 5.2% of all money. Two fixes at the agent loop, both verdict-neutral: (1) even when the separate extract invocation is armed (extract routed to a different model than the loop), a final loop turn whose text already validates against the schema IS the structured result and the wire is skipped, exactly the semantics of the no-separate-extract path; the separate invocation stays the repair lane for prose-wrapped or malformed finals. (2) The separate extract request now compiles the same prompt-cache hint the loop turns compile (RV2006 posture: explicit-caching adapters only, transport-level only), so the repair lane's re-sent prefix reads from cache instead of re-paying the input rate. Two mutation probes pin the ride-along guard and the cache compilation.
23fd0e0: The stale-doctrine corpus class and the proactive sectional reminder (RV3909, the fourth comparison experiment). The corpus gains
stale-doctrine-echo: a draft echoing a DOCUMENTED doctrine while the pool holds the diverging source fact, both sides cited, the experiment's decisive failure shape ("immutable after start" echoed from a guide six weeks stale into a pool that never carried the source side); the honest formulation naming the override door is pinned as a test-side control (the source-claim pairing is polarity-blind by design, and the exoneration belongs to the judge, who now holds both sides). The sectional repair round's prompt gains a deterministic evidence-discipline reminder (the experiment's rewritten section birthed two new evidence-grade offenders that the RV3801 patch then healed; a prompt line is cheaper than a healed failure), present only under the sectional block so every other prompt stays byte-identical; the kit's sectional scenario pins the line present in the round and absent from the initial composition. Two mutation probes pin the reminder and the class roster.
1.243.0
Minor Changes
- 746d1f4: The finish loop performs the evidence-grade prescription host side (RV3801). The third comparison run died fail closed twice on one failure class: sentences in the graded register with no artifact, whose verdict already told the model exactly which sentences to fix and exactly which id to write; the initial composition spent the mechanical pool on it, and the repair round's candidate hit it again with nothing left.
evidenceGradeValidator, with the runtime'srunIdin hand, now attaches structured repair hints to its failure (FinishRepairHint: the offending sentence's exact offsets and bytes, and the prescribed insertion), and the finish loop, when EVERY failure of a string candidate carries hints, applies the edit itself: the id lands inside each offending sentence before its trailing terminator, every other byte stays identical, and the FULL validator set re-judges the patched document. A surviving patch is an accepted verdict with no provider wire and no repair spent; the decision journals it (deterministicRepair: before and after hashes, the patch windows, the healed failures), the healed failures still feed the HOST VALIDATION LESSONS block, and everything short of a surviving patch falls through to the ordinary model repair pool with the original verdict bytes. Masking is excluded by construction: the claim judge rules on the PATCHED document, so an inserted id can satisfy provenance mechanics but never protect a false claim from the semantic pass. The fault kit gainsdeterministic-provenance-patch(the adversarial arc on the real engine: a false positive production claim healed mechanically, then caught semantically, the lesson carried into the round), andvalidator-guidance-conflictnow pins the c3 trap healing in ZERO model repairs with the guidance bytes journaled on the healed verdict. - 009b29c: The convergence hold grows its mechanical leg (RV3802). RV3701 holds the repair round's verdict money and RV3602 gives the round its own mechanical pool, but the one repair turn that pool can grant was funded by nothing: the third comparison run's round entered exactly that turn's price short of certainty. The round now holds a second named leg beside the verdict money from the moment it is admitted, sized from the declared
finishValidation.estRepairCostUsdfirst (a new opt, refused typed unless a nonnegative finite number), else from the run's own observed last mechanical repair window (lastMechanicalRepairCostUsd, a new pure fold over the journal's synthesis candidates, which also gainspanSeqso the pairing never crosses invocations), else zero and inert. The leg joins the projected admission sum and both remainders (repairReserveUsdon the account state and view), a refusal names BOTH legs in its printed arithmetic, and the release is STAGED: the mechanical leg frees at the round invocation's first journaled finish verdict (a repair verdict is about to spend it on the granted turn; an accepted one never needed it), while the verdict leg lives until the judge dispatch as before. The fault kit gainsrepair-round-mechanical-reserve(the ceiling where the round could pay its composition and verdict but not the granted repair: pre dispatch refusal, both clauses named), and two mutation probes hold the admission sum and the staged release. - 1674cbe: The claim repair round is sectional when it can be exact (RV3803). The third comparison run's round regenerated the whole 43k character document to consume findings living in a handful of sentences, inside a tail that was 80.1 percent of the run's wall. The round now plans its repair before dispatching (
sectionalRoundPlan, exported): each judged finding's excerpt is located in the accepted pre-repair document through a collapse-aware scan and owned by the nearest H2 heading above it; when every excerpt locates and the markers are unique, the round's prompt retains the accepted document and asks for ONLY the target sections through the RV808b splice vocabulary, the host splices the resubmitted bodies into the retained document with every other byte identical, and the FULL validator set plus the final judge rule on the spliced whole. Mechanics refusals journal nothing and spend no repair; the model may still resubmit the full document; and every inexact plan (no headings, duplicated markers, an unlocatable excerpt, no finish contract) falls back to the FULL regeneration, byte for byte the historical round. The fault kit gainssectional-repair-round(byte identity of untouched sections, whole-document judging, no mechanical repair spent) andsectional-repair-round-fallback; two mutation probes hold the splice and the fallback. - bd096bc: The cost report gains the byScope rollup (RV3805). The children versus whole workflow cut used to require hand-aggregating invoice rows (the third comparison analysis did exactly that to say the children cost $2.75 of the $5.58 run);
CostReport.byScopenow carries one addressable row per journal scope under the same net inclusion policy astotalUsd, so the rows sum to it, on both builders through one rule (scopeBucket): the root's OWN scope is the empty string by construction, present data rather than an absence, so it folds under the namedrootbucket; children keep their scope strings verbatim; andunknownstays reserved for a scope that is truly missing, the RV3604 fallback. Live accumulation and the pure journal fold agree by construction, abandoned subtrees contribute zero exactly like the net total, and one mutation probe holds the parity.
1.242.0
Minor Changes
- 6e3438e: The claim repair round pays for its verdict up front (RV3701, the third comparison experiment's arc). The round is a two invocation bargain, and admitting its composition on money that cannot also seat the second judge pass buys a candidate nobody can rule on: the budget now holds the verdict money (a new
convergenceReserveUsdhold with exactly the synthesis reserve mechanics: counted by projected admission and the layer-2b clamp, released to the pass it was held for) from the moment the round is admitted until its judge dispatches, sized from the declaredclaimConsistency.judge.estCostfirst (the same figure that pass reserves at admission, so the guarantee is exact) and else from the run's own observed post draft judge price. A round the budget can only start now refuses through the honest pre dispatch decline before any wire call. And when the verdict still cannot be ruled after a dispatched round, the typed failure carries the round context (roundDispatched: true,repairsUsed: 1,preRepairHash, the unconsumed findings) instead of describing a draft death while a paid repaired candidate sits in the journal. - ba5cf67: The host rejection becomes legible at the span level (RV3702, the third comparison experiment's arc). The third comparison run's reader saw the repair round's composition span end
cancelledwith both wires fine and had nothing to name the layer split. The finish contract's final rejection now aborts with the exportedFINISH_REJECTION_ABORT_REASON, and the settle layer stampshostRejected: trueonto the terminal agent entry (a policy field, replay carries it) and the liveagent:endevent; a defective throwing validator aborts with its own distinct reason and never stamps, because a host defect is not a verdict on the candidate. Both surfaces of the critical path cut count the stamps ashostRejectedSpans(unconditional, zero when none), and the invocation table's rows carry the flag, so a reader can tell a document refused by host validation from a provider failure without a journal dig. - c2d1531: The price table provenance grows its content tail (RV3703, the R11 remainder of the third comparison experiment's arc). Every pinned pricing segment, and the snapshot's top level, now carries
rowsHash(sha256 over the canonical JSON of the pinned rows) and theratesVerifiedAtfreshness range of its dated rows (oldest and newest, absent when no row is dated). The version string is a label the table author chose, and the arc held a price defect a label cannot expose: the hash is the content, so two tables sharing a version string but disagreeing on rates are distinguishable in any stored export, and two folds of one journal always derive the same hex. Computed at read time from the pinned bytes: the journal is unchanged and every existing pin gains the tail; invoice provenance and the CLI pass the segments through unchanged.
1.241.0
Minor Changes
- dbcdd24: The candidate milestones ride both critical path surfaces (RV3605). The third comparison run composed a mechanically accepted candidate at its 103rd journal seq and failed typed roughly 25 minutes later; the latent document its judge later scored 6.65 existed the whole time, and nothing on any timing surface said WHEN it materialized, so the analysts dug spans by hand.
reduceCriticalPathandcriticalPathFromJournalnow reportfirstCandidateMs(run start to the first completed composition-side synthesize span's end, when a candidate deliverable first existed) andlastCandidateMs(the same anchor to the last one), classified by the same one classifier as the RV3404 stage split, so both surfaces read the same run identically by construction. On a terminal carryingdeliverableAccepted: truethe last milestone is the time to the accepted deliverable; on a failed run it is when the last losing candidate settled, and the docs say to pair it with the acceptance verdict instead of reading latency off an error terminal, the comparison rule the third experiment wrote down. The journal side needs one segment (wall figures anchored at the first stamp) plus the full labelling condition of the split (an unlabelled span could be a judge, and a judge is not a candidate); absent otherwise, never guessed. - 7ae7243: The cost fold names its fallback buckets (RV3604). The third comparison run's report read
byPhase {"": 5.58}for the whole run and a''agentType bucket beside the named ones: the journal fold's phase fallback WAS the empty string, and the agentType?? 'unknown'fallback let an empty string straight through, so the report minted keys no downstream table can address. One exported rule now covers every path:attributionBucketfolds absent AND empty phase and agentType under'unknown', applied at the two report boundaries, the journal fold and the exported live builder (which normalizes and MERGES the accumulated live keys, a host supplied''beside an existing'unknown'becoming one bucket), so live spend and the replay accumulation of a resume land in the named bucket through the same boundary the fold enforces. The sum invariant holds on every surface: every breakdown still sums tototalUsd, live, replayed and folded alike, andCostReport.byPhase/byAgentTypedocs state the named fallback. The span level provider versus host outcome marker considered for this train stays a recorded candidate: the terminal already carries the machine truth underfinishValidationsince RV3601, and agent span status vocabulary is its own contract. - 4f832c4: The mechanical repair pool belongs to one composition invocation (RV3602).
finishValidation.maxRepairsused to count non accepted verdicts run wide, so the bounded claim repair round (RV3307) entered with zero mechanical retries whenever the initial composition had spent its own, and under the default bound of one its first regression was final by construction; that arithmetic is how the third comparison run died honest but unconverged with $1.42 of headroom left. The pool now restarts at each composition dispatch: the boundary is the journaled verdict count at dispatch (replay derives the identical index from the identical prefix, no new journal fields), the cycle 73 contract generation rule still applies on top, and validators bound to the coordination loop keep the run wide reading byte for byte, one loop being one invocation. Worst case stays bounded: at most two invocations (the initial and one repair round), each granting at mostmaxRepairsrepair turns; preflight's RV3402 working room term already prices the round at the declared synthesis reserve, which is the host's estimate of exactly one invocation with its repairs, and the RV2504 reserve tail sizing needs no doubling (comments and guide now say so). The fault kit gainsrepair-round-own-pool: the frozen third comparison sequence carried to the convergence the old pool made impossible, verdicts repair/accepted twice withrepairsUsedrestarting at the boundary. - 7452d3d: The bounded repair round keeps the lessons the run already bought (RV3603). The third comparison run's repair round regressed provenance, the exact failure class the initial composition's mechanical loop had fixed 18 seconds and $0.16 earlier, because the round is a fresh invocation with no memory of exchanges it never saw. The round's prompt now carries a
HOST VALIDATION LESSONS:block besideCLAIM CONTRADICTIONS:, folded only from the journaled finish validation failures of the current contract generation (validator names and reasons, deduplicated, journal order), so a resume re derives identical bytes. Present exactly when the prompt already carries judged findings and at least one rejected attempt exists: the initial composition predates any findings and a clean history folds nothing, so every existing prompt stays byte identical. Capped atFINISH_LESSON_CAP_CHARS(2000) with the dropped row count named, never silent. Therepair-round-own-poolkit scenario now also pins the lesson riding the round's prompt and absent from the initial composition's. - a4e22bf: The repair round's terminal names which death occurred (RV3601). The third comparison run's bounded repair round dispatched, paid two wires and produced a candidate its own finish contract rejected, and the terminal read
could not dispatchwithrepairsUsed: 0beside a null judge meta and null findings. A throw carrying theorchestrator_finish_validationsource is now its own class: the message names the dispatch and the host rejection, data carriesroundDispatched: true,repairsUsed: 1, the judge meta beside the findings, and the finish verdict facts verbatim underfinishValidation(the failed validators with reasons,candidateHash,candidateChars, mirrored from the decision the journal already holds; the typed finish failure itself now carries the candidate identity too). The true pre dispatch decline keeps its frame and gains the judge meta plusroundDispatched: false. The engine liftsclaimContradictionsonto RunOutcome, the journaled settle andrun:endbeside the meta, from the acceptance envelope or the typed error data alike, under the same defensive posture as the meta lift; the compact terminal envelope keeps the meta alone, itsfindingscount standing in for the details. The fault kit gainsrepair-round-host-rejectiondriving the arc end to end on the real engine. - 82df4af: Two hygiene defects the 181st session tripped over, made structural (RV3606). First,
pnpm --filter <package> testexited 0 silently for every workspace package: no package declared a test script and pnpm treats an absent script as a no-op, so a targeted test command was structurally incapable of failing. Every package holding*.test.tsfiles now declares"test": "pnpm -w exec vitest run --project <its name>", delegating to the single root Vitest config through its project filter (docs/11 still forbids per-package Vitest configs; the script adds an entry point, never a config), and a newscripts/package-test-scripts.test.mjsgate keeps the invariant for future packages, including refusing a script that selects a neighbor's project. The one documented exemption is@rulvar/compat: its published artifact is immutable (the compat-immutability gate compares packed bytes against the registry), so its package.json cannot gain a script until a real compat release; its single test still runs in the root suite. Second, the RV508 exactly once tombstone judged link TARGETS as claims: the durability registry's own anchor slug carries the vetted phrase, so linking#at-least-once-dispatch-exactly-once-payfrom any page outside the allowlist tripped the sentinel and pages linked the bare page instead, making the one vetted claim unaddressable. The sentinel now cuts[text](target)targets, autolinks and bare absolute URLs before judging, in markdown and source comments alike (an address is a quotation, not a claim), while link TEXT keeps being judged; thecost-auditrow in the CLI guide links the precise fragment again.
1.240.0
1.239.0
Minor Changes
- 74ce99a: The durable wire receipt (RV3405): the payment evidence of the at least once window becomes loss proof and reconciled, in three layers. The billing seam's return type widens to
void | Promise<void>and the loop AWAITS a returned promise;defaults.billingReceipts: 'awaited'makes the ctx layer return each RV2008 receipt append so it lands durably before the turn proceeds (the RV601 intent before effect precedent), at the cost of one journal IO await per wire call; a failed append still degrades loudly to the terminal lane and never fails the run; the default'async'stays byte identical. The invoice gains theorphanedReceiptslane: receipts of agents whose TERMINAL record set does not cover them, the real money a crash between the receipt and the checkpoint makes the resumed terminal forget; coverage is decided by response id whenever either side carries one (a resume redispatch reuses the ordinal, and reading the replacement as the orphan would absorb the double payment the resume honestly made), else by the full coordinate plus byte equal usage; summed apart from the settled totals exactly likeunsettled. AndreconcileStatementaccepts the invoice's receipt lanes: a per request statement row matching a receipt id reports underreceiptMatchedRows/receiptMatchedUsdinstead of counting foreign, its dollars never entering the totals, the coverage,settleableormonetarySettleable, because money the run did not settle must not close, it must be legible. Probes: the-awaited-receipt-blocks-the-next-wire, the-orphan-is-decided-by-id-evidence, the-receipt-join-explains-the-statement-row. - ccd0665: Preflight prices the claim consistency posture (RV3402). The input mirror gains
claimConsistency.onFoundandclaimConsistency.stage, and the static tail arithmetic now counts passes, not declarations: theorchestrator-working-roomfinding seats the judge estimate across the worst case pass count ('both'is two, an armed'repair'adds one more) plus one repair round composition priced at the declaredbudget.synthesisReserveUsd, and its consequence clause names the truth of the armed posture (a declined judge under'fail'or'repair'stops the run typed, RV3307, instead of degrading to the journaled verdict). Thetail-spawn-budgetcount gains the same passes and the round's composition, and spawns the judge off the configured pass itself, estimate declared or not. Pairingsorchestrate()refuses at intake (repair at the draft stage, repair without a synthesis, carry at the final stage, RV3301) surface asclaim-posture-refused-at-intakeerror findings: the run would refuse to start, and a planner should read that beside the budget findings instead of meeting theConfigErrorlive. Undeclared postures keep every reading byte for byte. Probe: the-armed-round-is-priced-in-passes. - 0c5ce21: The orchestration modes guide documents the bounded repair round (RV3401): a new section between the claim consistency pass and the assurance posture explains when to choose
report,carry,failorrepair, the intake contract ('single'synthesis, stage'final'or'both'), what one round costs, the fail closed edges (an undispatchable repair round, a dead or declined judge under the armed posture), and what the envelope and the typed failure payload carry (repairsUsed,preRepairHash,repairedHash). The assurance posture section points at the round as the armed polarity with one bounded correction. Docs only: no runtime change. - 0616934: The post fan in tail becomes legible on both surfaces (RV3404). Both critical path folds gain the stage split of the judge wall (
draftJudgeMs,finalJudgeMs: the exact label is the draft pass, every suffixed variant is a post draft pass, the final judge and the repair re-judge included) and span counters (compositionSpans,judgeSpans: two compositions in one run is the legible signature of the bounded repair round, RV3307), decided by ONE exported classifier,claimJudgeStageOf, the RV3302 doctrine extended from the judge predicate to the stage. The journal fold additionally gains the window itemization a journal CAN answer,postFanIn: the union of settled synthesize spans clipped to the window (synthesisCoveredMs, computed through the same exportedunionOfIntervalsMsthe live RV710 decomposition uses), the clipped halves under the same all or nothing labelling condition, andunaccountedMs, the window time no settled synthesize span accounts for, deliberately NOT namedresidueMsbecause the coordinator's tail time lives in it here and the live residue subtracts that. On the journal side every new field keeps the absence doctrine: absent where the stamps cannot answer, never zero. Probe: the-stage-classifier-holds-the-split.
1.238.0
Minor Changes
- cf00947: The bounded post judge repair (RV3307), the honest carry for the final stage. RV3301 made
stage: 'final'withonFound: 'carry'refuse, because the final pass has no prompt left to ride;onFound: 'repair'is what that host actually wanted: when the final claim consistency judge names findings, they ride ONE more synthesis invocation (the same CLAIM CONTRADICTIONS block, over a prompt that now lies ahead again), the repaired document is judged again, and only a clean second verdict settles. Findings that survive the round fail the run typed (source: 'orchestrator_claim_consistency', withrepairsUsed, the pre repair and repaired hashes, and the acceptance snapshot), a repair round that cannot dispatch fails the same way, and a dead or declined judge under the armed posture fails like it does under 'fail', because a gate armed to repair must not pass silently. 'repair' needsstage: 'final'or'both'and a 'single' synthesis (ConfigError otherwise); the draft pass keeps 'carry'. The headlineclaimConsistencyMetadescribes the last judged document,judgedHashequal to the shippeddraftToFinal.finalHash, and the first verdict stays readable in the journal as an ordinary judge entry. - c7b9382: One declaration for the shape a host prompts for and gates on (RV3308). The 2026-08-12 comparison run drifted exactly at this seam: the harness prompt named one heading while its finish contract named an older one, the host accepted its own contract, and the common audit refused the answer; separately, the answer's "all publishable packages" table dropped four of seventeen names under a passing shape contract, because no validator could see an enumerable universe.
requiredMentionsValidator({ terms })holds every declared literal against the finish text and names the missing ones with the universe size.OutputContractManifestplusmanifestValidators()andrenderContractRequirements()derive the gate and the prompt block from the same object, headings, word bounds, citation floor and mention universe byte for byte, so the two surfaces cannot disagree by construction. - 88aea96: The ceiling headroom floor can block (RV3310). RV3208's
ceiling-headroom-thinfinding was always a warning, and the 2026-08-12 comparison harness threw on error findings only: its declared 2 percent floor held against a 2.857 percent plan and the class nobody gated on never spoke.orchestrator.ceilingHeadroomSeverity: 'error'makes a breached floor blocking for exactly such hosts; the default 'warning' keeps RV3208 byte for byte, and the literal fails closed at intake. The orchestration guide gains the assurance posture section: the polarity flip (stage: 'final',onFound: 'fail',coverageTargetwithonLowCoverage: 'fail', declared criticals, run facts, a 10 percent headroom floor at error severity) for runs whose output a consumer acts on, beside what the terminal then proves. - 6da8d05: The evidence call floor accepts a journal observed prior (RV3309).
EvidenceContract.calibrationcarries thecallsPerEntryfiguretoolCalibrationFromJournalfolds from a prior run of the same profile (fractional on purpose) plus asourcelabel;preflightEstimatecomputes the evidence call floor from the HIGHER of the declared estimate and the prior, never the lower, and names a raise in anevidence-estimate-below-observedinfo finding. The 2026-08-12 comparison run observed 4.211 calls per entry where the default estimate says 3: a floor computed from the wish is how an evidence contract meets a cap it cannot actually fit. Contracts without a calibration are byte identical, integer floors included. - eae5c4c: Every invoice row carries the same usage envelope, and the CLI names its billing basis (RV3311). The 2026-08-12 comparison run's invoice had 77 rows with
reasoningTokensand one (the judge verdict extraction) without, so a FinOps consumer folding the column had to know that absence meant zero on exactly one row shape: rows now always carry the field (0 when the provider reported none) and the usage object is detached from the journal entry it was read from. The run summary and the inspect cost view printbilling basis: locally-estimated (a local estimate, never a provider statement)beside the dollars, the audit's ask said out loud on the surface an operator actually reads.
1.237.0
Minor Changes
- 9d6a279: The statement reconciliation names its dollar ground (RV3305, RV3306).
settleabledeliberately never required a dollar claim, so a usage-only request export that matched on response ids and token counts readsettleable: truewhile carrying not one dollar of provider evidence, the 2026-08-12 audit's counterexample.StatementReconciliationnow carriesdollarCoverage('complete' when every matched export row or component line claims money, a row total or a component split; 'partial'; 'none') andmonetarySettleable, which issettleableAND complete dollar coverage, the predicate to gate monetary closure on;settleableitself is byte identical and its docs now say out loud what it does not require. The docs honesty pair rides along: agents.md no longer states an unqualified never-pay-twice (dispatch is at-least-once and one partial turn is the documented worst case, matching durability.md), and providers.md documents the new fields. - 49a98f6:
claimConsistency.stage 'final'withonFound: 'carry'is now a ConfigError at intake (RV3301). The carry posture rides the 'single' synthesis prompt, and the final pass runs strictly after that prompt was built and consumed, so the pair read as a gate while behaving as 'report': the 2026-08-12 comparison run settled ok/complete with a contradiction its own final judge had already named. Understage: 'both'the carry keeps binding the draft pass, whose findings the synthesis prompt still lies ahead of, and the final pass reports;stage: 'draft'with 'carry' stays byte identical. Hosts that armed the refused pair should pick 'report' (the previous effective behavior, now named), 'fail', or a carried draft pass via 'both'. - a734ca0: One judge label predicate for both critical path surfaces (RV3302). The final claim consistency pass dispatches under
claim-consistency-judge-final(RV2509); the livereduceCriticalPathcompared the span label for exact equality while the journal fold accepted the suffix, so the 2026-08-12 comparison run reportedsemanticJudgeMs0 on the live surface, with the whole 272923 ms window read as final composition, while the journal fold correctly split 224864 against 48059. Both folds now classify through the exportedisClaimJudgeLabel(), and a parity test pins that run's shape to the same split on both surfaces. - deb406f: The terminal envelope carries the semantic outcome (RV3304). The 2026-08-12 comparison run settled ok/complete over a contradiction its own final judge had named, and neither the HTTP response nor a restarted reader could see the acceptance verdict a live SDK consumer held:
TerminalEnvelopenow mirrorsdeliverableAccepted,resultAvailable,acceptedArtifactRefand a detachedclaimConsistencyMetafrom the outcome, plus the run's declaredconfigFingerprint(RV3210), so the surface a consumer gates on says what was verified, over which document, what the judge found, and under which configuration.OrchestrateClaimConsistencyMetagainsfindings, the judged contradiction count, present exactly when the judge settled ok, because the meta travels alone onto surfaces the findings array never reaches. The journaled run settle has recorded the whole lift all along;lastRunSettlenow reads the semantic fields back defensively (a malformed meta drops whole, absence means NOT RECORDED), andpersistedTerminalEnveloperebuilds the same envelope a live consumer held,GET /runs/:idincluded, with zero server changes. Everything is additive: envelopes from runs that declared or judged nothing are byte identical.
1.236.0
Minor Changes
- 26306ea: The config fingerprint (RV3210), the honest answer to
hashWorkflowBody's closure blindness the 2026-08-11 experiment confirmed: the body-text hash cannot see captured values, so two byte-identical bodies over different closures pin identically.RunOptions.configFingerprint(an opaque host string, at most 512 characters) records in RunMeta at genesis;ResumeOptions.configFingerprintasserts it back, and a mismatch refuses the resume typed BEFORE ownership, meta writes, or any append, with no posture knob, because supplying the fingerprint IS the assertion. One-sided states warn instead of failing (RULVAR_RESUME_FINGERPRINT_UNCHECKEDfor a recorded pin the resume ignores,RULVAR_RESUME_FINGERPRINT_UNRECORDEDfor an assertion the run never declared): absence means NOT RECORDED. Runs that declare nothing are byte identical, and the preferred pattern remains closing over nothing and passing config through args. - 709b942: The admission cliff becomes a one-field read (RV3208). Preflight already named the whole-wave
requiredMinimumCeilingUsd, but the DISTANCE to the declared ceiling was left to the operator's subtraction: the 2026-08-11 experiment ran its whole workflow on a $0.20 remainder of a $7.00 ceiling (2.86 percent) that a small pricing or context drift would have refused at admission. The admission block now carriesceilingHeadroomUsdandceilingHeadroomShare(present exactly when both sides are recorded, absence means NOT RECORDED), and the opt-inorchestrator.minCeilingHeadroomSharethreshold turns a thin share into theceiling-headroom-thinwarning finding. The default threshold is 0, so existing preflight reports gain the two fields and change nothing else.
1.235.0
Minor Changes
- ba4e10d: A lost journal append now fails the settle closed (RV3201). Deterministic shims journal fire-and-forget through the serialized append queue, whose chain swallows rejections to keep later appends flowing, and the settle barrier used to swallow the flush verdict on top, so a failed persist was visible to nobody: the run settled
ok/completeover a journal missing a record it believes it wrote, and a resume regenerated a differentctx.random()value without one provider call. The first lost append now latches in the Replayer,flush()rethrows it as the new typedJournalIntegrityError, and the engine converts a would-beok(orsuspended) outcome into anerrorterminal whose settle decision records the converted status. Runs that never lose an append are byte identical. - 172402b: The MCP discovery deadline binds the page call itself (RV3205).
timeouts.discoveryMswas checked only between pages, so a hung or slow CURRENTtools/listcall was unbounded by it and the last (or only) page never paid the deadline at all: a single 86 ms page sailed under a 10 ms cap. Every page call now carries the smaller oflistMsand the remaining discovery budget as its wire timeout, a page cut at the remaining budget reports in the discovery deadline's vocabulary with the transport failure as its cause, and sweeps that never approach the deadline are byte identical. - 2ecd787: The extension finish gate (RV3202).
OrchestratorExtensiongainsfinishGate?(), consulted FIRST on every ordinary coordination finish: a refusal returns as the finish tool's typed error result (nothing journals, no repair spent), so the model resolves the named blockers and finishes again; the forced-finalization and synthesis finishes are never gated. PlanRunner implements it:finishis now refused while any plan node is ready or running, with the stragglers named, because quiescence participation alone gated only wakes and a root could settle a bare ok while the exit barrier cancelled a running node.allowEarlyFinish: truerestores the old behavior deliberately. Runs without an extension finish gate are byte identical. journal-shape-revision: the oscillation-freeze cassette re-recorded for the gate's live path (the scripted finish over the still-running frozen-signature node is now refused typed, and the scenario closes the straggler deliberately before finishing); already-journaled entries replay verbatim, so existing journals stay valid. - e20a5e9:
record_evidencebinds the quote to the cited lines (RV3206). The quote check searched the WHOLE loaded file, so a quote taken from the next line over verified against a citation it never belonged to, and every evidence floor counted the misbound entry. With bothlinesandquotegiven, the quote must now appear verbatim inside the cited range; the refusal tells the model to widen the range or fix the citation. Quote-only entries keep the whole-file check (with no lines claimed there is no location to bind), lines-only and file-only entries are untouched, and correctly bound citations are byte identical. - c70def0:
strictPricingenforces the presence thePricingtype promises (RV3204). The gate's rate checks were conditional on each field being present, so an untyped or JSON-loaded{}price row satisfied all of them and the downstream fold priced it at a zero debit: a "strictly priced" dispatch that debited nothing against every ceiling. UnderstrictPricinga resolved row must now CARRY finite non-negativeinputUsdPerMTokandoutputUsdPerMTok; a missing rate refuses typed before the wire, naming the field, withallowUnpricedunchanged as the explicit exception. Cache rates and long-context tiers stay optional exactly as the type declares them, and rows that already satisfied the type are byte identical.
Patch Changes
- 98c8691: The RV3205 discovery-deadline rewrap classifies by the SDK's request-timeout code instead of re-checking the wall clock: the re-check raced the SDK's own timer by a millisecond on a slow runner and leaked the raw
MCP error -32001where the deadline vocabulary was promised.
1.234.0
Minor Changes
- 8420c04: The synthesis mode gates (RV3102, the evidenceIndex precedent): every single-prompt surface now refuses typed at intake under
mode: 'incremental'instead of silently rendering nowhere, and the mirror holds. An armedsynthesis.policyFacts,synthesis.runFacts(either form),synthesis.exposeChildResultTools,synthesis.context: 'full', or a declaredsynthesis.limitsunder the deterministic incremental reconciliation is aConfigError, because that mode dispatches no synthesis model at all;synthesis.noteLimitsunder mode'single'(explicit or defaulted) refuses the same way, because that mode dispatches no note invocations, and until now the field was documented as ignored. Inert forms (an explicitfalse, the'digests'default) stay valid in both modes: they promise nothing. The draft-gate family (skipWhenDraftValid,carryDraftGaps,fallbackToValidDraft) was already gated transitively through itsfinishValidationrequirement. A config that used to no-op silently now fails loudly at intake; that is the change, and it is deliberate.
1.233.0
Minor Changes
- 48b5200:
ResumeOptions.bodyHash: 'warn' | 'refuse'(RV3001): the opt-in pin for hosts that treat an edited workflow body as a different workflow. Under the default'warn'an in-process body-hash mismatch keeps the historical design byte for byte: the loudRULVAR_RESUME_HASH_MISMATCHwarning fires and the resume proceeds, because the journal decides replay versus live per content keys and reports orphans honestly. Under'refuse'the same mismatch is a typedConfigErrorraised before ownership, meta writes, or any append, so a refused resume mutates nothing durable. Name mismatches and compiled-source mismatches remain hard errors under either value, and any other value refuses typed before any store read. - 73bc32b: Terminal agent entries journal the durable tool-budget subset (RV3002):
toolBudget: { used, cap? }, the loop's executed-call counter and the effective cap at settle, written whenever the live result carried the pressure snapshot. The counter has always been durable in the terminal checkpoint, but checkpoints are blobs and journal folds read entries only, so observed calls-per-evidence-entry calibration could not be a pure fold. Replay now restoresAgentResult.toolBudgetunconditionally from the entry on new journals, grant-free runs included, with the RV509 decision-backed fields (extensionsGranted,finalizationWindowEntered) merged on top; journals written before the field shipped keep the RV509 decision-conditional restoration byte for byte. Live-only summary fields (unitsUsed,noticesFired,limiter, and the rest) never journal, exactly as before. - e63b743:
synthesis.runFactswidens toboolean | { workflowSoFar?: boolean }(RV3004).runFacts: truekeeps today's child-only RUN FACTS line byte for byte. The object form keeps that line and, underworkflowSoFar: true, appends oneRUN FACTS SO FAR:sibling scopedrun-so-far-at-this-dispatch: the same counters folded over the settled children PLUS the orchestration's own settled internal spans as of the composing dispatch (the coordination dispatch, claim judges, synthesis notes, and any earlier settled composition), withchildrenandinternalSpanscounted separately. The nineteenth benchmark quoted child-only totals beside the whole-run invoice and invited a false drift reading; the sibling closes most of that gap from inside the prompt while its suffix names what stays outside (the composing dispatch itself and anything still running), so the terminal envelope and invoice remain the only whole-run truth. Folded from replay-stable settled material in deterministic settle order (a resumed composition re-derives identical bytes, zero live calls); dollars stay absent for the same replay reason; unknown keys and non-boolean values refuse typed. - ef45da7:
toolCalibrationFromJournal(entries)(RV3003): the observed calls-per-evidence-entry calibration as a pure fold over the journal. The ninth comparison run declared the stockestCallsPerEntryof 3 behind its preflight call floor and its workers actually spent 5.5 executed calls per recorded evidence entry, a number that had to be recomputed by hand from worker transcripts. The fold pairs the RV806 evidence verdict with the RV3002 executed-call counter on each terminal agent dispatch:observedrows carry both sides and their per-dispatch rate, theaggregatedivides summed calls by summed entries across observed rows only (unproductive calls included; a paired row with zero recorded entries keeps its calls visible and carries no ratio), and the unpaired sides are named per RV1209 (evidenceOnlyfor pre-RV3002 journals,budgetOnlyfor counters with no declared contract,unobservedfor neither), never counted as zero.childRostersFromJournalchildren additionally carry thetoolBudgetsubset beside their evidence verdict, so a post-mortem reads spend beside the verdict without a second fold.
1.232.0
Minor Changes
- 1440410: The synthesis candidates a journal already holds (RV2902).
synthesisCandidatesFromJournal(entries, priceUsd?)folds each journaled finish verdict into a candidate with the window of wall, wires, usage, and per-call priced cost that produced it, so the cost of a repair is separable from the cost of the candidate it repaired: the one question the ninth comparison run's frozen telemetry could not answer, with both candidates inside a single 177 second synthesize span priced as one number. Sequence numbers partition a settled span's incremental billing rows between its verdicts exactly; the fold refuses to price a window when the rows do not cover the terminal's own call records (they append asynchronously by design), counts verdicts outside every settled synthesize span instead of inventing candidates for them, and reports wires after the last verdict as an attributed-to-nobody tail. No new journal fields. - 6e467f4: The downloaded billing export parses fail-closed (RV2908).
statementRowsFromDelimited(text, { delimiter? })turns the CSV/TSV a provider console hands a host into the header-keyed rowsstatementFromRowsconsumes, closing the last manual step between a downloaded export andreconcileStatement. The library still hard-codes no provider's format: the host owns the column map, this owns only the strict delimited grammar (RFC 4180 quoting, CRLF or LF records, one trailing newline ignored). A ragged record, a torn quote, a stray quote in an unquoted cell, and an empty or duplicated header name each refuse typed with their line, because a column shifted one to the left prices outputTokens as dollars and calls it evidence. - e3bcab2: The engine labels its own synthesize dispatches (RV2901).
criticalPathFromJournalsplits the synthesize bucket into final composition and claim judge only when EVERY synthesize span carries a journaled label, and the comparison run's journal refused that split because the final composition dispatch stayed anonymous while the claim judge was labelled. The final composition now dispatches under the new exportedFINAL_COMPOSITION_LABELand incremental synthesis notes underSYNTHESIS_NOTE_LABEL, both policy on the attribution facts and never identity, so the journal of a fresh run reports the split by construction while journals written before the labels keep refusing it honestly. - b55a0f7: The claim-consistency pass sizes itself from a declared coverage target (RV2903). The ninth comparison run judged 43 of 115 citing sentences because its host guessed
max: 56and the run-fact pass cut 30 candidates to an unraisable default of 8: the honest 'partial' grade was a constant's echo, not a policy.claimConsistency.coverageTarget(a share in (0, 1]) makes the goal the input: the pairing selects coverage-first (every critical candidate, then one pair per still-uncovered sentence in draft order until the target is met, withmaxkept as a hard ceiling andtruncatedmeaning exactly that the ceiling cut wanted selection), the run-fact pass judges every matched candidate instead of the default bound, an undeclaredminimumCoverageRatiodefaults to the target so the RV1809 floor machinery (lowCoverage,onLowCoverage, the strict CLI exit) enforces the same number that sized the pass, and the meta echoescoverageTargetso a persisted outcome says what its coverage was held against. Unset, every selection reproduces byte for byte.
Patch Changes
- 0b14293: Three truths the ninth comparison audit caught, fixed with a tombstone (RV2905). Two guide pages still claimed "the current release enforces only the in-process tool executor" (one adding that subprocess and container "fail at registration") after that class was fixed on the architecture page: both now state the seam, a non-inprocess executor tag is a typed ConfigError at spawn time until a matching ToolExecutorProvider is registered under
EngineOptions.executors, and@rulvar/executorships both references. The roles.ts header now says its firing predicates cover six OF THE SEVEN invocation roles ('synthesize' is dispatched explicitly by the orchestrator, never by the trigger protocol). And because the executor claim already returned once after being fixed, the docs lint gains a tombstone sentinel forbidding it everywhere the lint reads, docs prose and source comments alike.
1.231.0
Minor Changes
4eb4b56: The critical path is readable OFFLINE (RV2803).
reduceCriticalPathfolds the shape of a run's wall clock out of the event stream, and a post-mortem has no event stream: the process that emitted it is gone, and what a paid run leaves behind is a journal. SopostFanInShare, the one number the comparison series steers by (RV2210 wrote the targeting rule around it), was a live-only reading, and the archived runs it was meant to judge could not answer for themselves.criticalPathFromJournal(entries)is the same reading taken from what survives. Every ingredient was already written down: a terminal agent entry carries its own span (startedAtcopied from the running entry it closes,endedAtstamped at the settle, so the interval is exact rather than reconstructed) andcostAttribution.rolesays whether the span was coordination, synthesis, or a worker. Nothing is re-derived and no validator runs again, so a journal from any prior version reads exactly as well as today's.Two things it refuses to claim, both because the alternative is a confident fiction:
- The wall figures (
runWallMs,postFanInMs,postFanInShare,synthesisShare) are ABSENT for a journal holding more than one segment. A killed run's first and last stamps are separated by however long the operator took to resume, and that difference is not a duration of anything.segmentsrides the reading so a consumer can see which case it is in. - The
synthesizesplit (RV1604'sfinalCompositionMsandsemanticJudgeMs) needs the dispatch LABEL, which rode the event stream alone.CostAttributionFacts.labelnow carries it: policy, never identity, absent on every unlabelled dispatch, so unlabelled runs journal exactly what they did before. The split is reported only when EVERY synthesize span in the journal carries a label, because one unlabelled span makes it a guess, and this split exists because a guess here read a 54 second judge as a second final composition.
unclassifiedSpanscounts settled spans whose entry records no role at all, so on a journal older than the attribution facts the worker count reads as a floor rather than quietly absorbing them.- The wall figures (
bc8f09e: The telemetry scope table's promise becomes its gate, and three of its declarations turn out to have been wrong (RV2801).
TERMINAL_TELEMETRY_SCOPEexists so a reader of a killed-and-resumed run never has to reconcile two terminals by hand, and RV2701 made its completeness a compile error. Both halves of that promise were bigger than the gate behind them.The type stopped at depth one.
TerminalTelemetryScopesrequired every key ofRunOutcomeand then admitted nested paths through a string index signature, which requires nothing. Socost.orchestrator.wakesand its four siblings were declared by hand and by luck,cost.usageApprox,cost.abandoned.usd,cost.abandoned.usageApproxandcost.orchestrator.sharewere not declared at all, and the doc promised every path was required. The type now requires every counted leaf undercost(numbers and flags, derived fromCostReportitself, breakdown maps excluded because their keys are data), so a new cost figure does not compile until it says what it counts. That is the RV2701 blindness one level down: a gate whose subject is nested figures cannot stop at the top level.Nothing checked whether a declared scope was TRUE. The two assertions that stood for that restated the table's own literal, so they could only fail together with the table. A doctrine test now suspends a real run on an approval, resumes it to
ok, and holds every declared figure against its own claim over the two terminals.It found three wrong declarations immediately. An outcome's
costiscostReportFromJournalover the replayer's snapshot, and a resumed segment's snapshot holds every prior segment, socost.orchestrator.wakes,cost.orchestrator.forcedFinishandcost.orchestrator.reserveUsedUsdhave always been folded over the whole logical run while the table called them'segment'. They are now'cumulative', which makes the taxonomy true rather than merely complete: every figure an outcome carries covers the logical run, and the only segment-scoped counters are the live-only ones that never reach a journal (the transport retries and the schema-exchange counters on an agent result). A wrong scope is worse than a missing one, because a missing one is noticed and a wrong one is believed.ff9b8c2: The offline child roster names the children the run ABANDONED (RV2804).
childRostersFromJournalpresented a child on a discarded branch exactly like a child whose work the run kept, so a post-mortem reading "four children settled ok" was counting branches the orchestration had thrown away. The money layer has refused that conflation since RV1904:grossUsdkeeps abandoned spend because the provider billed it,totalUsddoes not because the run kept none of it. The roster now says the same thing.JournaledChild.abandonedis present and true exactly when the first-wins abandon projection covers that child's dispatch, subtree coverage included, and absent otherwise, never false (RV1209). It needs nothing that was not already written down: the fold reads the same projection the replayer disposes by, over the same journal, and a child'shandleis the very seq an abandon entry targets, so journals from every prior version answer.rulvar inspectprints the discarded children under the roster it already prints, named by their handles.
1.230.0
Minor Changes
e9bf910: Every terminal field declares its telemetry scope, enforced by the type (RV2701).
TERMINAL_TELEMETRY_SCOPEpromised that a new terminal field cannot ship without saying whether it counts the segment, the logical run, or nothing at all, and the gate behind that promise read the keys of one SUCCESSFUL outcome. A field that exists only where a run FAILED is absent from every such sample by construction, so RV2602'schildrenAtFailure(present exactly when no acceptance verdict exists) shipped straight through it. A table whose whole subject is killed and resumed runs cannot be defended by an outcome that neither died nor resumed.The table's type is now
TerminalTelemetryScopes: every key ofRunOutcomeis required, so an undeclared field is a compile error at the table itself, and a string index signature still admits the nested paths a consumer reads off the same outcome (cost.orchestrator.wakes).childrenAtFailureis declared'cumulative', for the loss-list reason: a resumed segment re-admits every recovered child into the same roster before it dispatches anything new, so the fold covers the logical run rather than the segment that happened to die. Two doctrine tests hold the table against real terminals, one ok and one dead before acceptance, because a key that reaches an outcome without reaching the type would satisfy the compiler and still leave a reader guessing.57bfb38: The child roster of a run that died before acceptance is readable OFFLINE (RV2702).
childrenAtFailure(RV2602) answers "what had the children produced" for a consumer watching the run, and it dies with the process that held it. The settle persists the completion lift and nothing else, so a post-mortem over a journal, which is all a paid run leaves behind, had no way to ask the question at all: not for a run that crossed its ceiling mid-roster, and not for any run in an archive written before the field existed.childRostersFromJournal(entries)is the fold, and it reads what resume reads. Aspawn-admissiondecision names every child the controller judged, with its ordinal, its profile, its verdict and the scope its dispatch pins to; the dispatch and terminalagententries under that scope are the child itself, and the RV806 evidence verdict rides the terminal. Nothing new is written, nothing is re-derived and no validator runs again, so a journal from any prior version reads exactly as well as today's.rulvar inspectprints it: how many children were admitted, how many settled and with what statuses, how many were refused admission, and the ones that settled ok below a declared evidence floor, named by the dispatch seq the orchestrator's own turns used as their handle.Two things it does not claim. It is not the live roster: this reading happens after the RV1903 exit barrier settled the stragglers, so a child the live field called unsettled usually has a terminal here, and an absent status means the journal truly ends mid-flight rather than a child that failed. And it counts CHILDREN: the coordination loop, the synthesis and the judge dispatch through the same
ctx.agent, and only a child carries the spawn admission that pins it to the child scope.
1.229.0
Minor Changes
3370342: The finalization window entry explains a reserve it did not configure (RV2601). With
reserveForEvidenceDeficitthe effective reserve is widened by the outstanding evidence floor (RV1208), and the journaledfinalization_window_entrydecision carried only{remaining, reserveCalls, budget}: a reader after the fact could neither explain a reserve of 25 under a configured 20, nor see that the agent stopped searching owing its ENTIRE floor. The fourth parity run settled exactly there, and reconstructing it took the transcript.The decision now carries
evidenceDeficitandminEntries, exactly when the widening happened. Both numbers are the loop's own, and the same predicate feeds the notice the model reads and the fact the journal keeps, so the two can no longer disagree. Absence is the honest answer that the configured reserve is what bound: a run without the opt-in, without a declared contract, or with the floor already met journals what it always did, byte for byte.The doctrine is the one RV2203, RV2205 and RV2207 already ship under: a number the loop APPLIED belongs in the journal with the arithmetic that produced it, not only in prose addressed to a model nobody kept.
2fb6656: A run that dies before acceptance names what its children produced (RV2602). Every child-naming field on the envelope hangs off the acceptance fold:
childStatusCounts,belowFloorOkChildren,acceptanceChildren, all of them assembled inside the acceptance decision and enriched onto a failure only when that decision exists. A run that crosses its ceiling mid-roster therefore settled withcompletionabsent and said NOTHING about work already paid for, even though every child terminal was in the journal one entry at a time. That is the last row of the deliverable truth table, and the only one where the terminal was silent about spend.RunOutcomeand therun:endevent gainchildrenAtFailure:spawned,settled,statusCounts, thebelowFloorOkChildrenthat settledokunder a declared evidence contract they never met (the fourth parity run's silent worker, sixty one successful tool calls and not one recorded entry), and theunsettledchildren still running when the run gave up. Nothing new is written; it folds the children's own journaled terminals.Three lines draw its boundaries. It reports ONLY where no acceptance verdict exists, live or rolled forward from the journal, so one set of children never carries two folds under two authorities. It is deliberately not called
childStatusCounts, because that name belongs to the policy's number and a fold done by no policy must not borrow it. And it is lifted independently of the completion lift, because that lift bails out the moment there is no completion literal, which is exactly the terminal this field exists for.The roster is frozen at the moment of death, ahead of the RV1903 exit barrier, so it is the roster a verdict would have frozen rather than the one the stragglers land on afterwards; that is why
unsettledcan be non-empty. The error class is preserved exactly and only its data widens, an already-present field is never overwritten, and a run that spawned no child adds nothing.edce170:
rulvar inspectreports the logical run and what the contract refused (RV2605). Two surfaces shipped in v1.228.0 had no consumer in the tool people actually read a run with:inspectprintedentries: N, which over a resumed run is one undifferentiated heap with no boundaries in it, and said nothing at all about finish candidates the declared contract rejected.segments:islogicalRunTelemetry(RV2510) printed: how many segments ran, how each settled, how many entries each appended, and the count of entries that continued PAST the last settle (RV1407) when there are any, because the last settled status is then not the run's last word.rejected finish candidates:lists the RV2507 rows with verdict, size, hash prefix, failing validators, and the blob ref when the bytes were retained, and counts DISTINCT documents beside the row count, so three rows sharing one hash reads as the model serving one text three times rather than as three genuine attempts.lastRunSettlegainsrejectedFinishCandidates. The settle already persists the whole completion lift, so this is a read of what is recorded, not a re-fold and not a validator re-run, and every row is parsed defensively: any malformed row drops the WHOLE list, the same posture the live lift takes, because a partial history read as complete under-reports exactly the runs that misbehaved most, and offline is where nobody can check. A journal that records nothing of the kind reads as NOT RECORDED and both lines stay absent.
1.228.0
Minor Changes
4034fac: The terminal states its deliverable verdict (RV2506).
statussays whether the run RAN andcompletionis the acceptance policy's claim over CHILD statuses; neither says whether the artifact the terminal carries ever passed the declared finish contract. The twenty-fifth comparison run accepted four ok children, failed its synthesis against the same bundle three times, and settled carrying nothing the contract accepted, and the harness scoring it readstatus: 'ok'and could not tell. The answer lived only in the journal, behind a transcript dig.RunOutcomeand therun:endevent gain three lifted fields, computed once and spread onto both surfaces exactly like the completion lift they join.deliverableAcceptedis the contract's verdict on THIS artifact.resultAvailablesays whether there is an artifact to read at all.acceptedArtifactRefis the journal seq of the decision recording the acceptance, so the validators that rendered it and the draft hash they judged are onerulvar inspectaway. Three different decisions answer to that ref, which is why one field is worth having: the acceptedorchestrator_finish_validationverdict on the ordinary path, theorchestrator_synthesis_skipdecision when the RV510 gate settled on a valid draft, and theorchestrator_synthesis_regresseddecision when the RV2505 floor handed a failing synthesis back to its draft. All three are acceptances by the same bundle, and the terminal now says so.deliverableAcceptedis ABSENT, never false, when nofinishValidationwas declared: nothing judged anything, and absence means NOT RECORDED (RV1209). The verdict rides FAILED terminals too, lifted from the enriched error data the way RV2203 carries the pass truth, because the terminal a post-mortem policy must read is precisely the one where the children were accepted and the artifact was not. Malformed values mirror nothing, so a consumer gating on=== truecannot be defeated by a truthy string.The guide gains the truth table over every reading the fields can produce, and the normative consumer predicate written in them.
a54b085: The rejected finish candidates become first-class terminal artifacts (RV2507). A run that fails its contract already tells you the LAST verdict's validators and nothing else: not how many candidates were judged, not whether they differed from each other, not where to read them. The twenty-fifth comparison run rejected three syntheses, and the only way to see them was an external script that re-parsed the whole agent transcript.
RunOutcomeand therun:endevent gainrejectedFinishCandidates, one row per candidate the declared contract did not accept, in judgement order: thecallId, theverdict('repair'when another turn was granted,'rejected'when it was the last), the sha256hashnaming WHICH document drew the verdict, its size inchars, and thefailedvalidator diffs. It is a pure fold over decisions the journal already holds, so a resume re-derives the identical list without re-running a validator, and a superseded contract generation drops out of it exactly as it drops out of the repair budget. The list rides the ok terminal as well as the failed one, because a run that recovered on its second attempt still owes a post-mortem the first, and it is absent when a finish passed first try. One reading it makes possible was invisible before: three rows carrying ONE hash is the model serving the same document three times, a different failure from three genuine attempts.The BYTES are a separate, declared decision.
finishValidation.retainRejectedCandidates(default off) writes each rejected candidate to its own transcript blob at<runId>/finish-rejected/<callId>and puts therefon the row, onetranscripts.getfrom the document;Engine.deleteRuncascades over those blobs like every other run artifact, and the count is bounded bymaxRepairs + 1per finish-validated invocation. The split is the point: identity costs nothing and is therefore always recorded, a copy costs storage and is therefore the host's call. A store that refuses the write costs the run nothing, since the row keeps its identity and drops itsref.Malformed rows drop the whole list rather than a subset, the acceptance-roster posture: a partial history read as complete would under-report exactly the runs that misbehaved most.
9d0a9be: The semantic gate reaches the FINAL artifact, and every verdict names the document it read (RV2509). The claim-consistency pass runs strictly before the synthesis by design, so that a draft contradicting its own pool never pays for a composition. The cost of that ordering was never stated: the verdict describes the DRAFT, the synthesis then rewrites it, and the terminal reported the cleared verdict beside the replaced document with nothing to tell them apart. The twenty-fifth comparison run's judge cleared a draft its synthesis replaced three times over.
OrchestrateClaimConsistencyMetagainsjudgedStage('draft'or'final') andjudgedHash, stamped at the one assembly every exit path of the pass passes through, so acoverage: 'full'can never be read as a claim about the shipped artifact when it was rendered over a draft that no longer exists. The acceptance envelope gainsdraftToFinal(draftHash,finalHash,rewritten, andclaimsJudgedOn) whenever a synthesis is configured:claimConsistencyMeta.judgedHash === draftToFinal.finalHashis the machine test for "this verdict is about the document I received", and it works under the DEFAULT setting, where the answer is usually no.claimConsistency.stagemoves or duplicates the gate.'draft'is the default and is byte identical to the historical behavior.'final'runs the pass after the synthesis over the artifact the run settles on, so an armedonFound: 'fail'stops a run whose composition contradicts the pool it was composed from.'both'keeps the cheap pre-synthesis gate and adds a second judge over the final; the terminal then reports the final pass inclaimConsistencyMeta, because the shipped document is what a consumer gates on, and the earlier verdict in the newclaimConsistencyDraftMeta. A stage past'draft'without a synthesis is aConfigError, since there the draft IS the final.The two invocations of
'both'stay separable: the final judge carries its own telemetry label and a declined admission journals under its own key, so one run can honestly record two different degradations instead of the second reusing the first's arithmetic.be9ef28: Resume telemetry says what it counts (RV2510). A resumed run's terminal mixes two kinds of figure with nothing marking which is which: money and usage are cumulative over the whole logical run (they fold from the journal), the spawn count resumes from the journaled ledger, and
cost.orchestrator.wakes, the schema-exchange counters and the transport retries count ONLY the segment that produced the terminal. The twenty-fifth comparison run was killed and resumed, and turning its two terminals into one honest account of the logical run was hand work over a joined journal.TERMINAL_TELEMETRY_SCOPEdeclares it as one exported table: every terminal field mapped to'segment','cumulative', or'terminal'(not a count at all, but a claim about the run as it stands at this settle, which a later segment can only replace). A doctrine test holds the table against the keys a REAL outcome carries, so a new terminal field cannot ship without declaring what it counts.logicalRunTelemetry(entries)is the aggregate for the whole run: how many segments ran, how each settled, how many entries each one appended, andentriesAfterLastSettle, nonzero exactly when the journal continued past its terminal (RV1407) so the last status is not the run's last word. It adds no journal field and folds only what the settle already records, so it reads journals written by every prior version exactly as well as today's, and no existing journal changes by a byte.The replay dedup is the design. The aggregate deliberately carries no money and no usage: those already fold from the WHOLE journal, and re-summing them per segment would count every replayed operation once per segment that replayed it. What it reports instead is a PARTITION of the journal at the settle boundaries, so nothing is counted twice by construction, and the per-segment figures a terminal carries can finally be read against the segment that produced them.
1.227.0
Minor Changes
f262e9f: The run's own id becomes an artifact the evidence grade accepts (RV2501).
evidenceGradeValidatordemands that alive-observed,provider billorproduction-provensentence name an artifact IN THAT SENTENCE, andDEFAULT_ARTIFACT_PATTERNonly ever matched apath:linecitation or a ULID behind the literal wordrun. Every other run id was therefore unnameable: the 1.226.0 comparison run carried the idcomparison-rulvar-v12260-aug09-1786272840549, its verdict told the synthesis to state that id, the pattern matched nothing it could write, and the run spent both granted repairs and failed closed on two sentences telling the truth about the run they were part of.FinishValidationInputnow carriesrunId, and the orchestrator runtime supplies it at every gate that judges a finish: the validator-bound finish, the contract draft gate, and theskipWhenDraftValidpre-pass. A sentence carrying that id verbatim as a whole identifier satisfies the grade, and the verdict NAMES the id it wants written, so the repair instruction is executable instead of aspirational while the RV2202 composition warning stands (a run id written beside apath:linecitation is not in the cited window and trades this failure for acited-valueone, so the graded sentence must carry no source citation). The intake is bounded like every sibling: an id shorter than six characters is ignored, because a two character id would satisfy nearly every sentence by accident, the same fail open the empty-pattern guard refuses; the id is credited only as a whole identifier, sox<id>yis never an artifact; and with norunIdsupplied the verdict is byte identical to the historical one. The same defect had a second half in the prompt: the opt-inRUN FACTS:line (RV1503) ends in thelive-observedregister, the composing model is told to reproduce run facts only from it, and the line named no artifact at all, so the engine was steering its own synthesis into a sentence its own default bundle refuses. The line now carriesrunIdin its JSON and readslive-observed by run <id>in the same sentence as the graded phrase, so quoting it faithfully passesevidenceGradeValidatorand, carrying no source citation, passescitedValueValidatorbeside it; a test asserts exactly that over the bytes the engine actually writes, with the id-less contrast asserted as the historical failure. The RUN FACTS line stays folded only from replay-stable material, so a resumed synthesis re-derives identical bytes; hosts that pin synthesis prompt bytes across engine versions should expect this line to have changed. Thevalidator-guidance-conflictfault scenario drives the new arm end to end: its corrected finish now carries the run's OWN id rather than a fabricated ULID, and the scenario asserts the repair exchange names that id verbatim beside the citation-free composition, so the guidance the fault kit gates is the guidance a run can actually execute.f191ff7: Identity spans are not asserted values (RV2502).
citedValueValidatorreads every non-citation inline span in a citing sentence as a value asserted about that citation, and the 1.226.0 comparison run showed the class that rule over-reaches: its synthesis wrote the frozen commit shaf8d9c5131c99c843ed23da22af20651f95377dd0beside source citations, and the verdict demanded the sha appear in the cited source, an impossible repair delivered in the same reason list as three real value fixes; both granted repairs burned and the finish was rejected. A span naming the artefact under review says which commit, run, or release the document is about and asserts nothing about any cited line. Three shapes are now structural and always excluded: a commit sha (12 to 64 hex characters, a floor low enough for every real abbreviation and high enough that ordinary hex literals likedeadbeefstay judged), a release version (1.2.3,v1.2.3, optional prerelease or build tail), and the run's own id when the runtime suppliesrunId, on the same six-character floor the evidence grade uses. Host vocabulary is declared rather than guessed: the newnotValuesoption lists the spans a document writes as identity, verdict words likeconditionally readyamong them, matched whole and case sensitively; a malformed list is aConfigErrorat construction. Nothing else relaxes, and a genuine value the cited line does not carry still fails in the very same sentence as an excused sha.The run-id exclusion makes the shipped bundle self consistent.
evidenceGradeValidatorinstructs a failing model to write this run's id inside the offending sentence (RV2501), and RV2202's warning existed because obeying that beside a citation traded an evidence-grade failure for a cited-value one, the trap that burned both repairs of the third subscription run. The two arms of the grade's reason now each name the composition that is TRUE for them: with the id in hand the graded sentence may carry a citation as well, and without one the older separation advice stands, because there the sibling has no id to recognise. Thevalidator-guidance-conflictfault scenario converges on the direct shape, the run's own id written beside the citation in the graded sentence, which neither validator could accept before.fbbfbe8: The exposure ceiling clamps a lone dispatch instead of refusing it (RV2503). The budget ceiling has clamped every turn's
maxOutputTokensto what the remaining money affords since layer 2b existed; the in-flight exposure ceiling only ever answered yes or no, so a dispatch whose FULL plan overshot the line was refused even when a shorter one fit and the budget could still pay for it. The 1.226.0 comparison run died exactly there: nothing was in flight, the budget held $0.8642, the mandatory repair turn's 18,000 token plan priced $0.7066 against $0.5642 of room, and the dispatch was refused before any provider call; the same work, re-issued after an operator raised the ceiling, wrote 12,840 output tokens for $0.4788 and fit the very ceiling that refused it.RunOptions.clampTurnToExposurearms the other answer:RunBudget.maxExposureOutputTokensprices the room with the same function the admission charges it with, and the loop lowers the plan to fit.Scoped by what a refusal actually means. It applies only to a dispatch with NOTHING else in flight, because that refusal is permanent: no hold will ever release to fund the full plan, which is precisely why the RV2003 sweep wakes such a waiter
drained. With siblings live the refusal is transient, the RV1902 and RV2002 waits park on it, and the wave keeps the full-length turn RV711 promised. When the room cannot fund even the serving model's output floor the clamp stands aside, so a real exposure exhaustion still refuses through the typedin-flight-exposurepath and the drained terminals of RV1902, RV2002 and RV2003 keep their shapes. The clamp is independent of the USD ceiling: a run with an exposure cap and nobudgetUsdclamps too.Off unless declared, and validated on intake: a non boolean is a synchronous
ConfigErrorbefore any journal write, because a truthy string arming a dispatch posture nobody asked for is the same hazard as a typo'd flag silently reading as off. Absent, dispatch behavior is byte identical, which is why the existing exposure suites pass unchanged. LikestrictPricing, it is a per-segment posture: not recorded in RunMeta, so a resumed segment carries only what its own options declare. Flipping the default would rewrite the drained-refusal doctrine those three trains built out of live parity deaths, and that is a separate decision with its own gates.263b5e8: Preflight prices the mandatory synthesis tail off
maxRepairsand against both ceilings (RV2504). The 1.226.0 comparison run declared a 1.53 USD synthesis reserve, a 45000 token input floor, an 18000 token output allowance andmaxRepairs: 2: one composition turn priced 0.7650 USD, so the hold was EXACTLY two of them and the RV2104 check, which priced one composition plus one repair, passed a config whose mandatory tail is three turns and 2.2950 USD. The run then died on its second repair with 0.385 USD of its 6.00 envelope unspent.synthesis-reserve-below-cap-compositionnow counts the tail offmaxRepairsrather than offrepairTurnReserve: the reserve is a TURN budget, while the money is spent by every repair the runtime is willing to GRANT, out of reserved turns or ordinary ones alike (the default grant is one, so existing arithmetic is unchanged). The message prints the multiplication. The finding also prices that tail against the second ceiling: an in-flight exposure cap below the run ceiling leaves the tail onlymaxInFlightExposureUsd - (ceiling - reserve)above the reserve line however much money the hold carries, and the comparison run's 5.70 cap left its 2.2950 USD tail 1.23 USD of room. One short room warns; a tail neither room can pay is an error finding, sorulvar preflightexits non-zero on it.db4d56d: A no-regression floor under the synthesis (RV2505). The 1.226.0 comparison run's coordination draft satisfied the FULL declared contract (its
draftPolicy: 'contract'gate had judged it against the same bundle, which is why the synthesis dispatched at all),skipWhenDraftValidwas off because the operator wanted the composing pass anyway, and the synthesis then failed that bundle three times over: the run settled with NO result at all, having paid for four workers, for the draft that would have passed, and for three rejected compositions. The opt-insynthesis.fallbackToValidDraft: truecatches a synthesis failure at the post-fan-in chokepoint, judges the coordination draft by the SAMEfinishValidation.validatorsthat bind the synthesis finish, and settles the run on a draft every validator accepts, under a journaledorchestrator_synthesis_regresseddecision (the truncated failure message, the validator names, the contract hash when one is declared, the hash of the judged draft) plus a warn log event; the envelope carriessynthesisRegressed. It is the validated sibling of the existingorchestrator_synthesis_fallback, which already falls back to the draft when NO validators are configured. A draft that fails too journalsorchestrator_synthesis_fallback_declinednaming its own failing validators with their reasons, and the original failure rethrows untouched. AConfigErroris never caught: a broken contract is a defect to fix and resume, not a reason to settle on a draft. Deterministic by construction, so a resume that re-fails the synthesis re-derives the identical verdict and reuses the journaled decision. RequiresfinishValidation, orthogonal toskipWhenDraftValid(with both on, a valid draft skips before there is anything to regress), and default off: no catch, no decision entry, no envelope field, byte for byte.41f93a9: The claim-coverage grade sees a declined judge and a zero denominator (RV2508).
claimCoverageOfnever readjudgeDeclined, the RV2106 degradation where the claim judge is refused ADMISSION and never dispatched, so a pass that judged nothing was graded by the counts of a pass that did not happen; over a draft carrying no citing sentence it graded'full', the strongest word in the vocabulary. The vacuous'full'at a zero denominator was the same failure at its extreme: RV1702 exists to stop a consumer inferring semantic health from emptiness, and an empty set graded stronger than a bounded subset.ClaimCoverageGradegains two words.'judge-declined'ranks with'judge-failed'and above everything the counts could say, below it only because a failure at least had an invocation to fail and the two causes are worth telling apart.'vacuous'sits below'partial': no subset was chosen because there was no set.ClaimCoverageInputgainsjudgeDeclined?: true; the orchestrator already spreads that flag into the meta it grades, so no call site changes and every existing meta grades the same unless it carried one of the two states. The CLI's--strictexits nonzero on'judge-declined'exactly as on'judge-failed'(nothing was judged either way) and prints'vacuous'to stderr while keeping the exit, because citing nothing breaks no contract the pass declares.Consumers with an exhaustive
switchoverClaimCoverageGradewill see a type error until they handle the two new members. That is the intended shape of the change: both states existed before and were silently folded into words that did not describe them.
Patch Changes
98c8ca9: The invocation-role prose is generated from the exported union, and the B0 sentence tells the truth (RV2511).
InvocationRolehas carried SEVEN members since the synthesis role shipped, and the docs disagreed with themselves about it: the model-routing guide and the agents guide said seven, while the architecture guide and the design principles said six and listed six, droppingsynthesize. That prose is also what thellms-full.txtbundle ships, so the machine-readable surface carried the wrong contract. The newscripts/docs-role-truth.mjsgate (wired into the docs CI job andpnpm docs:roles) parses the union out of the source and holds every marked count and list against it, with--writeregenerating them; an unmarked count in front of "invocation roles" fails too, even when it is currently correct, because a number nothing owns is exactly what went stale last time. Page frontmatter is checked and rewritten in place, since HTML markers are not valid YAML. The changelog is excluded: its entries describe the contract of the release they announce, and rewriting them would falsify the record.budget.tssaid "B0 is immutable after start: no API tops it up", which RV2208 made false whenResumeOptions.runshipped. The comment now states the invariant that actually holds: B0 is immutable WITHIN a segment, and the one thing that can change it is an explicit host decision, journaled as its own entry, taking effect only by opening a new segment, so a live run can never raise the bound it is already being measured against.
1.226.0
1.225.0
1.224.0
Minor Changes
- 4eca1a3: The resume-time budget override (RV2208). A run that died against its own
budgetUsdwas unfinishable by doctrine: the RunMeta-recorded ceiling governed every later segment,ResumeOptionsdeliberately carried no budget field, and the only way forward re-paid the whole journaled prefix as a fresh run.ResumeOptions.run({ budgetUsd?, maxInFlightExposureUsd? }) is the one explicit door: each value is validated exactly like itsRunOptionscounterpart, applies to the resumed segment and the run's remaining life, and is recorded back by the segment's first meta write, so a LATER bare resume restores the overridden posture rather than the genesis one. The change is never silent: before the meta mirror flips, the segment journals arun_budget_overridedecision naming the recorded value, the applied value, the source, and the settled spend it was judged against (nullrecords a run that started uncapped). AbudgetUsdbelow the journal's settled spend refuses with a typedConfigErrorbefore ownership, meta, or any append: such a ceiling would exhaust the segment before its first turn and read like a fresh money death. Absent fields keep the recorded values, an absent object keeps the historical behavior byte for byte, andstrictPricingdeliberately stays out of the override: pricing hygiene is not a per-segment decision.
1.223.0
Minor Changes
- 549aabd: The bare root ceiling folds documented (RV2205). A coordination turn refused by the RUN account's own hard crossing was the last undocumented money death of the loop: the exposure and reserve-line arms fold typed (RV1902, RV2101), but a crossing that named the run root itself, whether the ctx boundary re-mint (
source: 'root', a crossing detected at or after execution: the first parity run's shape, B0 drained by children while the root sat at 16% of its cap) or a pre-admission refusal of the coordinator's own seat (account: 'run'), rethrew bare and tore the run down around its settled children. Both shapes now fold through the SAME forced-finish machinery: the journaledorchestrator_finalize_fallbackdecision gains reason'budget-ceiling'beside'budget-floor'and'exposure-abort', the settled children ride the partial envelope, and the synthesis redemption stays free to try: past a crossed run ceiling its spawn admission declines with the arithmetic and journals the declined verdict (RV2102), which is the honest record, not a special case; with nothing settled the redemption arm correctly stays out. Orchestrator-cap crossings keep their dedicated atCap machinery, and unrecognized budget shapes still rethrow. - 549aabd: The unfunded repair grant declines typed (RV2207). Validation can grant a repair the budget will never execute: the seventh parity run's synthesis died between a granted repair verdict and its dispatch, and even with the refusal's message riding the terminal (RV2104) the death stayed a generic budget re-mint with no journal record of the grant the money never covered. The agent loop now marks exactly that refusal (a would-be turn following a rejected terminal-tool exchange carries
the granted repair turn could not be funded:in front of the crossed-account arithmetic), the coordination path reads the marked terminal behind the re-mint'sentryRef(the RV2103 pattern), journalsorchestrator_repair_grant_declinedwith the reason, the terminal reference, and the remainder, and fails the run as a TYPED validation failure (FailRunError: the orchestrator finish could not complete its granted repair) instead of the generic budget error; on the synthesis path the redemption's declined verdict repeats the same marked message through its terminal read, so both repair surfaces tell one story.
1.222.0
Minor Changes
- 8326268: Counted section collections join the finish contract (RV2206). The parity contract demands numbered collections (48
N01.-style negative scenarios, 16C01.counterexamples), and nothing enforced them: the second accepted subscription dossier carried 0 and 0 against a synthesis instruction naming both, and only a runner-side format pre-teach closed the gap, by hope rather than contract, while citations enjoyed per-section validation since v1.71.finishContractgrowssectionPatterns: per entry, at leastminmatches of a regex INSIDE a named section's slice, DISTINCT by first capture when the pattern captures (a repeated id counts once), with literalsamplesembedded in the golden fixtures and quoted by the prompt statement (with a capturing pattern the samples must carrymindistinct captures, because the accept skeleton must satisfy the demand it embeds, and a boundary-sharp reject golden drops exactly one sample line). The standalone validator issectionPatternCountValidator(contract-section-patternsinside the bundle); a deficit reason names the section, the label, the found-against-required count, and how many are missing, so a repair turn knows exactly what to add. Absent the field, the manifest normalizes, hashes, and behaves byte-identically.
1.221.0
Minor Changes
- 032ce93: The exposure drain grants a mid-work seat one clamped finalization turn (RV2204). The third parity rerun killed three workers ~30 turns into research with evidence pools of 17 and 22 under a floor of 24 and a CONFIGURED finalization window: the drain came before the window, and the window's play needs the very wire the drain refuses, because a drained seat's next ordinary turn re-prices the whole per-turn allowance the pool just refused. With
limits.finalizationReserve.maxOutputTokensdeclared, a drained seat that already completed a turn now spends ONE finalization turn before its typedexposure-drainedterminal: the output clamp shrinks the turn's exposure estimate to the summary allowance, thefinalizationWindow.allowlist rides as the turn's only tools so outstandingrecord_evidencecalls land in parallel through the ordinary tool machinery, and the drain instruction is request-only, mirroring the tool-budget reserve turn. Best effort on every edge: a refusal of even the clamped estimate warns and keeps the typed terminal, and a seat with NO completed turns keeps dying at zero provider attempts (the RV2002 doctrine, pinned). Preflight learns the funding truth:drained-finalization-unfunded(info) names a window declared under an in-flight exposure cap with no reserve to fund the grant, andinert-finalization-reservestops warning when the exposure cap alone gives the reserve a trip path.
1.220.0
Minor Changes
- 0babe70: The failure envelope carries the pass truth (RV2203). Two live terminals hid facts their journals held: the RV2106 mirror run's error terminal read
claimConsistencyMeta: nullover a journaled declined-judge verdict, and the seventh subscription parity resume settled exhausted withcompletion: nullandchildStatusCounts: nullover a journaled accepted acceptance with four ok children, because the exhausted path lifted only from the partial value and the rawBudgetExhaustedErrorcarried nothing. Three fixes: the orchestrator enriches every synthesis-path failure with the acceptance snapshot, the claim-consistency meta, and the{ran, reason}pass summaries (the budget class is preserved, soexhaustedstaysexhausted, and the ok envelope and the failure enrichment now build their summaries with one shared builder whose synthesis arm readssynthesis-failedon the failure path); the run-completion lift falls back to the enriched error data on the exhausted path; and the lift itself (withrun:endandRunOutcome) growsclaimConsistencyMetaandsynthesisSkippedunder the established mirror posture, valid shapes mirrored, malformed shapes silently absent, on every terminal, ok and failed alike.
1.219.0
Minor Changes
- 65a4ce7: The evidence-grade repair guidance is composition-safe (RV2202). The RV2106 mirror run reached the synthesis finish and lost the run to two individually correct validators: evidence-grade demanded "name a run id or a file:line citation beside it", the synthesis obeyed literally and wove inline run ids into sentences that already carried source citations, and cited-value then rejected exactly those sentences, because a run id is never in the cited window; the model sat between the two verdicts and both granted repairs burned ($5.31 with no dossier, after an accepted acceptance and a typed judge degradation). A validator reason is a repair instruction, so it must be executable without violating any sibling in the bundle: the verdict now steers to the safe shape (a file:line citation in the claim's own sentence, or the run id in a SEPARATE sentence carrying no source citation, with the trade named explicitly), the pairwise rule is documented for validator authors beside the audited built-in bundle, and the regression suite pins the guided shape passing evidence-grade AND cited-value together while the trap shape keeps failing exactly one of them. The reason text is API for repair prompts; hosts matching the old bytes must update.
1.218.0
Minor Changes
- 088bda6: The lifetime spawn counter survives resume, the accepted-finish synthesis decline journals its verdict, and preflight prices the tail's spawn budget (RV2201). The seventh subscription parity run was killed mid-fan-out and resumed: the resumed segment seeded the counter from the journal fold (5 agents) and the roll-forward of the four journaled child admissions incremented it AGAIN, so the post-acceptance tail starved at 9 against a cap of 8 with its money whole: the claim judge declined typed (the RV2106 catch holds for non-monetary refusals), and the synthesis spawn refusal reached the terminal as a bare message with no decision entry while its 1.40 reserve sat intact. Three fixes:
admitRecoveredno longer increments the lifetime counter, so each spawned agent counts a single time across the run's whole life, never twice (at its fresh admission, or through the seed of whichever segment rolls it forward), and the c7 kill-and-resume shape now seats its judge and synthesis; a synthesis admission refused after the validated coordination finish journalsorchestrator_synthesis_redemption_declinedwith the refusal's reason, the remainder, the livespawnHeadroom, andpath: 'accepted-finish', the same verdict the redemption path writes, so a journal reader asks one question either way; and preflight growstail-spawn-budget(the declared wave rows are already denied row by row against the cap, but the claim judge and the synthesis spawn after the fan-out and no row priced them) plus theorchestrator.headroomTurnsknob for the previously hardwiredreserve-line-headroomthreshold (default 2, 0 silences the fence). journal-shape-revision:statsBefore.spawnsBeforeembedded in post-resume admission decisions now reflects the once-per-life count (the crash-during-revision and config-drift-resume cassettes re-recorded with exactly that one value changed); already-journaled entries replay verbatim, so existing journals stay valid.
1.217.0
Minor Changes
- ab80b97: The declined judge admission degrades typed, the refusal names its holds, and preflight prices the working room (RV2106). The ninth parity run finished its whole fan-out (four ok children, a composed and accepted draft) and then died bare: the claim-consistency judge's 0.28 admission estimate did not fit the orchestrator account's working room past the held 1.40 synthesis reserve, the pre-dispatch refusal flew out of the coordination uncaught, and the run settled exhausted with no fold and the funded synthesis never dispatched, while the refusal message printed arithmetic that fit with room to spare because the hold was in the sum and not in the text. Three fixes: the declined judge admission journals
orchestrator_claim_judge_declinedwith the refusal text and the post-refusal remainder, the meta carriesjudgeDeclined: truebeside thejudgeFailedprecedent, the synthesis still runs, and only the armed'fail'posture stops the run; the admission refusal message gains aplus the held synthesis reserve N USDclause exactly when a hold exists (hold-free refusals keep their bytes) withsynthesisReserveUsdandfinalizeReserveUsdstamped on the error data; and preflight growsorchestrator-working-room, judgingeffectiveCap - synthesisReserveUsdagainst one coordination turn floor plus the newly declarableorchestrator.claimConsistency.judge.estCost.
1.216.0
Minor Changes
- b357f4a: The evidence-grade verdict names its offending sentences (RV2105). The eighth parity run's synthesis was told
evidence-grade claims cite no run or repro artifact in their own sentence: live-observedover a 5000-word document, repaired blind twice (the second repair fixedproduction-provenand never found thelive-observedsentences), and the run failed closed with half its budget unspent.evidenceGradeValidatorreasons now carry the offending sentences verbatim beside the phrase list, bounded to five and truncated per sentence (whitespace-normalized), with anand N more offending sentencestail, so a granted repair turn reads exactly the lines the verdict judged. The blindness audit covered every other finish validator: each already names its material (sections, headings, fields, citations, missing pool items, codepoints with context), so the fix is exactly one validator wide.
1.215.0
Minor Changes
- e1da4c7: The refused turn's message rides the terminal, and the synthesis reserve is priced against its own composition (RV2104). The seventh parity run's synthesis composed to its 40000-token output allowance, failed the section validator on the truncation, was granted a repair, and the repair turn was refused at the crossed ceiling; the terminal journaled a bare
agent terminated with status errorbecause everybeforeTurncatch discarded the refusal's text, and the RV2103 declined verdict repeated it. The pre-dispatch ceiling guard's own message, naming the crossed account and the spent-of-ceiling arithmetic, now rides the agent terminal from all five refusal sites (the loop turn, summarize, finalize, extract, and the finalization-reserve skip's warn log), so the ctx terminal entry and the redemption's declined verdict tell the refusal's truth. Preflight growssynthesis-reserve-below-cap-composition: the minimal-payload check prices the shortest accepting finish, but a reasoning model writes to its allowance, so the finding prices one allowance-sized turn (plus the declared input floor) and one more when the validation declares a repair reserve, and warns when the committedbudget.synthesisReserveUsdis smaller; the seventh run's 0.70 hold funded a composition it could not repair.
1.214.0
Minor Changes
- c8af0ec: The declined verdict tells the terminal's truth, and a severed synthesis is retried once (RV2103). The sixth parity run's synthesis dispatched for the first time in six runs (the RV2102 drain worked by the book) and died as
stream idle for 240000mswith $0.9077 still uncommitted; the declined verdict then journaled the ctx boundary's genericrun budget ceiling reachedbecause the exhausted flag is armed at the fallback by design. The declined reason now reads the terminal entry behind the re-mint'sdata.entryRefand carries the message that actually ended the attempt, withterminalRefnaming the entry andtransportRetriescounting the second wire; a refusal thrown before dispatch keeps its own admission arithmetic. A synthesis attempt severed on the wire (a transport-class terminal marked retryable, past the loop's own wire retries) is granted at most one retry from the same remainder: the journaledorchestrator_synthesis_redemption_retrydecision keeps the second attempt auditable, and an unaffordable retry declines through spawn admission instead of dispatching.
1.213.0
Minor Changes
- 61680df: The redemption drains the stragglers first (RV2102). The fifth parity pair reached the RV2101 redemption twice and lost the synthesis to the same next layer both times: a still-running child's committed admission reserve pushed the synthesis spawn past the ceiling (
spent ~5.0 + straggler reserve 0.66 + est 0.78 > 6.00), the refusal lived only in a swallowed throw, and the straggler's post-boundary finalize burned 148k input tokens before teardown cancelled it. At the reserve line every remaining child faces the same refused arithmetic, so the redemption now aborts and awaits every unsettled child BEFORE the synthesis dispatch: their reserves release at their terminals, no NEW wire dispatches past the boundary, and a severed in-flight stream bills as the documented layer-3 overshoot. A redemption that still cannot fund the synthesis journals its verdict instead of folding silently: theorchestrator_synthesis_redemption_declineddecision carries the refusal text, the post-release remainder, and the drained-straggler count. With the drain in place both fifth-pair runs would have funded their synthesis from the freed remainder.
1.212.0
Minor Changes
- e6f8516: The reserve line is a boundary, not a death (RV2101). The third and fourth parity runs died on the two denominators the settle-time reserves sat in: the third at spent $4.7064 plus the $1.00 synthesis reserve against the 5.70 in-flight exposure cap (drain cascade with zero live estimates), the fourth at spent $5.065 against
ceiling - reserve = 5.00(the root refused one output token, the intact $1.00 reserve unreachable, no synthesis). Three fixes, one doctrine: money promised to the tail is fenced by the budget chain alone, and reaching its line runs the tail instead of killing the run. The in-flight exposure admission now countsspent + live estimatesonly (the finalize and synthesis reserves left the sum; the budget chain already fences them). The coordination loop's typedoutput-floorrefusal (a newAgentError.reasonbesideexposure-drained, preserved across the ctx boundary like the in-flight marker) now settles the documented forced-finish partial with the journaled fallback decision (reasonbudget-floorbesideexposure-abort), and when a synthesis step is configured with its reserve still committed and at least one settled child, the synthesis promise is REDEEMED: the ordinary synthesis invocation runs from the released reserve with no coordination draft and its contracted output rides the partial envelope asresult. Preflight prices the budget-side trajectory beside the re-priced exposure floor:admission.reserveLineUsdandadmission.reserveLineHeadroomUsd, with thereserve-line-headroomwarning when the admitted wave's steady state sits within two coordination turn floors of the line, andexposure.requiredMinimumExposureUsddrops the tail reserves in lockstep with the live formula.
1.211.0
Patch Changes
- d5a8a36: The third parity rerun's crash shapes become permanent fault-kit gates (RV2009), zero paid calls.
parity-quiescence-deadlockdrives the exact terminal shape in miniature: the coordination turn eats the exposure cap, every worker is refused DRAINED (typedexposure-drained, zero provider attempts, RV2001/RV2002), the root forced-finishes partial (RV1902), and the gate asserts the exhausted terminal, the closed roster,run_settleafter every agent entry, one wire denominator, and no unsettled invoice lane (RV2003/RV2008); any revert reads matched:false.parity-sequential-roster-floordrives the seat-by-seat roster under an unreachable acceptance floor and asserts the FIRST seat's typedroster_floorrefusal with the whole-roster arithmetic journaled and zero paid children (RV2005). The docs truth pass lands the no-silent-exit invariant in the README and the design principles (no path ends the process while a run has no journaled terminal) and extends the observability denominator map with the RV2008 incremental lane and its settled boundary.
1.210.0
Minor Changes
- c871ddc: Incremental billing journaling (RV2008). ProviderCallRecords rode ONLY the terminal agent entry, so when the third parity rerun's process died with the root still running, ~$0.99 of its dispatches existed nowhere durable: the live ledger read $4.467 while the journal folded $3.478. Every record now journals the moment its wire call settles, as a
provider-calldecision row keyed by the dispatch seq and the record ordinal in the invocation's own scope; the terminal entry still carries the canonical set, replayed segments append no duplicates, and the crash window shrinks from the invocation's whole history to the one in-flight turn.invoiceFromJournalgains the additiveunsettledlane: dispatches of agents still running at the journal's edge, priced from the incremental rows and kept OUTSIDE the settled totals (run_settle stays the billing boundary).rulvar cost-auditgrows a sixth check,incremental-rows-match: every settled agent's terminal dispatch set must equal its incremental rows, count and per-ordinal usage alike; agents with no rows (pre-RV2008 journals, replayed invocations) pass vacuously. The frozen cassette catalog is re-recorded for the additive rows (journal-shape-revision, policy not identity: existing entries byte-identical, no hashVersion change).
1.209.0
Minor Changes
- 514c7bb: Cache-aware preflight (RV2007). Every spawn report now prices its loop input floors both ways:
uncachedLoopInputFloorUsd(the declaredestInputTokensre-billed at the full input rate on every projected provider turn, exactly what the third parity rerun paid at ~$1.10 per worker cycle) andcachedLoopInputFloorUsd(one cache write plus a read per later turn at the price row's cache rates, the RV2006 policy's economics, ~$0.19 for the same shape). The newuncached-long-loopwarning fires when a shape projecting four or more provider turns is about to run with the cache policy OFF on an adapter that declares explicit prompt caching, naming both figures; under the default policy the loop caches and nothing fires. The budgets guide's sizing section carries the worked parity numbers.
1.208.0
Minor Changes
- e7d426f: First-class prompt-cache policy (RV2006).
ChatRequest.cacheHintexisted and the Anthropic adapter compiled it intocache_control, but nothing in the core ever populated it: the third parity rerun's workers re-paid the full input rate on every turn of their ~550k-token contexts (cacheReadTokens 0across the run), and the $6 envelope sized on OpenAI's implicit server cache was incomparable on Anthropic. The agent loop now compiles the hint on every tool-cycle turn: breakpoints after tools, after system, and after the deepest message, sliding with the history. Default ON exactly where the adapter declares the newModelCaps.promptCaching: 'explicit'(the Anthropic adapter does); OpenAI declares'implicit'and undeclared adapters get byte-identical requests. Configure withdefaults.cache,AgentProfile.cache, or per-callopts.cache(CachePolicy { mode?: 'auto' | 'off'; ttl?: '5m' | '1h' }), call over profile over engine. Billing note: on cache-capable Anthropic models this changes the wire requests of every loop turn to carry cache breakpoints, typically cutting long-cycle input cost several-fold (cached reads bill at a tenth of the input rate);CostReportcache accounting is unchanged, the hint never enters identity or journals, and@rulvar/testing'srequestHashstrips it so existing cassettes replay byte for byte.
1.207.0
Minor Changes
- 99beee2: Sequential roster feasibility (RV2005). The third parity rerun's model ignored the one-batch instruction and spawned seat by seat through spawn_agent, so the RV1908 batchGate never saw a batch: three seats were paid in full under an acceptance floor of four the money could never reach, and the settle verdict was bound to reject them. Under a declared
acceptance.minSpawnedChildren, every SINGLE spawn_agent admission now projects the whole remaining roster with the shared RV2004 arithmetic (this seat's own dispatch projection per remaining seat, live in-flight exposure included) and refuses the FIRST infeasible seat with the typedroster_floorverdict, its arithmetic journaled on the decision, zero paid children. Batch seats skip the per-seat check (their batchGate judged the wave entire), and spawn-admission decisions now journal their true origin (parallel_agentsseats no longer read asspawn_agent). For hosts that want the policy unsplittable,OrchestrateOptions.requireBatchSpawn: 'reject-spawn-agent'refuses every single spawn_agent call typed (code 'batch_required', nothing journaled, nothing paid) so the model re-issues the wave as one parallel_agents batch.
1.206.0
Minor Changes
- ec8e1f1: One admission arithmetic for preflight and the live spawn_agent verdict (RV2004). The third parity rerun's spawn verdicts journaled reserve/childCeiling $0.50 (the derived childBudgetFraction cap) under a declared profile estCost of $0.70 that dispatch actually committed: the journal lied about the held money, resume would have rolled the lie forward, and the 0.50 allowance would have severed the child mid-work. On the spawn-tool path (spawn_agent, parallel_agents), where the fraction never materializes as an account, the verdict reserve now IS the shared dispatch projection (the declared estimate or the flat default, clamped by an explicit budgetUsd alone), and every verdict names its derivation (
reserve.source: estCost | default;reserve.clampedBy: explicit-budget | fraction-ceiling). Origins with a real allowance account (ctx.workflow) keep the historical fraction ceiling and clamp. Preflight gains the live-root-exposure term: the orchestrator's own worst-case turn floor now rides the embedded spawn gate andadmission.requiredMinimumCeilingUsd(published asadmission.liveRootExposureTermUsd), so the parity envelope's fourth seat, which fit the plain 5.95-under-6.00 arithmetic and was refused live, is refused in preflight too. The frozen cassette catalog is re-recorded for the additivesource/clampedByfields on journaled admission verdicts (journal-shape-revision, policy not identity: existing entries byte-identical, no hashVersion change).
1.205.0
Minor Changes
- 6d224da: The quiescence guarantee: no silent exit (RV2003). The third parity rerun's process exited mid-run with an unsettled top-level await: the parked root's exposure wait held nothing on the event loop, and the journal kept a forever-running root with no
run_settleand no terminal. Three guards close the class. A parked exposure waiter arms a ref'd keepalive interval (disarmed with the last waiter), so a process whose only remaining work is the wait hangs visibly instead of vanishing; each tick sweeps for the drained state (no holder of any kind left) and wakes waiters'drained'as defense in depth behind the event-driven wakes. The engine registers every unsettled run with a processbeforeExitquiescence watchdog: an event loop about to die with an unsettled run forces that run through the ordinary cancel path, the RV1903 terminal barrier,run_settle, and a terminal envelope, even when the body is stuck on a bare promise no signal reaches (the settle race gains a watchdog arm). The invariant, pinned by a regression on the exact parity deadlock shape: no path ends the process while a run has no journaled terminal.
1.204.0
Minor Changes
- efaec9b: Spawned children wait out exposure refusals instead of dying (RV2002). The third parity rerun terminally killed three of four workers, each ~550k tokens into research, with a pre-wire in-flight exposure refusal that would have been a parking for the root. Orchestrator-spawned children (spawn_agent and parallel_agents) now share the RV1902 wait posture: the refused child parks (the
budget:exposure-waitevent carriesscope: 'child'), retries pre-wire when a live hold releases, and pays zero provider attempts while parked. Only a drained refusal (no live holder left to wait out) ends the seat, and it ends typed and cheap:AgentError.reason 'exposure-drained', carried into the journaled terminal'serror.data.reason, so the orchestrator tells a starved seat apart from a crashed child and can re-spawn it once money frees. The root keeps its documented forced-finish partial on the drained arm.
1.203.0
Minor Changes
- fb08c10: Every agent terminal returns its live exposure holds (RV2001). The third parity rerun died on the hole: three children killed pre-wire by the in-flight exposure cap left $0.478 of live dispatch estimates parked against the cap forever, and the root's exposure wait starved on money no live dispatch was holding. Holds are now attributed to the invocation whose dispatch they cover; every settle of that invocation (ok, error, exhausted, cancelled, thrown paths included) releases whatever a lost attempt closure leaked and wakes the parked waiters, a late closure can no longer eat the money of another holder, and the live total snaps to exactly zero when the last hold of any kind is gone.
RunBudget.releaseExposureHolderandRunBudget.liveExposureHolderCountpublish the surface; zero holders beside live waiters is the drained signal the wait machinery keys on.
1.202.0
1.201.0
Minor Changes
- 7e01189: The documentation says exactly what the lifecycle now guarantees (RV1909). The README and the design principles carried "a full cost report" as a promise the twenty-first benchmark falsified; with the exit barrier (RV1903), the settle drain and the journal seal (RV1904) the promise became a lifecycle guarantee, and the docs now state the enforcement rather than the aspiration. The observability guide gains the denominator map: the settled fold, the
run:endtotals, the terminal envelope andinvoiceFromJournalare one fold that agrees by construction; a mid-runbudget:updateor a refusal'sspentis an instant of the live ledger, never the terminal; and a later re-fold reproduces the settled figures byte for byte because the seal forbids the journal to move. The benchmark's four views were honest clocks over a roster that kept moving; the lifecycle now stops the roster before the first terminal figure exists.
1.200.0
Minor Changes
- e2ddbdf: The parallel_agents admission policy (RV1908). The four-role benchmark's batch died fail-fast at the third task: the fourth mandated specialist was never attempted, and the run paid two workers in full under a roster floor of four the wave could never reach.
OrchestrateOptions.parallelAdmissionnames the alternatives:'fail-fast'(the default, the RV805 shape) stops at the first refusal;'try-all'attempts every task and reports every refusal in arefusalslist beside the historicalrefusedslot;'all-or-none'projects the whole batch against the live remainder with the embedded gate's own formula and refuses it typed (code 'batch_atomic') with zero admissions when it cannot seat entirely, cancelling admitted siblings on a non-budget mid-batch failure. Independent of the policy, a declaredacceptance.minSpawnedChildrenarms the roster pre-check: a batch large enough to seat the floor whose feasible count cannot reach it is refused (code 'roster_floor') before the first child is paid. Runtime behavior only: the tool's schema and description never move, so toolset hashes stay byte identical.
1.199.0
Minor Changes
- 29891c6: The preflight prices the two minimums the benchmark lacked (RV1907).
admission.requiredMinimumCeilingUsdis the whole-wave fill: every declared row's reserve plus the finalize and synthesis carve-outs, the figure a viablebudgetUsdmust strictly exceed; the four-role benchmark's $6.00 ceiling sat $0.98 below its own wave's 6.98 and lost two of four mandated workers to it.exposure.requiredMinimumExposureUsdis the breathing floor ofmaxInFlightExposureUsd: the carve-outs plus the maxInFlight most expensive concurrent turn floors, the orchestrator's own turn among them; the recovery arm's $3.20 cap sat below it and stalled the coordinating turn beside its own full child wave. A declared cap below the floor draws the warning findingexposure-cap-tightwith the equation priced term by term, naming the RV1902 park it predicts. The budgets guide gains the sizing arithmetic with a worked four-worker example.
1.198.0
Minor Changes
- c097c96: The terminal event semantics say what happened (RV1906). The four-role benchmark's primary stream read a root
agent:endwith status ok followed by arun:enderror with nothing between them naming the policy fold, and its artifacts carriedcontradictions: nullandclaimConsistencyMeta: nullthat the judge had to annotate by hand as NOT RUN. The acceptance verdict now speaks on the stream:orchestrator:acceptancecarriesverdict,completion,childStatusCountsand the declared roster floor, emitted from the one journaled decision, fresh and on the resume roll-forward alike. And every semantic pass reports an explicit summary:semanticPasses({contradictions,claimConsistency,synthesis}, each{ran, reason?}with reasons'not-configured','run-rejected','valid-draft','not-run') rides the acceptance envelope, the typed rejection data, theRunOutcomeandrun:endthrough the same validated lift as the acceptance roster, so an absent findings field can never be read as a clean pass.
1.197.0
1.196.0
Minor Changes
- ec9c3e3: One terminal denominator (RV1904). The four-role benchmark's recovery run reported four mutually inconsistent cost views because the settle raced the roster: RV1903 barriered orchestrations, and this train closes the remaining lanes. The engine's settle drain terminates every live agent invocation of a PLAIN workflow (an un-awaited
ctx.agenta body returned over) to a journaled terminal beforerun_settleexists. The journal's billing lanes seal after the durable settle: a late append rejects with the typedJournalSealedError(code 'journal_sealed'), while the detached resolution lane stays open by contract, because resolutions answering a suspension or a parked approval are the documented post-settle appends. And the terminal grows the wire denominator:CostReport.wireRequestsandTerminalEnvelope.wireRequestscarry the per-dispatch ledger's provider request count, absorbed continuations included, equal to the invoice cardinality'swireRequestson ledger-covered runs by construction, so the terminal a consumer gates on and the invoice a finance pipeline folds finally agree on how many wires the run made.
1.195.0
Minor Changes
5702a70: The terminal child barrier (RV1903). The four-role benchmark's recovery journal recorded
run_settleat sequence 18 and three successful child terminals at sequences 19..21: the returnedRunOutcome, the terminal invoice, the captured event stream and the final journal each reported a different total, and none was wrong by its own clock. Every orchestration exit, returned or thrown, an accepted or rejected finish, a typed failure, a budget or exposure terminal alike, now passes a terminal child barrier before the workflow settles:OrchestrateOptions.onUnsettledAtExit: 'cancel'(the default) aborts the stragglers and awaits their journaled cancelled terminals,'drain'awaits their natural terminals bounded by their own limits and budgets, preserving their evidence at the price of the wait. The verdict the run settles with is journaled before the barrier runs, so late children never change it; what ends is the settle racing the roster, and with it the post-settle journal mutation that split the cost views.The frozen cassette catalog is re-recorded for the barrier's additive cancelled child terminals in runs that previously left stragglers running past the settle (journal-shape-revision, additive terminals only: existing entries byte-identical, no hashVersion change).
1.194.0
Minor Changes
- 360a659: The orchestrate root waits out transient exposure refusals (RV1902). The four-role benchmark's recovery arm died on a contract violation: the budgets guide names an in-flight exposure refusal transient, but when the refused agent was the workflow's coordinating root, the typed refusal escaped the orchestration and settled the whole run
exhaustedwith a null completion while four admitted children were still finalizing. An orchestrate-owned root dispatch (the coordination loop, the synthesis invocation, the forced-finish wake) now parks the refused turn until a live exposure hold releases and retries pre-wire, zero provider attempts while parked, emitting the typedbudget:exposure-waitevent with the refusal arithmetic (capUsd,spentUsd,inFlightUsd,estimateUsd,willWait: true). A drained refusal (no live hold left to wait out; spend never shrinks, so nothing can turn it into a fit) settles the documented forced-finish partial instead of a bare escape: the run exhausts with the settled children's fold as its value, a journaledorchestrator_finalize_fallbackdecision (reason 'exposure-abort') for replay identity, andwillWait: falseon the event. Plain agents keep the documented settle-as-budget-error behavior, because their caller can catch and decide.
1.193.0
Minor Changes
- 2bca1d1: The admission projection holds the synthesis reserve exactly like the live gates (RV1901). The four-role benchmark's primary arm configured a $6.00 ceiling, a $4.50 orchestrator cap, a $1.00 synthesis reserve and four workers at estCost $0.62; preflight read the wave 5/5 green while the live gate refused the third worker, because the projection netted the synthesis carve-out out of the orchestrator's own row and then held nothing for it at the run root, where the runtime registers it before any spawn admits and both live gates (
refuseSpawnIfInfeasible,remainderOf) count it. The wave arithmetic now carries the hold in both projection layers, and the exact benchmark configuration projects 2 of 4 seats before the first wire, matching the live gate for the same reason. The report exposes the equation:admission.synthesisReserveUsdnames the hold, every wave row carriesheldAtEvaluationUsd(the money already held when the row was evaluated), and the declaredorchestrator.acceptanceslice acceptsminSpawnedChildren, so a wave whose budget seats fewer children than the acceptance floor demands (minSpawnedChildrenorchildPolicy.minSuccessful) draws the error findingadmission-below-roster-floorinstead of paying for a roster the settle verdict is bound to reject.
1.192.0
Minor Changes
- 8757601: quota:denied becomes the primary event for recoverable pre-wire waits (RV1810). The twentieth benchmark's run emitted 13
agent:errorevents that were all healthy token-window waits (a clean run, zero provider errors, zero transport retries), so any alert keyed to the event TYPE read a failing run. A recoverable denial now emitsquota:denied(the denied model, the limiter's reason,retryAfterMs,willRetry: true); the legacyagent:errortwin is gone by default andcreateEngine({ telemetry: { quotaDeniedAgentError: true } })restores it, the versioned compat posture. Terminal denial exhaustion still ends in the realagent:error. The observability guide gains the vocabulary section beside it: throttling versus failure, whyorchestrator.wakescounts durable wait suspensions and not progressive await completions, and why internal root work reads frombyRolewhilebyAgentTypeandbyPhasekeep their honest empty-string buckets (synthetic phase wrappers would move journal bytes and re-key resumes).
1.191.0
Minor Changes
- 745387c: Enforceable coverage floors and two new corpus classes (RV1809). The claim pass graded itself honestly (RV1702) but nothing could enforce a floor:
claimConsistency.minimumCoverageRatioandrunFactCoverageRatio(each in(0, 1]) now declare the minimums,onLowCoverage: 'report'(default) stamps the machine-readablelowCoverageblock on the meta with each ratio beside its floor,'fail'fails the run typed BEFORE the judge dispatch exactly likeonUncoveredCritical, the meta additionally carriesrunFactCandidates(the uncapped matched count, so both ratios are computable from the meta alone, live or persisted), and--strictexits nonzero on a stamped block with the ratios printed. The adversarial corpus grows two classes from the nineteenth benchmark:modality-overclaim(a mitigation stated as an unconditional guarantee: the attestation "stops any tool drift" beside the pool reading naming the contract-hash boundary) andscope-ambiguity(child-only totals printed as whole-workflow figures), both forming pairs through the same pure folds.
1.190.0
Minor Changes
- 8e02021: MCP discovery gains the visited-cursor guard, the whole-sweep deadline, and the production bounds demand (RV1808). The RV1602 cycle guard caught only the immediate self-echo, so an alternating cursor pair (A, then B, then A again) paginated forever whenever
maxPageswas left unset; the sweep now refuses typed on ANY cursor it has already queried with, unconditionally, like the echo guard.timeouts.discoveryMsadds the wall clock over one whole tools/list sweep: per-pagelistMscannot bound a crawl of promptly-answered pages, andmaxPagesbinds only when declared, so the deadline is the bound that watches the sweep as a unit, refusing typed with the page count. AndrequireBounds: trueis the production posture: the source refuses at construction unlessmaxTools,maxPages,maxSchemaBytes, andtimeouts.discoveryMsare all declared, one typed error naming what is missing instead of four silent unboundeds; the production profiles guide now says to set it.
1.189.0
Minor Changes
- 6a5cc2d: The settled-set consume path, structured tool failure reasons, the labeled fact-sheet scope, and the machine-readable late-child boundary (RV1807). The nineteenth benchmark's root consumed six children with fourteen
get_child_resultcalls, eight of them speculative probes that errored on not-settled handles, its answer printed the child-only fact sheet as "the current workflow" totals, and public tool events said onlyoutcome: 'error'throughout. Everyawait_anydigest now carriessettledHandles(the settled subset of the waited set at return time, recorded truth like the digest itself);exposeSettledResultsTool: trueaddsget_settled_child_results(handles, maxCharsPerChild?), the bulk first-page read that refuses typed BEFORE any read when a handle is unknown or still running, under its own opt-in so no existing run's toolset hash moves;tool:endevents carry a structurederrorCodeon failures (unknown-tool,invalid-arguments,child-not-settled,unknown-handle, and the RV1807data.errorCodeconvention for tools that stamp their own); theRUN FACTSsynthesis sheet names its scope in the quoted bytes (scope: 'settled-children-only', with the whole-run totals delegated to the terminal envelope and invoice); and a finish that validates over a still-running child names it in the structuredunsettledAtFinishlist on the acceptance decision and the result envelope, beside the existing prose degradation note, with the pool boundary documented: a late child's output never re-enters the frozen contradiction and claim pools.
1.188.0
1.187.0
Minor Changes
- c9798ef: The absorbed pause_turn wire set survives the error arms (RV1805). The Anthropic adapter published the whole segment set (
wireRequests = { count, responseIds }) only on the successful terminal finish, so an error after absorbed continuations, acreate()failure, a truncated read, the continuation cap, or a pre-wire segment denial, yielded bare and orphaned exactly the paid wires a per-request statement join needs most (the segments' usage already survives through mid-stream reports; the ids and the count did not). Every error arm now rides the COMPLETED absorbed segments' wire set on its error data, the agent loop's provider call record reads it when the finish that would have named the set never came (a single absorbed segment included, since an errored dispatch has no plain responseId to join by), the invoice row keeps the ids and the count, and a first-segment failure stays a bare error with nothing invented.
1.186.0
Minor Changes
- 242647e: Three accounting-truth gates (RV1804). The admission
countTokensprobe becomes a policy surface: it is full-prompt provider egress billed to no invoice row, sodefaults.countTokens: 'deny'(engine-wide) orAgentProfile.countTokens(profile wins) forbids the control wire outright, the flat reserve admits exactly like an adapter withoutcountTokens, and every probe outcome is a typedcontrol:wireevent (okwith the counted tokens,failed,denied) instead of a log line only. Strict pricing's declared freshness bound now clamps the future too: aratesVerifiedAtmore than one day ahead of the engine clock refuses typed, because a stale-only check reads any future date (the classic typo'd year) as eternally fresh; the one-day tolerance absorbs date-only strings authored ahead of UTC. And statement reconciliation holds the join key unique on both sides: a duplicate response id among the local invoice rows (multi-wire segment ids included) now refuses typed exactly like a statement-side duplicate, because a usage-only export would otherwise settlematchwith a double-booked local row silently absorbed.
1.185.0
Minor Changes
- 1248623: A finalize route declared at the workflow level now fires the finalize phase (RV1803). The role trigger read
[call, profile, engine]while model resolution read all four layers, sodefineWorkflow({ routing: { finalize: … } })resolved the finalize model and then never dispatched the phase; the route worked only when repeated at the call, profile, or engine layer. The trigger now reads the same four layers resolution reads, a workflow-only route fires exactly one finalize dispatch, resume replays the journaled synthesis without paying a second one, and a workflow layer without a finalize route still never fires the phase.
1.184.0
Minor Changes
- 8a9caca: The toolset attestation gains an authority side (RV1802).
toolsetHashpins exactly the model-facing contract tuple {name, description, parameters, version} by design, so under an attested profile a tool whoseriskflipped from read to write, whoseneedsApprovalgate was dropped, or whoseexecutor/executorSpecrouting changed passed the pin silently while changing what the ask rules and the approval flow would do.resolveToolsetnow derives a per-tool authority record{ contract, risk, needsApproval, executor, executorSpec: sha256(JCS(spec)) }and an aggregateauthorityHashridingResolvedToolset;attestToolset()records both sides;enforceToolsetAttestationrefuses authority drift at the same pre-wire site as contract drift, naming the drifted field per tool, with missing and unexpected tools listed and shapes validated atcreateEnginetime. Execute bodies stay deliberately unhashable on both sides (versionremains the lever), and pins recorded before this release keep their documented contract-only posture until re-recorded withattestToolset().
1.183.0
Minor Changes
- dd3767c: The decision chain reads the canonical payloads the engine journals (RV1801). The fold shipped in RV1705 read a resolution's
by/target/decisionRefand an abandon'starget/authorizedByfromentry.value, but the engine writes those facts in the canonicalentry.resolutionandentry.abandonpayloads with no entry value at all, so on a live journal the reconstructed authority record lost who resolved, what sanctioned an abandon, and the decision value itself; the fields survived only on hand-authored journals that carried them invalue.reduceDecisionChainnow reads the canonical payloads first and keeps the value-carried forms as the fallback, a resolution row'svalueis the decision the ask was resolved WITH when the entry itself carries none, and the operational host acceptance test pins fold-to-journal parity on a live engine run: every canonical field the engine journaled (the externalby, the referenced ask, the allow, and the deny with its reason) is exactly what the chain row reports.
1.182.0
Minor Changes
- 144d026: The operational host reference ships executed, with the decision-chain audit fold in core (RV1705). The eighteenth comparison benchmark's operational acceptance named four behaviors a production host must prove, not describe: a tenant cannot read or effect across a tenant boundary, a revoked approval is never executed, a redelivered attempt cannot duplicate an external effect, and an audit reconstructs the decision chain. The new operational host guide walks the reference arrangement of shipped primitives for all four, and
examples/src/operational-host.tsexecutes them through the full engine onFakeAdapter: per-tenant engines by construction (own store, own toolset, strict approvals, ask on every mutating class, the journaled approval deadline), a pre-effect deny path proven empty-ledgered, a guarded effect whose idempotency key suppresses the re-fired side effect while the ledger records both attempts honestly, and a replay on an adapter that refuses to serve leaving the effect count at one. The core half isreduceDecisionChain(entries): one pure l0 fold that reconstructs a run's authority record (approvals with what was asked, resolutions referencing the ask by seq, admissions, abandons, terminations) in the journal's own total order, never inventing a field an entry did not record, tolerant of unknown kinds by the reader obligation, so "who allowed this and when" is a fold instead of an investigation.
1.181.0
1.180.0
Minor Changes
- b124d26: Statement reconciliation is core, with a fail-closed intake for raw exports and a fixed adapter contract matrix (RV1703).
reconcileStatementwas provider-neutral from birth, typing only against the invoice and the pricing SPI, but it lived in@rulvar/openaiand forced Anthropic-only consumers into an OpenAI dependency for a join that never touched OpenAI code; the eighteenth comparison benchmark graded provider readiness "conditionally ready" partly on exactly this asymmetry. The module now lives in@rulvar/coreand the historical@rulvar/openaiimport paths keep serving the identical functions as re-exports, so no consumer rebuild or import rewrite is forced. New beside it:statementFromRows({ kind, rows, map })normalizes a raw keyed export (a parsed CSV, a JSON download) into aProviderStatementunder one explicitStatementColumnMap, deliberately shipping no per-provider schema knowledge; every mapped cell validates fail-closed with the row index and column name (non-numeric dollars, fractional or negative token counts, empty response ids, unknown component names all refuse typed), absent cells omit their field, and a requests row left with no dollars, no component split, and no usage refuses, because a row without evidence cannot reconcile anything. The providers guide now fixes the per-adapter billing contract in one matrix: what each adapter surface contributes to the join (continuation absorption and the any-id-of-the-set rule forpause_turndispatches, the one-response-id-per-wire contract of the Responses API, the coverage posture for compatible endpoints and the AI SDK bridge), so reconciliation readiness is a documented contract per adapter instead of an inference.
1.179.0
Minor Changes
1a5a85a: The claim-coverage grade rides the acceptance envelope, and strict reads it (RV1702). The eighteenth comparison benchmark's run reported
completion: 'complete'withcontradictions: []while the judge had seen 40 of 144 citing sentences, and three material falsehoods rode that gap; the counts that told the truth (RV1603) still had to be interpreted. The claim-consistency meta now carriescoverage, one closed vocabulary a consumer reads instead of inferring semantic health from an empty findings array:'full'(every citing sentence had a judged pair, nothing cut, no declared critical anchor missed, the judge settled ok; zero citing sentences grade full vacuously),'partial'(a bound cut the fold or citing sentences went unjudged),'critical-uncovered'(declared critical anchors got no judged pair),'judge-failed'(nothing was judged at all), precedence strongest last. The pureclaimCoverageOfhelper derives the identical grade from any persisted meta, including metas written before the field shipped, so old envelopes grade without re-running. The CLI's--strictnow reads the grade beside the completion contract:'judge-failed'and'critical-uncovered'exit nonzero, both states that previously slipped through strict as green, while'partial'prints its counts to stderr and keeps the exit, because the bounded pass is the documented default and declaring critical anchors is the opt-in that makes the subset enforceable.Journal: the orchestrate acceptance envelope's
claimConsistencyMetagains the requiredcoveragefield on newly settled runs; persisted metas from older engines stay readable and grade throughclaimCoverageOf.
1.178.0
1.177.0
Minor Changes
- 94db8ff: Name and pin the progressive drafting pattern (RV1607). The eighteenth comparison benchmark measured 56% of a real run's wall sitting after fan-in, dominated not by validation or repair (both repair turns took seconds) but by the first full draft, composed only after
await_alleven though every primitive for starting earlier already shipped. Two changes make the better shape first-class. The per-child guarantees are now pinned by tests:await_anyreturns the first settled digest while siblings are mid-flight, andget_child_resultserves a settled child immediately, gated on that child's own settlement and nothing else. And underexposeChildResultToolsthe default orchestrator prompt gains a conditional nudge naming the pattern (spawn the wave, await_any, read the settled child in full, draft the sections its evidence supports, fold the rest in as they settle); the line rides only with the opt-in whose toolset carries the tools it names, so a run without it keeps its exact historical prompt bytes. The docs' orchestration-modes guide gains the pattern section, withreduceCriticalPath.postFanInShareas the measure of whether it worked.
1.176.0
Minor Changes
- a74304d: Ship the read-only pilot posture as one factory (RV1606). The production-profiles guide documents the controlled-pilot assembly; the eighteenth comparison benchmark's improvement plan asked for it as a deliverable profile with typed, pre-effect refusals.
pilotAgentProfile(options)(async: the attestation pins the resolved toolset) builds onresearchAgentProfileand returns{ profile, evidence, attestation }: the confined read-only research toolset with the progress contract and stop conditions, the resolved toolset attested so a drifted registration refuses typed at spawn (RV1514), permissions hard-denyingwrite,network,execute,destructive, andundeclaredrisk in one rule withstrictApprovalsarmed andinheritPermissionsoff, and isolation pinned to'none'. A write-risk tool smuggled throughextraToolsis attested but still refused at dispatch by the risk rule before its execute ever runs. Engine-level posture (budget ceiling, exposure cap, strict pricing, acceptance floors) stays explicit engine and run configuration, deliberately outside the profile's reach.
1.175.0
Minor Changes
- 1999c5d: Adopt recovered spawn decisions by the full canonical spec on a regenerated spawn turn (RV1605). When a dynamic-orchestrator root resumes without its turn-boundary checkpoint (a lost transcript store, or a crash before the first boundary), it regenerates the spawn turn instead of continuing past it. The recovery path for that shape compared only
agentTypeandpromptat a colliding ordinal, but recovery advances the ordinal counter past every journaled admission, so the collision could not occur: every regenerated spawn re-decided and re-paid its child even with an identical spec, and the eighteenth comparison benchmark separately flagged the two-field comparison as a stale-child hazard had it fired (a changed model hint, schema, or toolset reference would have adopted a child produced under the old spec). Adoption is now content-addressed: a regenerated call whose full spec matches an unclaimed journaled admission byte for byte (jcsSerializeover every field) claims the first such decision in journal order, with the settled child replaying free, a dangling one redispatching pinned to its journaled scope, and a recovered rejection rolling forward typed; a call diverging in any field decides fresh, and the prior decision's child stays paid (at-least-once). Checkpoint-continued resumes are untouched: they never re-execute the spawn turn.
1.174.0
Minor Changes
- aa9a772: Split the critical-path synthesize wall by purpose (RV1604). The claim-consistency judge dispatches under role 'synthesize', so
reduceCriticalPathfolded its wall intosynthesisMsand one number conflated two different tails: the eighteenth comparison benchmark's harness had to annotate a 54-secondsynthesisMsby hand because the run had skipped synthesis (synthesis_skipped_by_valid_draft) and the bucket was entirely the judge and its extract phase.CriticalPath(and the clippedpostFanInbreakdown) now carryfinalCompositionMs(synthesize spans that are not the judge) andsemanticJudgeMs(spans dispatched under the exportedCLAIM_JUDGE_LABEL, which the orchestrator's judge invocation now uses as its label constant);synthesisMsstays their exact sum, so existing consumers read the same number they always did.
1.173.0
Minor Changes
- 67d27ac: Make the claim-consistency pass say what it did not judge, steer its bounded budget, and hold the draft against the run's own facts (RV1603). The eighteenth comparison benchmark ran the judge over a real dossier: 40 pairs over 144 citing sentences, truncated honestly, with nothing steering which 40 and two run-fact falsehoods sailing through with
executionFactsenabled ("each role recorded 18-20 evidence entries" over recorded profiles of 23/18/22/20/20/20; "real models were not run" beside 125 recorded wire requests). Three additions close it.claimConsistencyMeta.coveredCitingSentencescounts the citing sentences with at least one judged pair, so partial coverage is one division away instead of an inference.claimConsistency.criticaldeclares anchors (a file, a directory prefix, or a span) whose pairs sort first, before themaxcap; the meta names every critical draft anchor left unjudged (criticalUncoveredcapped at 32,criticalUncoveredTotalbeside it), andonUncoveredCritical: 'fail'fails the run typed BEFORE the judge dispatch so a run whose declared claims cannot be verified never pays for a partial verdict.claimConsistency.runFactsadds the run's recorded execution facts (children, statuses, evidence entry counts, wire and token totals) as a pool reading under the(run-facts)anchor: draft sentences naming a minted id, a standalone recorded value of two or more digits, or arunFactTermsphrase are paired with the sheet and ruled on by the same judge invocation. All three are opt-in; unset configuration derives byte-identical judge prompts, and the pure fold half (pairDraftClaimswithcritical, the newpairRunFactClaims) is exported.
1.172.0
Minor Changes
- 0d4770b: Bound the MCP tools/list pagination itself (RV1602). The eighteenth comparison benchmark called out the gap the RV1515 bounds left open: a server answering unique cursors over empty pages grows neither the tool count (
maxToolsnever trips) nor any timeout (each page answers insidelistMs), so the sweep could spin wire calls forever. Two guards close it. The cursor-echo cycle guard is unconditional: a page whosenextCursorequals the cursor it was queried with makes no pagination progress and is never a legitimate step, so the sweep refuses with a typedConfigErroron the second page at the latest. The new opt-inmaxPages(positive integer, validated with the other bounds) caps the sweep's wire call count for the general no-progress case; likemaxToolsit fails closed, refusing a server that still reports another page past the cap rather than silently importing a subset of its declared surface. Absent config preserves previous behavior except the cycle refusal, which only ever fires on a protocol-violating server.
1.171.0
Minor Changes
- f6116b9: Enforce the retry namespace separation mechanically (RV1601). The eighteenth comparison benchmark caught the RV1510 promise leaking live: 21 pre-wire quota-limiter denials exported as
agent:endretryCount21 against an invoice holding zero provider error rows, and each post-denial success record readattempt2 with no attempt-1 sibling. Three changes close it. A denied turn no longer incrementstransportRetries, soretryCountreads clean against the provider ledger (the denial stays diagnosable onagent:errorviaerror.data.source: 'quota-limiter'). A denied turn no longer advances the dispatched try counter, soProviderCallRecord.attemptis the dense 1-based dispatched ordinal by construction and a busy window can no longer exhaustRetryPolicy.attemptsbefore the wire ever opens. Denied turns instead retry against their own budget: the newquota.maxDenials(positive integer, defaultDEFAULT_MAX_QUOTA_DENIALS= 8, validated atcreateEngineintake) bounds consecutive pre-wire denials per serving target, each still waiting the limiter's ownretryAfterMs, and exhaustion takes the unchanged failover path, so a permanently denied primary still fails over on the rate-limit trigger and terminates typed asrate-limitwith no fallback left.
1.170.0
Minor Changes
86e4c06: Name the MCP session posture: per-request auth refresh and the drift policy (RV1516, the P1 tail).
The auth story and the drift story of an
mcp()source get host-owned contracts.http.headers(streamable-http only, forbidden typed elsewhere) injects headers into every wire request through a wrapped fetch; the hook form is awaited before each send, which makes it the refresh point for rotating tokens, with no reconnect and no library-invented 401 retry.driftnames what a listChanged notification means:'rekey'is the documented default (the changed list re-keys subsequently spawned agents), and'refuse'fails closed: the notification poisons the source, every latertools()refuses typed, and onlyclose()clears it, so importing a changed list is always a deliberate host action. In-flight spawn snapshots are untouched either way, and the two refusal layers compose with the toolset attestation: refuse at the source vs refuse at the spawn.
1.169.0
Minor Changes
623b2ae: Bound the MCP import surface: the tools/list sweep, per-tool schema bytes, and per-source timeouts (RV1515, the P1 tail).
An MCP server sits across a trust boundary, and three of its behaviors were unbounded on the host side.
mcp()now takes three opt-in bounds:maxToolscaps the tools/list sweep itself (checked after each page against the accumulated WIRE tools, pre-filter, so a hostile server cannot stream past it and an allow list cannot admit past it),maxSchemaBytescaps each admitted tool's serialized inputSchema plus outputSchema (the allow/deny filter runs first, so a denied tool's schema bomb costs nothing), andtimeoutsbounds the latencies:connectMsraces the handshake and releases the client (and a stdio child) on expiry with a typed refusal, whilelistMsandcallMsride the SDK request timeout per page and per call, tightening the SDK's own 60s default; a call timeout surfaces as that tool's error result and never propagates past policy. Every bound refuses typed with the measured value and the declared cap in the message; absent bounds preserve the previous behavior byte for byte.
1.168.0
Minor Changes
ebba79a: Pin a profile's toolset with an attestation and refuse drift typed at spawn time (RV1514, the P1 tail).
Provider-side drift of an imported tool's description or schema re-keys new spawns silently by design, so a poisoned MCP tool description still reached the model, just under a new content key.
AgentProfile.toolsetAttestationnow pins the hash itself: a spawn whose resolved toolset hashes to anything else refuses with a typedConfigErrorbefore any provider call or budget admission.attestToolset()records the pin from a resolution (the aggregatetoolsetHashplus per-tooltoolContractHashvalues, both exported), and the refusal names the drift (changed/missing/unexpectedtools with both hashes) when the per-tool hashes are present, or lists the resolved per-tool hashes so a stale pin can be corrected from the refusal itself. The pin binds the spawn's RESOLVED toolset, so a call-level tools override and the opt-in escalate tool drift it deliberately; the attestation shape is validated atcreateEngine(64 lowercase hex chars, tool names inside the tool-name pattern), and unattested profiles keep today's re-keying behavior byte for byte.
1.167.0
1.166.0
Minor Changes
d8262c3: Record the semantic completion lift in the run settle and read it back on the persisted terminal (the persisted-terminal tail of the P1 list).
The persisted terminal (RV1209) documented its own gap:
completionwas unrecoverable by construction, because the workflow's semantic claim rides its result value and only the value's DIGEST is journaled. An offline reader, a restarted server, or a second replica saw the transport status and the money but never whether the work was COMPLETE, which is the one field the consumers doctrine (RV1414) says to gate on beside status.The settle now records the lift it already computed. The engine lifts the completion envelope once at the settlement chokepoint (RV-207); the same object now rides the journaled
run_settledecision value flat beside the output digest (completion,childStatusCounts,degradedReasons, the salvage lists,belowFloorOkChildren,acceptanceChildren), the outputHash precedent: additive, appended only by segments that computed the value, so a pure replay never overwrites the live baseline.lastRunSettleparses the literal back defensively, andpersistedTerminalEnvelopepasses it through the one producer, so a rebuilt envelope carries the samecompletionthe live consumer saw. A settle written before the lift rode it stays honestly absent underprovenance: 'journal'(absence means NOT RECORDED), and the run's ownerrorremains the one deliberately unrecoverable field.The six plan gating cassettes whose settles gained the recorded lift are re-recorded, and the frozen-fixture lock is refreshed through its ceremony (hashVersion-bump): the settle VALUE grew richer while the identity profile and every hash rule stay untouched, so replay identity is unchanged and the re-recorded fixtures are the same scenarios with the lift visible in their settle rows.
1.165.0
Minor Changes
6391274: Carry the recorded evidence entries through the agent terminal and pair the claim pool against them (the deferred RV1501 entries plumbing).
The seventeenth comparison run's decisive finding had one more half. The worker RECORDED the correct reading through
record_evidencewith the right anchor, its composed output paraphrased the citation away, and the root inverted the reading at synthesis. The claim-consistency pool was OUTPUTS only, so the recorded entry could never pair with the inverted draft, and nothing about the entries survived resume: a replayed child restored neither its evidence verdict nor its recorded content.Four halves, one plumbing. The loop collects the CONTENT behind the evidence counter from the same message window and the same result-
recordedrule (claim plusfileorfile:linescitation, bounded: 40 entries, 400 chars per claim), onAgentResult.evidenceEntrieswhenever at least one entry exists, contract or not. The agent terminal journals both the evidence verdict and the entries (JournalEntry.evidence,JournalEntry.evidenceEntries), additive and policy-only, exactly the artifacts precedent. Replay restores both verbatim, so a resumed orchestrate holds the same settled facts a live run holds. And the claim pool reads a SECOND source per accepted child from the restored entries, one sentence per claim with its citation in the anchor syntax, so a draft contradicting the recorded reading pairs even when the composed output carries no anchor at all;poolChildrencounts children, never sources.Validated live this cycle without paid API traffic: the judge ruling on these pairs was exercised against a real model through the Codex subscription CLI (an adapter over
codex exec, structured output through the prompt tier) and caught the benchmark inversion and a numeric flip while judging a paraphrased agreement clean, three for three, one dispatch each.
1.164.0
Minor Changes
9f2dda9: Seed re-opened budget accounts from the settled journal fold and re-admit reruns of journaled invocations as recovered (RV1505, closing the DEF-7 remainder the eighteenth plan recorded).
The recovered rerun (the unblock). The reserve recovery rule already said reserves are recovered from the journal and never re-estimated, but the dispatch itself still re-cleared projected admission live: a rerun of a journaled invocation (a dangling dispatch, or a non-replayable terminal retried by resume) was held to spent plus a fresh reserve against the ceiling, and the resume seed already carries the dollars that invocation's prior attempt burned. At an exact-fill ceiling this refused the continuation of the very work the money was spent on, with the ROOT seed alone, before any account seeding: a rerun after an error terminal resumed 'exhausted' with zero provider calls. The ctx.agent dispatch layer now follows the recoverInFlight rule: journaled reruns commit their reserve through admitRecovered, the pre-count feasibility floor gates NEW work only, and the per-turn guard, the pre-dispatch output bound, and the severing signal still bound every dollar a rerun actually spends.
The per-account seed (the reopened half). With reruns safe, the engine now seeds every re-opened sub-account from the per-account rows of the SAME settled fold the root already seeds from (
accountSpendFromJournal, RunBudgetseed.accounts), so a resumed segment admits new work and prices its turns against the history a continuous run would have accumulated. Before the seed, sub-account spend was per-process amnesia: a resumed child re-opened at zero and could silently overspend the very allowance its admission verdict recorded. Two deliberate exemptions keep the seed honest: the root row is ignored (the root seeds from the same fold's total, byte for byte as before), and orchestrator-cap accounts re-arm per segment, because the cap is a per-segment coordination bound and the documented resume after a budget-cancelled root exists precisely to continue past a crossed cap under the root ceiling. A malformed seeded row (non-finite or negative) refuses loud at construction, naming the account, exactly the root seed's poisoned-journal rule.
1.163.0
Minor Changes
e8d9ada: Report the import bundle's reference closure, serve verify-only journal reads, and close the documentation gaps the benchmark named (RV1511, RV1512, RV1513). The sixth and final PR of the eighteenth plan.
The import closure report (RV1511). The intake validated shapes, namespaces, and the runId, but nothing held the ENTRIES' own references against the blobs the bundle carries: a torn bundle imported whole and the missing transcript surfaced only when something later read it.
importRunnow returns{ unresolvedRefs }, every transcript, checkpoint, artifact, and workflow-source ref the entries (and meta) name that no bundle blob resolves; the default stays permissive (retention and checkpoint pruning legitimately drop blobs their entries still name) and the report makes the gap visible, whilerequireClosure: truerefuses typed BEFORE any write. A duplicate blob ref refuses always: last-write-wins over transcript bytes is a torn or edited bundle, never a valid export.The verify-only load (RV1512). The A1 salvage model repairs a torn trailing line ON LOAD, which is right for an owner about to append and wrong for an auditor: a verification read that rewrites the artifact it verifies destroys the evidence of the tear.
JsonlFileStore({ repairOnLoad: false })serves the salvageable records without touching the file, andrulvar runs audit --no-load-repairopens the default store that way (contradicting--repairis refused typed).The documentation debts (RV1513). The README package count now matches its own table (seventeen names, the unscoped pointer included);
@rulvar/executorships a README and LICENSE like every sibling; the package reference names the eval framework's real dependencies; and the isolated-executor guide gains "What the ledger is NOT", the explicit denial list (not an outbox, not authorization, not exactly-once, not always on) for exactly the facts the seventeenth comparison run's dossier inverted while citing the sources that state them.
1.162.0
Minor Changes
2031e82: Reject invisible format characters in dossier text and split the retry namespaces on the result surface (RV1509, RV1510). The fifth PR of the eighteenth plan.
The format-character lint (RV1509). The seventeenth comparison run's answer carried five U+200B characters immediately before hidden-file citations, and every configured check passed: the citation pattern's boundary class simply excluded the invisible byte from the match, so the extracted citations were clean while the LITERAL text was not byte-identical to any repository path.
formatCharacterValidatorrejects the whole Unicode format category (Cf) with each distinct character's codepoint, first index, occurrence count, and a visible-context excerpt, so the repair turn can find the exact bytes;allowadmits named characters for content that legitimately needs them (bidi marks in RTL prose), each entry itself required to be a singleCfcharacter.The retry namespaces (RV1510). The same benchmark exported one conflated "retries" number, and 17 pre-wire quota denials read as 17 provider retries. The agent result (and
agent:end) now carriesquotaDenialsbesidetransportRetries: pre-wire limiter denials split by dimension (requestsversustokens, classified by the limiter's own reason vocabulary) with the recovered-episode count. A denial never reached the provider and never billed; provider retry attempts stay intransportRetries, and the journaledproviderCallsrecords keep the wire cardinality the invoice sums. Live telemetry only, thetransportRetriesrule exactly: never journaled, absent on a replayed result, absent means "zero or unknown".
1.161.0
Minor Changes
d4547b7: Refuse unpriced, malformed, and stale-priced dispatches before the wire under the opt-in strict pricing gate (RV1508). The fourth PR of the eighteenth plan.
Dollars come from the price table, and a model absent from it debits NOTHING, so every USD ceiling silently fails to bound it; the docs called that hole honest, and the seventeenth comparison benchmark asked for a mode that closes it.
RunOptions.strictPricingarms the gate: every paid dispatch must resolve a well-formed price row for its serving model BEFORE the wire call, at the same dispatch chokepoint the exposure admission holds, or the dispatch refuses with a typedConfigErrornaming the model and the defect (no row, a non-finite or negative rate, a malformed long-context tier).maxRatesAgeDaysadditionally demands a freshratesVerifiedAton the row, binding only when declared;allowUnpricedlists the exact model refs the host KNOWS are free, the one explicit exception. Each model vets once per run, since the price table is fixed for the run's life.The posture follows the exposure cap's durability rule (RV1504): canonicalized and recorded in
RunMetaat genesis, restored by every resume with noResumeOptionsoverride, absence stays absent, and the store conformance kit holds stores to the round-trip, because a FinOps gate a resumed segment silently drops is not a gate.
1.160.0
Minor Changes
1c6f0d0: Require an explicit flavor B default decision and add the monotonic approval composition (RV1506, RV1507). The third PR of the eighteenth plan. BREAKING for flavor B configurations that omitted
defaultDecision.The explicit timeout meaning (RV1506). Flavor B escalation suspends the worker under a journaled deadline, and the deadline's expiry APPLIES the
defaultDecision; when none was declared the engine inventedaccept, so an unattended scope escalation resolved fail open, the seventeenth comparison benchmark's top authority hardening ask. Enabling flavor B now requires an explicitdefaultDecisionbeside the already-requireddeadlineMs, aConfigErrorbefore any LLM call; there is no engine default. The tool-approval channel already holds the opposite posture (an unattended approval DENIES at itsapprovalDeadlineMs), so{ kind: 'cancel' }is the declaration that makes both timeouts close the same way. Migration is one line on each flavor B config; the runtime semantics of a declared decision are unchanged, and a racing live decision still wins first-closed.The monotonic approval composition (RV1507). The permission chain's documented order lets a generic ALLOW (a hook or
canUseTool) clear aneedsApproval: truetool, which is deliberate for tests and trusted hosts and a fail-open hazard for a platform profile.permissions.strictApprovals: truemakes such an allow fall through instead of deciding, so the terminal default still asks for exactly the tools that declared the need; deny and ask keep their power,{ modifiedInput }still applies, tools without the declaration keep the historical composition byte for byte, and the flag merges as OR across the engine and profile layers, so a profile cannot loosen an engine-armed mode. A non-boolean value refuses at compile.
1.159.0
Minor Changes
e881c8b: Record the in-flight exposure cap in RunMeta and restore it on every resume, and fold each budget account's settled spend for audits (RV1504, RV1505 first half). The second PR of the eighteenth plan.
The durable exposure cap (RV1504).
RunOptions.maxInFlightExposureUsdwas operational and per-invocation, so a resumed segment silently ran WITHOUT the exposure bound the original invocation declared, the seventeenth comparison benchmark's top FinOps gap. The cap now follows the ceiling's exact rule: recorded inRunMetaat genesis, restored by every resume, noResumeOptionsfield to override it, absence stays absent (a run started uncapped stays uncapped, a pre-field journal resumes exactly as before), and the store conformance kit holds stores to the round-trip. One honest asymmetry is documented rather than papered over:limitsstay per-invocation, so a resumed segment that does not re-supply them prices turn estimates from the model's full output allowance, and a tight restored cap then refuses dispatches the original clamped estimates admitted; that direction is fail closed, never silent uncapping.The per-account audit fold (RV1505, the audit half).
accountSpendFromJournal, exported from@rulvar/core, folds the same settled entries the cost report folds into each budget account's INCLUSIVE spend, with the account tree read from the journaled spawn-admission decisions, so a host can hold any orchestrator cap or child allowance against what its subtree actually spent on a plain stored journal. Abandoned subtrees and unpriced slices contribute zero, exactly like the net total. Seeding the fold into re-opened accounts on resume is deliberately NOT wired yet: a rerun of a journaled invocation re-admits with exact-fill arithmetic today, so spend-at-reopen would refuse the continuation of the very work the money was spent on; the reopen seeding lands together with a seed-aware rerun re-admission, and the docs name the remaining amnesia instead of hiding it.
1.158.0
Minor Changes
a266bc7: Hold the composed draft to the pool it composed from, with a bounded model judge over anchor-paired claims, and show the run its own execution facts (RV1501, RV1502, RV1503). The first PR of the eighteenth plan.
The claim pairing fold (RV1501). The seventeenth comparison run's security child read
packages/executor/src/subprocess.ts:256-296correctly (a failed audit write does not mask success), and the ROOT inverted the claim in the final draft while citing the very same span; every configured check passed because each judged the draft alone, never against the pool that contradicted it.pairDraftClaims, exported from@rulvar/core, is the pure half that closes the gap: every draft sentence citing an anchor (path:lineorpath:start-end, the citation pattern extended with a range suffix) is paired with the accepted pool sentences citing an intersecting span of the same file, verbatim agreement dropped, everything bounded (pair cap, per-pair pool cap, excerpt cap) and fail closed at intake, deterministic and journal-free likefindContradictions.The claim-consistency judge (RV1502).
orchestrate({ claimConsistency })wires the fold to the post-fan-in chokepoint, strictly after the contradiction pass and before any synthesis dispatch, and rules on the pairs with ONE bounded structured-output invocation under role 'synthesize' (judge.model/judge.effort/judge.limits/judge.estCostoverride the routing chain). No pairs means no judge dispatch. The verdict is an ordinary journaled agent entry, so a resume replays it with zero paid calls.onFoundspeaks the contradiction pass's vocabulary: 'report' putsclaimContradictionsandclaimConsistencyMetaon the acceptance envelope, 'carry' rides aCLAIM CONTRADICTIONS:line in the single-mode synthesis prompt and blocks the valid-draft skip while findings stand, and 'fail' fails the run typed withdata.source'orchestrator_claim_consistency' before anything pays to compose the inversion away. A dead judge is a named fact (judgeFailedon the meta, findings absent, never an empty list that would claim agreement) and fails the run only under 'fail'.The execution self-facts (RV1503). The same run graded its whole dossier
live-observed: nowhile the harness had just watched 118 wire requests settle, because no surface ever showed the composing model what its run executed.executionFacts: trueputs a replay-stablefactsblock (wire requests, missing response ids, journaled token totals; dollars deliberately absent because replay re-prices) on every awaitTaskDigestand everyget_child_resultpage, andsynthesis.runFacts: truefolds the aggregateRUN FACTS:line into the synthesis prompt, naming its own boundary: live-observed by this run's own harness, production evidence it is not. Both off by default, byte-identical surfaces without them.
1.157.0
Minor Changes
1883421: Hold ok children to their declared evidence floor, declare the cost basis on every money surface, and document the terminal contract for consumers (RV1412, RV1413, RV1414). The sixth and final PR of the seventeenth plan.
The ok-child evidence floor (RV1412). RV1207 made a declared evidence contract binding for the salvage arms, but a child that settled 'ok' below its declared floor sailed through acceptance behind a clean headline: its roster row said
met: falsewhilecompletionsaid 'complete' anddegradedReasonsstayed empty. The shortfall is now a degradation note by default, so the completion claim stays honest ('partial', never 'complete' over an unmet declared contract) while the verdict and the status counts stay exactly what they were, and the envelope, therun:endlift, and theRunOutcomemirror carrybelowFloorOkChildrennaming such children machine-readably. Under the existingacceptance.requireEvidenceFloorflag the floor binds for ok children exactly as it does for the salvage arms: the child counts against the policy ('all-ok' rejects,{ minSuccessful: N }does not count it), its roster row is markedfloorRequired: true, and in an accepted run it stays out of the contradiction pool and the synthesis evidence index, read from the decision's own roster rows so live and resume derive the same pool. What neither mode changes:childStatusCountsstays factual and the child's output stays visible through the digest andget_child_result. Deliberately out of scope: the pre-acceptance finish validators keep reading ok children's citations as evidence, because validation runs before the verdict and paid journaled text is real either way.The cost provenance marker (RV1413). Every dollar the engine reports is journaled usage priced at the CALLER'S pricing table, never a provider statement, and the seventeenth comparison run's "$4.79" read as an invoice figure precisely because nothing said otherwise.
CostReport.basisandTerminalEnvelope.costBasisnow declare'locally-estimated'as a literal, stamped by both report builders and at the envelope's one producer (journal rebuilds included), mirroringInvoiceExport.pricingBasis. No field is renamed; reconcile real bills through the invoice export andreconcileStatement, which carry their own provenance.The terminal contract for consumers (RV1414). A new documentation section pins the doctrine the vocabulary was built for:
statusis transport,completionis the work's own claim, the acceptance verdict is a policy over statuses, and none of them, alone or together, authorizes a side effect. Effects during the run belong to tools behind the permission chain and approvals; effects after the run belong to the consumer's own policy over the terminal facts, read from the settled authority (the persisted envelope or its typed refusal), with the money read as whatcostBasisdeclares and absence read by each field's absence doctrine.
1.156.0
Minor Changes
537144e: Validate every restored counter at the checkpoint decode boundary, count single-wire rows in the invoice join-coverage aggregate, and resolve run profiles by own property (RV1409, RV1410, RV1411).
decodeCheckpointnow refuses a blob whose required counters are not non-negative finite numbers:turns,toolCallsUsed,schemaAttempts, every usage field (the optional ones when present), and the compaction points (RV1409). Those counters seed the loop's limit arithmetic and are reported to the budget as paid spend, and none of the refused shapes was ever produced by a boundary write (JSON delivers the NaN corruption asnulland1e999asInfinity), so the blob as a whole is untrustworthy and the dangling dispatch reruns from the top, exactly like a blob that does not parse. Before this shipped, a store-side corruption or a hostile writer could restoreturns: -2and credit themaxTurnsceiling with turns nobody paid. Deliberately not judged at decode: the Usage invariant, integer rules, and TTL splits. Checkpoints written before those invariants shipped are honest evidence of paid work and still decode; the restore path sanitizes them exactly as it always has.InvoiceCardinality.wireIdsMissingnow counts the requests across EVERY dispatch row that carry no join key (RV1410). A single-wire row is its one request, joined by the row's ownresponseId, so an id-less single-wire row contributes one missing key; failed requests count like any other, because the provider may have billed them and a statement line cannot be joined to a row with no id either way. Before this shipped the counter looked only inside multi-wire rows, so a fleet of single-wire dispatches whose adapter surfaced no response ids read as fully joined (wireIdsMissing: 0) while every row-level verdict saidmissing-provider-id: the aggregate contradicted its own rows.runProfile()resolves the shipped preset roster by own property (RV1411, the last prototype-sensitive surface of the RV1205 class): an inherited object name (toString,constructor,__proto__) is not a profile and now returnsundefined, the value hosts key their unknown-name refusal on. The CLI's--profile toStringbecomes the typed unknown-profileConfigErrornaming the shipped roster instead of a silently accepted empty profile.
1.155.0
Minor Changes
- 49b08a7: Make the persisted terminal tail-aware and give offline authorities the engine's own resolution validator (RV1407, RV1408). The persisted terminal (RV1209) served the journaled settle even when the journal had CONTINUED past it, so a restarted reader could hold yesterday's envelope over a run that a detached resolution had already destined to resume, or that a successor segment was actively working, while
auditRunderived a non-terminal status from exactly that evidence.persistedTerminalEnvelopenow refusesnot-terminalwhenever entries follow the last settle, with a message naming the continuation (count and settle seq), so the persisted surface and the audit read one journal one way; the conformance table pins the new refusal (settled-then-continued) beside the five terminal paths. And the CLI server's offline resolution used a lookalike validator that demanded the plain{ decision }from EVERY kind-'approval' suspension: a legitimateEscalationDecisionfor a flavor B escalation was refused, and a wrong-shaped plain approval payload was waved into the journal. The new exportvalidateDetachedResolutionis the engine's own detached validation (the RV1203 flavor classifier, both payload arms, the pinned schema) as one function; the engine's detached path and the CLI offline path now call the same bytes, so an escalation resolves offline with its OWN payload exactly as detached-live, and an invalid one is refused typed before anything is journaled.
1.154.0
Minor Changes
- 9259f24: Reserve the tail of the turns axis and project it in preflight (RV1405, RV1406). The seventeenth comparison experiment's worker burned
maxTurns28 at 66 of 96 executed tool calls and settledlimitwith no finalize phase, because the finalization reserve fires on tool-budget limiters and the finalization window watches tool-budget counts, and nothing watched the turns. The new opt-inlimits.finalizationTurns: { reserveTurns, allow? }extends the SAME window regime to the turns dimension: once the remaining turns againstmaxTurnsdrop toreserveTurns, non-allowlisted calls receive the typed window refusal, the one-time notice names the turns arithmetic, and the terminal tool stays admitted. The regime keeps one allowlist (finalizationWindow.allow, elsefinalizationTurns.allow, else the zero-cost tools); with both dimensions inside their reserves the smaller remaining binds, and the notice, every refusal, and the RV509 decision entry (budget: 'turns') all name the binding dimension's own reserve. The tail lives INSIDEmaxTurns(the ceiling stays a ceiling), the RV1208 deficit widening stays calls-only, repair-turn grants are deliberately not counted, resume re-arms identically, and configuring the reserve alone makes thetoolBudgetsnapshot (and the policy-facts window line) present so a turns-only run has a home forfinalizationWindowEntered. Preflight gains the turns-axis projectionturns-bind-before-tool-budget(RV1406): whenmaxTurnsfits fewer serial executed calls (one per turn plus the final answer turn) than the effective executed-call ceiling, extension grants included, the finding says the turns axis binds first, as a warning without the reserve and an info with it, never a stop; andfinalization-turns-covers-max-turns(warning) whenreserveTurnsis not belowmaxTurns.
1.153.0
Minor Changes
d8bebcb: The contradiction pass and every evidence pool judge the ACCEPTED roster, and the carry posture becomes an invariant (RV1403, RV1404).
The seventeenth comparison run exposed both halves. Its pass judged five of six accepted children, because a limit child accepted as a structured partial carried no terminal output and the pool's eligibility only knew the output arm; and its
onFound: 'carry'configuration would have silently carried nothing had the pool disputed itself, because a valid draft skipped the synthesis the carry line was supposed to ride.RV1403 makes the roster the acceptance decision counted the one pool every downstream surface reads. The contradiction pass and the synthesis
evidenceIndexjudge the ok children plus both salvage arms, taken from the decision itself (fresh or rolled forward from the journal, so live and resume derive the same set): an accepted structured partial's rival reading can now dispute the pool and its citations index, while a child blocked by the binding evidence floor (RV1207) stays out even when it carries a validated terminal output, because a reading the policy refused to count must not steer what composes the result. The finish validation snapshot predicts the same arms: a partial-accepted child is marked with the newFinishValidationChild.salvageablePartial(soevidencePreservedValidatorcounts the accepted partial's citations andrequireKnownno longer flags an honest quote of it as fabricated), and a below-floor child is no longer markedsalvageableOutput, mirroring exactly what acceptance will do.RV1404 adds two honesty guarantees. Non-empty findings under
'carry'disable theskipWhenDraftValidgate for that draft, announced in an info log (orchestrator synthesis skip blocked by contradictions); a clean pool keeps the skip byte for byte, and a skip already journaled stays the authority on resume. And the envelope gainscontradictionsMetabesidecontradictions, present exactly when the pass is configured:poolChildrensays how many accepted children were judged, andtruncatedsays whether more contradictions existed thanmaxallowed to report, so a capped findings list can never read as a complete one. The pass log event carries the same flag, and the'fail'posture's typed error data carries the meta beside the findings.
1.152.0
Minor Changes
dd6a616: Rebuild the repository-aware citation surface from scratch (RV1401, RV1402). v1.151.0 first shipped this surface; this release replaces that implementation with a fresh cut of the same declared contract, and the public signature is unchanged.
citationTargetsValidator(RV1401) resolves EVERY citation of the result text against the host's frozen source snapshot, inline code and plain prose alike, with no sentence-level precondition. The seventeenth comparison run's answer carriedghost.ts:0, a location no checkout ever held, and the whole configured chain passed it: the citation pattern accepts any digits (a line of 0 included),evidencePreservedValidator'srequireKnownproves only that some child SAID the string, andcitedValueValidatorresolves a citation only when its sentence asserts an inline value beside it, so a fabricated location nobody asserted anything about counted as provenance and licensed the valid-draft skip. Three refusals, each fail closed: a match of the citation pattern that does not parse aspath:linewith a safe integer line is refused rather than skipped, because the host's own pattern claims it IS a citation; a line below 1 is refused BEFORE the resolver runs, because source lines are 1-based and a sloppy resolver might well answer line 0; and a location the resolver does not know is refused, because a citation nothing resolves is not provenance. Repeated occurrences are judged once, refusal reasons cap at 20 listed offenders,fencedCode: 'excluded'strips fenced code before scanning (default'counted'), a text carrying no citation at all passes (demanding citations exist isminMatchesValidator's job), and intake is fail closed in the RV610 posture: a pattern that does not compile or that can match the empty string is refused typed. Wired intofinishValidation, the refusal reaches theskipWhenDraftValidgate like every other validator verdict, so a draft carrying a fabricated citation can no longer skip the synthesis it was supposed to earn.citedValueValidator(RV1402) now matches asserted values as WHOLE tokens instead of substrings. The boundary class is word characters plus the dot: an asserted3no longer counts as carried by a line saying30or3.5(the seventeenth comparison judge's repro),retry.tsno longer matches insidemyretry.ts, and the value itself is matched literally with regex metacharacters escaped.
1.151.0
Minor Changes
1de0610: Every citation in a finish result can now be resolved against the host's own source snapshot, and cited values match as whole tokens (RV1401, RV1402).
The seventeenth comparison run shipped an answer carrying
ghost.ts:0, a location no checkout ever held, and every configured check passed: the citation pattern accepts any digits (a line of 0 included),evidencePreservedValidator'srequireKnownproves only that a child SAID the string, andcitedValueValidatorresolves a citation only when its sentence asserts an inline value beside it. A fabricated location that no sentence asserted anything about therefore counted as provenance and licensed the valid-draft skip.citationTargetsValidatorcloses the hole at the root. Every match of the citation pattern in the result text, inline code and plain prose alike, is parsed aspath:lineand resolved through the same pureresolve(target)snapshot contractcitedValueValidatortakes, with no sentence-level precondition. Three refusals, each fail closed: a match that does not parse aspath:lineis refused rather than skipped, a line below 1 is refused BEFORE the resolver runs (source lines are 1-based, and a sloppy host resolver might well answer line 0), and a citation the resolver does not know is refused, because a citation nothing resolves is not provenance. Repeated occurrences are judged once,fencedCode: 'excluded'strips fenced code first for hosts whose contracts already exclude it, and intake is fail closed in the RV610 posture: a pattern that cannot compile or can match the empty string is refused typed. Wired intofinishValidation, the refusal also reaches theskipWhenDraftValidgate, so a draft carrying an unresolvable citation can no longer skip the synthesis it was supposed to earn.citedValueValidatornow requires an asserted value to appear in the cited line as a WHOLE token instead of a substring: judged byincludes, a claim of3was satisfied by a line saying30, which is the seventeenth judge's repro. The boundary class is word characters plus the dot, so3matches neither inside30nor inside3.5, andretry.tsno longer matches insidemyretry.ts; spaces, punctuation, operators, and the line edges still bound a token.
1.150.0
Minor Changes
a331211: The settled child pool is checked against itself before anything composes it (RV1301, RV1302, RV1303).
A fan-out produces N independent children, and nothing in the pipeline compared their claims against EACH OTHER. Acceptance judges each child alone, the finish validators judge the final text mechanically,
citedValueValidatorjudges a claim against the SOURCE rather than against another child, anddedupeClaimsmatches on agreement, so it is blind to disagreement by construction. A run where one child readattempts: 3atsrc/retry.ts:33and another readattempts: 5at the same line put both into the synthesis prompt, the composing model picked one, and the run settled confident with no surface recording that its own evidence had disputed itself. This is the sixteenth comparison judge's P2-1 remainder, deferred at the time as a phase that deserved its own release.orchestrate({ contradictions })folds the settled evidence pool at the post-fan-in chokepoint: after the accepted acceptance verdict, before any synthesis dispatch. It is bounded in the strongest sense available, a pure fold with no model call, no clock, no host code, and no journal entry of its own, so it costs nothing in the post-fan-in windowreduceCriticalPathmeasures and a resume re-derives the identical finding for free. The rule is deliberately narrow, so a finding is always explainable in one sentence: two DIFFERENT children credit the same cited location with different values for the same key. It reads the same span vocabulary the RV1212 validators read (inline-code spans that parse aspath:lineare the anchors, the rest are the values asserted about them) and splits each value at its first:or=into a key and a reading.Three non-findings are as deliberate as the finding. Two keys on one line (
attempts: 3besidebackoffMs: 100) are aspects of that line, not a dispute, so the key must match. A span with no separator names something without asserting anything about it, and two such spans can never conflict. And one child holding both readings is narrative inside a single document, not a pool contradiction, while two independent children disagreeing is exactly the signal the pool cannot resolve by itself. The pool judged is the evidence poolevidenceIndexindexes, ok children plus salvage-accepted ones, so a dead child's error text can never dispute a real finding.onFoundpicks the posture.'report'(the default) puts the findings on the acceptance envelope and in an infologevent and changes nothing else.'carry'additionally rides aCHILD CONTRADICTIONS:line in the'single'synthesis prompt demanding each disagreement be resolved explicitly instead of silently picked, and requires that synthesis (aConfigErrorat intake otherwise, and the deterministic'incremental'reconciliation has no prompt at all).'fail'fails the run typed withdata.source'orchestrator_contradictions', the findings, and the acceptance snapshot the run already earned, BEFORE any synthesis dispatch, so a self-contradicting pool never pays for the invocation that would compose the disagreement away.The envelope field distinguishes two facts that look alike:
contradictionsis present whenever the pass was configured and EMPTY when it ran and the pool agreed, while its absence means nothing looked. That is the RV1209 absence doctrine applied to a second surface.maxbounds the findings (default 20) andpatternoverrides the anchor shape, refused fail closed at intake on a pattern that can match the empty string. Everything stays byte identical without the option, and a'carry'run whose pool agrees emits the identical synthesis prompt bytes as a run without the pass.One honest bound: this is the mechanical half. Two children disagreeing in prose, with no shared citation and no shared key, are invisible to it, and closing that needs a bounded model pass with its own budget, journal, and resume semantics, which will consume this same
Contradictionshape. The pure fold ships first because it is free, deterministic, and reproduces on replay.findContradictionsis exported from@rulvar/coreso a host can run the same rule over any pool it holds.
1.149.0
Minor Changes
08b4537: The post-fan-in model bucket is profiled, the final answer gets two evidence validators, and the terminal envelope's typed error is detached (RV1211, RV1212, RV1213).
PostFanInBreakdownsplits the coordination model bucket three ways.coordinationModelMsByPhasekeys the activation wall by the activation's OWN invocation role, so a tail spent compacting is distinguishable from a tail spent drafting.coordinationModelOnlyMsis that wall with the tool executions NESTED inside it removed, the exact set difference of the two clipped unions rather than a subtraction of sums, because a tool an activation called runs inside the activation's wall and reading the wall as thinking time overstates it by exactly the tool share.coordinationToolCallsByNamecounts the executions beside their milliseconds, so one slow pagination and twenty fast ones stop reading as the same tail. The sixteenth comparison experiment put 222.6 seconds (50.9% of wall) in this bucket with a zero synthesis share, and one number for it could not say what the coordinator was doing.Two new finish validators judge the answer's evidence rather than its shape.
evidenceGradeValidatorrequires every sentence claiming something islive-observed, came from theprovider bill, or isproduction-provento name a run id or afile:linecitation in THAT sentence; the phrase list and the artifact pattern are configurable, and a pattern that can match the empty string is refused typed because it would satisfy every graded claim silently.citedValueValidatorchecks that a cited location actually carries the value its sentence asserts, against a source snapshot the host resolves: within one sentence the inline-code spans that are not citations are the asserted values, each must appear in the cited line (or withinwindowlines after it), a location the resolver does not know is a failure rather than a pass, and a sentence that cites without asserting an inline value passes untouched.resolvemust be pure over a snapshot frozen before the run, like every finish validator.TerminalEnvelope.erroris now a detached copy, itsdatanesting included, exactly likecostByModel: a consumer that annotates the error it holds can no longer reach back into the outcome the engine still owns.
1.148.0
Minor Changes
c85dac9: The terminal envelope survives the process that produced it, and the invoice states how many provider requests its rows represent (RV1209, RV1210).
A run this server never held used to answer
GET /runs/:idwith a bare status projection while a live consumer read the wholeTerminalEnvelope, so the durability story stopped one surface short of the one a host reads after a restart. The non-live response now carriesenvelopetoo, rebuilt from the journal through the same producer and markedprovenance: 'journal': the verdict comes from the journaled run settle (the authority, not the meta projection), the money from the same composed settle-pin foldGET /runs/:id/costruns, and the usage andagentsSpawnedfrom the same ledger fold the resume budget seed uses. Two fields are deliberately absent on a rebuilt envelope and the marker is what makes their absence honest:completion(the workflow's semantic claim rides its result value, and only that value's digest is journaled) anderror(the run's terminal wire error is never journaled as the run's own), so absence there means NOT RECORDED, never "the workflow claimed nothing" or "the run did not fail". A live envelope carries noprovenanceat all and keeps its original byte contract. Where nothing durable records a terminal, the body carries a typedterminalUnavailable: { reason, message }(unsettled,not-terminal, orunknown-workflow) instead of an envelope; it is its own field, nevererror, becauseerroron that body means the run failed.persistedTerminalEnvelopeis exported, and the terminal-envelope conformance table now drives every row through a restarted server as its final surface.The invoice declares the dispatch-versus-wire cardinality (
cardinality: { dispatchRows, wireRequests, multiWireRows, wireIdsMissing }). One row is one logical dispatch, and a dispatch that absorbed provider-side continuations is billed as several HTTP requests, so a per-request statement has more lines than the export has rows by construction: reconcile a statement line count againstwireRequests, neverrows.length. The per-rowwireRequestsbehind it comes from the count the adapter reported rather than the length ofwireResponseIds, because a provider that leaves an absorbed segment unnamed still billed it, and counting ids alone made the invoice contradict the quota window that settles on the same count. Single-wire dispatches carry neither field and stay byte-identical.Two limiter fixes ride with it. An abort landing inside an awaited quota reservation now stops the wire: a limiter that queues can hold
reservepast the dispatch's own abort check, and the engine rechecks the host and budget signals when the reservation resolves, releasing the granted admission rather than reconciling it, because a settlement only ever adds while that call provably never happened. And the unused-continuation release is fail closed on the wire count: only a finish that names its wire set proves which pre-wire grants went unused, so a finish carrying no count releases nothing, instead of reading the absence as one flown wire and handing a hook-granting adapter back exactly the capacity it had consumed.
1.147.0
Minor Changes
6367231: A declared evidence floor can be made binding, and the finalization window can reserve the calls that close it (RV1207, RV1208). Two opt-ins answer the sixteenth comparison run, where a worker spent 108 tool calls, settled
limitwith 10 of its 14 declared evidence entries, and was promoted through terminal-output salvage with the floor waived, so the run reportedstatus: 'ok'withcompletion: 'partial'over an unmet contract.acceptance.requireEvidenceFloor: truemakes the declared floor binding: a child that declared an evidence contract it did not meet is never promoted by a salvage arm, so it counts against the policy exactly like an unsalvageablelimitchild ('all-ok'rejects;{ minSuccessful: N }does not count it toward N). Salvage stays diagnostic: the acceptance roster still records the arm that would have applied and the evidence verdict, markedfloorRequired: trueinstead ofwaivedBySalvage: true, thedegradedReasonsname the shortfall with its counts, and the child's output stays visible through the digest andget_child_result. A child with no declared contract, or one that met its floor, is untouched.limits.finalizationWindow.reserveForEvidenceDeficit: truemakes the reserved tail evidence-aware: with an evidence contract declared, the effective reserve is the larger ofreserveCallsand the outstanding deficit plus one summary call, recomputed at every boundary from the same successful-record_evidencewindow the floor refusal and the RV809 deficit trigger read. A fixed reserve can be outgrown by the deficit it was meant to cover; this one cannot, so searching stops while the floor is still closable. The reserve collapses back toreserveCallsas entries land and never narrows below it, and the one-time window notice names the live deficit. Both options are off by default and the surrounding behavior is byte-identical without them.
1.146.0
Minor Changes
- 5d9bbc8: Profile vocabularies are what the host registered, nothing inherited, and
importRunapplies the one safe runId guard (RV1205, RV1206). Every profile map read went through a bare index, which resolves the JavaScript prototype chain: anagentTypenamingtoString,constructor, orhasOwnPropertyresolved a function as its "profile", passed theprofilesallowlist, recorded aspawn:admitteddecision, and burned the slot before dying downstream on the inherited value (the sixteenth experiment's judge reproduced it as R3). All four surfaces now read own properties: the orchestrate advertisement filter (which additionally builds a null-prototype advertised map), the allowlist enforcement and profile resolution at spawn,ctx.agent's agentType registration check, and the preflight spawn-spec resolution. A prototype name is now exactly as unknown as any unregistered name: it refuses typed before admission and consumes nothing. Separately,engine.importRunnow appliesassertSafeRunIdat its intake, the same guardengine.runandengine.resumeuse: an import previously validated only "non-empty string", so a bundle claiming.., a slashed path, or an over-length id reached the stores raw.
1.145.0
1.144.0
Minor Changes
- c11bcd6: Detached resolution picks its validator by the suspension's journaled flavor, and journaled deadlines are range-checked and corruption-checked (RV1203, RV1204). The v1.143.0 opt-in approval deadline made the detached resolver's deadline-presence heuristic wrong: a settled run's TIMED tool approval rejected the plain
{ decision: 'allow' }as a malformed escalation decision, so nobody could resolve it detached and the parked approval always died at its deny-by-timeout (the sixteenth experiment's judge reproduced it as R2). The detached path now classifies by the suspension's own shape: an escalation is recognized by its structural invariant (a required deadline plus the hardcoded toolNameescalate, true by construction since flavor B shipped), every approval suspension written since v1.144.0 journals an explicitflavor: 'approval'in its payload to pin the one ambiguous name (an ordinary tool literally calledescalatethat opted into the deadline), and the validator follows that flavor, deadline or not. Both deadline knobs (permissions.approvalDeadlineMs, the escalationdeadlineMs) now share a compile-time deadline ceiling of one hundred years in milliseconds, sonow + intervalalways journals as a valid absolute date instead of passing the positive-integer check and dying generic withInvalid time valueat theDateconversion (judge repro R4). A journaleddeadlineAtthat does not parse as a date refuses typed as journal corruption, atimportRunintake (the journal shape gate) and again before any timer arms; the oldDate.parse(...) || nowfallback silently resolved such an entry immediately, an instant deny for an approval and an instant default decision for an escalation.
1.143.0
Minor Changes
- f412169: The opt-in approval deadline (RV1107):
permissions.approvalDeadlineMs(engine-wide or per profile, most specific wins) journals an absolute deadline on the ask suspension entry, and an approval nobody resolves by then is DENIED by a resolutionby: 'timeout'through the same first-closing-wins arbiter every live decision uses. The machinery is the flavor B escalation deadline's, one suspension kind over: the timer arms FROM THE ENTRY (so the deadline survives resume and a config change never moves an already-journaled one), a live decision cancels it, the deny fails closed with a typed reason the model sees as the denied tool result, and a run parked'suspended'in a live process still denies at its deadline, the resolution appending durably for the next resume to fold. Absent config keeps the documented indefinite wait. The docs gain the deployment boundary section (RV1108): what the engine enforces versus advises, and the IAM, KMS, DLP, case-store, and PII-canary posture that deliberately lives outside the library.
1.142.0
1.141.0
Minor Changes
- 4f12a62: The unified terminal envelope (RV1105, the P1-5 arc): every terminal fact of a run travels in ONE exported shape,
TerminalEnvelope(run identity, status, the typed error, the completion claim,settled+settledReason,totalUsd/grossUsdwith the detached per-model split, the usage aggregate,usageApproxnormalized to a boolean, andagentsSpawned), assembled once at the settlement chokepoint by the exportedterminalEnvelopeOfafter the settlement verdict is known. Every surface carries that object: the resolved outcome (outcome.envelope, alwayssettled: true, because an unsettled terminal rejects typed instead of resolving), therun:endevent (event.envelope, where thesettled: falseenvelopes live with the superseded reason inside), the server'sGET /runs/:idresponse, and the OTel exporter (rulvar.run.total_usd,rulvar.run.agents_spawnedbeside the existing settled attributes; a persisted stream from an older engine still closes its span). Nothing pre-existing was renamed or removed: the envelope is an assembly over fields that all remain.
1.140.0
1.139.0
Minor Changes
- 03a2141: The live budget debits each provider call marginally against the call's own accumulated price (RV1101): a long-context tier crossed by the call's sum that no single mid-stream slice reached now re-prices the whole call live at the crossing slice, exactly the dollars the settled fold records, and a ceiling between the per-slice and tiered readings severs the run instead of settling ok over its own hard cap.
RunBudget.openCallMeterand the optionalBudgetHooks.openCallMetercarry the seam (one meter per provider call, the settled fold's billing basis; the mid-stream deltas and the settle remainder of one call share one accumulation; a marginal debit never credits; the tier still never fires on a run aggregate no single call crossed). The fault kit gains thetier-crossing-live-parityscenario (RV1102), pinning both money paths and the marginal live ladder on the real engine.
1.138.0
Minor Changes
ed0c4fb: Pre-wire continuation reservation, the self-describing fault kit, and the run-id surface (RV1013 + RV1014, PR VII closing the fourteenth plan)
- Pre-wire continuation admission (RV1013, opt-in). Post-hoc settlement is accounting, not admission: a hard provider RPM cap needs each
pause_turncontinuation reserved BEFORE its egress. Withquota: { reserveContinuations: true }the engine admits every provider-side continuation through the new adapter-sideStreamHooksseam (ProviderAdapter.streamgains an optional third parameter; the Anthropic adapter honors it): under a 2-request window the third wire of one absorbed dispatch never leaves and the denial rides the provider-429 machinery verbatim, the main settlement stops re-adding individually admitted segments (the window is never double-counted), and a granted admission whose wire never left is RELEASED back to the window through the new optionalQuotaLimiter.release(reservationId)(implemented bymemoryQuotaLimiter; a release returns exactly what admission consumed, and unknown or expired ids are no-ops). Adapters unaware of the hook keep the documented post-hoc semantics byte for byte, and the default stays post-hoc. The midstream-versus-finish usage confirmation now fires only when a finish CLAIM exists: an error-terminal absorption (a segment denial, a transport cut) no longer manufactures an invariant violation that shadows the real wire error. - The self-describing kit (RV1014).
runFaultInjectionrefuses an emptyonlyselection typed (a gate that runs zero scenarios used to reportallMatched: true), and the report carriesrequestedandselectedcounts so the gate can never quietly shrink. The audit scenario grows the RV1007 arcs (a page-only long-context tier and aNaNscalar are findings, never silent passes), completing kit coverage of every real defect of the fourteenth plan on its real path. - The run-id boundary surface (
assertSafeRunId,MAX_RUN_ID_LENGTH) is now exported from@rulvar/core, so hosts can pre-validate ids beforeengine.run.
- Pre-wire continuation admission (RV1013, opt-in). Post-hoc settlement is accounting, not admission: a hard provider RPM cap needs each
1.137.0
Minor Changes
96f6788: Integrity and boundaries: importRun fails closed with rollback, opts.profiles is an enforced allowlist, and a secret-shaped runId refuses at intake (RV1010 + RV1011 + RV1012, PR VI of the fourteenth plan)
importRunhardening (RV1010). The intake fails closed before the first write: every bundle blob ref must live in the bundle runId's own namespace (<runId>/...), so a crafted bundle for run A can never overwrite run B's blobs, and every entry must pass the journal codec's shape validation, so an import never appends garbage it would later refuse to replay. Writes land blobs, then entries, then meta, and a mid-import store failure rolls the partial import back best-effort: the exists-refusal never bricks the retry.opts.profilesis an enforced allowlist (RV1011). The advertisement was filtered but the dispatch resolved from the FULL registry, so a spawn naming a registered-but-hidden profile by a guessed name went straight through. The dispatch now resolves from the same filtered set, and withopts.profilespassed, a spawn naming anything outside the allowlist refuses with a typedConfigErrorbefore admission (no slot burned, nothing journaled); withoutopts.profilesbehavior is unchanged.- Secret-shaped runId refusal (RV1012). The runId is a correlation key: it rides every event envelope UNMASKED (body masking runs before the envelope is assembled), so a secret-shaped runId was a masking-bypass channel the host created itself. Under an active masking policy,
engine.runnow refuses typed a runId the policy would rewrite (the default credential patterns and any hostredaction.patternsalike), andassertSafeRunIdgains a 200-character ceiling (MAX_RUN_ID_LENGTH); withmaskEvents: falsenothing is masked anywhere and the check does not apply.
1.136.0
Minor Changes
aa6ca71: A superseded segment refuses green everywhere: typed SupersededError, the distinct settledReason on run:end, and exactly one authoritative successor (RV1009, PR V of the fourteenth plan)
The fencing design swallowed a superseded segment's
LeaseHeldErroron both settlement writes, so a stale segment whose settle bounced off the successor's fence resolvedokwith an unmarkedrun:end: a green terminal that no durable store wrote, exactly the split view the RV907 doctrine forbids.- The stale segment now rejects
handle.resultwith the typedSupersededError(codesuperseded, not retryable,data { runId, runStatus }, cause the fencing rejection): the successor owns settlement, and the authoritative outcome is its settle or the store's run meta, never the stale computation. The meta write is skipped instead of re-proving the fence. run:endrefuses green withsettled: falseand the distinctsettledReason: 'superseded'(an l0-compatible extension), so an event-only consumer can tell a superseded segment from a settlement write failure; the settlement-failure path and every ordinary terminal keep their exact bytes.- A meta-only lease bounce over an already durable settle stays swallowed: the journal records the outcome, and only the projection belongs to the current holder (the takeover no-op contract is unchanged).
- The CLI progress line renders
settled=false (superseded; the successor owns settlement)instead of the resume hint, and the OTel exporter stampsrulvar.run.settled_reasonbeside the refused span status. runFaultInjection(@rulvar/evals) grows the nineteenth scenario,superseded-terminal-honesty: the fenced-out segment must reject typed with the distinct reason and zero settle entries, and the successor must settleokby replay with exactly one settle entry and no second paid call.
- The stale segment now rejects
1.135.0
Minor Changes
cf75e22: The rates comparator fails closed on page-only tiers and NaN, and the checkpoint decoder honors never-throws on top-level nulls (RV1007 + RV1008, PR IV of the fourteenth plan)
The fourteenth comparison experiment found two small holes in fail-closed surfaces.
compareRatesran its tier comparison only when the SEED declared tiers, so a long-context premium the provider's page documents and the seed never declared produced no finding: exactly the silent underpricing channel the comparator's own doctrine names (the RV902 both-directions rule). Its scalar branch comparedMath.abs(a - b) > 1e-9, andNaN > epsilonis false, so a page extraction that stopped parsing read as agreement. AnddecodeCheckpointletJSON.parse('null')through the try/catch, then threw a rawTypeErroronparsed.vout of a function whose documented contract is never-throws (the RV804 fix closed the nested shapes and left the top level open).compareRates(RV1007): a page-only tier list is now a finding (tiers: the page shows N but the seed declares none; an empty page list claims nothing), and scalars compare in the negated NaN-safe form the tier fields always used, soNaNon either side is a finding, never agreement.decodeCheckpoint(RV1008): a top-level payload that is not an object (null, a primitive, an array) decodes toundefinedlike every other malformed shape; the dangling dispatch reruns from the top, and the malformed corpus runs without a single throw.
1.134.0
1.133.0
1.132.0
Minor Changes
2bec904: Live-budget parity for the cache-write TTL split, and the fault kit gates it on the real live path (RV1001 + RV1002, PR I of the fourteenth plan)
The fourteenth comparison experiment reproduced a hard-ceiling breach: a run with
budgetUsd: 4settledokat $4.50, because the mid-stream usage inlet, the reported/remainder fold, and every usage aggregate droppedcacheWrite5mTokens/cacheWrite1hTokens, so the live ledger priced a differentiated cache write at the plain 5m rate ($3.75) while settlement priced the split ($4.50). The two money paths now read one provider usage identically:- The mid-stream cleaner and the finish remainder carry the TTL split to the live debit, so the layer-3 ceiling holds against the same dollars settlement records; a ceiling between the unsplit and split readings severs the run instead of letting it settle
okover the ceiling. @rulvar/coreexportssumUsage, the canonical usage adder: aggregates (the run outcome, the settled ledger fold, the budget telemetry,reduceInvocationTablebuckets) keep the split they were billed under, and an undifferentiated side's writes count as the 5m share so mixed aggregates stay canonical under the split-sum invariant.- Mid-stream TTL counts the finish total does not confirm are a usage-invariant violation, loud like every other telemetry anomaly; per-field catch-up over a shifted attribution only ever overcharges, never credits.
runFaultInjection(@rulvar/evals) grows a sixteenth scenario,ttl-live-budget-parity: a mid-stream differentiated write against the real engine must debit live and settle to the same $4.50, keep the split on the aggregate, and refuse to settleokunder a $4 ceiling. Reverting the fix reportsmatched: falsein the kit, not only in the unit suite that shipped it.
- The mid-stream cleaner and the finish remainder carry the TTL split to the live debit, so the layer-3 ceiling holds against the same dollars settlement records; a ceiling between the unsplit and split readings severs the run instead of letting it settle
1.131.0
Minor Changes
256cae1: The thirteenth plan's probes become permanent gates, and the three moneys get their vocabulary (RV909, RV910; closes the thirteenth plan).
runFaultInjectiongrows eight fail-closed scenarios driving the plan's fixed defects end to end on the real engine, zero provider calls and zero keys:nan-statement-refusal(unsummable statement dollars refuse typed at reconciliation intake, never verdictmatchover NaN totals),token-mismatch-divergence(provider-reported counts that disagree with our recorded usage decide the verdict even when the dollars agree, withtokenComparison: 'informational'still the declared opt-out),audit-missing-field-finding(the documented-rates comparator fails closed in both directions),anthropic-1h-priced(the shipped Anthropic table prices the 1h cache-write share at the documented 2x-input premium under its pinnedpricingVersion, on the per-call reconciliation ledger where the TTL split lives),pause-turn-units(continuations absorbed into one dispatch settle at true wire units across the quota window, the invoice row's segment set, and the all-or-nothing statement join, with a partial segment set readingpartial-coverage, neverno-overlap),pre-admission-count-refusal(a spawn the budget could never admit refuses before thecountTokensegress, so the full child prompt never leaves the process),forced-finish-completion(a budget-capped adaptive orchestration settlesokwith the honest completion envelope mirrored onto the outcome), andsettlement-terminal-honesty(a failed settlement write rejects typed withsettled: falseonrun:end; the healed resume re-settles by replay with zero live calls). Reverting any of the fixes now reportsmatched: falsein the kit, not only in the unit suite that shipped the fix. To reach those surfaces@rulvar/evalsgains@rulvar/openai,@rulvar/anthropic, and@rulvar/planas dependencies.@rulvar/corepublishescompareRates(with itsDocumentedRatesinput type), the both-directions documented-rates comparator the weekly audit runs: moved from the audit script to a published home so the kit can drive it as a gate, with the script importing the same function from dist inside its entrypoint exactly like the seeds, one source of truth. And the pricing docs now name the three moneys of one run in one place: recorded money (settled history under thepricingVersionpins its own settles wrote, the numberCostReport,rulvar inspect, and the invoice's pinned rows show), the docs estimate (repricing at the current table, whatpreflightEstimateprojects and the invoice prints past the pins), and the provider bill (established only byreconcileStatementover saved exports, never by a dashboard headline), plus the rate-update order: audit, then release, then new pinned runs.
1.130.0
Minor Changes
d6bec7a: Every tool event names its call (RV908, the thirteenth experiment's OTel attribution risk).
tool:startandtool:endgaintoolCallId, the model-minted id the journal's messages and tool-result parts have always carried: present on every live event and on every replayed reconstruction (the id rides the checkpoint's tool-result parts, so even journals written before this release name their calls on resume), absent only on streams recorded before RV908 or written by foreign emitters.The OTel exporter pairs tool spans EXACTLY by the id (stamped as
rulvar.tool.call_id), so concurrent same-name calls that finish out of order keep their own durations and outcomes instead of FIFO-swapping attribution. Streams without the field keep the historical FIFO pairing byte for byte, an id-bearingtool:endwhose start carried no id falls back to the same FIFO (mixed streams pair no worse than before), and the orphan tolerance (a closer with no open start attaches as a span event) is unchanged.
1.129.0
Minor Changes
1612439: Honest terminals (RV906 + RV907, the thirteenth experiment's release risks six and seven): a forced finish names itself partial, and a failed settlement is never a green event.
RV906: under the default
budget.atCap: 'finish-with-partial', the capped terminal's value becomes the completion envelope{ result, completion }, and the literal is'partial'unless the finalizer's finish provably passed the FULL declared contract: the declared finish validators now BIND the reserved finalizer (on capped runs synthesis never runs, so that finish is the final output they must judge; a finish they reject never becomes the run value and the deterministic fallback settles the run), while a declared acceptance policy is still never judged at the cap, so with one declared the terminal stays'partial'. The finalize fallback's synthesized partial carries the samecompletion: 'partial'claim on itsexhaustedoutcome. The engine lifts the literal ontorun:endand the outcome mirror, so a consumer reading onlystatuscan no longer execute a truncated plan as a full success. The journaled finalize effects also roll forward on resume: a settled capped run reuses its recorded finalize terminal (or fallback decision) instead of re-deriving the prompt from the drifted live digest, which used to mint a fresh agent identity and re-pay the reserve on every resume of an already settled capped run.RV907:
run:endgainssettled: false, present ONLY when a settlement write failed (therun_settlejournal append or the terminalRunMetaprojection): the status stays true as computation, but nothing durable records it andhandle.resultrejects with the typedSettlementError, so an event-only consumer is refused the green terminal exactly like the rejected promise. The CLI progress line appendssettled=false (outcome withheld; resume re-settles), and the OTel exporter stampsrulvar.run.settled: falseand refuses the OK span status. The order stays warn, then the markedrun:end, then the throw; a healed resume re-settles by replay with zero paid calls and its terminal carries no field, byte for byte like every ordinary run.
1.128.0
Minor Changes
27c4e38: pause_turn continuations become accounted wire units (RV905, the thirteenth experiment's fifth release risk). The Anthropic adapter absorbs server-side turn pauses by re-sending, making up to six wire requests inside ONE core dispatch; until now the request quota window, the provider call record, and the invoice row all saw one, and a per-request provider statement matched one segment while the rest read statement-only.
The adapter's finish metadata now names the whole segment set (
providerMetadata.anthropic.wireRequests = { count, responseIds }); the provider call record and the invoice row carrywireResponseIds; and the quota reconciliation settles the reservation against the TRUE wire request count. TheQuotaLimiter.reconcileSPI gains an optionalactual.requestsargument, honored by all three reference limiters through one shared arithmetic (quotaActualRequestsDelta), so a window that admitted one request per reservation now reflects what the provider's own RPM meter saw; a settlement only ever adds, never denies retroactively, and implementations written against the two-argument form remain valid.reconcileStatementjoins a multi-wire invoice row by ANY id of its segment set, all-or-nothing: a partially delivered segment set readspartial-coveragewith its delivered segments never counted as statement-only (and neverno-overlapwhen segments touched our data), and provider-reported token counts compare as the SUM over the segments against the dispatch's recorded usage. Single-wire dispatches carry none of the new fields and stay byte-identical, journals and events included.
1.127.0
Minor Changes
b3b1805: Admission before egress for the pre-dispatch token count (RV904, the thirteenth experiment's pre-admission egress probe). ctx.agent calls the adapter's optional
countTokenswith the FULL child prompt to tighten the admission reserve; before this release that network call ran before the budget decided anything, so a spawn the budget could never admit still sent the prompt to the provider, the call honored no abort signal, and nothing observable recorded the egress.The reserve is monotone in the count, so the smallest reserve any count outcome could produce is computable without it: the priced floor at zero input tokens, or the flat fallback the count-failed path admits under. The engine now checks that floor against the budget first, through the exact refusal arithmetic
admitSpawnitself uses (RunBudget.refuseSpawnIfInfeasible, the refusal arm factored out so the two layers can never disagree), and a spawn that could never be admitted (the lifetime spawn cap, a full account, an exhausted ceiling) refuses with zero network calls. The provider SPI'scountTokensgains an options argument with anAbortSignal; the Anthropic adapter threads it into the SDK request, and an abort mid-count cancels the spawn instead of silently falling back to the flat reserve and dispatching behind a cancelled spawn. Every count is now observable: anadmission.countTokensinfo log names the model and the counted tokens, and a failed count warns with the failure the flat reserve then covers. An explicitestCost(per call or per profile) remains the zero-egress path that skips the count entirely, now documented as the posture for hosts whose privacy gates must run before any prompt byte reaches a provider. Spawns on adapters withoutcountTokens, and spawns carryingestCost, behave byte-identically to v1.126.0.
1.126.0
1.125.0
1.124.0
Minor Changes
- 37fd1f2: The twelfth plan's closing trio (RV809, RV810, RV811). The tool budget extension gains
coverEvidenceDeficit: with an evidence contract declared, the extension grants at a tool-turn boundary whenever the remaining call budget cannot cover the declared floor's outstanding deficit, under the same money, progress, and maxExtensions gates, so a limited child at 7 of 11 entries converts headroom into the missing evidence BEFORE the cap instead of dumping through the reserved tail; the journaled grant decision carriestrigger: 'evidence-deficit'and the announcement names the exact deficit. Canonical Usage gains the optional cache-write TTL split (cacheWrite5mTokensandcacheWrite1hTokens, invariant: the split sums tocacheWriteTokens);priceUsdOfbills the 1h share atcacheWrite1hUsdPerMTokwith everything unclaimed at the plain write rate (byte-identical arithmetic without a split), sanitize repairs broken splits with 1h priority (never an undercharge), and the Anthropic adapter fills the split from thecache_creationbreakdown when it agrees with the flat total. @rulvar/evals gains the fault-injection kit:runFaultInjectiondrives the never-observed-live fail-closed branches (in-flight-exposure refusal, duplicate quota rule, torn and glued JSONL tails, the settle-boundary crash resume, pricing rotation with an uncovered tail, unknown provider id) on the real engine offline, verifies each documented typed observable fail closed, and leaves experiment-grade artifacts.
1.123.0
Minor Changes
- 5c46468: Sectional bounded repair and the structured evidence index (RV808b, the second half of the split RV808).
finishValidation.sectionalRepair: { sections }teaches every gated finish a second repair shape: after a rejection the model resubmits ONLY the repaired sections asfinish({ sections }), and the host splices them into the retained rejected attempt (the exportedspliceSections, line anchored, missing declared sections append) and validates the reconstructed document whole; the synthesis invocation is seeded with the coordination draft as its retained base, so withcarryDraftGapsthe post-fan-in window collapses to one small patch instead of a full re-derivation. Mechanics refusals are typed, journal nothing, and spend no repairs; the gated invocations' finish tool schema moves only under the opt-in.synthesis.evidenceIndexadds a deterministicEVIDENCE INDEX:prompt line (per settled child: the distinct citations its output carries, evidence-pool children only, artifacts, chars, the handle when the read tools are exposed), so the composing model pages exactly what it needs instead of re-reading the whole pool; replay-stable, fail-closed pattern intake, byte identical when unset.
1.122.0
Minor Changes
- 8cf45c5: The post-fan-in double rework closed at its cheapest point (RV808a, the first half of RV808). The twelfth comparison run paid 80.157% of wall time AFTER fan-in: the coordination draft was repaired only against the weak
draftPolicysubset, theskipWhenDraftValidpre-pass then judged it by the FULL contract and failed, that verdict was silently discarded, and the synthesis invocation re-derived the whole document blind to the known defects and failed the same contract once more itself. Two opt-ins close the loop.finishValidation.draftPolicy: 'contract'gates the coordination draft by the full declared validator set (same validators, same children snapshot the synthesis-bound validation reads), with rejection feedback naming the failing validators, so the coordination repair loop drives the draft toward exactly what the pre-pass will judge and the skip becomes reachable; the preflightdraft-gate-below-contractwarning cannot fire under it, and the preflight input type accepts the sentinel.synthesis.carryDraftGaps: true(requiresskipWhenDraftValid) journals a failing pre-pass as anorchestrator_synthesis_draft_gapsdecision (failed validator names and reasons, bound to the contract generation and draft hash exactly like the skip decision) and feeds the synthesis prompt aDRAFT CONTRACT GAPS:line instructing it to repair the named gaps and preserve the draft otherwise; a resume reuses the journaled verdict without re-running a validator, so prompt bytes re-derive identically and the paid invocation replays. Both default off: journals and prompt bytes stay byte-identical without them. The sectional bounded repair and the structured evidence index (RV808b) follow separately, and the live acceptance measurement of the post-fan-in share stays gated on an explicit founder go.
1.121.0
Minor Changes
- 3d67d41: Rate provenance made checkable (RV807, RV813, RV814). The pricing row grows
ratesVerifiedAt(SPI), the ISO date it was last verified against the provider's documented rates or, stronger, its billing categories: the shipped seeds stamp it (the GPT-5.6 family reads2026-07-30, the day the statement reconciliation confirmed those rates against the provider's own per-component billing categories to the cent; the pre-5.6 OpenAI rows keep their2026-07-18docs verification; every Anthropic row was re-verified against the documented table on2026-07-30). The date is surfaced wherever a dollar is consumed:preflightEstimatecopies it onto each spawn report andrulvar preflightrendersratesVerified=<date>with its age on the spawn line; the settle pin journals it with the rest of the applied row so it survives any later table rewrite; andrulvar invoiceprints arates verified:line naming each priced model's date and age, pinned rows first, current table past them; the twelfth run's founder read the invoice doubting the rates and nothing said the seed was 12 days stale. The doctrine ships with the mechanism: seeds bound ceilings conservatively, billing truth is established only byreconcileStatementover saved exports, and a confirmed divergence corrects the seed in its own release with a changeset, never a silent rewrite. Enforcement rides two new gates: a weekly documented-rates audit (scripts/rates-audit.mjsin the live contract workflow) re-fetches exactly the pages the seed comments cite, compares every rate, write premium, and long-context tier, and opens an issue on drift or on a page that stops extracting, and a README release-table gate (scripts/readme-release-shas.mjs, in CI) requires every cited squash SHA to be an ancestor of HEAD, catching the v1.109.0 row that pointed at an object no branch contained for eleven releases (now corrected to the real squash58afdb5).
1.120.0
Minor Changes
- d630c9e: The partial fan-out contract and the per-child acceptance roster (RV805, RV806).
parallel_agentsadmits children sequentially in submission order, and a mid-loop admission refusal is now part of the TYPED tool result instead of a throw: the model keeps every started handle (awaitable and cancellable), andrefusednames the failed index, the typed error code, and the reason; a thrown refusal used to swallow the whole call while the started children kept spending invisibly, inviting a duplicate wave. The clean-wave result stays byte for byte{ handles }. The acceptance fold now journals a per-child machine roster inside its single decision and carries it asacceptanceChildrenon the envelope, theRunOutcome, andrun:end(same lift and malformed-drops-silently posture as the salvage lists, mirrored to OTel asrulvar.run.acceptanceChildren): each spawned child with its settled status, the salvage arm that accepted it, and, where the child declared an evidence contract, the evidence verdict{ recordedEntries, minEntries, met }withwaivedBySalvage: trueon a below-floor child a salvage arm accepted anyway; the twelfth comparison run accepted two below-floor children through salvage and nothing machine-readable said so. Behind it, a declared evidence contract now stamps EVERY settledAgentResultwithevidence(the same window-derived count as the enforce-refuse floor), absent without a contract so those results stay byte-identical.rulvar inspectprints the acceptance verdict with the completion, the salvage lists, and the per-child evidence verdicts from the journaled decision, plus journaledquota_driftdecisions labeled per-minute window, not cumulative. The guides now state the gating rule outright: gate on the (status,completion) pair, never onstatusalone.
1.119.0
Minor Changes
- 1e4ff3c: Validation symmetry closes two crash-shaped gaps the twelfth experiment found (RV803, RV804).
preflightEstimatenow validatesrun.budgetUsdwith the same typed guard the runtime applies toRunOptions.budgetUsd: a NaN, negative, or infinite ceiling refuses as a ConfigError namingpreflight.run.budgetUsdinstead of flowing silently into every projection the report is built from; preflight already validatedrun.limits,run.maxInFlightExposureUsd, and every spawn budget, and the run ceiling was the one raw read left.decodeCheckpointnow validates the nested message structure: a parseable blob whose messages are malformed ({v:1,messages:[{}]}, a message without a string role, a non-arrayparts, a garbage part) returns undefined per the function's own undefined-on-unparseable contract, so the dangling dispatch reruns from the top, instead of throwing a raw TypeError out ofmsg.parts.mapmid-resume. Well-formed checkpoints round-trip byte for byte as before, and both refusal shapes carry mutation-probe entries.
1.118.0
Minor Changes
- f8341a3: Provider statement reconciliation as a machine (RV812, the twelfth experiment's billing lesson). The run's billing question (a dashboard headline of 4.45 then 4.77 USD against the settled 7.304885) was closed by hand with screenshots; nothing in the system could close it. Now
@rulvar/openaiexportsreconcileStatement(invoice, statement, { pricingOf }): it joins the machine-readable invoice against a NORMALIZED provider export, per-request rows by response id or per-model per-component category totals (the Spend categories shape), and refuses a headline aggregate typed, because an eventually consistent dashboard total is not evidence. The report carries response-id coverage (a partially delivered export reads aspartial-coverage, never as false divergence: component deltas fold over the covered subset only), per-component deltas per serving model, and the implied actual rate of every component beside our effective rate over the same token base, so a real divergence NAMES the rate-card line that moved with the rate the provider actually applied. Unpriced models and usage-unknown rows are declared apart, never folded or silent; verdicts arematch,divergence,partial-coverage,no-overlap. Backing it,@rulvar/coreexportspriceComponentsOf(pricing, usage): the four billing components (uncached input, output, cached input, cache writes) with token bases and dollars, decomposed with exactly the settled fold's arithmetic;priceUsdOfis now defined as the sum of those four terms in the historical order, byte for byte the same number, so the reconciliation and the settled fold can never disagree about what a usage costs. Validated against the real twelfth-run artifacts offline: the founder's eight dashboard categories reconcile tomatchwith every delta under 0.0005 (3-decimal rounding), response-id coverage reads 120 of 120, a 100-row truncation reads partial coverage with zero divergence, and a synthetically distorted write rate namesgpt-5.6-terra cache-writewith implied 2.5 USD/MTok against effective 3.125.
1.117.0
1.116.0
Minor Changes
- a213878: One settled number on every public money surface (RV801, the twelfth experiment's P0).
run:endnow spreadsoutcome.cost.totalUsditself, so the terminal event and the settled report cannot disagree under any pricing table; live in the twelfth comparison run the event said 10.4148235 USD against 7.304885 USD on every other surface, because the kernel ledger re-priced per-phase usage aggregates through the 272k long-context tier no single request crossed.Replayer.ledger()folds dollars on the settled billing basis (RV504): per provider call where an entry's dispatch records cover its usage, the per-slice aggregate otherwise; usage sums and the spawn count are unchanged. The resume budget seed is the settled fold too, per-call basis composed with the per-segment pricing pins (RV505), so resuming a tier-heavy run no longer inherits aggregate-priced dollars and falsely exhausts a ceiling the real spend never crossed (the escalation on the experiment's finding: that exact journal would have resumed with 10.41 of a 10.00 ceiling already counted as spent), and a resume across a price-table rotation starts from the figure the prior segment actually reported instead of re-pricing settled history at the rotated rates.
1.115.0
Minor Changes
- 63642ae: Post-fan-in attribution and the opt-in in-flight exposure cap (RV710, RV711).
reduceCriticalPathnow decomposes the post-fan-in window whenever it exists:CriticalPath.postFanInfolds the coordination spans' model activations and tool executions (by tool name, so child-result pagination and the finish exchanges show up under their own names) and thesynthesizespan wall, each clipped to the window, withcoveredMsas the exact interval union andresidueMs/residueSharenaming what no recorded interval covers, from the same event vocabulary with no new types.RunOptions.maxInFlightExposureUsdbounds spent money plus the summed worst-case estimates of live dispatches: the admission holds each turn's own estimate from right before the provider call until the attempt settles, refuses the dispatch whose estimate does not fit with a typedBudgetExhaustedError(data.reason 'in-flight-exposure') instead of waiting, and thereby bounds the worst concurrent overshoot to the estimate error of the in-flight turns instead of one whole turn per agent; off by default with byte-identical wire traffic, and preflight reports a configured cap as thein-flight-exposure-capfinding.
1.114.0
Minor Changes
- 5759731: The fixed-window quota boundary is pinned as a named compromise, and the final model can opt into the run's own observed evidence (RV708, RV709).
QuotaRuleand the model-routing guide now name the window semantics exactly: every PerMinute cap counts over fixed epoch-aligned 60 s windows, each window enforces its cap exactly, and a burst placed astride a boundary can consume up to two caps inside one sliding 60 s, the bounded price of cross-process parity, pinned by test as intended behavior with no semantics change.runAgentgains the opt-inpolicyFacts: the finalize synthesis request carries ONE additional request-only message digesting what the loop observed (quota denials and recoveries, tool budget pressure and extension grants, the finalization window, recorded spend with its cost basis), never touching the durable transcript or spawn identity;orchestrategains the symmetricsynthesis.policyFacts, a deterministicPOLICY FACTS:prompt line folded only from replay-stable settled child facts (statuses, extension grants, finalization windows and reserves), so a resumed synthesis re-derives identical prompt bytes. Both are off by default and every request and prompt stays byte identical when unset.
1.113.0
Minor Changes
- a60807a: The pricing composition's second half names itself, and the effect-ledger quarantine is byte-true (RV706, RV707).
InvoicePricingProvenancegains optionalcurrentPricingVersion: on composed exports it is the version of the caller's current table, the one that priced everything pastpinnedThroughSeq(on current-table exports, the whole fold), so an invoice folded across a rotation now names both halves of the composition where the pinned segments already declared theirs;rulvar invoiceandrulvar inspectfill it from the configured table and extend their text suffix topins composed with the current table (v-a, v-b; current v-live), byte for byte unchanged when the config declares no version. The executor ledger's torn-tail quarantine row now carriesbytesBase64andsha256of the exact torn bytes alongside the lossybytesstring kept for old readers (two different byte tails used to collapse into one indistinguishable row), and the repair's parseable decision is made on the bytes, strict UTF-8 beforeJSON.parse: the lossy decode could make a fragment with invalid bytes inside a string literal parse, and the repair then terminated a line of invalid bytes in place, manufacturing exactly the corruption the fail-closed scan refuses.
1.112.0
Minor Changes
- 00ae55b: Duplicate quota rules are refused at construction in every reference limiter (RV704).
snapshotQuotaRules, the shared construction chokepoint ofmemoryQuotaLimiter,SqliteQuotaLimiter, andPostgresQuotaLimiter, now throws a typedConfigErrornaming both indexes and the canonicalquotaRuleKeywhen a rule set contains two identical rules. Before the refusal, the same duplicated configuration admitted differently per storage: the memory reference buckets by rule index, so each copy counted independently and the full cap admitted, while the store references bucket by rule key, so one shared bucket was debited once per matching copy and half the cap admitted (a cap-4 set granted 4 in memory and 2 on sqlite), breaking storage parity with a configuration nothing had refused.@rulvar/store-conformancegainsquotaRulesConformance, the executable construction contract any limiter implementation can register.
1.111.0
Minor Changes
- fd25169: A covered model's invoice rows are now exactly its recorded provider calls (RV703). Coverage is decided per model (RV604), but the remainder pass subtracted records per model AND role, so a covered model whose record roles differed from its slice roles (the schema-extract default splits one model's usage by role while the record carries one role, or none) fabricated a phantom
unattributedremainder row: the export then carried more tokens than the run used,sum(rows[].usd)exceededtotalUsdunder arowUsdNonAdditive: falsepromise, and the allocation pass siphoned dollars from the real call's row onto the phantom.invoiceFromJournalnow skips the per-slice remainder arithmetic entirely for models the billing fold covered; uncovered models keep the historical per-slice remainders byte for byte.EntryBillingFoldpublishes the fold's per-model coverage decision ascoveredModels, so row builders honor the same decision instead of recomputing it under a different key.
1.110.0
Minor Changes
58afdb5: Price the live and replayed event telemetry per provider request, exactly like the settled fold, and label every money-bearing event with its basis (RV702).
The eleventh comparison experiment measured the defect live:
agent:phase:endpriced the phase-aggregate usage delta in one call, so a nonlinear long-context tier fired on aggregates no single request crossed;agent:endandreduceInvocationTableinherited the inflated dollars (raw sum +60.2%, loop bucket +82.9%) while the settled CostReport and invoice priced per request (RV504). Now every recorded provider call is priced individually at its own chokepoint, phase events carry the delta of that per-call accumulator,agent:endcarries its sum, the replay path folds the terminal entry through the samepriceEntryBillingthe invoice uses, and the reducer's rows andbyRolebuckets match the settled fold whenever records cover the usage.New
costBasis: 'per-call' | 'aggregate-estimate'onagent:phase:end,agent:end,AgentResult, and the reducer's rows and buckets:'aggregate-estimate'appears only where per-request records cannot cover the number (a checkpoint written before the reconciliation ledger shipped restores usage without call records; the invocation total then keeps the aggregate-priced figure, labeled, instead of silently dropping restored spend), and the reducer defaults an absent field to'aggregate-estimate', never to a per-call claim the stream cannot back.
1.109.0
Minor Changes
85b1d39: Close the two fail-closed gaps the eleventh comparison experiment proved live (RV701, RV705).
RV701,
JsonlFileStore: a crash that persisted every JSON byte of an append but not its trailing\nleft a parseable unterminated tail;loadserved it, the nextappendglued the following record onto the same line, and the load after that classified the glued line as one torn fragment and repaired BOTH accepted records away (a first-line glue rewrote the journal to zero bytes; a later second append buried the glue mid-file and made the journal unreadable).appendnow terminates a parseable unterminated tail in place before this instance's first write, and torn-tail repair salvages every complete record a glued last line carries, discarding only the unacknowledged trailing fragment. An entryloadhas served once can no longer be un-served by a later repair.RV705,
buildCostReport: the exported live builder returned whatever numbers the host fed it, so anInfinityorNaNtotal, bucket, or abandoned ledger serialized intonulldownstream, whilecostReportFromJournalhad refused exactly that since RV610. The builder now runs the same deep finite validation and refuses non-finite reports with the same typedConfigError.
1.108.0
Minor Changes
affa3d4: Stored consumers compose the pricing pins exactly like the engine, and the invoice provenance declares every pinned version (RV611).
JournalPricingSnapshotexports the composition the engine's outcome mirror applies at settle:composedPriceUsd(current)prices pin-covered rows at the rates their own settle recorded and everything past the last pin (a segment journaled but never settled) at the caller's current table. The engine now consumes the same method, and the three stored consumers (rulvar inspect,rulvar invoice, the server's stored-run cost endpoint) fold through it instead of passing the raw snapshot, which silently priced the tail at the last pin's rates and folded never-pinned models as unpriced even when the current table knows them. Two fallbacks stay deliberate and documented: a covered model its covering pin missed back-reprices at the last pin when that pin names it, and a model no pin resolves falls to the current table.The snapshot also carries
segments(every pin's seq boundaries,pricingVersion, and rows in journal order), andInvoicePricingProvenancegains the'composed'source plussegmentsandpinnedThroughSeq, so an invoice folded across a price-table rotation names every version that priced it instead of hiding the rotation behind the last one. The CLI exports that priced through a pin now declaresource: 'composed'(previously'snapshot'), and thepricing rates:/pricing:text lines name the composition and every pinned version.
1.107.0
Minor Changes
9f5f6f6: Fail the evidence-preservation contract closed at intake and refuse non-finite accounting anywhere in a public report (RV610); the exactly-once claim sentinel now judges normalized prose blocks and the guarantee matrix states the two-phase row shape honestly (RV612).
evidencePreservedValidatorintake is fail closed: a pattern that can match the empty string is refused with a typedConfigErrorat construction (an empty match would enter the citation pool as fabricated evidence, trivially "preserved" by every result and defeatingrequireNonEmptyPool), zero-length matches never enter the pool even when a lookaround produces them in context past the construction probe, andrequireKnownandrequireNonEmptyPoolmust be real booleans, so a stray'true'or1can never silently disable the strict mode it names.Accounting refuses non-finite numbers at every layer: the per-entry price folds (
priceEntryUsage,priceEntryBilling) throw a typedConfigErrorthe moment individually finite prices overflow the running sum, andcostReportFromJournalandinvoiceFromJournalwalk their finished public objects and refuse anyInfinityorNaNbefore returning, because JSON serializes both asnulland a published report that quietly carriesnullwhere dollars belong is silent telemetry corruption. Previously two individually validNumber.MAX_VALUEprices producedtotalUsd: InfinityandallocatedUsd: NaN.The docs claim sentinel (RV508) now normalizes contiguous markdown prose and source comment blocks before matching, so a forbidden claim wrapped across a line break or spaced with double whitespace is caught at the block's first line, and the prior shipped recurrence "each ran once" is recognized as the same claim; the (file, anchor) allowlist is unchanged. The widened rule immediately caught one live wrapped occurrence in a core comment, which is rewritten with the precise guarantee. The guarantee matrix's effect-accounting cell no longer contradicts the ledger format: a completed two-phase attempt has TWO rows (intent and outcome, one
attemptId), a crash between the phases leaves the intent row alone as the orphan, and the legacy no-intent ledger keeps its one-outcome-row contract.
1.106.0
Minor Changes
9a4ce49: Alias recovered child attempts by admission identity, so a restored coordinator's old handles reach the reborn attempt (RV609).
The handle-stability alias required the old and new running entries to share
(scope, key, ordinal), but occurrence ordinals are strictly monotonic per(scope, key): a rerun always takes the NEXT ordinal, so the alias was unreachable for ANY rerun, not just a cancelled child. A restored coordinator transcript that kept calling the handle it saw (await_all,cancel_agent,get_child_result) gotunknown handlerepair turns instead of the reborn attempt and could exhaust before the acceptance policy or theminSpawnedChildrenfloor (RV507) was ever evaluated. The seam predates the ninth plan: it shipped in v1.7.0.Recovery now aliases by what is actually stable, the admission identity: every prior attempt's RUNNING row of the redispatched admission's
(scope, key)under the pinned child scope aliases to the reborn record (every handle is a running row's seq, so the claimable set is exactly the prior running rows; a terminal is a separate row and never a handle). A transiently claimed same-key sibling is content-interchangeable and is rebound the moment its own redispatch lands. Because several handles can now map to one record, every roster-shaped walk (wake digests, quiescence, finish-validation children, the forced-finish fold, incremental synthesis reconciliation, the acceptance decision, and the synthesis digest, now one row per spawn under its current handle) iterates the per-spawn-ordinal roster instead of the handle map, so an aliased child is never counted or digested twice. Without aliases the per-spawn walks are byte-identical to the old per-handle ones, so synthesis prompt bytes and existing journals roll forward unchanged.Fresh runs are byte-identical; the change is confined to recovery. Also freezes the clock in a real-clock store-postgres test that could straddle a minute boundary in CI (test-only).
1.105.0
Minor Changes
531dc88: Make quota rules an immutable snapshot with a canonical denial order in all three limiters, and give the postgres limiter rotation generations, a fenced stale host, a bounded bootstrap, and strict intake (RV608).
Immutable snapshot (all three limiters):
memoryQuotaLimiter,SqliteQuotaLimiter, andPostgresQuotaLimiternow admit under the new exportedsnapshotQuotaRules(rules): a validated, frozen copy carrying only the known rule fields, taken at construction. Mutating the caller's array or rule objects afterwards (a pushed rule, a reassigned cap) can no longer change a decision, a bucket key, telemetry, or the fingerprint the postgres schema records; previously the caller's live graph was read on every admission and the fingerprint was computed lazily from it at first boot. The canonical per-rule content key is also exported asquotaRuleKey, and every limiter folds a denial over matching rules in that canonical order, so permuted but identical rule sets now produce the byte-identical refusal object (reason and retryAfterMs), not just the same fingerprint.Rotation generations (postgres):
rulvar_quota_metanow records a rules generation beside the fingerprint. Every admission re-reads both inside its own locked transaction and, on a mismatch, is refused with the new typedQuotaGenerationErrorinstead of admitting under retired bucket keys, so a host that booted before a rotation is fenced rather than silently splitting the budget; its next call re-boots into the honest boot-timeConfigError, and its outstanding reservations age out with their window. Rotation (acceptRulesUpdate: true) now serializes with in-flight admissions on the same advisory lock, bumps the generation, and carries current-window consumption conservatively: a new bucket inherits the retired bucket's counters for the same(provider, model, tenant)dimension triple (the maximum when several retired rules share it), so a raised cap grants only the difference, a lowered cap counts what was already consumed, and a genuinely new dimension starts empty. The carry decision is conservative by design: estimates held by fenced hosts settle nowhere and age out, which errs toward under-admission inside the rotation window, never over.Bounded bootstrap and honest deadline phases (postgres): the bootstrap transaction now runs under the same
SET LOCAL lock_timeoutas admissions (a held boot lock used to wait unboundedly), and its connection is registered with the full-path deadline, which destroys it on expiry so an abandoned bootstrap can never commit DDL or a rotation after the caller was already refused.QuotaDeadlineError.phasegains'bootstrap', and each phase's message now narrates only what actually happened: an'acquire'refusal held no connection and no longer claims one was destroyed.Strict intake (postgres):
acceptRulesUpdateis runtime-checked as a real boolean (the string"false"used to enable rotation by truthiness), andadmissionDeadlineMsis refused above the Node timer maximum (2147483647 ms, now exported from@rulvar/coreasMAX_TIMER_DELAY_MS) before the pool is constructed; above it, the deadline timer used to clamp and refuse every admission after about a millisecond.Migration note: hosts running mixed rule sets over one schema now fail loud during a rotation instead of silently splitting the budget: old booted hosts receive
QuotaGenerationErroron their next admission the moment a new deployment boots withacceptRulesUpdate: true. That refusal is the designed rollout signal, not a regression; roll the refused hosts to the new rule set and remove the flag. Existing recorded fingerprints keep matching (the key encoding is unchanged), and pre-generation schemas are backfilled to generation 1 on the first matching boot.
1.104.0
1.103.0
Minor Changes
f2b809e: Symmetric billing coverage and the per-slice invoice residual (RV604, RV605: the round-52 accounting P1s).
Coverage is decided per model with a symmetric key (RV604). The per-call billing fold compared each usage slice against the per-MODEL sum of the provider-call records, while the slices split one model's usage by role. Several roles on one model, which is the DEFAULT configuration under a schema (the same-model extract), therefore always refused coverage and re-priced the aggregate, firing nonlinear long-context tiers no single request crossed: the audit reproduction turned 700 honest monetary units into 1900 while the live ceiling had debited ~700. Both sides now aggregate by serving model, coverage is decided per model, a covered model prices each of its records individually (the role rides the record, so byRole survives), and an uncovered model honestly keeps the aggregate basis.
fullyAttributedis true exactly when every slice model is covered and no record names a model absent from the slices. The engine-level coherence obligation gets its own test: on a fully attributed multi-role run under a tiered table, the settled fold equals what the live ceiling debited.The invoice residual is computed per slice (RV605). The unattributed remainder used to be one whole-entry row published under
entry.servedBy: a slice of another model with no records left its allocation pool rowless, and the dust pass dumped that model's whole USD onto the largest row of a different model so the column would sum. The remainder is now computed per usage slice, subtracting only the records of the slice's own serving model (and role, when the slice carries one), and each non-zero remainder becomes a row under that slice's model and role. The dust pass refuses to transfer a target into a pool with no rows: the amount is excluded from the reconciliation and declared in the newunallocatedUsdfield (absent when zero, which is every well-formed journal), so cross-model transfer is structurally impossible and additivity is honest rather than forced.
1.102.0
Minor Changes
3eb6515: Durable authorization before the authorized effect (RV601, RV602, RV603: the round-52 review of the ninth plan's own surface).
A tool budget grant is durable before it takes effect (RV601). The grant and finalization-window decision entries introduced by RV509 were journaled fire-and-forget, so a tool call could run under a raised cap whose authorizing decision never reached the store, and a rejected append left the run settling with the decision silently absent. Both hooks on
RunAgentOptions.toolBudgetDurabilitynow returnPromise<void>and the loop awaits them before the grant lifts an expiry, before the window binds a call, and before either announcement is queued. A refused append issues no grant and marks no entry, and the failure propagates exactly like a failed boundary checkpoint instead of being swallowed. Migration: a host wiring these hooks directly must return a promise, and a grant can now fail when the journal store is unavailable rather than proceeding unrecorded.The journaled cap anchors a resumed ceiling (RV602).
maxToolCallsandincrementare not part of the dispatch identity, so a host may legitimately change them between segments; recomputing the resumed cap from live limits revoked a raise the model had already been promised on the live-resume path while a pure replay honored it from the journal.toolBudgetDurability.restorednow carries the journaledcap, the loop measures from it, and grants taken after the restore point apply the currentincrementto that anchor. A restored cap that is not an integer at or above the base cap is ignored with a warning, leaving the executed-call derivation as the floor.A synthesis skip is bound to its contract generation and draft (RV603). The
orchestrator_synthesis_skipdecision written by RV510 was looked up by scope and key alone, so the documented fix-and-resume remedy was defeated: a crash between the skip and the run settle, followed by a contract fix, resumed with the stale skip and settledokcarrying output the current contract rejects. The entry now records the contract hash (when afinishValidation.contractis declared) and the hash of the draft it judged, and is reused only when the contract generation, the draft, and the validator names all still match; otherwise the gate re-runs on the current contract. Without a contract descriptor the binding falls back to draft plus validator names, which is honestly weaker and documented as such. Entries journaled before this field existed stay reusable, so runs in flight roll forward unchanged.
1.101.0
Minor Changes
- 51b215c: Conditional synthesis (RV510, the ninth-experiment review): the opt-in
synthesis.skipWhenDraftValid: trueruns the coordination draft through the FULL declared finish contract before the synthesis span starts. A draft that passes every validator becomes the final result without the synthesis invocation ever dispatching, under a journaledorchestrator_synthesis_skipdecision with the new machine-readable reasonsynthesis_skipped_by_valid_draft(the existingOrchestrateSynthesisSkipReasonvocabulary, additively extended); the info log and the acceptance envelope carry the same reason, and a resume rolls the journaled skip forward with zero paid calls. A draft that fails any validator goes to synthesis exactly as before, with the repair budget untouched. Deterministic by construction (only the declared contract judges, no semantic-delta heuristic); requiresfinishValidationat intake; default off, byte-identical journals and cassettes.
1.100.0
Minor Changes
- 9785bea: Durable parallel of the ToolBudgetSummary (RV509, the ninth-experiment review): an adaptive tool-budget extension grant and the finalization-window entry now journal as decision entries of the existing vocabulary (
tool_budget_extension,finalization_window_entry), bound to the agent dispatch by targetRef the moment each fires. A crash-resume restores the granted cap and the window-entry fact from the journal, so a granted-but-unspent extension is honored instead of silently revoked (the conservative executed-call derivation stays as the floor beneath a lost journal tail) andfinalizationWindowEnteredstays truthful when a later grant moved the counts back out of the window. A replayed result now carries the journal-backed summary subset (usedfrom the terminal checkpoint, the granted cap,extensionsGranted,finalizationWindowEntered) with zero provider calls. Pressure notices stay events, grant-free runs journal nothing new, and their journals and cassettes remain byte-identical.
1.99.1
Patch Changes
- ef08d73: Guarantee matrix and exactly-once claim hygiene (RV508); no runtime behavior changes. The isolated-executor guide now carries the guarantee matrix stating flatly who provides what: the library's layers give at-least-once execution with attempt binding and intent-before-effect, exactly-once effect execution is promised by NO library layer, and what IS exactly-once is pay and replay (the never-pay-twice invariant). The two claims the ninth comparison experiment's judge caught are rewritten to the precise statements ("each ran once" became attempt counting under a stable idempotency key; the approvals guide now says continuation is a run-level guarantee, not an effect-level one, with the at-least-once window named);
ctx.stepdocs state the same window for effectful steps; aResolutionBynote says the field records a channel, never a verified principal (identity, signatures, and separation of duties are host IAM). The worker header now points at the shippedSqliteQuotaLimiterandPostgresQuotaLimiterinstead of denying that cross-process limiters exist. A new docs-lint sentinel forbids "exactly once" claims in the hand-written docs and in package source comments outside a vetted (file, heading anchor) allowlist (the durability pay doctrine and the guarantee matrix), and every remaining occurrence in doc prose and source comments was rewritten to the precise wording; string literals are deliberately out of scope (tool descriptions enter the toolset hash).
1.99.0
Minor Changes
- 9e00888: Runtime floors for evidence and acceptance (RV507), all additive and opt in; defaults change nothing.
evidenceContract.enforce: 'refuse'makes the declared floor binding at the child's terminal: an ok finish whose transcript carries fewer successfulrecord_evidenceexecutions (the tool's ownrecorded: true; duplicates and failed verifications never count) thanminEntriesbecomes a typedterminalerror whose journaled data carries the machine-readableevidenceFloor: { recordedEntries, minEntries }, memoized so a resume rolls the refusal forward instead of re-paying (the default'warn'keeps the historical preflight-only signal).evidencePreservedValidator({ requireNonEmptyPool: true })refuses the empty known citation pool with anempty child citation poolreason instead of the vacuous pass.OrchestrateAcceptance.minSpawnedChildren: Nrejects a finish whose spawned roster is smaller than N under both child policies (zero spawned children stop being vacuously complete for a fan-out-shaped task), with the actual roster carried beside the floor in the journaled decision and the rejection's error data.
1.98.0
1.97.0
Minor Changes
5c3b453: Per-request cost accounting and per-segment pricing pins (RV504/RV505/RV511, the ninth-experiment accounting P1s).
RV504: when a terminal entry's per-dispatch
providerCallsexactly cover its usage,costReportFromJournalandinvoiceFromJournalnow price each provider call individually, so a nonlinear long-context tier fires per REQUEST, which is the pricing contract's stated semantics. An aggregate that crossed a threshold no single request crossed no longer re-prices the whole entry: the ninth comparison experiment's settled report ran 52.4% above the live budget's per-dispatch debits for exactly this reason, and the two figures now converge. Entries without records, or with records that do not cover their usage, fold exactly as before (the per-model aggregate), and the invoice says so:rowUsdNonAdditiveis now a computed boolean (false exactly when every contributing entry is fully attributed, so the per-call rows sum to the total;allocatedUsdremains the column that sums exactly in every case). The shared fold is public:priceEntryBillingwithEntryBillingUnit/EntryBillingFoldbesidepriceEntryUsage.RV505:
journalPricingSnapshotnow composes the run-settle pricing pins by their settle seq, with no journal shape change: a seq-aware fold prices each row under the pin of ITS OWN segment (the rates its live debits actually used), so a suspend/resume across a price-table rotation no longer re-prices settled history under the new table. Seq-less callers keep the historical last-pin behavior.priceUsdcallbacks across the accounting folds accept an optional thirdseqargument (existing two-argument implementations are unaffected), the snapshot exposespinnedThroughSeq, and the engine's settled-outcome cost mirror composes pinned history with the live table for the segment being settled.RV511: the CLI invoice text output now states the pricing basis honestly per export: additive per-request rows, or the aggregate basis with the reason (a remainder or legacy entry in the fold).
1.96.0
1.95.0
1.94.0
1.93.0
Minor Changes
- c62150a: The mid-batch checkpoint boundary (RV408, the eighth-experiment review). Checkpoints write once per completed tool turn, so a kill inside one large parallel batch re-paid every executed call of that batch on resume; with the whole executed-call budget fitting into a single batch (the
tool-cap-before-checkpointpreflight warning), the re-paid window was the entire budget. The opt-inlimits.checkpointEveryToolCalls: Kbounds it: after every K executed calls within a batch the loop durably writes the same pending state the ask-approval suspension already checkpoints (the executed prefix verbatim, the next call, the remaining tail), and the existing restore path reuses the prefix and re-runs at most the calls since the last boundary. Denied and refused calls never advance the cadence, the batch's last call writes no extra boundary, and isolated-executor idempotency keys are unchanged. Off by default and byte-identical when absent: no journal bytes and no model requests change, only the transcript checkpoint cadence. A cadence below the executed-call ceiling silences thetool-cap-before-checkpointwarning, whose message now names the mitigation.
1.92.0
Minor Changes
- 351d1f5: Historically stable invoices via the applied-pricing pin (RV407, the eighth-experiment review). The invoice and cost folds price at fold time, so a live price-table update used to silently re-price history. When
createEngine({ pricing })is configured, the settling segment now pins what it actually applied, the resolved pricing row of every model the journal used plus the table'spricingVersion, additively inside the existing run-settle decision value (theoutputHashprecedent: no journal shape change). The pin is gated on the configured table deliberately: caps-fallback pricing arrives ambiently from adapters and a setting the user never enabled must not change the journal, so table-less runs settle byte for byte as before; rates the fold would refuse anyway, non-finite or negative, are never pinned. NewjournalPricingSnapshot(entries)reads the pin back and rebuilds apriceUsdover exactly the pinned rows (absent models fold as unpriced, never a silent zero);invoiceFromJournalaccepts a declared provenance and the export carriespricing: { source: 'snapshot' | 'current-table', pricingVersion?, rows? }.rulvar invoice,rulvar inspect, and the server's stored-run cost endpoint prefer the pin, so a repeated fold after the table changes reproduces the original numbers; journals settled before the pin keep the current-table fold and say so. Live pricing, budget admission, and journaled spend debits are untouched.
1.91.0
1.90.0
Minor Changes
- 9603940: Scope the isolated-executor idempotency key to the run incarnation (RV403, the eighth-experiment review). A fresh run stamps the additive optional
RunMeta.execKeyDerivationfield (version 2) at genesis and every resume segment carries it verbatim; version 2 keys bind the run's generation token, so adeleteRun-then-recreate of the same explicit runId never reuses the deleted incarnation's keys against a long-lived external dedup store, while a crash-and-resume redispatch inside one incarnation keeps its key exactly as before. Runs recorded without the stamp derive the original genesis-free version 1 keys for their whole life, across resume and upgrade, so external dedup state accumulated for them stays valid; a recorded derivation the engine does not know, or a version 2 stamp whose store dropped the genesis token, is a typed resume refusal when executors are configured, never a silent fallback. The store conformance kit now checks the field's round trip alongsidegenesis.
1.89.0
Minor Changes
- f18b671: Provider-id provenance parity across every adapter path (RV401, the eighth comparison experiment). The AI SDK bridge now ships the flat
responseIdthe core reconciliation record reads, beside the nestedresponseobject it always emitted, and an error finish carries the accumulated response metadata and warnings on the error event instead of dropping them (retained parts stay deliberately absent there: a failed turn is discarded, never re-injected). The core agent loop captures provider metadata from error events and falls back to the AI SDK's nestedresponse.idshape when a third-party adapter ships only that, with the flat first-class form winning when both are present. The OpenAI adapter attaches the failed response's id to itsresponse.failederror event, so a billed failure reconciles against the provider statement exactly like an ok row. End-to-end tests pin a bridged engine run whose per-call reconciliation records carry ids on the success, retry, and billed-failure paths alike. - f18b671: The synthesis reserve lifecycle decision now journals BEFORE the finish-validation termination throw (RV402, the eighth comparison experiment): a synthesis the validators terminally reject was still paid for out of the released reserve, and the run now keeps the frozen configured/held/released/remaining/consumed record on that failure path exactly as on success, idempotently across resume. Docs drift closed alongside: the FAQ now says the subprocess and container executors ship in
@rulvar/executorinstead of calling them a plan, the workflow guide no longer promises deadlines on approval suspensions (escalations only, per the durability table), the server guide scopes the approved tool's "exactly once" to its continuation segment under the documented at-least-once tool window, the RunMeta.argsHash doc points atsecurity.argsHashSaltas the salted HMAC option, and the ctx dispatch comment names the full five-part idempotency key.
1.88.0
Minor Changes
3b339d9: The evidence floor, the exact-fill parity proof, and the direct container e12 (PR III of the seventh-comparison-experiment plan: RV303, RV307, RV308, and the recommended tool budget posture).
RV303, the declared evidence contract:
AgentProfile.evidenceContractandPreflightSpawnSpec.evidenceContract({ minEntries, estCallsPerEntry?, overheadCalls? }, the spawn declaration winning over the profile's,researchAgentProfilepassing it through) declare how many evidence entries a spawn MUST record. Preflight compares the resulting call floor (minEntries * estCallsPerEntry + overheadCalls, defaults 3 and 8, exported asDEFAULT_EVIDENCE_CALLS_PER_ENTRYandDEFAULT_EVIDENCE_OVERHEAD_CALLS) against the spawn's effective executed-call ceiling (weighted units and extension grants included) and warnstool-cap-below-evidence-floorwhen the cap cannot fit the contract. Purely declarative, validated typed at both intake boundaries; the runtime never enforces it. The experiment relation nobody computed: 14 mandatory entries against a cap two workers exhausted at 10.RV307, the exact-fill parity proof (the judge's P1.8): a scenario suite pinning that the strict-at-fill admission projection and the live layer-2 gate deny THE SAME child for THE SAME reason on one set of numbers, at the exact-fill boundary specifically, while the below-fill retry admits in both layers, riding the existing slot-ledger guarantees (a rejection burns no
maxSpawnsslot; resume recounts journaled admits only).RV308, the direct container e12 (the judge's P1.9): the container executor now carries a DIRECT conformance test for the protocol-failure-at-clean-exit-0 case (typed
protocolerror, ledger outcomeerrorwithexitCode: 0), both against the daemonless docker stub (runs everywhere) and against the real daemon (docker-gated), instead of relying on source symmetry with the subprocess executor.Docs: the new "The recommended tool budget posture" section in the agents guide (default no cap: the USD ceiling plus exploration guards bound spend; a cap is a safety valve, never bare, always with notices, an extension, a reserve or window, and a deliberate salvage decision; the full findings table), cross-linked from the budgets guide findings enumeration.
1.87.0
Minor Changes
c4c02b1: The finalization window, the bare-cap linter, and the synthesis reserve lifecycle (PR II of the seventh-comparison-experiment plan: RV302, RV305, RV306, and the deferred half of RV304).
RV302,
limits.finalizationWindow: { reserveCalls, allow? }: once the remaining tool budget (executed calls against the effectivemaxToolCalls, or remaining weighted units againsttoolUnits.max, whichever is closer) drops toreserveCalls, only finalization tools may execute. A call outside the allowlist receives a typed refusal (guard: 'finalization-window', visible to the model, never terminal, consuming no budget), and the model is told once, via a plain user message, to record its evidence and finish. The allowlist defaults to the tools priced attoolUnitscost 0; the engine terminal tool is always admitted, andescalateis structurally exempt. WithtoolBudgetExtensionconfigured, remaining money converts into a grant BEFORE any window refusal, so the two features form one policy: spend the headroom first, then finalize. On resume the window re-arms from the restored counts without re-announcing; without the field every request, journal, and cassette stays byte identical. ThetoolBudgetpressure snapshot gainsfinalizationWindowEntered, and thetool:endguard union is now honest about all three engine guards (repeated-signature,per-tool-cap,finalization-window).RV305, the bare-cap linter: preflight warns
bare-tool-capwhen a positivemaxToolCallsor atoolUnitsbudget has no softener at all (notoolBudgetNotices, notoolBudgetExtension, nofinalizationReserve, nofinalizationWindow); a cap of 0 is a deliberate no-tools spawn and stays quiet. Orchestrate waves with a DECLARED acceptance additionally get the infocapped-children-without-salvagewhen capped children meet a policy with both salvage arms off. The window itself gets three findings:inert-finalization-window,finalization-window-covers-cap,finalization-window-empty-allowlist, andPreflightOrchestratorSpecgains the declarableacceptanceslice.RV304 second half (the judge's P1.7): a configured
budget.synthesisReserveUsdnow reports its whole lifecycle{ configuredUsd, heldUsd, releasedUsd, remainingBeforeSynthesisUsd?, consumedUsd }, frozen into a journaled decision (orchestrator_synthesis_reserve) when the synthesis invocation settles, emitted as aloginfo event, and attached to the acceptance result envelope assynthesisReserve.heldUsd: 0under a configured reserve makes the silently inert no-cap case visible; a resume reads the frozen decision instead of recomputing. Without a configured reserve nothing is journaled, emitted, or attached.RV306: the engine-level terminal-at-exhausted-budget scenario suite (the judge's P0.3): the terminal finish dispatches after the cap through a real engine run with the journal underneath, its validator rejection travels back, the repair lands, batch neighbors get the typed skip, and the non-terminal control still journals
limit.
1.86.0
Minor Changes
2f71894: The adaptive tool budget and the pressure snapshot (RV301/RV304, the seventh comparison experiment).
limits.toolBudgetExtension: { increment, maxExtensions, minHeadroomUsd?, requireNewEvidence? }converts remaining budget headroom into more executed tool calls at amaxToolCallsexpiry instead of settlinglimit: up tomaxExtensionsgrants ofincrementcalls, each admitted only with chain headroom remaining (the same arithmetic the per-turn output clamp prices, now exposed asRunBudget.remainingUsdand theBudgetHooks.remainingUsdseam), by default only with new evidence since the previous grant (the exploration guard's digest chain; a result the canonical serialization cannot digest fails the grant closed), announced to the model as a deterministic user message with the exact new counts, and re-derived conservatively from the restored executed-call count on resume, so nothing new is journaled or checkpointed. A terminalfinishnever spends a grant (it already rides the v1.79 budget exemption),toolUnitsis never extended, and an invocation without the field stays byte identical. The experiment that motivated it starved two of four mandatory workers at a fixed 84-call cap while $3.85 of the $10 ceiling sat unspent.Preflight assumes the fully extended cap in every projection (executed-call ceilings, projected provider turns, quota windows, the checkpoint loss window) and adds two findings:
inert-tool-budget-extension(warning; an extension with nomaxToolCallsto extend) andtool-budget-extension-exposure(info; the declared worst case).Every invocation with
maxToolCalls,toolUnits, or the extension configured now carries thetoolBudgetpressure snapshot —{ used, cap?, unitsUsed?, unitsMax?, extensionsGranted?, noticesFired?, finalizationReserveUsed?, limiter? }— on the fullAgentResult, the liveagent:endevent, and the invocation table's agent rows, so a host sees cap pressure before a starved worker ever settleslimit. Live telemetry only, exactly liketransportRetries: never journaled, absent on a replayed result. The synthesis reserve lifecycle telemetry (the judge's P1.7) is deliberately deferred to the next cycle. Docs: the stores guide frontmatter now names PostgreSQL beside the other shipped stores, and the README states the exact never-pay-twice boundary (recorded as complete), matching the durability guide.
1.85.0
Minor Changes
6932a9f: Three fail-closed fixes from the cycle 83 sweep, plus the dependency refresh.
Engine. A typed error thrown out of
ProviderAdapter.stream()now keeps its own class instead of being laundered into a retryable transport fault. AConfigError(a bridged model id that does not match the wrapped model, an unsupported role, a namespaced option contradicting a canonical field) used to be retried through the whole backoff ladder and then trigger transport failover, so a misconfigured primary silently served the run from a fallback model the caller never asked for while the real fault vanished behind a generic message. Typed errors that ARE retryable by class (a lost lease) keep retrying exactly as before, and an untyped throw is still a retryable transport fault.Planner sandbox. The realm scrub replaced
Date.nowandMath.random, which left three ambient sources open: a barenew Date()never consultsDate.now(V8 reads the system clock directly),performance.now()is a second live clock, and WebCrypto (crypto.randomUUID(),crypto.getRandomValues()) is raw entropy. Those are the first idioms a machine-written script reaches for, and each silently produced a run that could not reproduce on replay. All of them now draw from the same seeded stream: zero-argumentnew Date()andDate()take the logical clock,performance.now()is that clock minus the segment base,crypto.randomUUID()is the journaled uuid shim, andcrypto.getRandomValues()fills from the seed. Passing a timestamp or a date string toDatestays a pure conversion.Server. A tracked run whose segment REJECTS instead of settling (the genesis ownership boot refusing a run another process owns, a withheld settlement whose durable write failed) was reported as
runningfor the life of the process, its SSE connections never closed, and neither retention nor the settled cap could release it.GET /runs/:idnow answersstatus: "error"with the typed wire error, connected streams close with a comment naming the failure, a late subscriber gets that comment instead of an empty stream, and the tracked run becomes eligible for retention like any other terminal run.Dependencies.
@anthropic-ai/sdkmoves to^0.115.0(the only shipped floor its caret was blocking); in-range minors refresh across the workspace. The four majors stay held: eslint 10 and@eslint/js10,@types/node26 against the Node 22.12 floor, and TypeScript 7. The tsdown resolution is pinned at 0.22.3 because it generates the frozen.d.tsartifacts, including the published@rulvar/compattarball that must repack byte identical.
1.84.0
1.83.0
1.82.0
Patch Changes
- 9cc5d66: The free-cleanup harvest (cycle 80).
leasableStoreConformancegains theexpiryoption: the mandatory lease checks follow the suite's no-wall-clock convention, so the harness now hands them a store whose ttl no scheduler stall can cross, and only the wall-clock expiry check keeps a short-ttl store of its own; the legacy single-ttlMspairing let one CI stall past 150 ms expire a just-acquired lease inside a fencing check (the flake observed on Node 22). All three shipped harnesses move to the split pairing, and the store-authors guide stops recommending the flaky shape. In@rulvar/cli, worker retention is no longer slot-bound: a worker whose every concurrency slot is busy still applies retention over settled runs during its sweeps instead of starving until idle. In@rulvar/core, concurrent coldtools()calls on an MCP source share one in-flighttools/listfetch instead of each sweeping the list, andAdmissionController'smaxTotalSpawnsTSDoc now tells the truth: it is the controller-lifetime cap on admitted spawns for hosts driving the controller directly (pinned by a test), while engine runs cap totals throughbudgetDefaults.lifetimeSpawnCap; the old comment claimed it was the per-orchestratemaxSpawns.
1.81.2
Patch Changes
- 296885b: Three defects from a deep review of the MCP bus and the queue worker (cycle 79). In
@rulvar/cli,createWorker().stop()now waits out a sweep that is still scanning the store before taking its cancel snapshot, and a sweep observes the stop before every lease: previously a stop() racing an in-flight sweep could resolve while that sweep went on to lease and drive a new run, leaving a live run and a held lease behind a "stopped" worker. In@rulvar/core, the MCP tool source no longer loses alistChangednotification that races the in-flighttools/listfetch (the fetched list is served but never pinned as the session cache, so the next snapshot refetches), and cursor pagination treats an emptynextCursoras exhaustion instead of spinning the import loop forever on a server that echoes it. A regression test also pins the SDK-level rejection of a declaredoutputSchemawith nostructuredContent, guarding the planned SDK v2 migration.
1.81.1
Patch Changes
- c030982: The side-effect ledger records the outcome a dispatch actually had: a tool whose stdout violates the result protocol (non-JSON output from a clean exit) now ledgers
errorinstead ofok, in both the subprocess and container executors, and the executor conformance kit pins it as check e12. In@rulvar/core,stripFencedBlockscloses fences in CRLF text (a trailing carriage return no longer keeps a fence open and swallows the rest of the document), whichfencedCode: 'excluded'validators andheadingStructureValidatorinherit. Docs drift closed alongside: the package count, tables, and dependency graphs catch up to@rulvar/executorand@rulvar/store-postgres, the durability page reflects the shipped data protection hooks instead of denying them, and the architecture page no longer claims only the in-process executor exists.
1.81.0
Minor Changes
- ce4c392: The sixth comparison experiment's P2 harvest (cycle 77).
maxSpawnsnow counts ADMITTED children instead of attempt ordinals: an admission-rejected spawn (budget, quota, depth) consumes no slot, so the orchestrator can retry a rejected mandated role at a viable budget instead of losing it toorchestrate maxSpawns N reached(the rematch's run 2 shape); recovery rebuilds the same ledger from journaled admits, and attempt volume stays bounded by the coordination turn's tool budget. New stock validatorheadingStructureValidator({ sections, ordered, exclusive }): the markdown headings of one level (derived from the shared marker) held to the declared set, in declaration order, each exactly once and none undeclared, fenced code always stripped first (the judge's P1.3: line presence proves existence, not structure). The near-JSON finish recovery is durable (the judge's P1.5):AgentResult.schemaRecoveredTerminalExchangescounts the terminal exchanges the unparsed second chance salvaged (a live process counter liketransportRetries, absent when zero), and orchestrations fold both windows intoschemaRecoveredFinishExchangeson the acceptance ok envelope and the typed failure data, beside the rejected twin.
1.80.0
Minor Changes
262e397: The synthesis budget reserve and the strict admission projection (the sixth comparison experiment, cycle 76). The opt-in
budget.synthesisReserveUsdholds absolute dollars out of the orchestrator sub-account while the coordination loop runs: spawn admission and the per-turn output clamp treat the hold as spent (the severing check does not, so a coordination running against the hold is clamped smaller, never aborted), and the hold is released to the synthesis invocation just before it dispatches. Without it the rematch's first run lost a full paid run: the default 0.2 sub-account funded the coordination prefix and the budget clamp shrank the synthesis turns below the contract's minimal accepting payload, so the finish was cut at its output allowance before any tool call and the validator-bound run failed closed atmaxTurns. The reserve requires thesynthesisoption (single mode), must stay below the effective cap (OrchestratorCapConfigErrorotherwise), and nets out of the capped orchestrator's exact-fill admission hint exactly like the finalize carve-out.preflightEstimateprices the contract's minimal accepting payload at the synthesis model's output rate and reports the warningsynthesis-reserve-unfundedwhen a contract binds the synthesis and the hold is missing or too small.The admission projection is now STRICT at exact fill for the children of an orchestrate wave: the coordination turn that issues the spawn tools is paid before any spawn executes, so a child whose reserve fits only at exact fill is certain to be rejected live, and the projection now says so (
partial-admission) instead of promising the full wave. The rematch's second run lost its mandated fourth specialist to exactly that promise: the estimator projected 5 of 5 admitted while the live gate rejected the fourth spawn with reasonbudget. The orchestrator's own row keeps its exact-fill admission (it admits at run start, before any spend exists), and plain waves are unchanged. Absent the new option every budget account, journal, prompt, and cassette stays byte identical.
1.79.0
Minor Changes
85956ab: Terminal admission at an exhausted tool budget, the two harness-shape preflight findings, and the degradation mirror (the fifth comparison experiment).
The fifth experiment lost a complete 3984 word answer to terminal tool starvation: the harness set the synthesis tool cap to the child count, the mandatory
get_child_resultreads spent the whole budget, and the readyfinishwas cut BEFORE the terminal interception, so the validators never ran, the funded repair reserve never armed, and the run failed closed with the candidate stranded in the transcript.- The terminal tool is now exempt from the tool budget in both directions: it never consumed
maxToolCallsortoolUnitsbelow the cap, and an exhausted budget no longer starves it either. An admitted finish validates and, on rejection, feeds the repair grants exactly as below the cap; non-terminal calls beside it are answered with typed skipped results so the continued exchange keeps a well formed history; a batch with only non-terminal calls past the cap settleslimitbyte identically to before. - New preflight warning
synthesis-terminal-tool-headroom:synthesis.exposeChildResultToolswith asynthesis.limits.maxToolCallsbelow one read per possible child (orchestrator.maxSpawns) loses evidence access to the reads themselves. - New preflight warning
draft-gate-below-contract: adraftPolicy.minWordsbelow the contract's own word minimum admits drafts the final validators must reject, so the paid synthesis starts from an underlength base. The preflight input mirrorsfinishValidation.draftPolicyfor it. - The completion lift now mirrors the degradation facts the acceptance envelope already emits:
degradedReasons,salvagedPartialChildren, andsalvagedTerminalOutputChildrenriderun:endand theRunOutcomeunder the same shape validation ascompletionandchildStatusCounts, and the OTel exporter maps them torulvar.run.*attributes. An empty array is the workflow's claim of zero degradation; absence means no claim.
- The terminal tool is now exempt from the tool budget in both directions: it never consumed
1.78.0
Minor Changes
- 941b6e1: Contract exactness (the v1.74 experiment review, cycle 74, the last fourth-report slice). The
finishContractbundle is now DEEPLY frozen: the nested manifest objects, the sections array, the validators array, and each validator object, so a post-construction mutation throws aTypeErrorinstead of silently diverging enforcement from the journaled contract hash (on 1.77.0, pushing intomanifest.sectionschanged the live validator through a shared array reference whilehashkept claiming the original manifest). The contract now carries one reject golden PER validator (goldenRejects), each proven at construction, and both the orchestrate construction self test andpreflightEstimatehold the CONFIGURED validator of each name against its golden: a same-name replacement weaker than the contract's own validator (a words minimum of one standing in for fifty, which on 1.77.0 passed the single shared reject fixture on the strength of an unrelated validator and let an end-to-end run accept a five-word result against awords.min: 50contract) is now aConfigErrorat construction and the new error findingoutput-contract-validator-weakenedin preflight;selfTestFinishValidationaccepts the goldens via the newrejectsoption. Two manifest knobs sharpen matching:sectionsMatch: 'line'demands each section marker as its own line (a mid-sentence mention or a marker echoed inside a code fence no longer satisfies a heading), andfencedCode: 'excluded'removes fenced code blocks (the exportedstripFencedBlocksgrammar) before section matching, per-section slicing, word counting, and citation matching, so code samples can neither padwords.minnor donate citations, and a fenced marker occurrence can no longer mis-anchor a section's citation slice. Both knobs default to the historical behavior, normalize away at their defaults, join the hash and the prompt statement only when non-default, and exist on the standalone validators too (matchonrequiredSectionsValidatorandsectionCitationsValidator,fencedCodeon those pluswordCountValidatorandminMatchesValidator). Absent knobs and untouched bundles keep every existing configuration byte-identical: prompts, hashes, journals, and validator verdicts.
1.77.0
Minor Changes
6aba271: The v1.74 experiment review, cycle 73: contract turn feasibility in preflight, contract generation scoping, and error-outcome parity.
Preflight now proves a conforming answer can physically fit one finish turn of the invocation the validators bind: the contract's minimal accepting payload priced at the loop's four characters per token heuristic against the effective output bound is the error finding
output-contract-turn-infeasiblewhen it cannot fit and the warningoutput-contract-turn-headroomwhen the margin is under double; validators with repairs possible but norepairTurnReservedraw the warningrepair-reserve-unfunded, and the preflightfinishValidationinput mirrorsmaxRepairs.The fix-and-resume remedy is generation scoped: finish-validation decisions written under a contract carry
contractHash,repairsUsedcounts only the current generation, and a final rejection a superseded generation left in the crash window neither rolls forward at boot nor re-arms on replay (the stale exchange replays byte identical and the loop continues into a live repair turn). Pre 1.77 decisions carry no hash and bind to the current contract only while the journal holds a single bundle descriptor.Typed finish failures now mirror the full acceptance snapshot (
degradedReasonsand the salvage lists besidecompletionandchildStatusCounts) and count the invisible exchange class:AgentResult.schemaRejectedTerminalExchangesreports the terminal exchanges that died at the schema gate (window derived, absent when zero), and orchestrate folds the coordination and synthesis windows intoschemaRejectedFinishExchangeson the failure data. Absent options and contractless configurations keep byte-identical journals, prompts, and cassettes.
1.76.0
Minor Changes
- 22cba47: Synthesis evidence symmetry and the coordination draft gate (the v1.74 comparison review, P0.2 + P0.3). The finish validators judge the synthesis result against the FULL child outputs while the synthesis model saw only the draft and 400 char digest rows on a finish-only toolset; when the v1.74 experiment's draft collapsed to 'test', preserving the demanded 66 citations was model-impossible and the run ended answerless. Three opt-ins, each byte identical when unset:
synthesis.exposeChildResultToolsgives the synthesis invocation the RV-201 read toolsget_child_resultandread_child_artifact(the digest rows then carry each child'shandle);synthesis.context: 'full'embeds aCHILD OUTPUTSsection with every settled child's full serialized output beside the digests;finishValidation.draftPolicy(minWords,requireSections) rejects a schema-valid but collapsed coordination draft as the call's error result BEFORE any paid synthesis dispatch, with deterministic library checks that journal nothing and the samerepairTurnReserveheadroom the synthesis finish gets.preflightEstimatereports the asymmetric shape as the new warning findingsynthesis-evidence-asymmetry, and the preflight synthesis input mirrors the two new fields.
1.75.1
Patch Changes
- 82bc0f0: The unparsed-arguments second chance now covers the terminal tool (the v1.74 experiment review, P1.5 completion). The terminal tool validates its arguments at its own interception site, so 1.75.0 recovered regular tools only while the experiment's actual casualty was the coordination finish. Both sites now share one validation path: a near-JSON finish payload recovers deterministically and ends the loop in one turn with the recovered result; truncations and imitated wrappers keep the exact old error result.
1.75.0
Minor Changes
- c486de8: The provider output floor and the finish arguments second chance (the v1.74 comparison review, P0.1 + P1.5).
ModelCaps.minOutputTokensPerTurndeclares the smallest request output cap the provider accepts (OpenAI Responses: 16; absent means one), and the layer-2b budget clamp never dispatches below it: the last-gasp turn goes out AT the floor instead of one token, a remainder that cannot buy the floor is refused as a typedBudgetExhaustedErrorwith zero wire calls, and a configured per-turn cap below the floor is aConfigError;preflightEstimatereports that configuration as the error findingoutput-cap-below-provider-minimum. Tool arguments an adapter delivered as the parse-failure wrapper{__unparsed: raw}now get one deterministic second chance before the schema rejection: a strict re-parse, then one bounded normalization (markdown fence, first balanced object, raw control characters escaped inside string literals); a recovered object that passes the tool schema executes as if it had parsed on the wire, with a warn log naming the pass, and replay or resume recovers identically with nothing journaled. The OpenAI wire re-projects an unparseable call as the ORIGINAL raw arguments string instead of the wrapper JSON, so a model no longer learns to imitate{"__unparsed": ...}from its own rewritten history. Both wires drop unsafe-integerx-ratelimitvalues instead of normalizing 400 digits intoInfinity.FakeAdaptergainscapsOverridesso offline tests can drive caps-declared behavior like the floor.
1.74.0
Minor Changes
- d94beab: Quota drift telemetry and the honest zero (the v1.71 experiment review, P0.5 resized + P1.4). The experiment declared 12M TPM over a provider-real 1M, the local limiter went quiet, and seven live 429s followed with nothing recording the mismatch. Now: both wire adapters parse the provider's x-ratelimit headers on every real 429 into normalized per-minute limits (
WireError.data.reportedLimits; the openai wire also gains the raw bucket capture the anthropic wire already had), the loop remembers them per (provider, model) as live telemetry, and the opt-inquota.declaredRules(the SAME rule array preflight takes) makes the engine journal aquota_driftdecision plus a warn log whenever a binding declared cap EXCEEDS the provider-reported one, per invocation and dimension, with anthropic's split input and output windows summed against a combined declared tokensPerMinute. Purely observational, synthetic limiter denials never count, and without declaredRules journals and events stay byte identical. On the invoice, anunconfirmedrow that recorded zero usage on every counter now carriesusageUnknown: true(export-levelusageUnknownRowscount, CLIusage-unknownmarker): the zeros mean "nothing recorded", never "the provider metered nothing"; derived at export time, no journal shape change.
1.73.0
Minor Changes
- 3e95bd1: The synthesis repair envelope (the v1.71 experiment review, P0.4/P0.8/P1.7):
finishValidation.repairTurnReservegrants bounded EXTRA turns to the invocation the validators bind, one per rejected finish exchange (schema-invalid finish arguments and host validation rejections alike), derived from the message window itself so resumes recount identically and nothing new journals; the deliberately-deferred RV-204 reserve, now that the experiment showed one malformed finish plus one validator rejection killing a whole run inside maxTurns 3. Every typed synthesis failure now carries the acceptance snapshot (completion,childStatusCounts, lifted onto the error outcome by the completion mirror, so an errored run still reports "the fan-out work is complete") and the verdict-derived repair taxonomy (repairsUsed,maxRepairs,rejectedValidators) read from journaled decisions.preflightEstimatemodels the separate synthesis invocation (orchestrator.synthesis: limits, model, estInputTokens; echoed atbudget.orchestrator.synthesis, priced intoexposure.runCeiling, the gap the experiment's projection stopped short of) and folds a declaredfinishValidation.repairTurnReserveinto the projected turns of the bound invocation; the CLI prints the synthesis projection line. Zero reserve and no synthesis declaration keep every ceiling, journal, and report byte identical.
1.72.0
Minor Changes
- 662e9e0: The unified output contract (the v1.71 experiment review, P0.1/P0.2/P0.3/P1.1):
finishContract(manifest)generates the prompt statement, the stock validator set, a stable sha256 hash, and golden self-test fixtures from ONE immutable manifest, so the prompt a model follows and the validators a host enforces cannot drift apart by construction.finishValidation.contractwires it into orchestrate: the construction-time golden self test fails a stale validator as a ConfigError BEFORE any provider call (the experiment burned a full paid run on three renamed section headings), the contract statement is injected into the coordination and synthesis prompts, every contract validator must be present in the configured set by name, and the run journals a frozen bundle descriptor (orchestrator_finish_validation_bundle) with supersession on resume under a fixed contract.preflightEstimateaccepts the same declaration and reports drift as the error findingoutput-contract-validator-mismatchwith afinishValidationecho block. Two new stock validators:wordCountValidator(formal length bounds as code) andsectionCitationsValidator(per-section citation coverage, because a total count hides sections with zero provenance). Absent contract and selfTest, every existing configuration keeps byte-identical prompts, journals, and reports.
1.71.0
Minor Changes
- 20d02e0: The preflight quota planner follows the run past the first wave (the second experiment report, rec 9). Every declared spawn now reports
projectedProviderTurns, the provider-call ceiling of its whole loop (maxTurnsbounded by the executed-call ceiling plus the final no-tool turn, plus the finalization summary turn when a tool budget limiter arms it), and the orchestrator echoes its own.exposure.runCeilingtotals the declared wave run to those ceilings at the declared estimates: provider calls as fan-out times per-spawn turns, and cumulative tokens with the context regrowing every turn (turn k re-sends the declared prompt plus the k-1 prior output bounds, so a K-turn loop costs K x est + outputBound x K(K+1)/2). Three findings compare that projection against the declaredquotaRuleswhen the first-wave checks stay silent:quota-requests-below-run(the loops project more wire requests thanrequestsPerMinuteadmits; the message names about how many windows the run needs at best),quota-tokens-below-run(the regrowth cumulative exceedstokensPerMinute), and the spawn-attributedquota-turn-never-fits(by turn k the single context-grown reservation exceeds the whole token window, which the limiter denies withretryAfterMs 0and no wait helps). The first-wave checks are byte-identical, and a run whose ceiling fits its windows produces exactly the findings it did before.rulvar preflightprints the new turn ceiling per spawn and the run ceiling on the exposure line;--jsoncarries the fields verbatim. The experiment run behind the recommendation had zero preflight quota findings and eleven live limiter denials; this projection is what would have said so before the first dispatch.
1.70.1
1.70.0
1.69.0
Minor Changes
- b21a681: The tool-cap-before-checkpoint preflight warning (the experiment review, recommendation P1.8). The runtime checkpoints once per COMPLETED tool turn, and nothing in the limits vocabulary bounds a parallel batch below the executed-call ceiling, so a worker on a parallel-tools model can consume its whole tool budget inside the first batch, before any checkpoint exists: a kill mid-batch re-pays every executed call on resume.
preflightEstimatenow emits the stable warningtool-cap-before-checkpointfor every declared spawn whose effective executed-call ceiling is finite and positive while the resolved model's caps report parallel tool support, with the exact ceiling named in the message. Serial models (one call per turn, a one-call loss window), uncapped spawns, and zero caps stay silent, and reports over such shapes are byte-identical to before.
1.68.0
Minor Changes
- b227874: The machine-readable synthesis-skip reason (the experiment review, item 11.4, recommendation P1.5). A run that configures the post-fan-in
synthesisinvocation and never runs it used to show zerosynthesizespend with no recorded cause: the artifacts of a rejected run with synthesis configured were byte-indistinguishable from a run that never configured synthesis at all, and a host had to infer the skip from the acceptance decision and the RV-211 design. Both designed skips now record the exportedOrchestrateSynthesisSkipReason: the journaled decision that causes the skip freezessynthesisSkipped('synthesis_skipped_by_acceptance'on the rejected acceptance decision,'synthesis_skipped_by_budget_cap'on the budget-cap decision, immune to live-option drift on resume), the typedFailRunErrordata of the failing paths carries the same field, and an infologevent (orchestrator synthesis skipped) announces it beside the zero spend, on the live pass and on every resume roll-forward alike. The field is absent when synthesis is not configured or when it actually ran, so existing runs stay byte identical.
1.67.0
Minor Changes
- 8e6006d: The honest invoice (the experiment review, items 11.2/11.3, recommendations P1.2/P1.3/P1.4). The reconciliation verdict now names exactly what it asserts: the value
matchedis renamed toprovider-id-present, because the library never sees provider billing data and the old term read as a statement match it cannot make (deeper reconciliation tiers are host-side joins keyed onresponseId). Consumers comparingrow.reconciliation === 'matched'must switch to'provider-id-present';reconciliationFailureskeeps its meaning (rows without a provider id).InvoiceExportis now self-describing about pricing:pricingBasis: 'per-call'declares that per-rowusdprices each call individually at current rates, androwUsdNonAdditive: truewarns that those values need not sum tototalUsdunder a nonlinear price table (long-context tiers price a split differently from its sum). For consumers whose rows must sum, everyInvoiceRowgains the additiveallocatedUsdcolumn: each (entry, serving model) slice of the same gross fold the totals run is distributed across its rows in proportion to per-rowusd(token weights when every row priced to zero), one row absorbs the IEEE rounding dust, and the flat sum overrowsreproducestotalUsdexactly.rulvar invoiceprints the declared basis in the text form and passes the new fields through--jsonunchanged.
1.66.0
Minor Changes
- 1b8987e: The RunOutcome completion mirror (the 1.65.0 experiment review, P0.5). The semantic completion lift (
completion,childStatusCounts) rode ONLY therun:endtelemetry event, so a host consuminghandle.resulthad to parse the workflow-shaped value on the accepted path and dig the typed error data on the rejected one. The engine now computes the lift once and spreads the same object onto both surfaces:RunOutcome.completionandRunOutcome.childStatusCountsare present exactly whenrun:endcarries them (an ok/exhausted run whose result value makes a valid completion claim, or an error run whose typed error data does, the orchestrator acceptance path emits both), absent otherwise, so the outcome and the event can never disagree and a replayed resume mirrors the identical fields.
1.65.0
Minor Changes
- 0b6b859: Terminal-output salvage for limit children (the 1.64.0 experiment review, P0.4 + P1.1). A child that hits its tool budget with
limits.finalizationReserveconfigured can endlimitCARRYING a terminal output that already validated against its declared output schema; published bits discarded that paid, journaled work at every orchestrator surface. Now the digest appendsfinal: {...}andget_child_resultpages the full output unconditionally, and the new opt-inacceptance.acceptValidatedTerminalOutputOnLimitlets the completion policy count such a child as a success: the accepted envelope reportscompletion: 'partial'and lists the children insalvagedTerminalOutputChildren, an invalid summary keepsoutput: nulland still rejects (validation runs before acceptance by construction), and a child carrying both an output and a progress partial salvages by its output. The finish validation input gainsFinishValidationChild.salvageableOutput(set only under the option), andevidencePreservedValidatorcounts a marked child's citations in the cited pool, sorequireKnownno longer flags the orchestrator for quoting salvaged evidence. Every configuration without the option keeps byte-identical prompts and acceptance folds.
1.64.0
Minor Changes
991f9b5: Preflight and live admission share one reserve arithmetic (the 1.63.0 experiment review, P0.3).
Published 1.63.0 drifted from the runtime in both directions for orchestrate waves. A capped orchestrator below the flat reserve made
preflightEstimateemit the error-tierorchestrator-cap-below-reservefinding (exit 1 in CI) while the live run started fine, because the live dispatch admits the capped orchestrator at EXACT FILL with theeffectiveCap - committedFinalizeReserveestimate hint. And the projection admitted children whose priced layer-1 arm was tiny while the live embedded layer-2 spawn gate, which never sees the priced estimate, rejected every one of them against the remainder net of the orchestrator's own hold.Now the two formulas are exported pure functions the live paths themselves call, and
preflightEstimatecalls the same two:dispatchProjectionReserveUsd(the layer-2 spawn-gate projection: the declared estimate or the flat default, clamped by the spawn's explicit budget) andorchestratorAdmissionEstCostUsd(the capped orchestrator's exact-fill dispatch hint). An orchestrate wave now mirrors the runtime's two gates per spawn in live order; a plain wave keeps the parity-provenadmitSpawnmirror. New inputs:PreflightSpawnSpec.budgetUsd(the spawn param; layer-2 clamp only) andPreflightOrchestratorSpec.estInputTokens(the uncapped orchestrator's goal-prompt stand-in). Removed: the falseorchestrator-cap-below-reserveerror finding and the'orchestrator-cap'deniedBy value (a tight cap is a tight loop budget, never a refused run). Three new parity tests run live orchestrations beside the projection: the capped-below-flat config, the all-children-denied wave, and the layer-2-pass-layer-1-bust spawn.
1.63.0
Minor Changes
8a28aed: Durable settlement acknowledgement and the fencing-epoch tombstone (the 1.62.0 experiment review, P0.1 and P0.2).
Settlement acknowledgement: a NON-fencing failure of either settlement write now rejects
handle.resultwith the new typedSettlementError(codesettlement, retryable;stagenames the write,datacarries the runId and the computed run status) instead of resolving as if nothing happened. Only a superseded segment'sLeaseHeldErrorstays swallowed, on both writes, because the successor owns settlement. A failedrun_settleappend also skips the terminal meta write, so the projection can never run ahead of the journal (published 1.62.0 wrote metaokover a journal with no settle record when the append failed). Recovery is deterministic and free: the run's work entries are already durable,engine.resumereplays to the same outcome without one paid provider call and re-attempts the settlement writes (a non-empty journal with no recorded settle now re-settles on pure replay), andrulvar runs audit [--repair]reconciles offline.Fencing-epoch tombstone:
SqliteStoreandPostgresStoreno longer erase the per-run epoch high-water mark ondelete, so a recreate of the same explicit runId always acquires a strictly higher epoch and a zombie lease from the deleted incarnation (same runId, same stable owner identity) is rejected on every fenced surface instead of fencing green. TheLeasableStorecontract now states the rule, and the conformance kit enforces it with two new mandatory checks (fencing-epoch-tombstoneinleasableStoreConformance,fenced-tombstone-zombie-rejectedinfencedWritesConformance). The tombstone holds only the runId and a counter, never run content; the data-protection guide documents the erasure boundary.
1.62.0
Minor Changes
fca5fd1: Ship the preflight effective-limits estimator and effective-config linter (the experiment-review P2.2): everything the engine derives from a configuration, computed before any provider dispatch, machine readable, with zero paid requests by construction.
Core exports
preflightEstimate(input): a pure function over the same optionscreateEngineandengine.runreceive plus a declared spawn wave, returning the JSON-serializablePreflightReport. The estimate cannot drift from the engine because it reuses the runtime's own arithmetic:mergeUsageLimitsfor the effective per-spawn limit merge (call over profile over engine defaults),admissionReserveUsdfor the layer-1 reserve formula arm for arm (estCost, profile estCost, the priced estimate fromestInputTokens, the flat default, and the unpriced-model zero), the settlement price resolution, and the shared-quota dimension match. The report carries the admission projection over the declared wave mirroringadmitSpawnexactly (which spawns admit, which are denied and by what: budget, spawn cap, orchestrator maxSpawns, or an orchestrator cap its own reserve cannot fit), the per-tool and weighted-unit executed-call ceilings with the first bottleneck named, the orchestrator effective cap and finalize reserve echo, the concurrency and per-provider exposure floors with the one-more-turn overshoot floor, and the linter findings with stable kebab-case codes (errors:unrouted-role,unknown-profile,nothing-admitted,orchestrator-cap-below-reserve; warnings:partial-admission,weighted-units-bind-first,tool-unaffordable,unpriced-under-ceiling,inert-finalization-reserve,inert-tool-budget-notices,orchestrator-cap-fraction-bound, the quota-window comparisons; infos:overshoot-exposure,no-usd-ceiling,no-quota,per-tool-cap-unreachable).The CLI gains
rulvar preflight <file|name> [--budget-usd N] [--profile NAME] [--spawns JSON] [--json]: it assembles exactly the optionsrulvar runwould (config, module exports, run profile) but constructs no engine, opens no store, and dispatches nothing. The declared wave comes from the newpreflightexport of the config or workflow module ({ spawns?, orchestrator?, quotaRules? }),--spawnsoverrides it,--jsonemits the machine-readable report, and the exit code is the linter contract: 1 when any finding has severity error.
1.61.0
Minor Changes
b4c1f1f: Durable provider reconciliation (the experiment-review P1.3): every live provider dispatch now mints a
ProviderCallRecordon the terminal entry'sproviderCallsledger, the CostReport splits gross from net, andinvoiceFromJournalplusrulvar invoiceexport the rows.- The per-dispatch ledger. Every wire call the engine actually makes, successful or not, records
{ ordinal, role, servedBy, attempt, outcome, responseId?, usage, usageApprox?, errorCode?, aborted? }, minted at the single dispatch chokepoint from the same sanitized usage the phase slices accumulate. Failed and retried attempts keep their billed usage attributable instead of dissolving into the aggregate; quota denials and abort short circuits that never reached the adapter mint nothing. The providerresponseIdboth shipped adapters already surface on every finish is now persisted. The ledger rides every checkpoint boundary (kill-and-resume keeps pre-kill calls attributable, ordinals continuing) and restores verbatim on replay with zero live calls. - Gross versus net.
CostReport.totalUsdstays the net ledger it always was (abandoned subtrees contribute zero). New required fields make the provider's view first class:grossUsd(net plus abandoned, the figure an invoice reconciles against; abandoning a branch never shrinks it) andabandoned: { usd, unpriced, usageApprox? }.rulvar inspectprints the gross line whenever a run abandoned paid work. - The invoice export.
invoiceFromJournal(entries, priceUsd)returns one row per billable call with a reconciliation verdict per row:matched(response id present),missing-provider-id(a finished call without one),unconfirmed(a failed or severed call without one),unattributed(pre-ledger entries and restored remainders; the spend surfaces instead of vanishing). Totals are the same slice fold the CostReport runs, sototalUsd === CostReport.grossUsdexactly.rulvar invoice <runId> [--json]is the CLI form.
The frozen cassette catalog is re-recorded for the additive
providerCallsfield on terminal agent entries (journal-shape-revision, policy not identity: no hashVersion change, no matching impact).- The per-dispatch ledger. Every wire call the engine actually makes, successful or not, records
1.60.0
Minor Changes
59bbeaa: The finalization reserve (the experiment-review P1.1):
limits.finalizationReserveguarantees the model one bounded summary turn when a tool budget expires, so a research agent that pays for its evidence no longer dies mid-batch without its final report.Before this, a
maxToolCallsortoolUnitsexpiry inside a tool batch dropped the batch tail silently (dangling tool calls without results in the transcript), settledlimitbefore any further model turn, and named no limiter on the terminal. With the reserve configured (an object;{}enables it):- The batch tail closes explicitly: every call the budget did not admit gets a typed error tool result
{ error: 'skipped: the tool budget is exhausted; the call was not executed', limiter, skipped: true }, keeping the transcript well formed and the skipped calls visible to the model and to transcript readers. - The model always gets ONE summary turn on the loop chain (failover, retry policy, quota, and the budget all apply; usage is attributed to the loop role) with tools withheld and a request-only instruction naming the limiter, its counts, and the skipped calls.
finalizationReserve.maxOutputTokensbounds this turn alone. - The
limitterminal names the exact limiter:error: { kind: 'terminal' }with an errorMessage such astool budget exhausted: maxToolCalls (72/72); skipped tool calls: 3. - The summary becomes the limit result's
output(typed when a ridden schema parses it; one attempt, no re-prompt), the terminal journals the value, and a replayed result restores the same output with zero live calls. The structured terminal partial fromreport_progressstill derives beside it.
The reserve fires only for the two tool-budget limiters, never for
maxTurns,timeoutMs, or the exploration aborts. A transport failure on the summary turn keeps the earnedlimitterminal with alogwarning; host cancellation and the budget ceiling keep their own semantics. Without the field every byte stays as before, exactly like the other opt-in limits.- The batch tail closes explicitly: every call the budget did not admit gets a typed error tool result
1.59.4
Patch Changes
- c49d7a1: The genesis ownership protocol (P0.2): over a leasable journal store, every execution segment now holds the run's lease while it drives. A fresh
engine.runand an in-processengine.resumethat were not handed a lease acquire their own before their first durable write, renew it at a third of the store TTL exactly like a queue worker, and release it at settle; a second driver (a worker sweep adopting a live fresh run, a double resume from another process, a simultaneous genesis of one explicit runId) rejects at its own boot with the typedLeaseHeldError, before any journal write, meta write, or provider dispatch. Previously a fresh run held no lease at all, so a worker sweep on the same store adopted the live run, redispatched its in-flight provider turn (double spend), raced the journal from a stale tail, and could overwrite the settled meta with a stale error status.RunOptions.leasenow exists as the genesis twin ofResumeOptions.leasefor hosts that acquire at admission time and keep the lifecycle;createEngine({ ownership: 'none' })opts an engine out of automatic acquisition; dry-run previews never acquire. Journals stay byte-identical: leases live beside the journal and never enter run identity. The serialization wrapper now also forwards the store'sleaseTtlMs, so the renew cadence over an encrypted store follows the configured expiry.
1.59.3
Patch Changes
- deaef36: Bind the isolated-executor idempotency key to the logical invocation, not just the arguments (v1.59.x review P0.4). The key was
sha256(runId, tool, args), so two intentionally separate out-of-process tool calls in one run with byte-identical arguments received the same key, and an external system deduplicating on it would silently drop the second intended effect. The key now folds in the containing agent entry's journal seq and the call's ordinal within that agent's tool loop; both are journal- and checkpoint-stable, so distinct calls (different ordinals, or different agents) never collide, while an at-least-once crash-resume of the same logical call reuses the same agent entry and the restored ordinal and therefore the same key.deriveExecIdempotencyKeyand the internalToolRuntime.executeExternalgain the invocation parameters; the key never enters run identity (no content key or toolset hash), so journals stay byte-identical.
1.59.2
Patch Changes
- dd0e10f: Bind envelope-encrypted journal ciphertext to the full entry identity (RV-217 follow-up from the external experiment review). The v1 associated data covered only
seqandkey, so a ciphertext could be transplanted between two runs of the same tenant wherever(seq, key)matched, and a stored entry's clear identity fields (status,scope,ordinal,kind) could be rewritten on disk without failing authentication. The new v2 envelope schema authenticates over therunIdplus every immutable clear field (hashVersion,seq,ref,scope,key,ordinal,kind,status); a transplant into another run or entry, or a rewritten clear field, now fails typed instead of decrypting. The journal serialization hook gains an optionalJournalSerializationContextcarrying therunId(the wrapping store always supplies it; a host hook written against the original single-argument shape stays valid). Writes always emit v2; pre-upgrade v1 envelopes still decrypt on read, so an encrypting store upgrades in place with no migration step. Transcript blobs were already ref-bound (the ref embeds the runId) and are unchanged.
1.59.1
Patch Changes
- c127770: Two fixes from the v1.59.0 external experiment review.
CostReport.byRole.synthesizefolded toNaNin the journal cost report and in settled run outcomes because the role-bucket initializer predated thesynthesizerole; the initializer is now an uncast exhaustive literal, so a future role that misses it is a compile error instead of a NaN bucket. The engine's own retry jitter defaulted to the liveMath.random, which the bare-nondeterminism detector classified as workflow provenance when rulvar is imported from a checkout build rather thannode_modules; the default retry rng is now bound at module load, the same convention as the engine clock, so engine-internal retries never emitRULVAR_BARE_MATH_RANDOMor fail a run underdeterminism.mode: 'error'.
1.59.0
Minor Changes
- 615dc90: RV-216: the isolated tool executor, the last open item in the improvement plan. In-process tools are ordinary function calls with full host capabilities (an execution convenience, never a sandbox for hostile or model-generated code); this release adds an official out-of-process executor contract so a tool whose input is untrusted cannot reach host capabilities. (1) THE SEAM in
@rulvar/core: aToolExecutorProviderSPI, registered on the engine ascreateEngine({ executors: { subprocess, container } }). A tool declaringexecutor: 'subprocess'or'container'(previously a hard "only inprocess in v1" rejection) dispatches through the matching provider instead of running itsexecuteclosure; an unregistered tag is a typed ConfigError at spawn time, before any provider or model call. The dispatch mints the tool span exactly like an inprocess call and derives a stable idempotency key (a pure function of runId, tool name, and canonical args) so a side-effecting tool can fold an at-least-once retry into effectively-once; the tag never enterstoolsetHash, so opting a tool into isolation does not change run identity, and inprocess dispatch stays byte-identical. (2) THE REFERENCE ADAPTERS in the new@rulvar/executorpackage:subprocessExecutorruns the tool in a child process with a REPLACED environment (host credentials scrubbed; the usual exfiltration path removed), a fresh ephemeral working directory per call, per-call short-lived credentials, a hard timeout that escalates SIGTERM to SIGKILL, and a bounded output capture, plus asandboxlauncher hook where bwrap/firejail/sandbox-exec plug in for filesystem and network isolation;containerExecutorruns it in a one-shot container with the network dropped (--network none), the root filesystem read-only, memory/CPU/pid caps, and all Linux capabilities dropped, which is where the strong isolation the subprocess adapter cannot promise on its own actually holds (a microVM adapter implements the same seam).subprocessTooldefines a tool that dispatches through them; aToolEffectLedgerrecords every dispatch (idempotency key, tool, argsHash, workdir, outcome) so a host can bind an approval to the effect it authorized. (3) THE CONFORMANCE KIT:executorConformanceis the executable shared-contract battery any command-based executor must pass, foremost the gate the epic exists for, a hostile tool cannot read the host's ambient credentials; the subprocess reference passes all of it, and the container reference additionally proves the network and filesystem isolation against a real runtime. New guide page: https://docs.rulvar.com/guide/isolated-executor.
1.58.0
Minor Changes
- 4fa35ce: RV-217: data protection hooks, the full close. The plan's gate ("PII never persists or emits in plaintext under policy") now holds end to end. (1) ENVELOPE ENCRYPTION on the serialization seam:
createEnvelopeEncryption({provider, historicalWrappedKeys?, plaintextReads?})returns aSerializationHookthat AES-256-GCM encrypts every persisted byte (journal payloads, transcript blobs, checkpoints) with entry identity as associated data (a ciphertext moved between entries or refs fails authentication), keeping only the kernel-pinned ordering/identity fields plus spanId and timestamps plaintext;DataKeyProvideris the KMS seam (the exact shape of GenerateDataKey/Decrypt, called only in the async factory so the sync hooks run on in-memory data keys, and every envelope carries its wrapped key so reads need no live KMS); the shippedlocalKeyProviderderives KEKs via HKDF-SHA256 with aninfopartition for tenant-scoped keys (a different tenant's provider cannot unwrap, pinned by tests); reads of non-enveloped data fail closed by default withplaintextReads: 'passthrough'as the explicit migration mode;fromStored(toStored(e))reproduces entries exactly, so replay, resume, and recovery are untouched and a run over real files greps to ZERO plaintext PII whileEngine.storesreads plaintext through the one policy point. (2) REDACTION POLICY:redaction.patternsadds host-defined patterns (RegExp or strings, compiled once, typed ConfigError on an invalid one) on top of the default credential set for every emitted event, via the new exportedcompileSecretMasker; the OTel exporter accepts the samepatternsfor trace parity. (3) EXPORT/IMPORT:engine.exportRun(runId)produces the portable bundle (meta, entries, blobs) read through the policy point, so encrypted deployments export plaintext for subject-access requests;engine.importRun(bundle)writes through the target's stores (re-encrypting under its policy), keeps the original runId, and refuses an existing run typed; together with the existingdeleteRun/pruneRunthis completes the retention/deletion/export surface. (4) SALTED METADATA DIGESTS:security.argsHashSaltswitchesRunMeta.argsHashto HMAC-SHA256 under a deployment salt (equal args stop correlating across deployments; low-entropy args stop being recoverable from the digest),hashRunArgsgains the optional salt, and the CLI resume args gate picks the salt up fromengineOptions.securityautomatically. (5) AUDIT TRAIL:reduceAuditTrail(entries)folds a journal into the typed, ordered sequence of authority events (suspensions with deadlines, resolutions with who and what, abandons with reasons, engine decisions, termination denials, run settles), tolerant across journal vintages. New guide page: https://docs.rulvar.com/guide/data-protection.
1.57.0
Patch Changes
- 5897232: Two follow-ups from the RV-210 and RV-215 cycles. (1) Resume of a run that already SETTLED ok no longer re-dispatches plain cap-expiry
limitchildren live: the canonical replay predicate now takes arunSettledOkinput (computed by the engine from the loaded journal's run settle entry), and the memoize-limit rule replays unstamped limit entries when the run is finished history, so resuming a completed run makes ZERO adapter calls andreplay --assert-no-livestyle verification holds. Non-ok settles and never-settled journals keep the rerun retry semantics (a crashed segment still resumes into a second chance), and an explicit invalidate still forces a rerun. (2)SqliteQuotaLimitercarries its own class TSDoc (the api page previously inherited the bare SPI interface line), documenting the single-transaction admission, cross-process reconciliation, identical-rules requirement, pruning, and the busy_timeout contract.
1.56.0
Minor Changes
- f26dba0: RV-215: distributed provider limiting. The new
QuotaLimiterSPI is the extension seam for SHARED rate/quota limiting across engine instances and OS processes:createEngine({quota: {limiter, tenant?, onLimiterError?}})makes the engine reserve capacity before EVERY live wire dispatch (initial attempts, transport retries, and failover takeovers alike, in every phase), dimensioned by provider/model/tenant with a heuristic token estimate, and reconcile each granted reservation with the attempt's actual usage after the outcome settles. A denial becomes a synthetic rate-limit-class WireError that rides the existing provider-429 retry and failover machinery verbatim, except no wire call is paid: the limiter's retryAfterMs (the honest window remainder) drives the interruptible backoff, attempts stay bounded by RetryPolicy, exhaustion fails over (the takeover reserves under its own model), and the terminal is the typederrorof kindrate-limit.onLimiterErrordecides what a limiter INFRASTRUCTURE failure means:'deny'(default) fails closed as a retryable transport-class denial,'allow'logs a warning and dispatches without a reservation. Quota admission is live-only by construction (nothing journaled; replay and resume of memoized work never touch the limiter), and an unconfigured engine takes the exact pre-quota dispatch path down to promise-tick identity. Two reference implementations share one rule model (QuotaRule: optional provider/model/tenant dimensions;requestsPerMinuteexact and hard,tokensPerMinuteestimated at admission and settled to actual; every matching rule must admit; fixed epoch-aligned one-minute windows;validateQuotaRulesat intake):memoryQuotaLimiterin @rulvar/core coordinates engines inside one process, andSqliteQuotaLimiterin @rulvar/store-sqlite coordinates PROCESSES over one database file, with admission inside a single BEGIN IMMEDIATE transaction, cross-process reconciliation via reservation rows, lazy two-window pruning, and the store's boot-scoped busy retry; a multi-process test fleet of real engines proves the global cap holds (dispatched wire calls exactly equal recorded window consumption, no window over cap).createTestEnginein @rulvar/testing passes aquotaoption through to the engine.
1.55.0
Minor Changes
- e9b005b: Close RV-210 in full: the partial-work contract. (1) Weighted tool units and per-tool call caps:
UsageLimits.toolUnits { max, costs? }terminates as a plainlimitwhen the weighted budget is reached (each executed call of tool T costscosts[T] ?? 1; denied calls cost nothing), andUsageLimits.maxCallsPerTool { name: cap }denies the excess call of a NAMED tool pre-dispatch with a typed error result (guard: 'per-tool-cap', no budget or unit consumed;0bans the tool); both validate at intake, merge as whole-object per layer, and surface inExplorationSummaryastoolUnitsUsed/deniedToolCap. (2) The progress contract and the structured terminal partial: the stockprogressReportTool()(report_progress) lets an agent state its facts, evidence refs, and open questions after every batch, and alimitterminal now keeps the LAST successful report asAgentResult.partial(derived deterministically from the transcript; a final boundary checkpoint pins the window so replay and recovery rebuild the identical partial; invocations that never report stay byte-identical). (3) Partial-child salvage: the digest of a limit child appendspartial: {...},get_child_resultpages the full report, andacceptance.acceptPartialChildren: truecounts a partial-bearing limit child as a success for both child policies (completion'partial', the salvaged children listed insalvagedPartialChildrenon the envelope and inside the single journaled acceptance decision; a bare limit child still rejects; one deterministic coordination-prompt line appears only when the option is on). (4) Profile templates with the stop conditions built in:researchAgentProfile({ root })composes the repository research toolset, the progress tool, andRESEARCH_PROFILE_LIMITS;implementationAgentProfile/reviewAgentProfilepreset the caller's task tools withreport_progressprepended under their own exported limit constants. Unconfigured behavior is byte-identical everywhere.
1.54.0
Minor Changes
3f6bc03: Three improvement-plan remainders: the
run:endsemantic completion lift (RV-207 tail), the standard repository research toolset (RV-210), and incremental synthesis with pre-model claim deduplication (RV-211).The completion lift. Transport status and semantic completeness are different claims, and
run:endnow carries both: a workflow that returns an object result with a validcompletionliteral ('complete' | 'partial' | 'rejected') and optionally achildStatusCountsrecord, or throws a typed error whosedatacarries them, gets both lifted onto therun:endevent. The orchestrator acceptance path emits the envelope on every terminal, including the typed rejection (itsFailRunErrordata now carriescompletion: 'rejected'). Malformed shapes stay silently absent, replay recomputes identical fields, the CLI progress line renderscompletion=..., and the OTel exporter mapsrulvar.run.completionandrulvar.run.childStatusCounts.The repository research toolset.
repositoryResearchToolset({ root })ships fiverisk: 'read'tools over a confined directory root:list_files,search_files, andread_filewith deterministic byte ordering and STABLE keyset cursors (a page boundary never shifts when unrelated entries appear; every cursor embeds its query identity), plusrecord_evidence, which verifies citations at collection time (the file must exist under the root,linesmust be a valid 1-based range inside it,quotemust appear verbatim), andlist_evidence. Pages are canonical: byte-identical however addressed, which is exactly what the exploration guards measure, somaxRepeatedToolSignatureandmaxNoNewEvidenceCallscompose with the kit instead of being defeated by marker fields. Absolute paths,..escapes, and symlink escapes are typed error results; the host reads collected evidence viakit.evidence().Incremental synthesis and claim dedup.
synthesis.mode: 'incremental'dispatches one boundedsynthesize-role NOTE invocation per settled child the moment it settles (defaultnoteLimits{ maxTurns: 2 }), overlapping the still-running fan-out, and the final result is a DETERMINISTIC reconciliation envelope (IncrementalSynthesisResult), never another model call; a dead note falls back to that child's raw digest summary under a journaled per-childorchestrator_synthesis_note_fallbackdecision, replay reproduces the envelope with zero paid calls, andfinishValidationplus incremental mode is aConfigErrorat intake because the reconciliation has no model-composed finish to validate.synthesis.dedupeClaims: truededuplicates repeated claim lines across children BEFORE any model call (whitespace-collapsed exact matching via the exported purededupeRepeatedClaims, never fuzzy): in single mode the digest keeps first occurrences with aREPEATED CLAIMSindex riding the prompt, in incremental mode the envelope carriesrepeatedClaims. Both options default off and the synthesis prompt stays byte-identical when unset.
1.53.0
Minor Changes
- b821bd1: Ship the RV-211 synthesis role and critical-path metrics.
InvocationRolegains'synthesize': the dynamic orchestrator's opt-in post-fan-in synthesis invocation (OrchestrateOptions.synthesis { model?, effort?, limits?, instructions?, estCost? }). With it configured, the coordination loop'sfinish({ result })becomes a draft and one fresh finish-only invocation with rolesynthesizecomposes the final run result from the goal, the draft, and the settled child digest, routable independently of coordination through the ordinary chain (the routing key picks its model and never summons it; no role effort default, likeloopandfinalize). Ordering and failure posture are strict: synthesis runs only after an accepted acceptance verdict;finishValidationvalidators bind the synthesis finish instead of the draft (same repair loop, same journaled verdicts); a dead synthesis falls back to the draft under a journaledorchestrator_synthesis_fallbackdecision and a warn log without validators, or fails the run typed (data.source'orchestrator_synthesis') with them. The invocation is an ordinary journaled agent entry, so a resume replays it with zero paid calls (the prompt derives from journaled state, and the replayed root now awaits recovery before the digest fold). Telemetry: fullsynthesizespan and phase pairs (CostReport.byRole.synthesize), a debuglogevent with the actual draft/digest/prompt sizes, and the new pure reducerreduceCriticalPath(events)(CriticalPath), which computes run wall, the post-fan-in interval, the synthesis wall, and their shares, so the improvement plan's post-fan-in gate (at most 40% of wall time) is a field read; the benchmark kit can expose any of them as metric extractors.createTestEngineroutessynthesizeto the fake model like every other model-picking key. Demonstrated against published 1.52.0 first: the whole orchestration emitted only orchestrate/loop roles, the final synthesis request ran on the coordination model,byRolehad no synthesize bucket, the post-fan-in share was hand-rolled or nothing, and the synthesis vocabulary was silently ignored words.
1.52.0
Minor Changes
- e138df9: Ship the RV-210 exploration guards (first slice): three opt-in
UsageLimitsfields that make an oscillating tool loop visible and boundable.toolBudgetNoticessurfaces soft 50%/80% thresholds overmaxToolCallsto the model as a plain user message with the exact remaining count (once per threshold, checkpoint-safe, inert with a loud warning withoutmaxToolCalls).maxRepeatedToolSignaturecaps executions of the byte-identical call (tool name plus RFC 8785 canonical args): the excess call is never dispatched, the model receives a typed error result naming the count, the denial does not consume the tool budget, andtool:endcarriesoutcome: 'denied'withguard: 'repeated-signature'.maxNoNewEvidenceCallsaborts the invocation as statuslimitwith the newabortClass: 'exploration'when N consecutive successful executions return only already-seen result digests; the executed work is kept, the terminal memoizes, and the structuredExplorationSummary(toolCallsUsed,distinctSignatures,repeatedCalls,duplicateResultCalls,deniedRepeats,byTool) journals beside the abort class so a replayed consumer sees the same typed evidence with zero live calls. Whenever any guard field is configured the summary also rides the fullAgentResultand the liveagent:endevent (live-only for non-abort terminals, liketransportRetries); values JCS cannot serialize fail open (unique signatures, fresh evidence); on resume the guard rebuilds from the restored checkpoint messages. The CLI TUI renders the guard marker on denied tool lines and the OTel exporter maps the counters torulvar.exploration.*andrulvar.tool.guardattributes. Unconfigured invocations are byte-identical to before. Demonstrated against published 1.51.0 first: the identical call executed six of six times with zero signal, the model never saw a remaining count, duplicate pages never flagged, and the terminal was a barelimitindistinguishable from honest work.
1.51.0
1.50.0
Minor Changes
e39a885: The structured determinism contract (RV-209): bare-nondeterminism detection is engine-owned, classified, localized, and enforceable, and replay verification is a first-class CLI gate.
- New
determinism:warningevent on the run stream: a bareDate.now()orMath.random()call observed inside an in-process workflow body emitscategory,provenance(workflow|allowlisted), the callingframe, and the parsedfile/line/column, at most once per (category, provenance) per execution segment. Installed dependencies (node_modules) and Node runtime frames are classified exempt and stay silent, so an SDK's internal randomness never brands the run nondeterministic. Never journaled; because replay re-executes the body, a violation still in the code fires again on every replay organically. CreateEngineOptions.determinism:mode: 'off' | 'warn' | 'error'(warn stays the default and the pre-RV-209 dev-only behavior; the process warnings now name the callsite),allowlist(substring or RegExp patterns for confirmed-safe frames, classifiedallowlisted, never rejected), andredact(applied to frames and file paths before they leave in events, warnings, and errors). Config is validated loudly atcreateEngine.mode: 'error'detects in every environment including production and rejects the run: the offending call throws a typedDeterminismError(new error codedeterminism, localization indata) at the call site, and a workflow that swallows it is re-thrown at settle, so the run ends'error'instead of recording a value replay cannot reproduce.- The journaled run-settle decision now records
outputHash(canonical JCS sha256 of the settling segment's result; absent for undefined or non-serializable values). Pure replays append no settle, so a divergent replayed result can never overwrite the live baseline.hashRunOutputand the extendedlastRunSettleare exported. - New
rulvar replay <runId> [--args JSON] [--store PATH] [--assert-no-live] [--compare-output-hash]: a dry-run resume (zero journal or meta writes, zero adapter calls) that reports replay accounting, every localized determinism warning, and the digest comparison;--assert-no-liveexits 1 unless the replay is pure,--compare-output-hashexits 1 unless the replayed result's digest equals the journaled one. Deliberately no--allow-args-change: verifying a different logical run proves nothing. - The TUI renders
determinism:warninglines, and the OTel exporter attaches the event to its span withrulvar.determinism.*pluscode.filepath/code.linenoattributes. - The frozen cassette catalog is re-recorded for the additive
outputHashfield on run-settle decisions (journal-shape-revision, policy not identity: no hashVersion change, no matching impact).
- New
1.49.0
Minor Changes
bab7b2c: Make the agent event model unambiguous (RV-207): one
agent:start/agent:endpair per logical agent span, a pairedagent:phase:start/agent:phase:endper model invocation phase, an official reducer, and the OTel exporter leak the old shape caused is closed.Before this release one spanId emitted an extra unpaired
agent:startfor every phase of the dispatch (loop, thensummarizeper compaction,finalize,extract) with a singleagent:end, so durations and attempts were underivable without heuristics: a consumer pairing starts with the end read the LAST phase's duration as the agent's, a starts-minus-ends gauge leaked one running agent per phase, and the shippedtoOtelexporter (reproduced on the published 1.48.0) leaked a never-ended OTel span per multi-phase agent while the span it did close measured only the last phase. The replayed stream had a different shape than the live one (one start), so the same consumer built different tables live and on replay.Now every phase activation emits
agent:phase:start/agent:phase:endkeyed(spanId, invocation)(a 1-based activation ordinal; a summarize that fires three times gets three pairs), carrying the phase's role, the serving model,durationMs, the usage delta the activation added to its(role, model)slice (the pairs sum exactly toagent:endand to the journaledusageByModelsplit),costUsdpriced at each serving model's own rate, a binaryoutcome, andretries(transport retries inside the activation).agent:endgainsretryCount. The retry facts are live telemetry only, never journaled: replayed events omit them, and replayed phase pairs are reconstructed from the terminal entry's recorded slices withdurationMs0, so a live stream and its replay reduce to IDENTICAL usage and cost tables.reduceInvocationTable(new in@rulvar/core) is the official no-heuristics reducer: per-agent per-phase rows plus a per-role aggregate that matchesCostReport.byRole; truncated streams stay honest (open: true), never guessed at.@rulvar/cli:toOtelmaps each phase pair to aninvocation <role>child span of its agent span withgen_ai.usage.*,rulvar.cost_usd, andrulvar.retriesattributes, closes the agent span with the whole dispatch's totals andrulvar.retry_count, and an opener for an already-open span never duplicates it, so even a stream from a pre-RV-207 core cannot overwrite the tracked agent span and leak it unended. The progress renderer prints the phase lines (agent w extract phase on model, then the settle line with per-phase cost, tokens, duration, and retries). Journal bytes, cassettes, and toolset hashes are untouched: events are telemetry, never identity.
1.48.0
1.47.0
Minor Changes
- a3687fe: Ship phase 3 of the fenced run state RFC, reconcile and recover. The engine now journals every run settle whose segment did durable work (or changed the recorded status) as a
run_settledecision entry ordered BEFORE the meta write, so the run's outcome is part of the journal andRunMetais a rebuildable projection; the write-on-change rule keeps pure replay byte stable, so a resume that only replays appends nothing. On top of it,auditRunnames the divergences a worker sweep can never see,auditRunssweeps the catalog, andreconcileRunMetarewrites the sound cases from the journal with zero model calls and no workflow:meta-behind(the crash residue between the journal flush and the meta write, or a stale write contradicted by a journaled settle) takes the journaled status, andstranded(a terminal meta over live journal work, the F1 residue an unfenced store admits, demonstrated against the published 1.46.0 first) becomes sweepable again; ambiguous residues are reported assuspectand never rewritten. The CLI gainsrulvar runs audit [--repair], the operator probe: it lists every divergence, repairs under a brief per-run lease on a leasable store (a live owner is skipped, never raced), and exits 0 only when the catalog ends consistent.ResolutionOutcomeadditionally carrieswoke: trueexactly when a resolution settled a live in-process waiter, and the HTTP server uses it to close a quiesce-window race: a resolve that applied through the fold while the segment was closing now awaits the imminent settle and continues the run in place instead of answeringresumed: falseon timing grounds and stranding it suspended. The committed cassette catalog is re-frozen for the additive settle entry under the journal-shape-revision lane of the fixtures lock: an additive journal evolution that revises no identity (the hashVersion stays 2; entry identity, adapter requests, and the frozen v1 resume fixtures are untouched byte for byte).
1.46.0
Minor Changes
- 865e7bf: Close finding F2 of the fenced run state RFC with the sqlite transcript twin.
SqliteStore.transcripts()returns aTranscriptStorethat declaresfencedWritesbecause its blobs live in the store's own database, beside the lease rows: a lease-carryingputordeleteverifies the current holder of the run the ref's leading path segment names atomically with the blob mutation, in the same one-immediate-transaction shape as the journal side, and rejects stale or cross-run holders with the typedLeaseHeldErrorleaving the prior blob byte intact. Demonstrated against the published 1.45.0 first: the engine threaded the superseded segment's lease into its late checkpoint save, both shipped transcript stores ignored it, and the blob at the deterministic ref both segments share regressed to older turn state (the state a later boot decodes, replaying turns the successor already paid for) while the same holder's journal append bounced typed. Over the{ journal: store, transcripts: store.transcripts() }pair,assertFencedWritesnow passes and every durable run mutation is fenced. The conformance kit gainsfencedTranscriptsConformance, the executable definition of the transcript-side promise, taking a factory for the pair that shares the fencing domain; staleness is produced with release plus reacquire, so the suite needs no wall sleeps.
1.45.0
Minor Changes
- b96305d: The fenced writes capability (the fenced run state RFC, phase 2).
JournalStore.putMetaanddeleteandTranscriptStore.putanddeleteaccept the same optional trailing lease thatappendalways took, and a store declares enforcement with thefencedWrites: truemarker: a mutation carrying a lease that is not the current holder for the mutated run rejects with the typedLeaseHeldError, atomically and leaving nothing changed, including a live lease for a different run. The engine threads the segment's lease into every durable mutation of a leased resume (meta writes, checkpoints, compaction summaries, worktree patches, workflow sources), so over a declaring store a superseded worker can no longer overwrite the successor's meta at its late settle and strand the run from worker sweeps, and its very first refused meta write now fails the stale segment typed at boot with zero paid calls.SqliteStoredeclares the marker and enforces it onputMeta,delete, andappend(with the run-match rule as defense in depth); the conformance kit gainsfencedWritesConformanceas the capability's executable definition; the queue worker's retention sweep passes its brief lease through the new optional second argument ofengine.deleteRun(pruneRuntakes the same); andhasFencedWritesplusassertFencedWriteslet a host assert the full fence at deployment time. Stores written before the capability are untouched: without the marker the extra argument is ignored and the journal-append fence works exactly as before.
1.44.1
1.44.0
Minor Changes
- 299f7d2: Evidence preservation contract for the orchestrator finish (the improvement plan's RV-202 slice). The finish validation input now carries
children: every spawned child at finish time, in spawn order, with its handle, nodeId, status, and full output text, a pure read of the durable state the orchestrator already tracks, so validators can hold the finish result against the evidence the children actually produced. The newevidencePreservedValidatorenforces the plan's gate: at leastminShare(default 0.95) of the distinct citations found in the outputs of children settled ok must appear literally in the result text, with the missing ones listed in the rejection so the bounded repair turn can restore them;requireKnown: trueadditionally rejects citations no child ever produced, closing the fabrication path that satisfied a plain count check. Purely textual and deterministic; verdicts journal exactly like every finish validation verdict, so replay and resume reproduce them without re-running validator code.
1.43.0
Minor Changes
- 71b7181: Deterministic finish validators with bounded repair for the dynamic orchestrator (the improvement plan's RV-204 slice).
OrchestrateOptions.finishValidationruns host validators over every schema validfinish({ result })call: a rejection returns the failure reasons to the model as the call's error tool result and grants a bounded repair turn (maxRepairs, default one); a rejection past the bound fails the run with the typedFailRunError(codefail_run,data.source'orchestrator_finish_validation') BEFORE the acceptance settle, so acceptance never judges a rejected finish. Every verdict journals as a decision entry keyed by the finish call id, so a resume rolls the same verdicts forward without re-running validator code, and a journaled final rejection short circuits at boot without a model call. The toolset never changes and zero configuration adds zero journal entries, so existing runs and frozen cassettes replay byte for byte. ShipsrequiredSectionsValidator,requiredFieldsValidator, andminMatchesValidator, plus theFinishValidatorcontract for custom checks.
1.42.0
Minor Changes
9b70f27: Add the opt in child-result evidence tools get_child_result and read_child_artifact (the v1.40.0 improvement plan, narrow RV-201 slice)
The digest an await returns is a wake signal truncated to 400 characters, so an evidence-heavy child settles with its findings intact in the journal but only a snippet in the digest, and until now there was no way for the orchestrator to fetch the rest. OrchestrateOptions.exposeChildResultTools now adds two pure read tools. get_child_result pages a settled child's FULL output (its string or JSON; a failed child's error message, so the orchestrator can read why it failed), reporting totalChars and hasMore and clamping maxChars to 20000 per call so one read can never flood the orchestrator context. read_child_artifact pages a settled child's artifact content by id: inline data, an offloaded transcript blob decoded as UTF-8, or a patch's changed-file list.
Both are pure reads of already-durable journal state, so a resume reproduces them with no new spend. The option is off by default: adding the tools changes the orchestrator toolset hash by design (exactly like the extension's plan tools), so a run that does not opt in keeps the default toolset, and every frozen cassette, unchanged.
1.41.0
Minor Changes
be589ec: Add the orchestrate acceptance policy and the CLI --strict flag (the v1.40.0 improvement plan's completion contract)
Run status ok proves that finish validated, and nothing more: the model may call finish after any mix of child outcomes, so ok alone never proves the children succeeded. The new opt in OrchestrateOptions.acceptance turns that into a checked contract. childPolicy 'all-ok' requires every spawned child to have settled ok when finish validates (a child still running counts against it); { minSuccessful: N } tolerates failures beyond the first N successes. The verdict is journaled as one decision entry, so a resume rolls the same verdict forward, immune to drift of the live options. An accepted result becomes the acceptance envelope { result, completion, childStatusCounts, degradedReasons }; a violated policy fails the run with the typed FailRunError (code fail_run, data.source 'orchestrator_acceptance') instead of settling ok. Without acceptance nothing changes: the result value stays the raw finish payload and no new journal entry is written.
The CLI pairs with the envelope: rulvar run --strict and rulvar resume --strict exit nonzero when a settled ok value reports completion 'partial', printing the degraded reasons (strictExitCode is exported for hosts). The guides also now state the adjacent contracts plainly: await_any and await_all return truncated TaskDigests rather than full child reports, cost totals are price registry estimates with usageApprox marking estimated usage, the fencing epoch covers journal appends while RunMeta and transcript blobs stay advisory projections, and data protection at rest is owned by the host.
1.40.0
Minor Changes
cf33550: Fence the offline resolution append and surface approximate usage (v1.39.0 review)
The CLI server's offline resolution path acquired a store lease but never threaded it into the Replayer, so the resolution append ran unfenced: if the process stalled past its lease ttl and a queue worker took the run over, the stale append could land alongside the new owner's writes. The append now carries the acquired lease, so a superseded owner is rejected with LeaseHeldError (HTTP 409) instead of racing the current owner.
Approximate usage is now visible where the run is reported. usageApprox rides the agent:end and run:end events and the CostReport, and the CLI cost line marks an estimated total, so a total that includes usage estimated after a transport cut, a ceiling that severed a stream, or an abort is never shown as though it were the exact provider charge. The field is present only when true, so every exact usage report and event is byte for byte unchanged.
1.39.0
1.38.0
1.37.0
Minor Changes
- e6b1481: Validate the persisted
KnowledgeSnapshoton everyFileModelKnowledgeStoreread (v1.36.0 review P2-6). The old read checked only thatversionwas a number,hasha string, andclaimsan array, so a hand edited or tornrulvar.models.jsoncould forge a negative or fractionalversionand a mismatchedhash, and anullor partial claim flowed on to crash the card render with an untypedTypeError. The read now requires a nonnegative integerversion, a lowercase sha256hashthat MATCHESknowledgeHash(claims), and structurally sound claims (a persisted snapshot may hold non active statuses), refusing any inconsistency as a typedConfigErrorthat names the offending path.commitreads first, so it refuses to append onto a corrupt base. - e6b1481: Contain
FileTranscriptStorerefs under their configured root (v1.36.0 review SEC-P1). The per-segment check accepted.and..(dots are in its alphabet), sojoinlet a..segment escape: a caller passing an untrusted ref toput,get,list, ordelete, or an untrustedrunId(which prefixes the checkpoint and workflow source refs), could read, write, or delete.binfiles outside the directory. Every segment now must be a nonempty safe token that is neither.nor.., and the resolved path must stay under the resolved root. The engine also refuses an unsaferunIdwith a typedConfigErrorbefore its first store write, so a compiled run cannot persist its source outside the transcript root.
1.36.0
Minor Changes
- 101795b: Fix the v1.35.0 review P1 and the core P2 groups. The parked flavor B decision wait is abort aware:
handle.cancel(), aRunOptions.signalabort, the rundeadlineAt, and fail fast sibling aborts settle the run in bounded time instead of waiting out the escalation deadline; the suspension entry stays open so resume re parks it, worktree salvage still precedes destruction, and the wait rejects with the newEscalationDecisionAbortedError.budget.atCap: 'fail-run'is executable: the journaled cap decision drives the branch, the reserved finalizer is skipped, and the run fails with the newFailRunError(registry codefail_run), rolled forward deterministically on resume.OrchestrateOptionsvalidate at construction (maxSpawns,renderBudgetChars,budget.capUsd,budget.capFraction,budget.finalizeReserveUsd,budget.finalizeTurns, and theatCapliteral), and the digest render budget is a hard upper bound of the rendered row, marker included, at both distillation tiers. The extension seam gains an optionalterminatecapability so a journaled policy verdict can close the run typed. Knowledge and isolation intake validate too:FileModelKnowledgeStore.activeClaimsCap,GitWorktreeProvider.maxPinnedWorktrees, andmodelKnowledgeCardbudgetChars(now a hard bound of the whole card). The sweep also validatedescalation.minSpendUsd(a NaN silently disabled the minimum spend gate) and gaveLeasableStorethe optional readonlyleaseTtlMscapability.
1.35.0
Minor Changes
- d4ac3bf: Validate every numeric engine option at its intake and survive far future deadlines (v1.34.0 review P2-1, P2-2, P2-3, P2-4).
createEnginenow refuses malformedconcurrency.perRunandconcurrency.perProvidercaps,budgetDefaultsfields, engine and profilelimits, profileestCost, escalationdeadlineMs, and compaction thresholds with a typedConfigError;engine.runvalidatesbudgetUsdandlimitssynchronously and requiresdeadlineAtto be an ISO 8601 date-time with an explicit UTC designator or offset (an impossible calendar day is refused rather than silently rolled into the next month, and a malformed string no longer cancels the run after the first provider dispatch).ctx.agentvalidatesestCostandlimitsper call, so a negative reserve can no longer shrink the committed total and admit a sibling past its ceiling, and the admission gate refuses a non finite reserve as a backstop. The per run semaphore requires a positive integer limit (a NaN cap used to park the first request forever withcancel()unable to settle the run) and queue waits are abort aware, so a cancelled run always drains its queued calls in FIFO order. Absolute deadlines (RunOptions.deadlineAtand the journaled escalation deadline) are honored through sliced timers beyond the Node timer maximum instead of firing immediately, whilestreamIdleTimeoutMsis bounded by that maximum like retry policy delays.validateUsageLimitsis exported for hosts that want the same check at their own boundary.
1.34.0
Minor Changes
- f1505ec:
mcp()now returns aMcpToolSource: the frozenToolSourceseam plus an idempotentclose()that releases everything the source created on first use, the SDK client, its transport, and, for stdio, the spawned child process. Without it a one shot host that ran a workflow over a stdio MCP server could never exit naturally, because the child and its pipes kept the event loop alive (v1.33.0 review P2).close()resolves even when the connection never succeeded, and it resets the source, so a latertools()call connects afresh; a failed connect now also releases its transport and child on the way out instead of leaking them behind the error it rethrows. The engine still never closes a source, because one source may serve many runs: the host owns the lifecycle, and the MCP guide documents thetry/finallypattern for one shot scripts. Real stdio and streamable http integration tests now cover both external transports, including child process release, reconnect after close, and cleanup after a failed connect.
1.33.0
1.32.0
1.31.0
1.30.0
Minor Changes
- 87ce985: Validate every RetryPolicy before anything runs under it (v1.29.0 review P2). Published 1.29.0 accepted
attempts: 0, fractional and NaN attempts, negative backoff numbers, and a NaN factor, then dispatched the adapter under them: the invalid values silently reshaped retry semantics (zero or NaN attempts behaved as no retries; a negative initialMs or NaN factor collapsed the delay to zero, removing backoff entirely). The new exportedvalidateRetryPolicyenforces the documented contract, a positive safe integerattempts(the engine always makes the first try, so zero attempts has no meaning), timer safe integerinitialMsandmaxMs(maxMsbelowinitialMsstays legal as aMath.minceiling), a finite positivefactor(below 1 is a legal decaying backoff), a booleanjitter, and unique knownretryOnclasses, and throws a typedConfigErrornaming the offending field and its config source.createEnginevalidatesdefaults.retryand every profile retry at construction; the per call merge inctx.agentvalidates the winning policy before identity, admission, or any journal append, so an invalid policy can never reach a provider or record a partial agent execution.
1.29.0
Minor Changes
621d566: Make the retry and failover backoff interruptible and validate every provider supplied retry delay (v1.28.0 review P1 and P2).
The retry engine now races its backoff wait against the host cancel signal (which the run deadline also drives) and the budget ceiling signal: an abort wakes the wait immediately, settles through the canonical aborted outcome (
cancelledorexhausted, with every already recorded usage kept), and forbids every further dispatch, including the one behind a keyed limiter queue, so an adapter that ignores its signal can no longer be re entered after an abort. Previously a provider suppliedretryAfterMsarmed an uninterruptible sleep: a cancel, a crossed deadline, and a crossed budget ceiling all waited out the full backoff and the adapter was dispatched again. The injectedretry.sleep(ms)test hook keeps its signature; a hook that loses the race is abandoned without an unhandled rejection, and the native timer path clears its timer so an abandoned long backoff never pins the event loop.retryDelayMsis now the defensive boundary the docs promise: only a finite nonnegative providerretryAfterMsreplaces the computed delay, anything else (NaN, Infinity, a negative) is ignored as adapter noise, and every returned delay is a finite nonnegative integer clamped to the Node timer maximum, so a malformed or huge value can never arm an instant or overflowing timer. Both first party adapters stop emitting unvalidatedRetry-Afterparses: an unparsable header (the HTTP date form included) omitsretryAfterMsentirely instead of producing NaN (which also broke theWireError.dataJson invariant by serializing to null), and a huge but finite value is clamped. ThemapAnthropicStreamTSDoc now states precisely how a truncated stream is reported (thefinishedflag on the return value, with the adapter synthesizing the terminal error).Four frozen fixture cassettes are refrozen for this release (the hashVersion-bump refreeze ceremony applies; hashVersion itself is unchanged and existing journals replay identically): in three cap freeze scenarios the main orchestrator entry now honestly settles cancelled at the cap instead of paying one more ordinary turn whose result the forced finish machinery discarded anyway, and one scenario loses a post abort wait suspension that can no longer be dispatched. Entry identities, keys, and every other row are byte identical.
1.28.0
Minor Changes
- d98eb0b: Enforce the terminal stream contract end to end (v1.27.0 deep E2E review P1 and P2). The runtime now fails closed when an adapter stream drains without a terminal
finishorerrorevent: the partial turn becomes a retryable transport fault that feeds the ordinary retry and failover machinery instead of settling asokwith truncated text, and a requested abort (cancel, budget ceiling, idle severance) remains a clean end with no fabricated provider error. Consumption stops at the first terminal event, so events afterfinishcan no longer mutate the value, revise the authoritative bill, or trigger tool execution. The first party adapters enforce the same contract at the wire: the Chat Completions mapper no longer synthesizesfinish: stopwhen the stream is cut before afinish_reason(usage the provider did report is still forwarded, half assembled tool calls are dropped), the Responses mapper fails closed on EOF without a response terminal event, and the Anthropic adapter surfaces a read cut beforemessage_stopas a retryable transport error and no longer converts a caller requested abort duringmessages.create()into a terminal error.mapResponsesStreamandmapChatCompletionsStreamaccept an optionalsignalso a requested abort keeps ending the stream without a terminal event. The VCRrecordwrapper now commits its cassette row even when the consumer stops reading at the terminal event (the engine always does now); adapter middleware must not rely on being drained past the terminal. The committedcombined-loop-descentcatalog cassette is refrozen because stopping consumption at the terminal shifts the deterministic interleaving of two parallel plan children by one scheduler turn; entry content, keys, and the actualhashVersionare unchanged, journals recorded under earlier versions replay unchanged, and this changeset carries the frozen fixture gate's hashVersion-bump ceremony token only to unlock that refreeze.
1.27.0
Minor Changes
- 884a433: Types referenced by public signatures are now exported from their package barrels, so the API docs resolve them instead of carrying known incomplete references (v1.26.0 deep E2E review):
BaseAppendfrom@rulvar/core(the fields common to everyReplayerappend),BlockandMappedStopfrom@rulvar/anthropic(the wire level content block alias and the stop reason mapping), andVcrHeaderfrom@rulvar/testing(the first line of every cassette file). The frozen TypeDoc baseline shrinks from eleven entries to the four vendored Standard Schema notices.
1.26.0
Minor Changes
- a4fc757: Scale fixes from the v1.25.0 review.
RunHandle.eventskeeps its gapless contract (buffered from handle creation) but drains linearly: the iterator queue uses a head index with in place compaction instead ofArray.shift(), so a late read of a 100k event backlog takes milliseconds instead of seconds, and delivered events are released eagerly.engine.pruneRunnow collects exact whole string references in one recursive pass over the journal (values and object keys) instead of a per terminal substring scan: a checkpoint ref that is a prefix of another (ckpt/2insideckpt/20) no longer survives pruning, matching what the stores and durability guides always promised, and the scan is linear in journal size instead of quadratic in entries. New optional store capabilityMetaLookupStore.getMeta(runId)with thehasMetaLookupguard and thereadRunMetahelper:engine.resumeand every shell point lookup use it when present and fall back to the historicallistRunsscan otherwise; all three shipped stores implement it and the serialization wrapper preserves it.RunFiltergains an advisorystatusesarray (match any, combining withstatusas either matches; the shared predicate ships asmetaMatchesFilter).RunMetagainsgenesis, a generation token minted at the fresh start and preserved verbatim across resume segments, so adeleteRunand recreate of the same explicit runId is distinguishable from the original run.
1.25.0
1.24.1
Patch Changes
- 0bb14db: Correct the
RunMeta.argsHashdocumentation (v1.24.0 review P2-2). The digest is a deterministic, unsalted SHA-256 over the JCS form of a run's genesis args, so it reveals when two runs shared identical args and low-entropy args (a boolean, an approval flag, a role, a short id) are recoverable by hashing candidate values. The TSDoc onRunMeta.argsHashandhashRunArgsno longer claims that nothing sensitive lands in meta; it now states the digest is sensitive-derived metadata that confers no confidentiality and must be access-controlled like the journal and transcripts. The raw args are still never journaled, and no runtime behavior changes.
1.24.0
Minor Changes
- 2b033e8: Record the genesis args binding in RunMeta and make the dry-run preview mutation-free (the v1.23.0 review).
RunMetagainsargsProvided(whether the run started with defined args) andargsHash(sha256 over the JCS canonical serialization of the genesis args, never the raw value), written by the engine at genesis and preserved verbatim by every resume segment, so hosts can refuse a resume whose re-supplied args silently diverge from the original invocation; the new publichashRunArgs()derives the same hash host-side. Legacy metas never gain the marker retroactively, and unserializable args record presence without a hash. AdryRunresume now performs ZERO store mutations by invariant:putMetais skipped entirely (no status flip, nosegmentsbump), the compiled-source blob is not re-put, and the Replayer's single append site refuses any journal append under replay-strict with a typedJournalMissError. The store conformance kit checks the round-trip of both new fields.
1.23.0
Minor Changes
1f9c272: Resume correctness and telemetry integrity, the v1.22.0 review's two P1 findings plus the event-layer P2s.
- Resume ordinal continuation (P1-1). Since M2, the ordinal map key minted for new operations and the key used to seed that map from prior entries on resume were built by two hand-written composites whose separators differed, and the minting one contained an INVISIBLE literal NUL byte in the source, so the seeding filled a bucket
mint()never read. Every identical-identity live operation after any resume re-minted ordinal 0, duplicating the journal identity triple(scope, key, ordinal)and corrupting sibling binding on the next replay. Both sites now go through oneordinalMapKeyhelper (escapedU+0000separators, no printable-separator aliasing), the seeding computes an order-independent max, and the regression suite covers identical siblings across suspend, process recreation, and replay-strict re-resume. NoCURRENT_HASH_VERSIONchange: ordinal bookkeeping never entered content-key derivation, and journals written by broken versions still load (their ordinals seed the map exactly as recorded). - Event
seqandspanIddurability across segments (P1-2). Every resume segment restarted the telemetry counters at 0, so onerunIdrepeatedseq: 0andspanId: 's0'per segment, against the documented per-run contracts, and the CLI SSELast-Event-IDcursor became ambiguous.RunMetagains an optionalsegmentscount, bumped durably at every segment start strictly BEFORE the segment's first emission (crash-safe: a killed segment still advanced it), and each segment seedsEventBusandSpanRegistryatsegments * EVENT_SEGMENT_STRIDE(exported, informational).seqstays a plain number, strictly increasing across the whole run and NOT contiguous across segments; span ids never repeat. Stores must round-trip the new field (the conformance kit now checks); a store that drops it degrades telemetry counters to per-segment, never the journal. - Listener-failure ordering and masking (P2-1). The v1.22.0 subscriber-isolation warn was delivered mid-fan-out (observers saw it BEFORE the event that caused it, with descending seq) and was built outside the masking boundary (a key-shaped fragment of the listener's error reached observers raw). The warn now goes through the ordinary
emit()after the triggering event's fan-out completes: masked like every event, seq stamped at delivery,[event, warn]order on every surface, still at most once per bus and recursion-proof. - Spawn admission events on every boundary (P2-5).
spawn:admittedonly ever fired from the dynamic orchestrator's spawn tools;ctx.agentlineage admissions andctx.workflowchild admissions emitted nothing (ctx.workflownot evenspawn:rejected). All admission boundaries now emit both events through one helper; journal-recovered decisions re-announce withreplayed: truewhen they take effect, and a cleanly replayed dispatch does not re-announce.spawn:admitted.spawnUnitsAfteris now optional: absent on lineage-layer admissions, whose spawn-unit debit rides the dispatch itself. - The replayed flag actually reaches observers. The engine's internal event sink dropped the third argument of
emit, so everyreplayed: truemarker (replayed agent and tool lifecycle events, recovered suspensions, recovered rejections) was silently stripped since M2 and rendered as live. The sink now forwards it; the documented replay re-emission table is true again. SANDBOX_AGENT_OPT_KEYSexported. The sanctioned sandbox agent-option allowlist is a documented public constant, the single source for the runtime validator and the planner API card.
- Resume ordinal continuation (P1-1). Since M2, the ordinal map key minted for new operations and the key used to seed that map from prior entries on resume were built by two hand-written composites whose separators differed, and the minting one contained an INVISIBLE literal NUL byte in the source, so the seeding filled a bucket
1.22.0
Minor Changes
77b554f: Add
sanitizeTerminalText, the rendering-boundary counterpart tomaskSecrets: it neutralizes terminal control sequences and control characters in one untrusted string so a provider error message, tool name, model id, or log line can never inject a control sequence or a second physical line into a rendered terminal line (v1.21.0 review P2-1). After sanitization the result carries no C0 control, noDEL, no C1 byte (including every 8-bit escape-sequence introducer), and no ESC-initiated CSI/OSC/DCS sequence; control runs collapse to a single space and visible text is preserved. The bundled renderers use it internally, and it is exported for host terminal sinks.Also isolate event-bus subscribers: a throwing
on()listener (a renderer, a metrics hook) is best-effort telemetry and can no longer propagate out ofemitto disrupt a paid run; the failure surfaces once as a warn log on the same bus instead (v1.21.0 review follow-up).
1.21.0
Minor Changes
- 7ee42a0: Enforce the financial-telemetry invariant at the adapter boundary for every adapter, injected clients and mocks included (v1.20.0 review P1-1). Every canonical token count must be a finite nonnegative integer with the cache subsets inside the full input; a violation fails the call loud as a typed transport-class terminal while accounting sees only conservatively sanitized values (garbage floors to zero, fractions round up, so a repaired charge is never an undercharge and never a credit). Both inlets are guarded: finish usage and mid-stream usage deltas, which previously reached the budget with no clamp at all. New exports
usageViolations,sanitizeUsage,sanitizeUsageDelta,snapshotUsage, andsanitizeTokenCountcarry the shared rules; the accounting boundaries snapshot adapter-owned usage objects before validating them, mid-stream deltas are repaired per field without the whole-usage subset rule (partial increments legitimately carry cache counts alone), counts are bounded to the safe integer range, mid-stream reports the finish total does not confirm fail the call loud with over-reported cache reads re-debited conservatively at the input rate, a duplicate finish or a post-finish usage event is refused, checkpoint restores sanitize the persisted counts exactly like the resume seed, and every cost fold treats a NaN or negative priced amount as unpriced instead of poisoning the totals. RunBudget grows defense in depth behind the validator: hostile priced amounts clamp to zero with a one-time error event,spentUsdstays finite and monotone under fuzzed hostile usage, and NaN or negative ceilings and resume seeds reject up front asConfigErrorinstead of silently disarming every comparison. Journal entries also gain the optional policy fieldusageSemantics(adapter-declared, never identity), and resuming a journal whose unstamped OpenAI entries carry cache writes emits a one-timeRULVAR_LEGACY_CACHE_SEMANTICSwarning pointing at the audit procedure (v1.20.0 review P1/P2-2).
1.20.0
Minor Changes
- 9367030:
CostReport.byRolenow attributes every paid invocation phase to its own bucket. Usage accumulates by (invocation role, serving model):UsageSlicegains an optionalrole, terminal entries and turn-boundary checkpoints persist the roled slices, and both the live buckets and the pure journal fold bumpbyRoleper priced slice, so a routed finalize, a separate extract, or a mid-loop compaction summarize lands underfinalize/extract/summarizeeven when one model serves several phases of one agent (previously the whole entry folded under its single primary role and those documented buckets could never be nonzero). Backward compatible end to end: slices without a role and entries without slices fold under the entry's primarycostAttribution.roleexactly as before, pre-split checkpoints restore under the primary pair, a single-phase single-model call still writes no slices (those journals stay byte-identical), and role buckets and model buckets both sum to the same total on live runs, same-engine replay, and fresh-engine replay.
1.19.0
Minor Changes
- 8cc9a9c: The finalize synthesis invocation now appends a deterministic synthesis instruction (
FINALIZE_SYNTHESIS_INSTRUCTION, exported) to its request, and a non-truncated empty synthesis falls back to the loop turn's text instead of erasing it. Previously the routed finalize call sent the projected transcript ending at the assistant message with no instruction at all; a real model reads that as a fresh conversation opening, and its greeting unconditionally replaced the loop's correct answer as the schema-free output (reproduced live: a tool loop that had already answered42returnedHow can I help?). The instruction is request-only: the durable transcript keeps the raw history, so journal identity, extract input, and replay are untouched, and no recorded fixture moves. The truncated-empty synthesis case stays a boundedoutput-truncatedfailure. An opt-in live smoke (RULVAR_LIVE_TESTS=1plusOPENAI_API_KEY) pins the contract on a real provider. - 8cc9a9c:
orchestrate(engine, goal, opts?, runOptions?)andorchestratePlanned(engine, goal, opts?, runOptions?)accept the created run'sRunOptionsas an optional fourth argument, threaded verbatim toengine.run.runOptions.budgetUsdis the ROOT hard ceiling over the whole tree (the orchestrator and every child), immutable after start and frozen intoRunMeta, whileopts.budgetonly shapes the orchestrator's own sub-account inside that ceiling; the two layers were previously conflatable, and the canonical shortcuts could not set a root ceiling (or signal, runId, limits, deadline) at all without dropping toengine.run(makeOrchestratorWorkflow(goal, opts), undefined, runOptions). Purely additive; existing calls are unchanged, and a call withoutrunOptionsstill starts an UNCAPPED run, which the docs now state explicitly.
Patch Changes
- 8cc9a9c: Internal real-time reads bind the wall clock at module load, never the live global, eliminating false
RULVAR_BARE_DATE_NOWwarnings for consumers whose rulvar frames live outsidenode_modules(workspace dists, monorepo checkouts). Two composing defects:createEnginecapturedDate.nowper call, so an engine created after a previous run had installed the dev-mode patch bound the PATCHED wrapper as its real clock (itsEventBusthen warned from the engine's own frames), and the ULID factory read the live global at every mint, so ids minted mid-run (the orchestrator extension IO, PlanRunner revisions, adapter id maps) routed through the patch too. The engine now uses a module-loadrealNowbinding (module load always precedes the first patch install), the vendored ULID factory defaults to its own module-load clock, and@rulvar/store-sqlitefollows the same convention. The dev-mode guard itself is untouched and stays exactly as sharp for workflow code, which keeps reading the live global.
1.18.0
Minor Changes
- 943962d: Registered toolset names now resolve everywhere a tools option is taken. A string entry of
AgentOpts.tools, a profile'stools, or the sandbox dialect'stoolsnames a toolset registered undercreateEngine({ defaults: { toolsets } }), expanded through the same canonicalresolveToolsetpath as ToolDef and ToolSource values: unknown names are a typedConfigErrorat spawn time before any provider call, duplicates and collisions are validated after the union, the resolved contracts land intoolsetHashand the journal identity exactly like directly passed definitions, and registry values may not nest other names, so no cycle can exist. This closes the v1.17.0 review P1-3: the planner API card and the docs taughttools: ["name"], the sandbox bridge required strings, and the core rejected every string, so the documented construct could never run.profileCardnow renders the registered toolset names as a closing line when the registry is non-empty (byte-identical output for engines without toolsets), so a planner can only name declared registries. Migration: strings previously always threw (tools by registered name ... are not supported here); they now resolve or fail withunknown registered toolset '<name>'. No behavior changes for ToolDef and ToolSource entries.
1.17.0
1.16.2
1.16.1
1.16.0
1.15.0
1.14.0
1.13.0
1.12.0
Patch Changes
- 46edcc0: An exhausted run settle no longer drops the typed failure when the throw was an
AgentCallError: the exhausted branch now projects it throughagentResultWireexactly like the error branch, sooutcome.errorkeeps the agent's typed budget failure (and any engine-decided abort class) in the parallel-exhaustion race where one branch's agent fails while the run budget is already exhausted. The common paths were already typed: a directBudgetExhaustedErrorcarried its wire before, and the in-loop turn-guard denial surfaces asbudget_exhaustedwith zero over-ceiling calls, now pinned by an engine-level regression test.
1.11.0
Minor Changes
- 0c70c5e: Close the execution segment at settle: exactly one segment owns a run (v1.10 deep E2E review, P1). Previously,
resolveExternalon a handle whoseresulthad already settled'suspended'silently woke the parked body through the live registry, and the documented resolve-then-resume sequence then started a second segment over the same journal: the approved tool executed twice, the post-approval turn was paid twice, and both segments minted the same journal seq (two terminal agent entries with duplicate seqs). Now every settle closes the registry: parked branches never run again, a post-settleresolveExternalvalidates like the live path and appends the durable resolution through the journal fold WITHOUT waking anything, and the one continuation belongs to the nextengine.resume. The pre-settle live path (resolving from anapproval:pendinglistener) is unchanged. Repeated resolution is now the documented no-op instead of a throw: once the target suspension is closed,resolveExternalreturns{ applied: false, reason: 'already_resolved' }(journaled through the first-closing-wins arbiter) rather thanInvalidResolutionError; an unknown key still throws, and an invalid payload still throws without journaling. Segment ownership is also enforced at the front door: a second concurrentengine.runorengine.resumeof a runId that already has a live segment in the same engine throws a typedConfigErrorbefore any side effect. Defense in depth at the store boundary:InMemoryStoreandJsonlFileStorenow enforce the monotonic-seq obligation, rejecting an append whoseseqis not strictly greater than the stored tail with the typedJournalOrderViolation, so two stale-tail writers can never both persist. New public API:ExternalRegistry.close(),ExternalRegistry.closed, andExternalRegistry.suspensionKeyOf(entry). Docs:guide/durability#resolving-a-settled-runstates the ownership rule and both safe orders; tools, testing, troubleshooting, CLI, stores, and store-authors pages align with it, and the documented sequences are now executable regression fixtures.
1.10.0
Minor Changes
- 0e8d78e: Settle empty max-tokens turns as a typed output truncation, never an empty success. A schema-less turn (no schema, no required terminal tool) whose completion ends with finish reason
max-tokensand no visible text now settleslimitwith the newabortClass: 'output-truncated', a terminal-kind error, and an actionable message, instead ofokwith''. The same check covers a routed finalize invocation, whose synthesis is the schema-less answer; a max-tokens turn with visible text keeps settlingokwith the partial text. Like the no-progress abort, the truncation stampsmemoizeOutcomeon the terminal entry, so every resume replays the typed outcome with zero provider calls. The abort class now rides every projection of the failure: the journaled terminal error payload, the run-leveloutcome.error.data, dropped items, and thrownAgentCallErrorwires, so consumers such as the planner see the typed truncation instead of burning self-repair rounds oncompile/empty-sourceunder an unchanged output limit.AbortClasswidens to'no-progress' | 'output-truncated', and the projection helper is exported asagentResultWire(result, fallbackMessage)alongsideagentErrorToWire.
1.9.0
Minor Changes
3a53383: Report pricingVersion drift on resume.
The
orchestrator_budget_reservedecision already pins thepricingVersionin effect when a run started, but the resume recovery only compared the frozen cap dollars. A resumed run now also compares the journaled version against the live table (unpricedwhen priced from the adapter caps fallback) and emitstermination:config-driftwith fieldpricingVersionwhen they differ. The divergence is reported, never honored or refused: price interpretation is live by design (the journal stores usage; dollars are re-derived from the current table against the frozen cap dollars), replay stays byte-identical, and no provider work is repeated. Reserve decisions journaled before the field shipped resume quietly.
1.8.0
Minor Changes
57ea1de:
ResumeReport.orphanednow follows entry-type pairing rules and lists only effect roots that genuinely need recovery: dangling dispatches (arunningentry with no terminal) and suspensions with no resolution, neither consumed by a live call nor covered by abandon. Terminal decisions,termination.*andplan.*entries, settled roots (whatever their terminal status), and resolved suspensions are complete by construction and never appear, so a fully successful replay reportsorphaned: []. Previously the list contained every journaled operation not consumed through forward matching, which flagged spawn-admission decisions, plan revisions, settled agent roots, and resolved wake suspensions on perfectly healthy replays (the v1.7.0 follow-up review's finding).Deleted settled calls are still silently skipped and never re-paid; they are just no longer listed. A deleted call whose dispatch was left dangling still reports, which is the case that actually needs attention.
7884ec5: PlanRunner plan admission is now atomic with child dispatch admission (the v1.7.0 follow-up review's P1). Previously a
plan_reviseop could be journaled asadmit(consuming its spawn unit) and only then havescheduleReady's dispatch rejected by the engine budget, stranding the node ready forever, losing theplan:revisedevent, and burning the orchestrator budget with no worker output.- An
add_taskop whose resolved profileestCostcannot fit the effective child ceiling (rung-resolvedmaxCostUsd, elsebudgetUsd) is bounced at rebase time with the new typed reasonreserve_exceeds_budgetnaming the child account, requested and resolved reserve, ceiling, and minimum correction. No plan state changes and no spawn unit is consumed; theplan_revisetool result carries the reason verbatim. - The read-only admission branch now projects the SAME reserve the dispatch layer will commit (estimate clamped by the explicit child budget only), plus the pending reserves of earlier ops in the same revision, so every embedded admit of one batch is dispatchable under the snapshot it was decided on. The dynamic
spawn_agentpath passes the profile estimate into admission for the same reason. - Layer 1 (ctx.agent) clamps its committed reserve to the tightest
child-allowanceaccount headroom on the chain (a plan node's own sub-account, actx.workflowchild ceiling): an allowance already bounds the child's lifetime spend, so an estimate above it clamps instead of denying, which is what makes "admit implies dispatchable" hold by construction. The run root and orchestrator cap are never clamped against; their headroom is shared money that projected admission keeps protecting. plan:revisedandtermination:debitnow emit strictly after the durable revision append and before the scheduling effects, so a scheduling fault cannot erase an applied revision from the event stream.- The residual class (facts that genuinely changed between admit and dispatch, e.g. the engine lifetime spawn cap) lands the node terminally
failedthrough a journaledplan.decisionwith the new origin/causedispatch-rejected; other ready nodes still dispatch and the run proceeds.
Acceptance tests cover the review's live shape (profile
estCost0.015 againstbudgetUsd0.01), the positive control, resume idempotence, the containment path, and an admit-implies-dispatchable property grid over estimates, budgets, ceilings, flat reserves, and prior commitments.- An
52db30d:
termination.initnow freezes the ACTUAL orchestrator budget dollars instead of zeros, closing the journal-contract gap the v1.7.0 follow-up review found: the budgets guide documentsorchestratorCapUsdandfinalizeReserveUsdas frozen in the same limits vector as the counters, but PlanRunner journals stored0for both and only the laterorchestrator_budget_reservedecision carried the real values.- The engine resolves the effective cap and finalize reserve strictly before extension boot and exposes them on
OrchestratorExtensionIO(orchestratorCapUsd,finalizeReserveUsd); PlanRunner writes them intotermination.init. - On resume the cap dollars are now recovered from the frozen
orchestrator_budget_reservedecision instead of being re-derived from live options (DEF-2 config-drift-resume: the journal wins). A diverging livecapUsd/capFraction/finalizeReserveUsdemitstermination:config-driftand is never honored. - Journals recorded before this release (zeros in
termination.init) replay unchanged: the fold reads the init entry by kind, and the reserve decision remains their authority. - The reserve-decision presence guard is now scoped to the orchestrate call, so nested capped orchestrations each journal their own freeze.
The frozen cassette catalog is re-recorded (the init limits vector and its content key change); hashVersion stays 2, and the fixture lock refresh carries the required hashVersion-bump token.
- The engine resolves the effective cap and finalize reserve strictly before extension boot and exposes them on
Patch Changes
- 25724b5: The no-progress abort message now links the public docs (https://docs.rulvar.com/guide/agents#the-agent-loop-and-turns) instead of the retired internal spec reference "docs/06 Appendix A". Runtime-visible errors reference public documentation only. The stall-streak cassette embedding the message was re-recorded byte-for-byte otherwise; hashVersion stays 2, but the fixture lock refresh requires the hashVersion-bump token.
1.7.0
Minor Changes
- 45285aa: Budget exhaustion errors now name the ceiling that actually ended the work.
BudgetExhaustedErrorfrom agent execution reports the first closed account walking up from the debited scope (its scope, ceiling, spend, and reserves) plus the run root state, classified asroot,orchestrator-cap, orchild-account, both in the message and in typeddata; a crossed orchestrator cap no longer masquerades asrun budget ceiling reached.RunBudgetgains theexhaustionDiagnostics(scope)projection behind this, and the orchestrator emits a warn log when an explicitbudget.capUsdis silently bounded by the defaultcapFraction0.2 of the run ceiling (passcapFraction: 1.0to makecapUsdthe sole bound; the docs now spell out the min formula trap). - 2f20d1d:
CostReportis now replay stable and internally consistent: the engine builds every settled outcome's report from one pure journal fold (costReportFromJournal), so a replay only resume reproduces the complete report byte for byte, including the orchestrator block (spentUsd,share,wakes,forcedFinish,reserveUsedUsd), which previously read this process's live budget accounts and collapsed to zero on replay. Terminal entries now carry additivecostAttributionfacts (phase, agent type, primary role, debited budget account, finalize reserve flag); they are policy, never identity, exactly likeusageByModel, and entries written before the field shipped fold under documented fallback buckets. One inclusion policy applies to the total and every breakdown alike: non abandoned terminal usage exactly once, sobyModel,byPhase,byAgentType, andbyRoleeach sum tototalUsdeven after resumes that re paid attempts.orchestrator.wakesnow counts armed (journaled) wake suspensions. The frozen cassette catalog was re recorded for the new journal byte form; identity derivation is untouched and old journals replay unchanged (the hashVersion stays 2; the token hashVersion-bump here sanctions the fixture lock refresh ceremony, not a version change).
Patch Changes
- 22f65a8: The development mode bare nondeterminism detector no longer warns when Node's own machinery consults
Date.noworMath.randominside a run's async context. Frames withnode:specifiers (the undici transport behind globalfetch, timers, stream internals) are now classified as library provenance alongsidenode_modules, eliminating the falseRULVAR_BARE_DATE_NOWobserved atprocessResponseEndOfBodyduring in runfetchcalls. Direct calls from workflow files still warn exactly once per run. - 2ddfa29: Documentation: the mode (c) resume contract is now stated as it actually works.
orchestrate()builds its workflow internally and never registers it, so bareengine.resume(runId)cannot resolve it; the orchestration modes guide and the resume table now document the two working forms,engine.resume(runId, makeOrchestratorWorkflow(goal, opts))with the original inputs or a one time registration underdefaults.workflowswithORCHESTRATE_WORKFLOW_NAME, with an executable test covering both, and the troubleshooting guide gains the symptom first entry for therulvar-orchestratenot registered error. - 2abd9c2: A resumed dynamic orchestration now honors the documented mode (c) contract after a budget cancelled root. Recovery is orchestration scoped instead of attempt scoped: journaled spawn decisions recover across root attempts (they live at the orchestrate call's own stable scope), recovered children re dispatch pinned to their journaled child scope so settled ones replay by content key for free and only dangling ones rerun, prior attempt handles alias to the recovered records so a restored transcript's await and cancel calls keep working, and the rerun root boots from the cancelled attempt's last turn boundary checkpoint instead of re planning from scratch. A regenerated turn that diverges from a lost one decides fresh (the recovered verdict binds only when the incoming spec matches the journaled one). Previously the rerun derived its recovery scope from the new dispatch seq, saw nothing, re decided every spawn, and re paid completed children.
- 1c1175d: An agent configured with a required terminal tool (the dynamic orchestrator's
finish) no longer settles ok on a turn that ends without any tool call. Such a turn, including one cut by the output token bound before any call, now consumes the no progress budget and re prompts the model toward the tool, soorchestrate()returns ok only after a validatedfinish({ result })was intercepted; a model that never complies terminates as a bounded typedlimit, never as ok with unproven output. The forced finish exhaustion path keeps synthesizing its documented partial. Ordinaryctx.agentcalls without a terminal tool are unchanged.
1.6.0
Minor Changes
df416fc: Correct and extend model pricing: GPT-5.6 entries, long-context tiers, no fabricated prices, no double-charged cache.
Pricinggains optional long-contexttiers(PricingTier): the highest threshold strictly below the full prompt re-prices the entire request, input-side rates (cache included) scaling byinputMultiplierand the output rate byoutputMultiplier. Existing linear rows are untouched.@rulvar/openaiseedsgpt-5.6-soland itsgpt-5.6alias with the official caps and pricing (1,050,000 context, 128,000 max output, $5/$0.50/$30 per MTok, $6.25 cache write, 2x input and 1.5x output above 272K input tokens). Previously the unknown-model fallback silently priced them as gpt-5.4.- Unknown model ids in both first-class adapters keep conservative transport caps but no longer receive a fabricated price row: their usage surfaces in
CostReport.unpricedand a USD ceiling warns that it cannot bound them. Provide a versionedcreateEngine({ pricing })row for hosted models the tables do not know yet. priceUsdOfno longer double-charges cache tokens: under the Usage invariantinputTokensis the full prompt, so the input rate now bills only the uncached remainder while cache reads and writes bill at their own rates (a row without cache rates bills them at the input rate). Cache-heavy runs previously over-attributed cost by the full input rate on every cached token.- Admission reserve estimation routes through the same
priceUsdOf, so estimates and settled costs share one formula, tiers included. - Model id resolution picks the longest matching table prefix, so a dated
gpt-5.5-pro-...snapshot resolves to the pro entry, never the shortergpt-5.5sibling.
a737810: Make budget admission projected and add a pre-dispatch output bound (layer 2b).
- Projected admission (layer 1). A spawn is admitted only when
spent + committedReserve + finalizeReserve + proposedReservefits the ceiling of every account in its ancestor chain, checked atomically before anything commits. An exact fill is allowed; one dollar past the ceiling is not. Previously the proposed reserve was not part of the check, so the first call under abudgetUsd: 0.001run with a0.01estimate was admitted and one full provider turn was paid (10.5x the ceiling in the live reproduction). The denial happens strictly before any provider dispatch, journal entry, spawn counter, or reserve commit. - Pre-dispatch output bound (layer 2b). Every turn's wire
maxOutputTokensis clamped tomin(model capability, limits.maxOutputTokensPerTurn, budget-derived limit), where the budget-derived limit is what the tightest remaining ceiling in the chain buys at the serving model's output price (long-context tiers included) after a heuristic prompt-cost estimate. A turn is denied outright only when the remainder cannot buy one output token at zero input (exact, no heuristic); when only the prompt estimate says the turn does not fit, it dispatches with a one-token output floor and the exact layers settle the difference.RunBudget.maxAffordableOutputTokensand the pureaffordableOutputTokenshelper are new public API;BudgetHooksgains the optional hook. - Reserves never exceed what a spawn can spend. A child with its own sub-account ceiling reserves at most that ceiling; a capped orchestrator reserves its cap minus the committed finalize carve-out (the forced finish has its own reserve); an unpriced model reserves nothing unless an explicit
estCostis given, because a USD ceiling cannot bound it anyway (the existing loud warning andCostReport.unpricedstill apply). admissionReserveUsdacceptsmaxOutputTokensPerTurnand clamps the priced worst-case output term with it, so hosts can bound reserves through limits instead of hand-written estimates.
Migration: runs whose ceilings are smaller than their spawns' reserves now fail fast at admission with
BudgetExhaustedErrorinstead of overshooting. Give calls realisticestCosthints (see the updated Quickstart), setlimits.maxOutputTokensPerTurn, or raise the ceiling.- Projected admission (layer 1). A spawn is admitted only when
9eb66b4: Scope the dev-mode bare-nondeterminism detector to the workflow's async context.
The
RULVAR_BARE_DATE_NOW/RULVAR_BARE_MATH_RANDOMdetector patchedDate.nowandMath.randomper execute inside a process-global window and restored them on exit. Anything on the event loop during that window (host code, telemetry, code entirely unrelated to the run) could trigger a false warning, and two overlapping runs could race the patch/restore pair, leaving a stale patched global installed forever that then warned outside any run. The published Quickstart reproduced a falseRULVAR_BARE_DATE_NOWthis way.The globals are now patched once per process (dev mode only, never restored) and attribution rides an
AsyncLocalStoragestore entered around the workflow body: only code inside a run's own async context can warn, at most once per run per global. Host code running concurrently with a run, engine internals awaiting the result, and other runs are structurally silent; thenode_modulesexemption for provider SDKs and installed dependencies stays as the secondary check. DirectDate.now()/Math.random()inside workflow code still warns exactly as before.
Patch Changes
da4dbad: Write the product name as Rulvar in prose: package READMEs, npm descriptions, and the documentation site now capitalize the brand. Identifiers keep their exact casing, so package names, the
rulvarbinary,rulvar.config.mjs, the.rulvarstore directory, therulvar.*OTel attributes, and every URL are unchanged. Documentation and metadata only; no runtime behaviour changes.487da86: Align every budget claim with the enforced contract.
One precise formulation now appears everywhere the budget is described (README, docs landing, quickstart, budgets guide, design principles, invariants table, and the
RunOptions.budgetUsdAPI comment): an immutable run budget with pre-dispatch reservation (projected admission, exact fill allowed), a budget-derivedmaxOutputTokensclamp on every turn, live stream cuts on crossing, and a documented provider-dependent residual overshoot of at most one clamped in-flight turn per concurrent agent. No surface claims a literal hard dollar cap without stating the bound in the same breath.
1.5.2
Patch Changes
- 54936a0: Assemble the Slack and Google credential samples in the masking policy test at runtime so public secret scanners stop flagging the source blob; the runtime strings the policy masks are unchanged.
1.5.1
Patch Changes
6c6d56f: The too-old-journal refusal no longer points at an export that does not exist.
JournalCompatibilityErrorwith subCodeHASH_VERSION_TOO_OLDinterpolated the version into a symbol name, so a v0 journal produced the hintenable deriverV0 from @rulvar/compat via extraDerivers.@rulvar/compatshipsderiverV0Synthetic; there is noderiverV0. A reader with a genuinely too-old journal was sent to an import that is not there, and a dead end is worse than no hint.The hint now names the mechanism and the package, never a symbol, so it cannot go stale when a frozen profile is named something else:
register a hashVersion 0 KeyDeriver through createEngine({ extraDerivers }); @rulvar/compat ships the frozen profilesNothing else changes: the refusal is still typed, still raised before any live call, append, or admission reserve, and
extraDeriversstill reopens the window exactly as before.
1.5.0
Minor Changes
4fba3c7: Cost attribution is now correct for agent calls that span several models, and the two adjacent holes around them are closed.
- Per-serving-model pricing. The
loop,extract,finalize, andsummarizeroles resolve independently, so onectx.agentcall routinely spans models at different prices. The whole call was priced at the loop model's rate, which billed a cheap extract as if it had been the expensive loop and made routing extraction to a small model look free of savings. Usage is now split by the model that actually served it, and every fold (the liveCostReport, the kernel ledger behindoutcome.cost.totalUsd,costReportFromJournal, and replay) prices each slice at its own rate. The split rides the terminal journal entry as the new optionalusageByModelfield and the turn checkpoint, so it survives a crash and a resume; it is written only when a call genuinely spanned models, leaving single-model journals byte-identical.usageandservedBywere never part of the content key, so identity and replay are untouched. CostReport.byModelis keyed consistently. The live path bucketed by the requested model while the journal fold bucketed by the serving one, so the same run reported two different breakdowns under transport failover. Both now key by the serving model, andAgentResultcarries the optionalusageByModelbreakdown.- An unpriced model can no longer escape a ceiling in silence. A model absent from the price table debits nothing, so a USD ceiling does not bound it. That is honest for a local model and a hole for a hosted one whose price row is merely missing: the run now emits a warning-level
logevent, once per model, naming the model and saying the ceiling does not bound it. Its usage still surfaces underCostReport.unpriced. - Routing to an unregistered adapter names the role and the adapters you do have. Every schema-bearing
ctx.agentcall resolves theextractrole up front, so a routing default that crosses providers (the recommendedextractdefault targets OpenAI) failed with a bare "no adapter registered for 'openai'". The error now readsrole 'extract': no adapter registered for 'openai' (ModelRef 'openai:gpt-5.4-mini'); registered: anthropic. Pass the adapter to createEngine, or route this role to a registered adapter through defaults.routing.
- Per-serving-model pricing. The
8655c0f:
defineWorkflowacceptsmodel,routing, andeffort, wiring the workflow-defaults layer the resolution chain always documented.The router has always taken a
workflowlayer and the model routing guide has always described a four-layer chain (call override, agent profile, workflow defaults, engine defaults), but nothing could populate layer 3:defineWorkflowtook only{ name, args, errorPolicy }, so a workflow could not carry a model policy of its own. It now can, which is what you usually want for a whole class of work ("triage is cheap; the incident report is not") instead of repeating the routing on everyctx.agentcall.tsconst triage = defineWorkflow( { name: 'triage', routing: { loop: 'anthropic:claude-haiku-4-5' } }, async (ctx, args: { issues: string[] }) => ctx.parallel(args.issues.map((i) => () => ctx.agent(`Classify: ${i}`))), );The layer rides the scope, so it follows the call tree, not the file: a child spawned through
ctx.workflowcontributes its own defaults inside its scope and they stop at its boundary. It sits under the agent profile and the call override and over the engine defaults, exactly as documented, and it applies to every invocation role the call resolves (loop, extract, finalize, summarize, and each failover fallback).Backward compatible by construction: a workflow that declares nothing contributes no layer and resolves precisely as before, so existing journals keep their content keys. A
CompiledWorkflowhas no routing surface and contributes no layer.
1.4.0
Minor Changes
c4f563d: Production readiness fixes from the July 2026 full audit.
The
budgetUsdceiling now survives resume: the engine records it inRunMeta.budgetUsdand restores it on every resume, so the replayed spend counts against the original invocation's bound andResumeOptionsstill exposes no way to raise it. Journals written before the field existed (or read through a store that drops optionalRunMetafields) resume uncapped, exactly as before; the conformance kit gains a round-trip check so custom stores cannot drop the field silently.spawn:rejectedandresolution:applied/resolution:supersededare now emitted: live admission rejections carry the rejectioncode,agentType, and the journaled decisionentryRef(absent only for pre-admission config gates), and live resolution attempts report winning or losing the first-closing-wins fold.spawn:admittednow carries the decisionentryRefand the admittingverdictarm. Theorchestrator:budgetunion member now types the two payload shapes actually emitted;journal:compatstays declared but unemitted (the scan runs before a run's event stream exists) and its TSDoc says so.toOtelimplements real parent-child span nesting whencontextApiandsetSpanare passed; without them spans stay flat but attributed.'readonly'isolation now compiles a deny rule for tools declaring riskwriteordestructiveinto the spawn's permission chain, exactly as the tools guide documents; read tools and other isolation modes are unaffected.VCR
replay()refuses a cassette recorded outside the engine's hashVersion support window ([CURRENT-1, CURRENT]) with a typedConfigErrorinstead of silently drifting; in-window cassettes replay as before.InMemoryStoreaccepts{ quiet: true }to opt out of the durability warning, and the warning text now states the precise truth: nothing survives a process exit and cross-process resume is impossible (same-process resume of a kept instance works).createTestEngineconstructs its store quietly, so the blessed offline tier no longer prints a misleading warning.The bare
Date.now()/Math.random()development warnings no longer blame workflow code for calls that originate in library internals (the engine's own retry jitter, provider SDKs): the retry jitter uses a natively capturedMath.random, and the in-process guard skips callers that live undernode_modules.rulvar run --profilenow applies the profile's per-role effort hints: entries indefaults.routingthat carry no effort are seeded fromRunProfile.effortByRole(an explicit host effort always wins; ladder entries and unrouted roles stay untouched).rulvar --helpdocuments the shippedkb inboxandkb gatesubcommands.The unscoped
rulvarpointer package ships TypeScript declarations (index.d.tswith atypesexport condition), so strict TypeScript projects can import the bare name; the install smoke gate now packs and checks the pointer alongside the umbrella.
1.3.2
Patch Changes
- ddef383: Every published package now ships a README, so its npm page states what the package is, how it installs, and where the documentation lives (npm includes README.md in the tarball regardless of the files allowlist, so no manifest changes are involved; @rulvar/compat gains its README on its own next release). Alongside, the repository-level pages are refreshed to the current project state: the root README is rewritten around the never-pay-twice pitch with a runnable quickstart condensation and the full package table, CONTRIBUTING.md lists the complete PR gate set, the examples README drops retired-spec citations for live docs.rulvar.com links and documents the dogfood journal replay, and the pointer README gets the same treatment.
1.3.1
Patch Changes
- 7d1552e: Runtime message strings no longer cite the retired internal specification set: error and warning messages, validation issues, and the CLI help text drop the dangling
docs/NN, section ...references, pointing at https://docs.rulvar.com pages where a pointer earns its place (the CLI help header, tool naming, toolset registries, bare resume). The umbrella package description sheds the naming-contingency note: the unscoped alias is published and owned. Three strings embedded in frozen recordings stay byte-identical on purpose (the no-progress abort reason and two testing-internal recorder strings), as does the byte-locked golden-fold fixture. Test-file comments lose their citations too; test titles are unchanged.
1.3.0
Minor Changes
- 7d1a287: ModelKnowledge phase 3, first slice (M12-T02, unlocked by the passed measured-value checkpoint): the kb_propose orchestrator tool and the quarantined modelObservations write path. PlanRunner registers kb_propose on explicit opt-in (PlanRunnerOptions.kbPropose, like any opt-in tool); its payload is tier-relative (the orchestrator never names a model) and the engine resolves the tier against the referenced lineage's declared ladder into the concrete KbProposal subject, validates that the tier has a journaled attempt and that evidence refs resolve to this run's decision entries, and journals the proposal as the observation_add ledger.op through the single-writer path. Quarantine is absolute: the ack is entryRef only, ledger_read withholds observation content behind a count (byte-stable for observation-free renders), worker prompts never see it, and nothing can commit during a run (the runtime handle has no write path by API shape); proposals reach the human gate only through the post-run LedgerExport. Core exports KbProposal, KbProposalTrigger and the typed model-free proposalStatement template. The kb-propose-quarantine cassette joins the frozen catalog (61 IDs).
1.2.0
Minor Changes
- 890f42c: The knowledge card gains the profile-evidence section (docs/05 section 4.3 as amended): eval-measured claims project onto the advertised spawn vocabulary, one line per concrete-model profile with a conservative weakness-over-strength fold across efforts, plus a fixed spawn-guidance line. FR-607 commits the card to feeding agentType choice at spawn, and the M12 checkpoint measured that tier-relative rows alone carry no agentType-actionable signal (criterion 2: equal quality, cost overhead, no steering). Ladder declarers and model-less profiles do not participate; the section renders only when at least one profile line exists, so every previously recorded card stays byte-identical; model names still never render.
Patch Changes
- 3bfaec0: A capped orchestrator dispatches its own agent with estCost equal to its effectiveCap, and the forced-finish agent with the finalize reserve (docs/07 section 12.2 as amended): layer 2 makes those the true admission worst cases. Without the hints the default reserve priced the model's full maxOutputTokens (about one dollar on strong tiers) and the commitment rode the whole ancestor chain for the orchestrator's lifetime, so small run ceilings sat at zero admission remainder and every child spawn died with a budget rejection. Found live by the M12 checkpoint: no orchestrated child was ever admitted under the case ceilings, and both A/B arms measured a self-solving orchestrator instead of agentType selection.
- 154507b: TSDoc and inline comments no longer cite the retired internal specification set (the pre-docs-site
docs/NN, section ...references). The citations either became links to the public documentation at docs.rulvar.com or were dropped where the comment already carried the rule; traceability markers (DEF-n, XF-nn, FR-nnn, OQ-nn, W-nnn) are untouched. Comment-only change: no runtime behavior, no API shapes, and no runtime message strings were modified; the frozen golden-fold fixture is byte-identical.
1.1.0
Patch Changes
- d16b04a: Plain orchestrate treats ladder-declaring profiles as declaration-only (docs/07 section 10 as amended): the spawn vocabulary in the profile card advertises concrete profiles and lists declarers on a separate context line, and spawn_agent naming a declarer is rejected with a typed ConfigError before admission instead of dying later at wire resolution. Found live by the fifth M12 checkpoint run: the knowledge card praises ladder tiers by profile name, so the card-informed arm kept spawning the declarers and measured far below the uninformed baseline.
1.0.0
Major Changes
- 464ab6e: rulvar v1.0.0: the first published release. An embeddable TypeScript engine for durable, budget-bounded, testable multi-agent LLM workflows: an append-only journal with byte-deterministic replay and crash resume over JSONL or SQLite (multi-process workers with lease fencing), hermetic VCR cassettes gating CI through a frozen 60-cassette defect catalog, hard per-run USD ceilings with orchestrator sub-budgets, finalize reserves and admission control, adaptive orchestration (typed plan revisions with rebase, escalation protocols, model ladders, wake digests, lineage and reuse), ModelKnowledge phases 1 and 2 (the git-reviewed model-suitability claim store with TTL decay, eval-measured claims from matrix sweeps, canary fingerprints, and the one-rung-clamped verified layer), provider adapters for Anthropic, OpenAI-compatible and Google plus a Vercel AI SDK bridge, an eval framework, and the rulvar CLI (run, resume, runs, inspect, plan, kb). Licensed Apache-2.0. The six core SPI seams are frozen; ModelKnowledgeStore freezes with this release per docs/05. Ships the M9 through M11 scope together per the 2026-07-11 amendment to docs/12 section 2.
Minor Changes
0e0b569: M10 entry: the render budgets of docs/06 Appendix A are committed (the TBD-before-M10 rule) and wired as engine defaults; OQ-04 (the renderBudget measure) closes on the CHARACTER measure.
- WakeDigest: 400 chars per outputSummary row, one exported constant (
WAKE_SUMMARY_RENDER_BUDGET_CHARS) now serving both the distillation cap (adopted unchanged, the value frozen into every cassette since M6) and the digest render default ofrenderBudgetChars, which stays overridable per orchestration. - ledger_read render: 65536 chars over the serialized view via the new pure
boundLedgerRender(exported withLEDGER_RENDER_BUDGET_CHARS): over budget, rows drop deterministically oldest-first (auto-derived joins before authored sections, the mission brief slices last) and every drop renders as a FLAGGED discrepancy line. The section caps stay the primary bound, so under default termination limits the belt never engages; all frozen fixtures are byte-identical. - KB card: 4096 chars, committed in docs and consumed by the M10-T03 card renderer.
- WakeDigest: 400 chars per outputSummary row, one exported constant (
b28b7a3: M10-T01: the ModelKnowledgeStore SPI and the default file store (docs/05, sections "Data model" and "Commit discipline"). The engine-scoped, per-project, append-only claim store lands as a new SPI seam, a neighbor of JournalStore, freezing with knowledge-base phase 1 post-1.0 (never touching the six frozen core seams).
ModelKnowledgeStore { current; commit(ops, expectedVersion) }with CAS on the monotonic snapshot version, mirroring the lease fencing discipline; concurrent commits serialize through the retryableKnowledgeCasErrorand rebase. There is NO propose() method in the SPI at all, and the runtime handle typeModelKnowledgeHandle = Pick<..., 'current'>physically lacks commit (docs/05 security channels 2 and 3).- The full docs/05 claim data model as types:
ModelClaim(subject with effort as part of identity, mandatory taskClass and evidence, TTL fields, append-only supersede),GateRecord(the human variant does not assemble without the attribution attestation),ClaimOp,EvidenceRef(entryRef is the journal seq),KnowledgeSnapshot. TheTaskClassvocabulary upgrades from bare string to the docs/05 union (the six floor-aligned classes plus open extension), canonically resident with the knowledge SPI and re-exported by the floors module. FileModelKnowledgeStoredefaulting to./rulvar.models.json: git-diffable pretty JSON with atomic temp-plus-rename replace; append-only mechanics (supersede and archive flip status, never delete, preserving the audit trail); referential integrity as typed ConfigErrors; the empty snapshot (version 0) when no file exists.
b53a89e: M10-T02: the editorial claim path, validated (docs/05, sections "Data model", "The human gate", "Grounding and decay"). The runtime enforcement the T01 types promise:
- A gated op without the attribution attestation is now a RUNTIME error at commit, not only a type error: the human gate requires a non-empty ruledOut checklist over the docs/05 vocabulary, and the eval-confirmed gate rejects as reserved for v2.
- The editorial path is the only committable path in phase 1: eval-measured claims and the metrics block reject until the M11 eval-committer identity ships (the validators already model the identity flag M11 will pass).
- The active-claims cap holds at commit: 8 per (model, taskClass) by default (docs/06, Appendix A), configurable per store; supersede chains keep only the head active, so a supersede never grows the count.
- Statement bounds (200 chars), mandatory evidence and taskClass, date coherence, and the asymmetric TTL table land as pure helpers:
claimExpiry(eval 90/30, editorial 120/45 days by polarity) andclaimExpiredfor the read-path filters of M10-T03.
4454175: M10-T03: the ModelKnowledge read path (docs/05, sections "Read path" and "Security"). kb_pinned and kb_repinned land, the card renders, and the whole feature is store-gated: an engine without
stores.modelKnowledgewrites no kb entries at all, so every existing journal and cassette stays byte-stable (zero added awaits on the off path).createEngineacceptsstores.modelKnowledge; the runtime holds ONLY thecurrent()handle (commit is physically absent inside runs).- One read at run admission for orchestrate-role runs: the engine filters claims (active, unexpired, reachable through the run's declared ladders after the role-floor filter) and journals
kb_pinned { version, hash, cardText }with the card bytes EMBEDDED, strictly before the first orchestrator turn. Resume and replay read the entry bytes and never touch the live store. - A fresh
kb_repinnedlands on every wait_for_events wake under the same filtering rules against a FRESH store read, so expired, stale, and archived claims never steer spawns after pauses; a mid-run store commit affects only subsequent pins. modelKnowledgeCard: deterministic, two-layer, tier-relative, 4096-char budget (oldest notes withhold behind an explicit marker). The verified layer compiles EXCLUSIVELY from eval-measured claims (empty in phase 1) with the one-rung clamp; editorial notes render dated and explicitly marked, never compiled into a tier; the orchestrator never sees model names. The card docks into the spawn tool description beside the profile card.- OQ-11 closes: editorial notes render for every taskClass with no self-description suppression (the nameless tier-relative render already blunts the feared bias).
- Two catalog cassettes (docs/09, new section 6.11): kb-pin-replay and kb-repin-expiry, recorded offline over a deterministic stub store with time-stable dates; the cassette-catalog CI job runs them.
6599ca8: M10-T05: the taskClass binding interim rule becomes the phase-1 resolution (docs/05, section "Phases and placement"; docs/14 OQ-12 CLOSED). The classification source is author declaration: the optional
taskClasson AgentProfile, TaskSpec, and spawn_agent params; absence means unclassified and stores no literal string anywhere. Card recommendations never apply to unclassified spawns (in phase 1 no recommendation application exists at all; the M11 compiler inherits the rule as normative).- The plan dispatch now forwards the declared TaskSpec.taskClass onto the ExtensionDispatchSpec, completing the substrate: a declared class journals inside the spawn-admission decision (spawn_agent path) and the plan.revision spec of record (PlanRunner path), so M11 matrix sweeps and the recommendation compiler slice attempts by class from journals alone.
- Byte-neutral: journals without declared classes are unchanged; floors stay profile-driven per docs/04.
6649e5f: M11-T01: the eval-committer identity activates eval-measured claims (docs/05, sections "Data model" and "Commit discipline", amended with the dedicated
eval-committerGateRecord variant, distinct from the v2-reserved eval-confirmed proposal auto-gate).- Commit validation is now GATE-DRIVEN and the coherence square is schema-enforced in both directions: an eval-committer-gated op MUST carry class eval-measured, author kind eval-pipeline, and the metrics block; a human-gated op MUST NOT carry any of the three (a human-authored op with metrics keeps rejecting). Observational data never carries metrics and never auto-promotes.
@rulvar/evalsships the pipeline side:evalMeasuredClaim(the docs/05 TTL table applied by polarity: strength 90 days, weakness 30) andcommitEvalMeasuredwith the documented CAS-rebase recipe against any ModelKnowledgeStore.
fd2f83b: M11-T03: TTL and staleness (docs/05, section "Grounding and decay"). The decay module (
src/knowledge/decay.ts) becomes the decay owner: the asymmetric TTL table (eval 90/30, editorial 120/45; inbox 14 days exported as a constant, reserved for M12) andclaimExpiry/claimExpiredmove there with their names re-exported through the claims module unchanged.- The re-measurement queue lands as documented:
remeasureQueue(claims, at)is JUST a status filter over expired, still-active eval-measured claims (nothing archives them: the next sweep re-measures the subjects);ttlStatefeeds maintenance views. - Archive-never-delete maintenance:
archiveDeprecatedModelOps(claims, models)produces archive ops (reasondeprecated) for every live claim of a deprecated model; historical runs keep their audit trail. - Expiry stays enforced at every pin AND repin through the M10-T03 read-path filter; the acceptance test drives the same filter across the boundary clock: an expired claim stops influencing the card at the next pin or repin.
- The re-measurement queue lands as documented:
01d6b2d: M11-T04: modelEpoch capture and the canary fingerprint (docs/05, section "Grounding and decay"; OQ-06 CLOSED with the committed design).
- Core:
modelEpochOf/capsHashOfbuild the honestly coarse epoch signal (registry version, pricing version, caps hash; silent alias re-pointing stays a documented uncaught case absent probes). The ClaimOp union gainsmark_stale(docs/05 amended): section 6 requires status stale at fingerprint drift and the closed op set could not produce it; active flips to stale, already-stale is an idempotent noop, terminals never revive. - Evals:
canaryFingerprint(engine, probes)runs the FIXED caller-versioned probe set sequentially through the ordinary engine and hashes NFC-normalized, whitespace-collapsed outputs (the probe count prefixes the hash so probe-set edits never collide with drift).flipStaleOnCanaryDriftflips the model's active eval-measured claims whose recorded fingerprint differs, in one CAS-rebased command; claims without a baseline stay untouched. Sweeps stamp the epoch per pool member viamodelEpochFor.
- Core:
9a20dbb: M11-T06: the verified-layer compiler goes public (docs/05, sections "Read path" and "Composition with the model layer").
compileVerifiedLayer(claims, ladders)compiles start-tier recommendations per (ladder, taskClass) EXCLUSIVELY from eval-measured claims with the one-rung clamp (the price of any false belief stays one rung; ties hold the default and compile nothing; editorial claims never compile); the card renders from it and future consumers read the structured rows, never the card text. Floors and ModelCaps stay hard; budget is touched only through the existing admission path.Property-tested over seeded random snapshots: no compiled recommendation ever exceeds one rung of displacement or leaves the ladder, editorial-only snapshots compile to nothing, and compilation is deterministic. The M11 OQ sweep rides along in docs/14: OQ-09 closes with the defined M12 gate criteria (A/B sweeps, rung and agentType selection against the no-card baseline); OQ-07, OQ-08, and OQ-10 carry honestly (their triggers cannot fire while every release is founder-deferred).
0fbe7ea: M9-T04 (part 1): the DEF-2 and DEF-3 catalog rows deferred at M7 (docs/09 sections 6.2 and 6.3; docs/10 M9 row "Complete catalog green in one CI run"), plus the producers and liveness fixes the rows exposed.
- Nine new frozen cassettes with public runners and byte-for-byte replay tests: combined-loop-descent, config-drift-resume, class-storm-single-turn, oscillation-bounded, race-timeout-vs-live (DEF-2); respawn-preserves-counter, reworded-lessons-collide, stall-streak-classes-and-pinning, legacy-journal-resume (DEF-3). The class and race rows additionally round-trip their frozen bytes through BOTH reference stores (JsonlFileStore and SqliteStore) with identical loads, per the store-independence rule.
@rulvar/plan: the class-level escalation decision producer lands (docs/07 6.5): two or more same-kind reports resolved by ONE revision merge into ONE escalation-decision entry with per-lineagedebitsrows and resolvedBy 'class'; a denied per-lineage debit degrades the group to single-target decisions so denial semantics stay per report. The folds already consumed this form; single-target behavior and all existing cassette bytes are unchanged.@rulvar/plan:termination:config-driftnow actually fires on resume when a live termination knob diverges from the journaledtermination.init(the journal wins, the divergence is reported per field; docs/07 11.2). Events are never journaled, so frozen cassettes are unaffected.@rulvar/plan: aretryescalation decision re-opens the node AND clears its stale dispatch handle; previously the re-opened node sat ready forever while the scheduler skipped it (the re-dispatch liveness gap behind Flavor B defaultDecision retry).@rulvar/plan:lesson_addkeys once (docs/07 9.2): a repeated add with the same content key acks the recorded lesson instead of appending a duplicate; re-executed-turn recovery is unchanged.@rulvar/core: an extension dispatch whose agent dies BEFORE its root entry lands now surfaces the underlying failure loudly to the dispatching caller instead of hanging the dispatch await forever (the pre-root cousin of the stale-writer liveness rule). Healthy paths and replays are byte- and timing-identical.- Known residual, unchanged: repeated Flavor B suspensions on ONE re-opened node dedup onto the first suspension's decision key; the recorded cassettes route around it and the at-cap immediate-resolution flavor rows stay with M9-T04's later parts.
ebe0abc: M9-T04 (part 2): the six DEF-5 catalog cassettes (docs/09 section 6.5; docs/03 section 9), plus the reuse-producer completions the rows forced.
- Six new frozen cassettes with public runners and byte-for-byte replay tests: oscillation-full-reuse (escalated-terminal donor, shared full link, by-ref root, reclaimedUsdAtLink carries the donor spend), graft-partial-subtree (a three-rung limit ladder severed mid-top-rung grafts exclusively; the completed rung attempts forward-match through the scope alias and only the interrupted rung reruns live, exactly once), crash-between-link-and-root (cut strictly between the durable node.link and the by-ref root; the resume rolls forward with zero repayment), oscillation-guard-trip (the third re-add at maxOscillationsPerKey 2 rejects osc_guard with the embedded verdict and the run closes non-HITL), worktree-disposed-degrade (an unpinned worktree graft donor degrades to a fresh admit with DedupNote graft_unsafe; reuse_full stays allowed for a worktree donor with a terminal root), claim-exclusivity-and-chain (two identical adds in ONE revision: the first grafts exclusively, the second degrades donor_active; the severed grafted node becomes the chain head and the third add drains the chain transitively; oscillationCount reaches 2).
@rulvar/core(docs/03 9.3/9.6 producer completions, folds and bytes of existing journals unchanged): evaluateReuse now skips exclusively-claimed donors (first-wins) and degrades to a fresh admit with the documenteddonor_activereason when every candidate is captured; a severed grafted node inherits its captured link's chain (ancestry plus chain-tail graft eligibility), so the next add links to the chain head and drains transitively; agent dispatch roots record their resolved isolation (value.isolation, only when not 'none') so the DedupIndex worktree rules can read it from the journal.@rulvar/plan: exclusive captures are first-wins WITHIN one revision too: the second identical add of the same revision degrades todonor_activeinstead of double-claiming the donor.- All fifteen M9 cassettes re-record byte-identically under the double-run agreement; the nine part-1 fixtures are untouched by the producer changes. fixtures.sha256 covers 50 frozen files.
a3079d0: M9-T04 (part 3): the six DEF-8 catalog cassettes plus the DEF-7 reserve-survives-run-exhaustion row (docs/09 sections 6.7 and 6.8), with the roll-forward and reserve producers the rows exposed.
- Seven new frozen cassettes with public runners and byte-for-byte replay tests: revise-racing-defaultDecision (the mandatory stale-wake trio dropping dep_already_resolved with blockingRef, node_escalated, node_already_done in ONE revision), crash-after-append-before-effects (the pre-effects kill point; both children spawn live exactly once on resume and the request-only cancel lands on the redispatched branch), amend-vs-running-then-cancel-add, intra-revision-self-conflict (sequential intra-revision semantics), bad-base-streak-terminates (three fabricated-base all-dropped entries then the non-HITL guards fallback), park-races-child-completion (parkRequested extinguished by the child-result transition, no park retention), and reserve-survives-run-exhaustion (adds that would invade the committed finalize reserve drop admission_denied inside the revision outcomes; the forced finish executes FROM the reserve and closes the run ok).
@rulvar/plan: the idempotent plan_revise recovery path now also re-lands request-only cancels and parks by aborting the redispatched mid-flight branch; previously the crash-after-append-before-effects roll-forward left the cancelled branch running forever.@rulvar/plan: an accepted escalation resolution records the node's done reference (doneRefs), so a later waive_dep against the resolved dependency drops dep_already_resolved with the blockingRef pointing at the resolving reference, exactly like a child-result transition.@rulvar/core: the forced finish now RELEASES the finalize reserve as it begins (releaseFinalizeReserve): the reserve stops subtracting from the admission remainder at the moment it is being spent, or the finalize agent could never draw the money reserved for it under a tight run ceiling. Admissions stay frozen past the cap, so nothing else can take it. Cap behavior under unlimited ceilings (all existing cassettes) is byte-identical.- All 22 M9 cassettes re-record byte-identically under the double-run agreement; fixtures.sha256 covers 57 frozen files.
596a39b: The project is renamed to rulvar (the founder decision of 2026-07-11 closing OQ-24; the official domain is rulvar.com). Every package moves to the @rulvar scope (the umbrella is @rulvar/rulvar, the ESLint plugin is eslint-plugin-rulvar), the CLI binary is
rulvar, the config convention is rulvar.config.mjs, the knowledge store default is rulvar.models.json, the default journal directory is .rulvar, engine warnings use the RULVAR_ prefix, and the orchestrator workflow name is rulvar-orchestrate. Because journaled bytes embed the workflow name and content keys, the entire frozen catalog (60 cassettes and the dogfood journals) was re-recorded under the new name and re-frozen; the turbo lint task now orders after upstream builds (a latent race the rename surfaced). Nothing was ever published under the former name, so no consumer migration exists.
0.9.0
Minor Changes
84f94d4: The v0.9.0 BREAKING release notes (M8 server and queue; the flagged BREAKING sections of the pre-1.0 convention, docs/12 registry).
BREAKING: TranscriptStore gains the REQUIRED
delete(ref)method (docs/03 12.4; the OQ-20 interim rule executed at M8-T04: retention is impossible without blob deletion, andJournalStore.deletealone would orphan every transcript). How it fails: third-party TranscriptStore implementations stop compiling against the widened SPI. Migration: implementdelete(ref); deleting a missing ref MUST be a no-op, never an error; the cascade over a run's blobs stays ENGINE-side (Engine.deleteRun), never a store obligation. The shipped InMemoryTranscriptStore and FileTranscriptStore already implement it.BREAKING: the Engine interface gains required members
stores,deleteRun, andpruneRun(docs/06 10.2; the M8 seam and retention amendments: the shells read the run picture through the engine's stores, and retention needs the cascade and the checkpoint pruning as first-class engine operations). How it fails: custom Engine implementations and structural Engine test doubles stop compiling; ordinary consumers ofcreateEngineare unaffected, andResumeOptions.leasestays additive-optional. Migration: expose the configured stores and delegatedeleteRun/pruneRunto the underlying engine (the pattern in@rulvar/testing'screateTestEngine).65c7b2c: M8-T01: createServer, the HTTP shell (docs/02 section 8.2; FR-702), plus the Engine.stores seam it stands on (docs/06 10.2, M8 entry amendment).
@rulvar/cli:createServer({ engine, workflows })returns{ fetch(req: Request): Promise<Response> }with the five canonical routes: POST /runs (start a registered workflow), GET /runs/:id (status and outcome), GET /runs/:id/events (SSE; Last-Event-ID maps to the event seq, replay is at-least-once and consumers deduplicate onreplayed), POST /runs/:id/external/:key (programmatic resolution,by: 'external'; a run that settled suspended in-process auto-resumes; a run not live in this process gets the documented offline append under a lease where the store is leasable, and resumes on a worker), GET /runs/:id/cost (the settled in-process CostReport, or the pure journal fold priced by the optionalpriceUsd). Authentication stays host middleware (docs/14, OQ-16).@rulvar/core: the Engine interface gains the readonlystoresaccessor exposing the configured journal and transcript stores; exactly the instances createEngine received (or defaulted), no store contract widens.@rulvar/testing:createTestEngineforwards the newstoresaccessor.
a2a3243: M8-T02: createWorker, the queue shell (docs/02 section 8.3; FR-703), plus the two queue seams it stands on (docs/06 10.2 and docs/03 12.3, M8 entry amendment).
@rulvar/cli:createWorker(engine, { store: LeasableStore, concurrency? })leases resumable and suspended runs via acquire/renew/release with fencing epochs (renew cadence ttl/3; Appendix A reference ttl 60000 ms; concurrency default 1). A store without lease capability is a typed ConfigError at start, never a silent split-brain; leasing a store other thanengine.stores.journalis equally a ConfigError. DEF-6 repeats at acquire: a journal outside the hashVersion window releases the lease and poisons the run for this worker. Stateless workers call bareengine.resumewith the lease; unchanged suspended runs are skipped until their journal grows; queue semantics stay honestly at-least-once with deduplication by the journal. The OQ-21 residual (original in-process args are not journaled) is bridged by the optionalargsForhook.@rulvar/core:ResumeOptions.leasecarries the worker's lease through the kernel's single append site, so a stale writer's appends are rejected by the fencing epoch and never become visible (lease theft impossible by construction); bareengine.resume(runId)now falls back from the persisted CompiledWorkflow source todefaults.workflows[workflowName](the registry the queue worker resolves through, docs/06 10.4); the Replayer accepts the lease option.
ebc8101: M8-T04: the redaction and retention interim rules executed (docs/14 OQ-20 and OQ-22; docs/09 section 8 rewritten to the executed state; docs/03 12.4 and 12.8; docs/06 10.1 and 10.2 amendments).
@rulvar/core: the L0 SerializationHook (createEngine({ serialization })): redact/encrypt at the append/put boundaries, symmetric on load/get, applied by wrapping the stores soEngine.storesexposes the one policy point; kernel ordering fields are drift-checked with a loud ConfigError. Default key masking at the telemetry boundary: every emitted WorkflowEvent passesmaskSecrets(provider keys, PATs, bearer tokens, JWTs, private-key blocks become[masked-secret]); opt out viaredaction: { maskEvents: false }; never touches the journal. Retention:TranscriptStore.delete(ref)joins the SPI (missing ref is a no-op; InMemory and File stores implement it),Engine.deleteRun(runId)cascades blob deletion before the journal (no orphan transcripts), andEngine.pruneRun(runId)deletes checkpoint blobs of ok-terminal attempts that nothing else references (parked, cancelled, escalated, and hanging attempts keep theirs).@rulvar/cli:createServerandcreateWorkertake the opt-inretentionpredicate over RunMeta (the server applies it at terminal settles, the worker during sweeps under a brief lease); the OTel exporter masks string span attributes with the same policy, defense in depth over the already conservative attribute content policy.@rulvar/testing:createTestEngineforwardsdeleteRun/pruneRun.
0.8.0
Minor Changes
85d55cf: The v0.8.0 BREAKING release notes (M7 adaptive orchestration full; the flagged BREAKING minor of the pre-1.0 convention, docs/12 registry).
BREAKING: the unified
AdmitVerdictunion is extended with the reuse verdicts (reuse_full,admit_graft) and the new reject codes (termination_exhausted,ladder_exceeds_frozen,lineage_exhausted,lineage_busy,osc_guard) (DEF-5). How it fails: exhaustive switches over the verdict kind or reject code in custom shells and admission SPI extensions stop compiling. Migration: add branches for the new arms; reject-code switches should route unknown codes to their generic-denial path.BREAKING: reuse-by-reference is the DEFAULT (DEF-5). A byte-identical
add_taskafter a cancel or abandon no longer re-executes the subtree: the result returns by reference (reuse_full) or continues from the paid prefix (admit_graft). How it fails: changed semantics; runs that relied on re-execution against a changed world observe referenced results instead. This is the only intentional change of visible semantics in the pre-1.0 line. Migration: setreuse.enabled: falseon the admission config, orfresh: trueon the specificadd_task.BREAKING: the config key
maxEscalationsPerNodeis renamed tomaxEscalationsPerLogicalTask(XF-10): escalations count per logical task across respawns via the lineage chain. How it fails: a typedConfigErrornaming the new key rejects the old one. Migration: rename the key; the default stays 2.BREAKING: the plan-size-scaled revision budget option is removed without deprecation (DEF-2).
maxRevisionsPerRunis an absolute, non-replenishable counter (default 32) debited by exactly 1 per journaledplan_revise; nothing increments it. How it fails: the removed option is rejected at config validation. Migration: sizemaxRevisionsPerRundirectly.BREAKING:
plan_reviseresult and error schemas widen (rebase outcomes, embedded admissions,revisionUnitsRemaining) andWakeDigestgains the MANDATORYterminationfield besideplanHash,budget, andreuse(DEF-2/DEF-8). How it fails: schemaHash and toolsetHash of orchestrator scopes change, so VCR cassettes recorded over orchestrator turns invalidate. Migration: re-record affected cassettes; consumers of the digest type add the new mandatory blocks (all-zero outside PlanRunner).BREAKING: B0, the run budget ceiling, is immutable after start (DEF-2): no API, including HITL decisions, can top it up. How it fails: code that mutated the run budget mid-run or expected an HITL top-up hits a typed runtime error; overshoot stays bounded by one turn per in-flight agent. Migration: size the ceiling at start; use the orchestrator cap and the finalize reserve (DEF-7) for graceful degradation instead of top-ups.
BREAKING: PlanRunner requires a resolvable orchestrator cap (DEF-7).
orchestratePlannedwith no run USD ceiling and no explicitbudget.capUsd, or witheffectiveCap < finalizeReserve, refuses to start with a typedOrchestratorCapConfigErrorbefore any LLM call. Migration: passbudget: { capUsd }(or run under a USD ceiling and rely oncapFraction, default 0.2; up to 1.0 opts out explicitly with a telemetry warning).b88c9e3: M7-T02: lineage LogicalTaskId (DEF-3). New
src/journal/lineage.ts:LogicalTaskId/LineageRelation/LineageRef/SpawnLineage,AttemptOutcomeClass,LineageStats,SpawnLineageOpt; approach signatures (normalizeApproachTag,approachSigCoarse,approachSigOf,canonicalIsolationTag, sigVersion 1) with prompt prose excluded by construction;EscalationLimitswith the committed defaults (maxEscalationsPerLogicalTask 2, maxAttemptsPerLogicalTask 8) and a validator that rejects the pre-renamemaxEscalationsPerNodewith a migration hint (XF-10);LineageIndex, the incremental pure counter fold (attemptsUsed / escalationsUsed under first-closing-wins and class-decision rules / stallStreak with class skips and resets / approaches grouping), pinnable to a snapshot seq, with deterministiclegacy:contentHash LTIDs canonized onto journals written before lineage existed (random ULIDs on replay are forbidden). AdmissionController:AdmitSpecwidens (lineage: SpawnLineageOpt,approach,ancestry,signature),evaluateLineageenforces the single-live-attempt invariant (lineage_busy) and monotonic attempt consumption (lineage_exhausted) strictly BEFORE the carrying decision entry is appended, and every non-reject decision now embeds the computedSpawnLineagevalue block reused byte-exact on replay.ctx.agentandctx.workflowgainlineage/approachoptions; a ctx.agent declaration journals one spawn-admission decision entry before dispatch and recovers it on resume without re-minting.budgetDefaults.lineageconfigures the limits engine-wide.f3c4613: M7-T03: TerminationAccount and the termination lemma (DEF-2). New
src/journal/termination.ts: the frozenTerminationLimitsvector (V0 32, S0 128, E0 2, D0, kMax from the profile-registry snapshot, B0 immutable, orchestratorCapUsd and finalizeReserveUsd per XF-09) with a validator rejecting the pre-renamemaxEscalationsPerNode(XF-10); the debit-onlyTerminationAccount(no credit operation exists by construction) with per-resource debits embedding balance-after, atomic NEW-lineage allocation (E0 plus K_l minus 1 rungs) on the spawn debit, strictly monotone rung indices, and thedebit()surface that writestermination.deniedstrictly BEFORE resolving an underflow; the variant function Phi withphiInitialOf(V0 + C by S0, C = E0 + kMax);buildTerminationInitValue/readTerminationInitfor thetermination.initentry;foldTermination, the replay-strict recomputation that rebuilds the account from init, asserts every embedded balance (revisionUnitsAfter, spawnUnitsAfter, escalationUnitsAfter, rungIndexAfter/rungsRemainingAfter) at exactly the diverging entry, debits class-level decision arrays once per lineage, counts timeout defaultDecision resolutions once under first-closing-wins, and collects denials for zero-live-call re-issue;terminationConfigDrift(the journal always wins). AdmissionController gainsbindTermination: under a bound account every admitted spawn of any origin debits one spawnUnit atomically with its decision entry (spawnUnitsAfter becomes the account balance), a declared ladder longer than the frozen kMax rejects withladder_exceeds_frozen, and exhaustion rejects withtermination_exhausted;AdmitSpec.ladderLengthand the recordedAdmissionDecision.ladderLengthfeed the fold. The closed AdaptiveEvents catalog (docs/09 section 1.4) joins WorkflowEventBody, including termination:debit / termination:denied / termination:config-drift.a41c20f: M7-T05: PlanRunner scheduling and toolset. Core gains the PUBLIC orchestrator extension seam (docs/02 section 4 seam-sufficiency: orchestration packages build exclusively from the public API):
OrchestrateOptions.extensionhosts anOrchestratorExtensionwith boot strictly before the orchestrator's first agent entry, extension tools appended to the mode (c) toolset, an activity hook running after every child settlement strictly before wake evaluation, quiescence participation (nothing running AND nothing ready), digest extras, wake observation, prompt lines, and anOrchestratorExtensionIOexposing total-order appends into extension-owned scopes, the journal snapshot, the single admission point, explicit-scope child dispatch through the ordinary ctx.agent path (plan/NodeId sub-accounts open beside the orchestrator account), settled lookups, cancel, ULID minting, and telemetry.outputSchemaRef/toolsetRefnow RESOLVE against the newdefaults.schemasanddefaults.toolsetsengine registries (unknown names stay typed tool errors);TerminationAccount.bindDeniedWriterbinds I/O onto fold-rebuilt accounts. @rulvar/plan shipsplanRunner(options)andorchestratePlanned(engine, goal, opts): boot writestermination.init(frozen limits with kMax and the profile-registry snapshot hash) strictly before the first scheduling entry and binds the account into admission; plan_view renders the pinned pure fold (plan state, per-node LineageStats, the TerminationAccount snapshot) at the last delivered WakeDigest, with digestSeq 0 seeded as the empty-plan bootstrap snapshot; plan_revise (normative docs/07 4.7 schema) debits one revisionUnit per journaled revision (underflow writes termination.denied first), evaluates the committed rebase at the fold head, appends ONE plan.revision strictly before effects, schedules newly-ready nodes under plan/NodeId scopes, lands cancel requests, re-issues idempotently on re-executed turns (roll-forward), and emits plan:revised plus termination:debit; the engine (never the model) schedules ready nodes and journals ready-to-running and terminal transitions as plan.decision entries whose terminal transitions extinguish pending flags; quiescence completes (nothing running and nothing ready). The end-to-end revise-mid-run shape and a full crash-resume with zero live calls and no duplicate entries are covered by integration tests against the public engine API.f4e70be: M7-T07: reuse-by-reference (DEF-5). Core: new
journal/reuse.tswith the richDonorRef(replacing the M6 seq placeholder inside the closed AdmitVerdict union),GraftBoot,DedupNote,ReuseConfig,NodeLinkValueand its content identity (nodeLinkKeyover {kind, spawnKey, donorScope, targetNodeId}), theDedupIndexpure fold (severed roots become donor candidates when their pre-abandon effective status is not error, memoized failures excluded, exclusive claims resolve first-wins, plan-node scopes sweep their own branch payments, unpinned worktree donors degrade),evaluateReusewith the four-outcome verdict table (reuse_full | admit_graft | fresh-with-note | reject osc_guard at the link count), and the abandoned-spend ledger fold (abandonedUsd/reclaimedUsd/netLostUsd, per-key oscillation counts). The kernel matcher gains scope-prefix aliasing (docs/03 9.5):registerAliasmerges donor-scope candidates into the target scope in journal order at every nested level, and the alias disposition bypasses the abandon overlay so donor entries regain their pre-abandon status ONLY through the alias (the standalone old scope stays skipped); a dangling donor root through the alias IS the graft frontier (rerun-dangling continues from the donor checkpoint).AbandonAttemptcarries logicalTaskId (XF-04); the extension IO gainsabandonBranch,registerAlias, andpriceUsd. Plan: PlanRunner wires the DedupIndex at the fold head under the PlanWriteLock into the rebase dedup hook (transforms embed the verdict, the donor descriptor, and the placement into the revision entry), applies the per-SpawnKey osc_guard rejection, attaches DedupNotes to fresh admits, compiles applied cancel_task (and cancel-landed) into severing abandon entries with lineage attribution, lands node.link entries and by-ref roots in the mandatory write order with idempotent roll-forward, registers aliases (rebuilt by fold at boot), completes full-linked nodes by reference through an engine decision instead of a dispatch, debits a spawnUnit per reuse link, and renders the abandoned-spend view in plan_view (pinned) and the WakeDigest extras;PlanRunnerOptions.reusecarries the docs/03 9.9 config.75d1646: M7-T08: park and unpark. Core: the internal boot-checkpoint channel lets a FRESH dispatch boot from a retained transcript checkpoint (
ExtensionDispatchSpec.bootCheckpointRef; dangling redispatch checkpoints take precedence), serving park/unpark continuation and the DEF-5 graft boot. Plan: newpark.tswith thePinLedgerfold (live pins counted from abandon entries carrying retainWorktree, park pinning and DEF-5 retention SHAREmaxPinnedWorktrees, default 4),parkDispositionOf(checkpoints always retained; worktrees pinned only under capacity, overflow keeps the checkpoint but drops the tree), andunparkPlacementOf(continuation from the retained checkpoint; restart when no checkpoint exists or a worktree-isolated node lost its tree: silent resume against a fresh tree is impossible). PlanRunner lands parks at the turn boundary: a park-requested running child is aborted, thepark-landedplan.decision transitions running to parked carrying the checkpoint anchor (set_node_status gains the optional checkpointRef field, applied by the fold), the branch is severed with retainCheckpoint plus retainWorktree per the pin disposition, the dispatch slot frees for the unpark, and node:parked emits. unpark_task applies with the embedded admission: a previously dispatched branch is a lineage rebirth (relation 'unpark-restart' continuing the node's LTID), while a never-started parked node resumes scheduling without consuming an attempt; the unparked dispatch boots fromcheckpointRefFor(runId, anchor)on the continuation path and restarts otherwise. The park-unpark integration test drives the full shape deterministically (one paid tool turn, park inside the second turn, unpark continuation whose booted history carries the paid turn) plus the pin-cap overflow and placement rows as units.0627413: M7-T10: ModelLadder full (docs/07 section 10; docs/04 section 12; FR-119/FR-313). Core: ladders now RESOLVE through the chain (
canonicalizeLaddervalidates the declaration once, FR-119 undeclared-judge-rung ConfigError included, and resolves every rung's effort explicitly;ladderRungChoiceyields the concrete per-rung ModelChoice; a higher concrete layer shadows a lower ladder and vice versa; a ladder that WINS wire resolution stays a typed ConfigError since rung attempts always carry a concrete override).ladderLengthOfreads the normative declaration points (profilemodel: { ladder }or the loop-role routing entry).foldTerminationdebits the rung RESPAWN's embedded admission on raising ladder verdicts (docs/07 11.3 b). New per-engine mechanical gate registrydefaults.gates(MechanicalGateProfileover AgentResult.artifacts). The extension seam gainsio.random(journaled ctx.random for spot-checks),io.gates, and dispatch fieldsmodel(the concrete rung resolution entering the attempt's identity hash),memoizeOutcome, and inlineschemafor the engine-synthesized judge. Plan: newladder.tsplus the PlanRunner ladder driver: rung attempts are ordinary agent scopes on the concrete rung model with rung caps binding (tier N+1 = new content key = one live attempt, all sharing the LTID via relationrung-retryregistered from the raising verdict'snextAttempt); triggers classify typed (error, limit, schema-exhausted, no-progress first-class via the abort class, verify-failed from gates only); acceptance gates run per ok attempt in declaration order with journaledgate-verdictdecisions (mechanical registry profiles, judge on a declared rung >= the executing rung or explicit override with a forced verdict schema and derived identity, spot-check selection strictly via the journaled draw); every ladder verdict is a decision entry computed once live and recovered by content key, so folds consume only journaled values; a denied respawn writestermination.deniedstrictly before the fallback lands; an ok attempt whose acceptance fails with no raise left landsfailed, neverdone. Mid-flight resume redispatches running nodes through forward matching (dangling attempts continue, settled ones replay instantly): the half-escalated-ladder shape resumes without repaying completed rungs, proven by the truncated-journal test.55c0f87: M7-T11: EscalationProtocol completion (docs/07 section 6; DEF-2/3/4). Core: Flavor B now REQUIRES an explicit
deadlineMs(the knob has no engine default per the frozen Appendix A row; a flavor B spawn without it is a typed ConfigError before any LLM call); SpawnRecord captures the dispatch's escalation flavor and the WakeDigest escalations block reports it (a flavor B report reaching the digest is already decided by the DEF-4 winner). Plan: newescalation.tswith the authoritativeescalation-decisionentry contract (decide-once per report by content key;countsAgainstLimitderived from the report kind, XF-06; the counting debit atomic with the append embeddingescalationUnitsAfter; a DENIED debit writestermination.deniedstrictly before and flips the entry tocapExceededwithcountsAgainstLimit: false, so the cap yields the flagged decision plus the final report, never a bare limit, and the folds stay replay-strict). PlanRunner completes the decision flow: thecancel_taskrevision transform on an escalated node lands the verdictcanceldecision, theresolve_escalationplan.decision (originescalation-live), and the severing abandon strictly after the revision append; a settled Flavor B suspension's DEF-4 winner (timeoutdefaultDecisionbytimeout, a live decision, or a class fan-out) is absorbed into the authoritative entry (originsescalation-default/escalation-class) and the fate applies through the single applier (retry re-opens the node in place with the journaledamendedPrompt/startTierhonored at re-dispatch, accept closes the paid partial result done, cancel closes cancelled, decompose leaves the node escalated while the proposed children enter throughspawn_admittedops with FRESH lineages and embedded admissions debiting spawn units through the decision entry).fd33871: M7-T12: orchestrator cap and finalize reserve (DEF-7; docs/07 section 12). BREAKING for PlanRunner runs (v0.8.0 registry, docs/12):
orchestratePlannednow REQUIRES a resolvable orchestrator cap; a run with no USD ceiling and no explicitbudget.capUsd, or witheffectiveCap < finalizeReserve, refuses to start with a typedOrchestratorCapConfigErrorBEFORE the first LLM call and before any journal entries (an uncapped orchestrator was precisely the defect;capFractionup to 1.0 opts out explicitly).effectiveCapUsd = min(capUsd, capFraction x runCeiling), default fraction 0.2. The engine writes ONEorchestrator_budget_reservedecision entry strictly aftertermination.initand strictly before the orchestrator's first agent entry, freezing the cap and the finalize reserve (explicit, orfinalizeTurnsx the deterministic per-turn estimate) in absolute dollars, recovered by content key on resume and never re-evaluated. The reserve registers on the orchestrator account AND the run root (kept separate from committedReserve; the admission block checks add it), so no spawn ever eats the finalization money. At the pre-wake soft boundary (orchSpent + turnEstimate > effectiveCap - finalizeReserve) the engine writes exactly ONEorchestrator_budget_capdecision strictly before any effects (an in-flight latch closes the wake-ordinal race): the plan freezes for adaptation but not for work (the rebase contextfrozenflag drops every opplan_frozenwhile admitted nodes run to completion), all wake triggers except quiescence disarm, and the orchestrator unwinds to the reserved FINAL wake: a fresh agent entry on the restricted single-finishtoolset with afinalizeTurnslimit, paid from the reserve; success yields outcomeokwithforcedFinishmarked in the CostReport. If the final finish fails,orchestrator_finalize_fallbackjournals and the engine SYNTHESIZES a deterministic partial result by pure fold with zero LLM calls; the run endsexhaustedwith the non-null partial (RunOutcome.valuenow survives exhaustion). Every digest carries theWakeBudgetBlock(run and orchestrator spend, cap, reserve, the epsilon-floored orchestrator share,softWarningat 0.8) withorchestrator:budgettelemetry at each wake boundary and at the cap;CostReport.orchestratorpopulates spentUsd, wakes, forcedFinish, and reserveUsedUsd for H-OrchShare.e70e7f4: M7-T13: the FINAL normative WakeDigest in ONE coordinated schema change (docs/07 section 5; XF-08/XF-12, inside the frozen hashVersion-2 identity rules).
WakeDigestnow declares every block first-class:digestSeq,planHash(emission-time plan hash, empty outside PlanRunner),coversToOrdinal,completedDigestsordered by spawn ordinal,escalations(with the Flavor BdeadlineAt), the MANDATORYterminationsnapshot (DEF-2, contributed by the PlanRunner extension as a pure fold), the MANDATORYbudgetblock (WakeBudgetBlock, DEF-7), and thereusestats (the AbandonedSpendView shape, DEF-5). Runs without the PlanRunner extension ship all-zero blocks (emptyDigestBlocks), mirroring the CostReport convention. The digest render is bounded deterministically: the newrenderBudgetCharsoption clamps each TaskDigestoutputSummaryby CHARACTERS (the model-independent interim measure; the tokenizer choice stays the docs/14 open question, the numeric default TBD before M10). Pinning semantics are unchanged: the digest is part of the wake snapshot and a re-executed turn reads identical bytes.bc9c903: M7-T14: the M7 gating cassettes and the remaining metric wiring (docs/09 sections "Metrics" and "Mandatory defect cassette catalog"). Thirteen frozen cassettes record the round-2 set (revise-mid-run, crash-during-revision, park-unpark, oscillation-freeze, half-escalated-ladder, budget-denied-rung), the DEF-7 set minus queue-failover (cap-freeze-then-finish, crash-between-cap-and-effects, finalize-fallback-synthesized, escalation-storm-frozen), and representative DEF-2/DEF-3 rows (revision-exhaustion, rung-retry-lineage, decompose-mints-children), each double-run at record time and replayed byte-for-byte in CI through the new public
@rulvar/plancassette runners with deterministic journal normalization (ULIDs, content hashes, wall clock, spans, and refs collapse to first-appearance placeholders). Metric events:orchestrator:wokenow carriesplanHash,coversToOrdinal, andrenderSize(the deterministic character measure of the delivered digest, the wake-render-size metric); the escalated landing emitsescalation:raisedwith the report kind, the lineage attribution,agentType(the escalation-rate slice), andcostToDateUsd; the abandoned/reclaimed/netLost USD view rides every digest through the T13 reuse block andledger:opplusspawn:*events already feed ledger-ops-per-spawn.
0.7.0
Minor Changes
- fd1d06c: M6-T02: WorkerSandboxRunner and the sandbox contract.
@rulvar/plannergainsWorkerSandboxRunner(accepts CompiledWorkflow ONLY; worker_threads with the exact curated 12-global scope; timeoutMs 300000 / memoryMb 512 breaches terminate the worker with the new typedSandboxError, codesandbox_limit). Core gains the public host half,createSandboxBridge: proxied primitives (agent, step, workflow, awaitExternal, parallel, pipeline, phase, budget) served against the canonical run ctx with worker thunks executing under host-allocated scope tokens; the worker's SYNC seeded now/random/uuid (and the Date.now/Math.random replacements) mirror-journal as ordinary kindrandentries with match-first resume semantics; a busy-state protocol keeps suspension and quiescence behavior identical to in-process runs.createEnginegainsrunners.sandbox;engine.run/engine.resumeaccept CompiledWorkflow, persist the source blob plus workflowSourceRef/workflowHash at start, andresume(runId)with no workflow rehydrates the hash-pinned source (a differing supplied source is a typed ConfigError). NewFileTranscriptStoremakes compiled runs resumable across processes. The sandbox dialect exposes asyncbudget.spent()/remaining(); import/fetch/process are absent from the worker scope. - 6fcf296: M6-T04: profileCard and the API card. Core gains
profileCard(profiles): the one agent vocabulary both orchestration modes speak, feeding the planner prompt (mode b) and spawn_agent agentType guidance (mode c) with IDENTICAL text; pure function of the registry, sorted, byte-stable, rendering only model-agnostic fields (name, description, tool names, taskClass, estCost, escalation opt-in; models are never named). The planner gainsapiCard(): the byte-stable card teaching exactly the curated 12-global sandbox dialect (schema literals only, tools by profile name, onError throw|null, async budget, no imports, the opts.key repeat rule) with usage patterns distilled from the examples corpus. - dcc97a9: M6-T05: the plan agent and the self-repair loop (mode b).
plan(engine, goal, { model?, profiles?, repairRounds? })asks a planner model under roleplanto write a script against the API card plus the engine's profile card, lints it (eslint-plugin-rulvar preset + compileScript), self-repairs up to repairRounds (default 3) from the machine-readable JSON diagnostics, and returns{ source, workflow, lint }. The planner conversation is an ordinary journaled run with a goal-derived deterministic runId, so re-planning the same goal replays the unchanged prefix free; exhausting the rounds throws a typed ScriptRejected carrying the last diagnostics.runPlanned(engine, goal, args?)composes plan-then-sandbox-run (async by amendment). Core gainsAgentOpts.role('loop' | 'plan' | 'orchestrate', the primary invocation role threading through resolution, effort defaults, floors, cost buckets, and events) and the narrowEngine.profileCard(names?)accessor rendering the registered profiles through the public API. - 434dc83: M6-T06: AdmissionController v1 and nested workflows.
ctx.workflow(wf | 'name', args, { key? })runs a child workflow under the single admission point: aspawn-admissiondecision entry embeds the closedAdmitVerdictunion (admit | reuse_full | admit_graft | reject with the merged reject-code set; reuse branches produced from M7), the committed reserve, and statsBefore strictly before the two-phasechilddispatch entry, so replay recovers verdicts and reserves without re-evaluating admission. Enforced:maxDepth(default 1, hard ceiling 4),maxChildrenPerNode(16),childBudgetFraction(0.3 of the parent remainder minus the parent finalize reserve), and the engine lifetime cap. The budget grows into a hierarchical account tree (run root plus one sub-account per child) with spend propagating to every ancestor, per-account layer-2 guards, and per-subtree layer-3 severing. Structural rejections throw the new typedAdmissionRejectedError(codeadmission_rejected); budget-class rejections keepBudgetExhaustedErrorsemantics. The string form resolves againstdefaults.workflows;budgetDefaultsgainschildBudgetFractionandmaxDepth, andflatReserveUsdis now honored. The abandon fold covers child-workflow scopes via the recorded dispatch payload. - 03173c1: M6-T07 and M6-T08: the mode (c) dynamic orchestrator.
orchestrate(engine, goal, { model?, profiles?, maxSpawns?, budget?, limits? })andctx.orchestrate(goal, opts)share one implementation: an ordinary workflow whose agent (roleorchestrate) holds the typed toolset with the normative docs/07 schemas:spawn_agent,parallel_agents,await_any,await_all,cancel_agent, and the loop-terminalfinish(a new engine interception alongside escalate). Every spawn is an ordinary kindagententry under the orchestrator'sagent:<seq>scope, admitted through the single AdmissionController with the verdict, evaluated reserve, and statsBefore embedded in aspawn-admissiondecision entry (the budget debit itself rides the child's dispatch: one debit, never two); rejections surface as typed tool errors and never kill the run. Handles ARE the child dispatch seqs and stay stable across resume: a crashed orchestrator restores its transcript from the mandatory turn-boundary checkpoint, rebuilds its spawn records from the journal, redispatches only what was in flight, and finds settled children by content keys with zero re-paid spawns and no duplicate spawn decisions.await_any/await_alldeliver deterministic TaskDigests;cancel_agentaborts an in-flight child to acancelledterminal (caller intent; abandon coverage arrives with M7 cancel_task). The nested surface rides ctx.workflow, so maxDepth and the budget account tree clamp it for free; the orchestrator gets its own budget sub-account when a cap resolves (reserve decisions and the at-cap freeze are M7, DEF-7). - 11c0afc: M6-T09 and M6-T10: wait_for_events, the WakeDigest substrate, and ctx.brief.
wait_for_events(the normative docs/07 4.8 schema) parks the orchestrator on an ordinary DEF-4 suspension; the closed v1 trigger vocabulary is quiescence (always armed), child_terminal, escalation, and budget_threshold at the fixed 50/80 percents; a REQUESTED trigger set that can never fire (no run ceiling, unknown or fully delivered handles, no live children) is an immediate typed tool error, so an embedded run cannot hang unrecoverably. The wake is the closing resolution whose value IS the coalescedWakeDigest(substrate fields: digestSeq, coversToOrdinal, completedDigests ordered by spawn ordinal, escalations with reportRef): a re-executed post-crash turn reads exactly the same digest bytes, replay never rebuilds a digest, and simultaneous ready triggers journal one applied resolution plus noop losers under first-closing-wins. Trigger evaluation runs at arm time and on every child settlement; the orchestrator sleeps between wakes and its context grows O(wakes).ctx.brief({ content, instruction?, model?, agentType? })is a journaled summarize-role invocation (one agent-kind entry, free on replay) for handing an inheritable brief to a child.
0.6.0
Minor Changes
fa05007: M5-T01 workflow registry and the @rulvar/cli base.
@rulvar/coregains the per-engineWorkflowRegistrytype anddefaults.workflowson createEngine (docs/06 section 10.4): an explicit first-class value, no module-level registry; shells resolve by-name runs against it (ctx.workflow's string form arrives M6, the queue worker M8).- Spec-conformance fix: the M4-T09 quality floors option moves from the createEngine top level to its canonical home
defaults.roleFloors(docs/06 section 10.1). UpdatecreateEngine({ floors })call sites tocreateEngine({ defaults: { roleFloors } }). @rulvar/cliships its first real surface: the canonical grammarrulvar run <file|name> [--args JSON] [--store PATH] [--budget-usd N],rulvar resume <runId> [--args JSON] [--store PATH],rulvar runs ls [--store PATH],rulvar inspect <runId> [--store PATH](no aliases), a line-oriented TUI progress renderer over the event stream, and interactive resolution of suspended approvals and externals (EOF leaves the run suspended, never errors). Engine assembly follows the host-config convention:rulvar.config.mjsdefault-exports{ engineOptions?, workflows? }, a workflow module may exportworkflow/engineOptions/workflows, and --store selects the JsonlFileStore directory (default.rulvar), so the CLI itself depends only on @rulvar/core. Therulvarbin is included; the resume/inspect grammar amendment (--args re-supply, --store symmetry) is recorded in docs/06 section 10.5.
9234dc8: M5-T03 cost reports. The CostReport builder moves to its own module (
engine/cost-report.ts) and report totals become the LEDGER FOLD totals at settle: RunOutcome.usage and cost.totalUsd are computed from the journal's terminal entries (the same summation the kernel budget seed uses), so report totals equal ledger fold totals exactly, live and across resume, by construction. The newcostReportFromJournal(entries, priceUsd)is the pure fold for STORED runs: byModel and totals from terminal servedBy with abandoned subtrees contributing zero; phase, agentType, and role attribution are live-run facts that entries do not carry (byRole and the orchestrator block complete in M7 per DEF-7). Unpriced models keep surfacing, never as silent zeros.rulvar inspectgains the cost view (total, byModel, unpriced) over the config-assembled price function (table wins over caps.pricing), and live run output prints the byModel/byPhase buckets.644512c: M5-T05 permission presets, audit, dry-run and M5-T06 argv shell matcher.
compilePermissionPreset('strict' | 'standard' | 'open')(tools/presets.ts) compiles the shipped presets to the documented verdict-by-risk tables and folds INTO the existing deny/ask chain layers, after host-authored rules, never a fifth layer and never an allow-override (a needsApproval tool still asks under every preset).opencompiles to empty tables.AgentProfilePermissions.presetnow compiles instead of throwing; undeclared tool risk is matched conservatively via a first-class{ risk: 'undeclared' }rule.- The argv shell matcher (
tools/shell-matcher.ts) replaces the M5 fail-early stub for{ tool, argv }rules: a POSIX-like lexer honors quotes and escapes with no expansion, splits on;/&&/||/|/&/ newline, poisons segments containing command or process substitution or here-docs to ask, strips leading env assignments, and retains redirections as tokens. Verdicts compose strictest-across-segments, sonpm test; rm -rf /yields deny (or ask) even withnpm testallow-listed, and any unmatched segment yields ask. evaluatePermissiongains an offline overload (by tool name, no execution) for the docs/08 4.5 dry-run/shell-tooling API, and every verdict carries the audit payload (verdict, deciding layer, matched rule) that now ridestool:endevents; advisory network-domain rules are reported there but never enforced outside first-party fetch (honest posture, docs/08 4.4).
8a41656: M5-T07 RunProfile presets and M5-T08 OTel exporter.
engine/run-profiles.ts:RUN_PROFILES(fast/standard/deep/ultra) andrunProfile(name)ship the presets as pure DATA, bundles of per-role effort hints, per-run concurrency, budget, permission preset, and spawn limits, with no functions and no named model strings (named strong defaults stay in the umbrella). They are never engine semantics: a source-scan test asserts the engine has zero branches keyed on profile names.rulvar run --profile <name>applies the chosen profile UNDER the host's own engine options (host always wins; the engine then sees only ordinary options), compiling the profile's permission preset into the engine deny/ask layers as data.@rulvar/cligainstoOtel(run, tracer): it maps a settled run's spanId tree 1:1 onto OpenTelemetry spans (run > phase > agent > tool > child), with rulvar.* and gen_ai.* attributes, start/end timestamps from the lifecycle events, and payload-only events attached as span events. Prompts, completions, and tool payloads are NEVER exported; replayed events never create duplicate spans.@opentelemetry/api^1.9 is an optional peer dependency and the exporter is typed against a minimal structural TracerLike, so an absent OTel package never breaks the CLI.
Patch Changes
- 02f7f7a: M5-T09 examples corpus. A new (unpublished)
examples/vitest project ships runnable reference implementations of the documented quality patterns as recipes over the publicctxAPI, never engine flags: adversarial panel (N independent skeptics prompted to refute; majority survives), judge panel (N angled attempts each scored; top wins), loop-until-dry (keep finding until K consecutive empty rounds), and completeness critic (draft, then gap-driven revision passes). Each example is a realdefineWorkflowand doubles as an integration test under FakeAdapter with zero live calls, so an example that stops compiling fails CI like any test. The corpus is registered in the pnpm workspace and the single Vitest project set; the umbrella marker package is unchanged (patch to carry the changeset).
0.5.0
Minor Changes
ac274f4: M4-T01 role protocol completion. The full trigger protocol for the six invocation roles lands in
@rulvar/core(model/roles.ts):- Extract necessity is completed per docs/04 section 8.3: a separate final structured-output invocation fires when a schema is set AND (routing directs extract to a different model OR the loop model's required tier cannot ride a tools-available turn OR finalize is routed). The required-tier rule is new: a
forced-tooltier pins toolChoice toemit_resultand cannot ride while the agent's tools must remain available, so such agents now pay one separate extract call instead of silently losing tool access. Agents without tools keep the M1 single-shot behavior byte for byte. - The finalize role fires for the first time: only when configured in routing and only for tool-bearing agents, as one synthesis invocation with toolChoice
'none'over the full transcript after tools stop. Its text is the output for schema-less calls; with a schema the separate extract runs over the transcript including the synthesis. - A separate extract invocation over a tool-bearing transcript now carries the agent's tool contracts (both providers reject tool-use history without tool definitions) with toolChoice pinned to
'none'or toemit_resultper tier. - Both adapters map
toolChoice: 'none'to the provider's explicit none choice with the tools param present instead of dropping tools from the request. createTestEngineno longer routesfinalizeby default: the routing key is the firing opt-in, and the old default would have summoned a synthesis call for every tool-bearing test agent. Tests that want finalize route it explicitly.
Identity is untouched: extract and finalize resolutions never enter the spawn content key, and existing journals replay unchanged.
- Extract necessity is completed per docs/04 section 8.3: a separate final structured-output invocation fires when a schema is set AND (routing directs extract to a different model OR the loop model's required tier cannot ride a tools-available turn OR finalize is routed). The required-tier rule is new: a
5735d92: M4-T02 HistoryProjector. Cross-provider history projection lands in
@rulvar/core(model/projector.ts) and the retention pipeline that feeds it:projectHistoryprojects the canonical history into a target provider's view: provider-raw parts ride if and only if the target adapter's provider family matches the part's provider; everything else passes through untouched. The agent loop projects EVERY outgoing request (loop turns, finalize, extract), so per-role provider mixing inside one agent yields a valid wire history on each side.- Retention transport: adapters ship a turn's blocks-to-retain in stream order via
finish.providerMetadata[<adapter id>].retainedParts; the runtime lifts them into provider-raw parts at the HEAD of the turn's canonical assistant message.@rulvar/anthropicships thinking and redacted_thinking blocks (signatures intact, pause_turn continuations included);@rulvar/openaiships reasoning items with their encrypted_content. Retained blocks now actually reach the canonical history, survive checkpoints, and echo byte-exact to their own provider on every subsequent turn. ProviderAdaptergains an optionalproviderfield: the provider family for provider-raw matching (default = adapter id). The first-class adapters declare 'anthropic' and 'openai';openaiCompatiblegateways declare 'openai' whatever their custom id, so same-family adapters share retained blocks and projections.
Identity is untouched: projection state never enters content keys, and adapters that ship no retention payload (FakeAdapter included) produce byte-identical histories.
46ca98e: M4-T03 compaction ownership. The Agent Runtime owns compaction (
runtime/compaction.ts):- Compaction is ON by default for every agent at threshold 0.8 of the loop model's contextWindow (docs/06 Appendix A);
AgentProfile.compaction.thresholdadjusts it per profile. The context estimate is the last loop turn's inputTokens + outputTokens. - At a tool turn boundary past the threshold the summarize role fires through the resolution chain (falling back to the loop model when routing resolves no summarize model; the low role-effort default applies either way), and the transcript after the first message is replaced by one user-role summary message. The summarize request is projected like any other and carries the tool contracts with toolChoice 'none'.
- Compaction points (the turn numbers at which compaction fired) ride every checkpoint and restore verbatim: a resumed run continues from the compacted history and never re-summarizes it. Full-journal replay stays free as before.
- A failed or empty summarize disables compaction for the rest of the run with a warning instead of failing paid work; budget and cancellation aborts propagate normally.
- Compaction is ON by default for every agent at threshold 0.8 of the loop model's contextWindow (docs/06 Appendix A);
8ae129e: M4-T04 failover and M4-T05 RetryPolicy under the journal.
- Transport RetryPolicy (
model/retry.ts): the Appendix A defaults (attempts 3; backoff 500ms x2 max 8000ms with equal jitter; retryOn transport, rate-limit, overloaded) now actually retry around every adapter.stream dispatch: loop turns, extract, finalize, and summarize alike. Retries live UNDER the journal: a retried-then-successful call is one journal entry with one usage total, one turn, and no lineage attempts (DEF-3). A provider retryAfterMs replaces the computed delay; task-class failures never retry by construction; stream-idle severance retries as transport-class. Configure per call (AgentOpts.retry), per profile, or engine-wide (defaults.retry). - Transport failover (
model/failover.ts):ModelChoice.fallbacksnow works. When a serving model exhausts its tries on a transport or rate-limit failure, the sticky chain advances to the next resolved fallback (per-phase, effort defaults and caps scrubbing re-applied per serving model). The content key hashes the REQUESTED spec, so a failover-served response replays for free; onlyservedByrecords the actual server (now surfaced on AgentResult and stamped on the terminal entry). Budget is explicitly excluded as a trigger. - The degenerate fallback field (
AgentOpts.fallback, docs/04 11.3): an agent-level second attempt on a stronger model when the terminal matcheson(error, limit, schema-exhausted), with exactly one journaled decision entry (decisionType: 'model.fallback') reused on resume, and the fallback attempt under its own content key. Cancelled, escalated, and budget outcomes never trigger it.
AgentResultgains the requiredservedByfield (additive for consumers reading results; literal constructions in tests need the new member).- Transport RetryPolicy (
d1c4525: M4-T06 versioned price table and M4-T07 per-provider concurrency keys.
model/pricing.ts:PriceTable { pricingVersion, models }configured viacreateEngine({ pricing }). The table wins over adapter-reportedcaps.pricing(a fallback only); unpriced models keep surfacing in CostReport, never as a silent zero. Engine-writtenmodel.fallbackdecision entries pin the activepricingVersionso replayed cost attribution is stable against later table bumps; a price update is a registry update with a version bump, never a caps refresh side effect (refreshCaps()remains the adapter-level caps path).model/concurrency.ts:KeyedLimiter, engine-scoped, configured viacreateEngine({ concurrency: { perProvider } })per adapter id. The Appendix A default stays unlimited: the per-run semaphore remains the only default bound and provider 429s ride RetryPolicy. When configured, every wire dispatch (retries and failover re-acquire) gates under its serving adapter's key, adapters throttle independently, and queueing surfaces as agent:queued telemetry with the provider key. There is deliberately no distributed cross-process limiter (docs/14).
b840aba: M4-T08 canonical effort completion and M4-T09 role quality floors.
- Effort semantics are complete: the role effort defaults and the per-adapter mapping tables (Anthropic passthrough including max, OpenAI max downmapped to xhigh and recorded in providerMetadata, provider none only via namespaced providerOptions) shipped earlier milestones; this change completes VISIBLE scrubbing everywhere it was still silent: the summarize invocation surfaces its scrubs at fire time and a failover takeover surfaces the fallback's scrubs the moment it starts serving. Scrubbed effort is never mapped into max_tokens.
- The effort-defaults-shift cassette is now RECORDED through the live runtime (docs/10 M4 gating row): the frozen v1 prefix, closed offline the way an operator would, resumes live under explicit high effort with the completed semantics; every v1 entry matches and the one new spawn carries canonical effort in v2 identity. The recorder output is pinned byte-for-byte by the frozen-drift suite and the fixture lock now covers 18 files.
- Quality floors (
model/floors.ts, M4-T09): per-role and per-declared-taskClass allow/deny lists supplied viacreateEngine({ floors }), enforced INSIDE the router at resolution, before any live call and before any journal entry, for every invocation the chain produces (primaries, failover fallbacks, and the summarize fallback alike).AgentProfile.taskClassdeclares the class; unclassified profiles see only byRole floors. A violation is a typed ConfigError. - The umbrella
rulvarpackage now ships floors opinions next to its strong routing defaults:recommendedDefaults.floorspins orchestrate and plan to strong named models. The core itself ships no named model strings, and the umbrella suite enforces that with a source scan.
0.4.0
Minor Changes
dfe03b5: M3-T11 gating cassettes and the v0.4.0 BREAKING release notes.
BREAKING (pre-1.0 convention, docs/12):
AgentStatusnow produces'escalated'at runtime andAgentResultcarries the optionalescalation: EscalationReportfield (present if and only if the status is escalated). This is the third kernel amendment of the replay predicate (escalated-replays-as-ok, DEF-1) whose table row shipped frozen in M2; the producers ship here. Migration: add anescalatedbranch to every switch overAgentStatus; consumers not adopting the protocol are advised to mapescalatedtolimit(paid partial work, output null, the report stays available for logs).isEscalatedandEscalatedResultare exported for narrowing. Status production stays gated by opt-in: workflows that never passescalationoptions cannot observe the new status at runtime.Cassettes: the DEF-1 live set (escalate-replay, crash-between-report-and-decision, flavor-b-timeout) is recorded through the live runtime and replayed strict; the M2 synthetic DEF-1 subset is re-recorded (memoize-classifier fully live; abandon-subtree through the kernel write APIs with a realistic escalated child report and an authorizing owner cancel decision; both re-record again with the orchestrator producers in M7). FakeAdapter gains fakeToolCalls and fakeWireError responder markers; replayRun gains the onEscalation pass-through so replay tests can prove the hook stays cold. The deliberate fixture regeneration updates fixtures.sha256 in the same change (the identity profile is UNCHANGED; this is the docs/10 M3-T11 ordered re-record, not an identity-pipeline revision).
d2089a7: M3-T02 turn-boundary checkpoints. The runtime writes a canonical-history checkpoint into TranscriptStore at every turn boundary where the loop continues (tool boundaries and schema re-prompts), at a deterministic ref derived from the dispatch seq; the terminal entry records checkpointRef. A dangling-dispatch resume (kill-and-resume) re-enters at the last boundary with zero re-paid turns, restored usage folds into the terminal exactly once, and an unreadable or unknown-format blob falls back to a full redispatch (tools stay at-least-once between execution and the checkpoint write). The blob format is engine-internal with a leading format byte; replayed agents recover their turn count from the checkpoint and re-emit tool:start/tool:end with the replay marker.
3f60234: M3-T07 terminal escalated status and EscalationProtocol producers (the BREAKING section for v0.4.0 rides the milestone release notes). Typed EscalationKind/EscalationReport/EscalationDecision/EscalationOptions; the escalate tool registers under escalation opt-in of either flavor through the same path as any tool (opting in changes toolsetHash by design) and is engine-intercepted after the permission chain. Status production is gated: without opt-in the escalate tool does not exist and 'escalated' is physically unproducible. Flavor A terminates the worker with a runtime-completed report (costToDate and salvage are never model-authored; the request schema rejects them; the full report is validated BEFORE append; usage/costUsd/turns/transcriptRef as for ok, output null). Flavor B suspends on the approval machinery with a journaled deadlineAt (explicit deadlineMs required); a live decision and the deadline timer race through the ResolutionArbiter first-closing-wins (timeout applies defaultDecision, default accept); dispose collects the worktree patch into salvage BEFORE destruction; the terminal escalated entry and the authoritative escalation-decision entry follow strictly after, with countsAgainstLimit derived once (true iff scope_bigger). Replays synthesize the byte-identical report with zero adapter calls and read the owner's decision from the decision entry (a crash between report and decision pays the decision live exactly once). In ctx.parallel an escalated child is a settled outcome that never aborts siblings; a plain value-form call opting in requires the onEscalation hook (ConfigError before any LLM call otherwise). The in-run minSpend gate (M3-T09) rejects early scope_bigger escalations with a bounded "keep working" re-prompt; scope_different and blocked_with_evidence are exempt and never debit the counter.
f668890: M3-T05 worktree isolation and M3-T06 openaiCompatible. GitWorktreeProvider implements the IsolationProvider seam: acquire creates a detached worktree from HEAD or a given ref (non-git host is a typed ConfigError), tools receive cwd inside the tree, collect() snapshots changed files and a binary patch, dispose removes the tree with keepOnError retention under the shared maxPinnedWorktrees cap (default 4). ctx.agent resolves isolation call-over-profile into spawn identity, stores the collected patch in TranscriptStore, and surfaces it as a kind 'patch' Artifact on AgentResult.artifacts and the terminal journal entry, so replays reconstruct artifacts with zero live calls; applying the patch stays with the caller. isolation 'readonly' is accepted as a declaration (its compiled deny rule ships with risk presets in M5).
@rulvar/openai gains openaiCompatible({ id, baseURL, apiKey?, caps? }) for Ollama, vLLM, and gateways: the Chat Completions dialect by construction, explicit ids so several endpoints coexist (duplicate id stays a ConfigError at createEngine), and the most conservative caps when unprobed (prompt-tier structured output, no parallel tools, no pricing; supplied caps merge over the floor).
16d7aa6: M3-T04 MCP ToolSource.
mcp(cfg)imports Model Context Protocol tools over stdio, streamable-http, or an in-process server instance (pinned SDK line @modelcontextprotocol/sdk ^1.29; the v2 migration is the logged post-M3 task M5-T10). tools/list is fetched with cursor pagination until exhaustion and cached per session; a listChanged notification invalidates the cache for subsequently spawned agents only (a spawn's toolset snapshot stays immutable). allow/deny filters apply to pre-prefix names with deny winning;prefixnamespaces collisions;approvalmaps to needsApproval per tool; host-suppliedrisklabels feed the permission presets. inputSchema becomes bare-JSON-Schema parameters (form 3); outputSchema validates structuredContent; isError maps to an error tool result surfaced to the model, never a protocol error; MCP tools hash version as absent, so provider-side contract drift re-keys new spawns by design.6513ce8: M3-T08 no-progress abort class and M3-T10 UsageLimits completion. The engine-defined detector implements the committed docs/06 Appendix A interim rule (N consecutive turns without tool calls or artifact deltas, N = 3, configurable via the new UsageLimits.noProgressTurns knob): the abort journals as the agent's terminal entry with status 'limit', the dedicated 'no-progress' class marker in the error payload (AgentResult.abortClass), and memoizeOutcome stamped by the ENGINE on the terminal entry, so it replays on every resume without a live rerun regardless of the user's dispatch-time memoize policy (the predicate's entry-read consults the terminal stamp first; docs/03 section 6.6 amendment). Tool-calling turns reset the streak: a working agent never trips. UsageLimits is complete: maxTurns, maxToolCalls, maxOutputTokensPerTurn, timeoutMs, streamIdleTimeoutMs, noProgressTurns, and the run-level deadline each independently produce their documented outcome, with per-limit tests including the memoized-limit replay/unmemoized rerun predicate integration. The M3-T09 minSpend gate gains the accumulation path test (scope_bigger passes once spend crosses minSpendUsd).
7dad493: M3-T03 permission chain and ask suspensions. The normative layered chain (hooks -> deny rules -> ask rules -> canUseTool -> terminal default) is the single approval surface for every tool dispatch; hooks run in deterministic registration order with modifiedInput substitution; rules never yield allow; an explicit canUseTool allow is decisive including over needsApproval; argv/domain rules and presets fail early until M5. Engine-wide defaults.permissions merges under profile permissions; inheritPermissions is carried as data for subagent spawning (mode c). An ask verdict journals a suspended approval entry (kind 'approval', identity {toolName, post-hook input}, agent child scope) together with the turn checkpoint; the run settles 'suspended' with the synthesized approval:<seq> key; RunHandle.resolveExternal validates { decision: 'allow' | 'deny' } and a denial surfaces to the model as an error tool result carrying the reason. An approval round-trip across process exit resumes the SAME turn: executed tool results are reused from the checkpoint, the resolved decision applies without re-suspension, and only post-approval turns are paid live.
2bbf180: M3-T01 tool system core plus the M3 entry-gate docs amendment.
tool()definitions over the three SchemaSpec forms with definition-time validation (name pattern, schema projection, recursive/remote ref rejection); the ToolSource SPI seam types (ToolDef, ToolRisk, ToolContext, ToolSourceSession); per-spawn toolset resolution with duplicate-name and executor fail-early ConfigErrors; toolsetHash derived from contracts only (editing an execute body never re-keys a journal, bumpingversiondoes) and wired into spawn identity; agent-loop tool dispatch with argument validation, bounded ModelRetry conversion, NonSerializableValueError surfacing, maxToolCalls expiry as terminallimit, and tool:start / tool:end telemetry. The docs/06 Appendix A knob "no-progress detector N" is committed at 3 consecutive turns without tool calls or artifact deltas (consumed by M3-T08).
0.3.0
Minor Changes
43444f6: M2-T11/T12: the executable store conformance kit and the M2 gating cassettes with frozen fixtures.
@rulvar/store-conformance ships its first real API: journalStoreConformance (A1 append atomicity, A2 total per-run order, A3 read-your-writes, A4 opaque payload with read-side-only normalization, meta separation, the golden fold-state fixture with a frozen reference hash, the decide-once oracle, and the abandon-derived-skip fixture) and leasableStoreConformance (typed LeaseHeldError on held acquire, monotonic fencing epochs, stale-epoch appends rejected and invisible, released leases fenced from renew and append, optional ttl/renew-cadence timing checks), plus registerConformance for Vitest/Jest and the stableStringify fold-state hasher. InMemoryStore and JsonlFileStore pass; deliberately broken stores (reordering, normalizing, tearing, fencing-less) fail loudly.
@rulvar/core kernel closes three DEF-1/DEF-4 gaps the cassettes gate: an abandon-covered hanging dispatch derives skipped instead of redispatching, abandon-covered operations contribute a zero ledger increment, the resume report lists covered entries as skipped (never orphaned), and an abandon over an already-resolved suspension folds to a noop with already_resolved (first-closing-wins per target, both closer kinds).
@rulvar/testing ships the M2 cassette suite over committed frozen fixtures: the DEF-1 synthetic subset (abandon-subtree, memoize-classifier, v1-journal-on-v2), the DEF-4 set (timeout-vs-live-race, class-decision-fanout, abandon-then-crash-then-resume, abandon-vs-resolution-race, offline-invalid-then-valid, double-abandon-idempotent), the DEF-6 six IDs (resume-v1-on-engine-v2, resume-v1-with-inserted-call, suspended-v1-resolves-on-v2, reject-version-too-old via deriverV0Synthetic, reject-version-from-future, effort-defaults-shift), the mandatory mixed-version scenarios (ordinal-space split, forward-cursor preference, cross-version resolution, the compatibility and never-pay-twice-through-upgrade lemmas), and KeyDeriver contract tests against the frozen v2 golden identities including the docs/03 worked example. Fixture regeneration is deliberate: scripts/record-m2-cassettes.mjs rebuilds, and CI write protection (scripts/check-frozen-fixtures.mjs plus fixtures.sha256) fails any fixture diff shipped without the explicit bump token (the hyphenated compound of hashVersion and bump) in a changeset.
279881b: M2-T05/T06: the hashVersion mechanism and the canonical replay predicate. Frozen KeyDeriver profiles (v2 current; v1 with the effort-stripping projection, round-1 disposition table, and foldDefaults), the per-engine deriver registry with extraDerivers validation as the only window extender, the side-effect-free compatibility scan raising JournalCompatibilityError with sub-codes and hints, versioned matching through the registry KeyRing (live calls projected DOWN, incomparable is a guaranteed non-match, keys memoized per call and version); the single canonical replayDisposition with the three kernel amendments (memoizeOutcome on task-class failures via classifyAgentError, abandon-derived skipped through the append-order AbandonFold with transitive child-scope coverage, escalated-replays-as-ok), version dispatch by the entry's own profile, and the invalidate/retry unpinning API. @rulvar/compat ships the extraDerivers plumbing plus the synthetic hashVersion 0 deriver (manually versioned 0.1.0 per the lockstep exemption).
9fd0966: M2-T03/T04: scoped forward-matching and the kinds/grammar freeze. The JournalMatcher (per-scope insertion-stable cursors, first unconsumed match wins, cache/never per-call modes, orphan reporting) integrated into the Replayer with seeded seq/ordinal spaces and the resume ledger fold; ctx.agent/step/now/random/uuid replay journaled results byte-identically with zero adapter calls, dangling running entries redispatch with the terminal referencing the original dispatch, and replayed lifecycle events carry replayed: true. Kinds registry v2 payload validators enforce the docs/03 shapes on engine-written entries; the scope grammar gains a parser with round-trip guarantees. The interim disposition is round-1; the full DEF-1 table plugs in with M2-T06.
24ebadf: M2-T07/T08: suspension machinery (DEF-4). Strict ResolutionPayload and AbandonPayload with the normative by-source mapping; the first-closing-wins ResolutionFold (schema validation at consumption against the schema pinned inside the suspended entry, invalid offline resolutions never close, abandon coverage with transitive child scope-prefix and the AbandonFold projection consumed by the replay predicate); the per-target FIFO ResolutionArbiter (classify, durable append, settle exactly once; losing attempts are journaled noops); rule O2 hard errors on forward or dangling refs; Replayer resolveSuspended/abandonBranch/suspensionState; ctx.awaitExternal (NO deadline in v1, duplicate key in scope is a typed error) with run outcome 'suspended' plus pending[] on quiescence; and RunHandle.resolveExternal returning ResolutionOutcome, validating live payloads BEFORE append and journaling nothing on InvalidResolutionError.
a1b35d3: M2-T09/T10: engine.resume under the run-to-definition binding contract (wf required for in-process runs, name mismatch is a typed ConfigError, body-hash mismatch warns loudly and proceeds; the compatibility scan runs strictly before any side effect; the resumed run seeds the budget from the ledger fold, re-emits open suspensions, and reports ResumePreview hits/misses/reruns/orphans plus invalid offline resolutions), the dryRun option (replay-strict matching: the first would-be-live call settles the run with the typed journal_miss error and zero live calls), and @rulvar/testing replayRun (tier 3: strict replay of any journal with JournalMissError on ANY live call; suspended journals finish suspended with zero live calls).
18a5821: M2-T01/T02 groundwork: JsonlFileStore (one JSON entry per line, the journal doubles as an event log; torn-trailing-line tolerance and repair for A1 atomicity; atomic temp-plus-rename meta replace; listRuns without payload parsing; mid-file corruption is a hard JournalOrderViolation) and the committed large-value soft warn threshold (262144 bytes, docs/06 Appendix A M2 entry gate) wired into the journal append path as a warning event, never an error.
0.2.0
Minor Changes
- c24228d: M1-T10/T11: the WorkflowEvent envelope and M1 catalog (per-run telemetry seq distinct from JournalEntry.seq, span hierarchy run > phase > agent), the per-run EventBus feeding RunHandle.events and on(), RunOutcome with exhausted-overrides-error precedence and the normative CostReport (byModel/byPhase/byAgentType/byRole, the all-zero orchestrator block, unpriced evidence); createEngine with per-engine registries and engine.run over the ScriptRunner seam; InProcessRunner with the dev-mode bare-Date.now/Math.random warnings; run cancellation (host signal, handle.cancel, run deadline) and RunMeta run-to-definition binding fields. The umbrella ships the minimal terminal progress renderer (renderProgress) and re-exports the core surface.
- c50871e: M1-T04/T05: journal write path and model router core. JournalEntry form with the kinds registry v2 and hashVersion (written as 2 from day one), IdentityInput records per spawn kind with content-key derivation (sha256 over RFC 8785 JCS; reproduces the docs/03 worked example byte-identically), the scope-path grammar, ordinal assignment, the per-run serialized append queue with the JSON-serializability check, the budget-ledger fold, JournalStore/LeasableStore/TranscriptStore SPI types, InMemoryStore (loud one-time resume-disabled warning) and InMemoryTranscriptStore; the per-engine adapter registry (duplicate adapterId is a ConfigError), strict ModelRef parsing, the per-invocation resolution chain with role effort defaults, CanonicalModelSpec canonicalization, visible caps scrubbing (effort and sampling parameters), and structured-output tier selection with the strict-compatibility predicate.
- 1af8fb9: M1-T01/T02/T03: L0 foundations. Wire contracts (Msg/Part with provider-raw, ChatRequest, the ChatEvent union with typed refusal finish outcomes, the Usage invariant, CanonicalId minting, cacheHint, canonical five-level Effort, the ModelSpec family declarations); the closed error taxonomy (RulvarError base, WireError projection, all named error classes, the AgentError value projection); SchemaSpec in its three forms with Out<S> inference, StandardJSONSchemaV1 projection (draft 2020-12 with draft-07 fallback), canonical schema derivation (JCS, local $ref inlining, annotation stripping), schemaHash/toolsetHash, and runtime validation via the vendored draft 2020-12 validator.
- 1fe0249: M1-T06/T07/T08/T09: agent runtime v1 (single subagent loop, structured output in three tiers with client validation and the bounded re-prompt, typed AgentResult with the ok/error/limit/cancelled/skipped vocabulary, ModelRetry declaration, UsageLimits with the normative merge and defaults, typed refusal handling, Usage-invariant verification at the adapter boundary); ctx primitives (defineWorkflow with the errorPolicy literal generic, ctx.agent overloads including result: 'full', ctx.parallel with Settled and abortSiblings semantics, ctx.pipeline with up to six stages and onItemError drop/throw/collect, ctx.step with useMemo-style deps keying, ctx.phase cost attribution, ctx.log, ctx.budget, and the deterministic now/random/uuid shims journaled as rand entries); the per-run FIFO semaphore scheduler; and the three-layer budget (admission reserves, the per-turn guard, the AbortSignal ceiling with usageApprox, immutable B0, BudgetExhaustedError thrown uniformly by every ctx primitive, run.dropped evidence for every silent loss).
- 5c4fc32: M1-T14/T15: @rulvar/testing tier 1 (FakeAdapter matching on agentType/label/prompt regex with a '*' fallback, honoring the selected structured-output tier, zero USD by construction; createTestEngine over the full real engine with recorded event streams; toHaveCalledAgent and toStayUnderBudget matchers at '@rulvar/testing/matchers') and the completed umbrella (re-exports of @rulvar/core and both first-class adapters, renderProgress, the umbrella-only recommendedDefaults strong model slots, the M1 exit-criteria example workflow, and the CI install smoke on packed tarballs). The core now populates the reserved providerOptions 'rulvar' telemetry namespace on every request (docs/04 section 1.8 as amended) and AgentResult carries errorMessage detail for journaled WireError fidelity.
0.1.0
Minor Changes
- f4e2be9: M0 repo bootstrap (v0.1.0, docs/10-implementation-plan.md section "M0"): monorepo scaffold on the committed toolchain (pnpm 11 workspaces with catalogs, TypeScript 6.0, tsdown, Vitest 4, ESLint 9 flat config, Turborepo 2, changesets fixed mode, npm trusted publishing), the docs/ canon as single source of truth, the L0 contracts skeleton in @rulvar/core, and the vendored dependencies (StandardSchemaV1/StandardJSONSchemaV1 types, the @cfworker/json-schema lineage validator subset, a first-party monotonic ULID). Placeholder scaffolds only: no public API ships in this release.
@rulvar/effects
1.252.0
Patch Changes
- Updated dependencies [3ccb6cf]
- Updated dependencies [52d807f]
- Updated dependencies [517ed00]
- Updated dependencies [a7e589d]
- Updated dependencies [76e95eb]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.251.0
Patch Changes
- Updated dependencies [e7e829c]
- Updated dependencies [5982be8]
- Updated dependencies [7c58fb2]
- Updated dependencies [b3e465a]
- Updated dependencies [c4e5d6a]
- Updated dependencies [c6fc3da]
- Updated dependencies [c6fc3da]
- Updated dependencies [0ae8b85]
- Updated dependencies [7932936]
- Updated dependencies [7932936]
- Updated dependencies [88da0ed]
- Updated dependencies [06c0e85]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.250.0
Minor Changes
- 565c13b: The @rulvar/effects package is born (RV4504, plan 45, rfcs/effects.md sections 4.4, 6, 8, 11): the effect adapter seam that cannot send without an attempt record (dispatch receives the seq of the attempt appended BEFORE the call), the provider capability matrix types, and the crash-window dispatcher whose recovery is licensed exclusively by provider-side fencing: the idempotency-key row re-dispatches under the same key and lets the provider dedupe, the conditional-create row leans on the unique natural key, the acceptance-closing row closes the ambiguous ATTEMPT identity (so the fresh attempt stays legal while the stale one is refused at the provider), and the 'neither' row quarantines every ambiguous window with the possible late stale send named in the record. From a revocation or expiry position recovery is reconcile-only on every row: a found receipt confirms (a revocation then opens the compensation decision path as a linked incident; an expiry opens none, because it bounds the grant, not the past), a closed negative cancels with the proof on the record, and anything unresolvable quarantines. Provider fakes enforce exactly the fencing their row claims, including the deliberately stalled predecessor of kill point 17, where elapsed time licenses nothing. In core, the
cancelled-before-dispatchlegality widens per RFC section 4.7 row 2 (every attempt provably failed also proves no effect) and the writer gainsrefresh(). Kill points 4, 5, 6, 7, 8, 14, 15, 17, 27, 28, 29 are pinned by tests. - c6d197b: The reconciler, the trust envelope, and the whole kill point kit (RV4505, plan 45, rfcs/effects.md sections 3.1, 7, 8, 9). The sweep makes "every intent deterministically reaches confirmed, compensated, or quarantined" true: crossing
reconcileByquarantines whatever state with the state recorded, receipt waits and attempt budgets quarantine on exhaustion, lookups are bounded SEPARATELY through journaledeffect_proberows (countable from the journal alone, crash-proof), pre-terminal conflicting receipts quarantine, and effect authorizations past their deadline refuse durably instead of waiting forever. Receipt verification runs a declared trust envelope: issuer identity, per-class content bindings, key validity windows, revocation from its time forward, and the host's signature check; every failure classifies unverified, which routes to unknown. The post-restore reconciliation (kill 25) quarantines provider effects the journal cannot reconstruct by name (or the whole range without authoritative enumeration), and a restoration epoch stays undispatchable until the neweffect_reconciliation_completedecision cites it. Section 9 telemetry folds effective dispositions (the compensated overlay included), pressure, duplicate classification, and open incidents. The kit exports all thirtyeffects.kill.*rows as named conformance checks parameterized by a store factory (ambiguous acks and restoration generations injected through delegating proxies, so any store qualifies), registered over the in-memory reference store in single-process posture and over the REAL sqlite and postgres stores in their own packages.
Patch Changes
- Updated dependencies [0e240b9]
- Updated dependencies [6fe585e]
- Updated dependencies [c5eb19c]
- Updated dependencies [565c13b]
- Updated dependencies [c6d197b]
- Updated dependencies [c9d9729]
- Updated dependencies [fed9db6]
- Updated dependencies [df9ed76]
- Updated dependencies [3020912]
- Updated dependencies [d8d598d]
- @rulvar/[email protected]
- @rulvar/[email protected]
eslint-plugin-rulvar
1.252.0
1.251.0
1.250.0
1.249.0
1.248.0
1.247.0
1.246.0
1.245.0
1.244.0
1.243.0
1.242.0
1.241.0
1.240.0
1.239.0
1.238.0
1.237.0
1.236.0
1.235.0
1.234.0
1.233.0
1.232.0
1.231.0
1.230.0
1.229.0
1.228.0
1.227.0
1.226.0
1.225.0
1.224.0
1.223.0
1.222.0
1.221.0
1.220.0
1.219.0
1.218.0
1.217.0
1.216.0
1.215.0
1.214.0
1.213.0
1.212.0
1.211.0
1.210.0
1.209.0
1.208.0
1.207.0
1.206.0
1.205.0
1.204.0
1.203.0
1.202.0
1.201.0
1.200.0
1.199.0
1.198.0
1.197.0
1.196.0
1.195.0
1.194.0
1.193.0
1.192.0
1.191.0
1.190.0
1.189.0
1.188.0
1.187.0
1.186.0
1.185.0
1.184.0
1.183.0
1.182.0
1.181.0
1.180.0
1.179.0
1.178.0
1.177.0
1.176.0
1.175.0
1.174.0
1.173.0
1.172.0
1.171.0
1.170.0
1.169.0
1.168.0
1.167.0
1.166.0
1.165.0
1.164.0
1.163.0
1.162.0
1.161.0
1.160.0
1.159.0
1.158.0
1.157.0
1.156.0
1.155.0
1.154.0
1.153.0
1.152.0
1.151.0
1.150.0
1.149.0
1.148.0
1.147.0
1.146.0
1.145.0
1.144.0
1.143.0
1.142.0
1.141.0
1.140.0
1.139.0
1.138.0
1.137.0
1.136.0
1.135.0
1.134.0
1.133.0
1.132.0
1.131.0
1.130.0
1.129.0
1.128.0
1.127.0
1.126.0
1.125.0
1.124.0
1.123.0
1.122.0
1.121.0
1.120.0
1.119.0
1.118.0
1.117.0
1.116.0
1.115.0
1.114.0
1.113.0
1.112.0
1.111.0
1.110.0
1.109.0
1.108.0
1.107.0
1.106.0
1.105.0
1.104.0
1.103.0
1.102.0
1.101.0
1.100.0
1.99.1
1.99.0
1.98.0
1.97.0
1.96.0
1.95.0
1.94.0
1.93.0
1.92.0
1.91.0
1.90.0
1.89.0
1.88.0
1.87.0
1.86.0
1.85.0
1.84.0
1.83.0
1.82.0
1.81.2
1.81.1
1.81.0
1.80.0
1.79.0
1.78.0
1.77.0
1.76.0
1.75.1
1.75.0
1.74.0
1.73.0
1.72.0
1.71.0
1.70.1
1.70.0
1.69.0
1.68.0
1.67.0
1.66.0
1.65.0
1.64.0
1.63.0
1.62.0
1.61.0
1.60.0
1.59.4
1.59.3
1.59.2
1.59.1
1.59.0
1.58.0
1.57.0
1.56.0
1.55.0
1.54.0
1.53.0
1.52.0
1.51.0
1.50.0
1.49.0
1.48.0
1.47.0
1.46.0
1.45.0
1.44.1
1.44.0
1.43.0
1.42.0
1.41.0
1.40.0
1.39.0
Minor Changes
0cff035: Close the dynamic code generation parity gap in the planner sandbox dialect (v1.38.0 review P2-CODEGEN-PARITY).
compileScriptand therulvar/no-code-generationESLint rule now share one AST policy (scanDialect), so both reach the same decision for every statically visible constructor reconstruction form:.constructor,["constructor"], a computed key that folds to the constant,{ constructor: x }destructuring, andReflect.get(fn, "constructor"). The previous regex compile gate matched only the dotted form, so a bracket or computed key passed compile while the linter flagged some of them; moving to an AST also drops the regex false positives, where a property merely namedeval,Function, orconstructorwas wrongly rejected.A key assembled only at runtime (
fn[parts.join("")]) cannot be decided statically without rejecting every dynamic property access, so the worker realm now neutralizes the constructor reconstruction path at runtime by replacing theconstructorslot on all four Function family prototypes with a thrower. A script that compiles clean can no longer reach the Function constructor through a dynamic key.The planner and orchestration docs are corrected to state the exact boundary: the dialect rejects the statically visible forms and the worker neutralizes the runtime path, but a worker in the same process shares its intrinsics with the code it runs and remains a determinism and blast radius boundary, not a hostile code wall.
1.38.0
Minor Changes
- 3e2d591: Reject dynamic code generation in the planner sandbox dialect (v1.37.0 review SEC-P2).
compileScriptbannedimportbut noteval, theFunctionconstructor, or.constructoraccess, so a machine script could reach the Function constructor and compile a dynamic import the literal scan never saw, recovering the import allowlist and, throughnode:child_process, arbitrary host capability at run statusok.compileScriptnow rejectseval,Function, and.constructor(diagnostic idsno-eval,no-function-constructor,no-constructor-access); a newrulvar/no-code-generationESLint rule carries the same ban into theworkflowspreset and the self repair loop; and the worker additionally unbindsevalandFunctionas defense in depth. This keeps the import allowlist meaningful and the dialect consistent. It is not a hostile code boundary, which the sandbox has never claimed to be: JavaScript intrinsics can still reconstruct the constructors, so the docs continue to call the sandbox a determinism and blast radius boundary, not a security one.
1.37.0
1.36.0
1.35.0
1.34.0
1.33.0
1.32.0
1.31.0
1.30.0
1.29.0
1.28.0
1.27.0
1.26.0
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.0
1.19.0
1.18.0
1.17.0
1.16.2
1.16.1
1.16.0
1.15.0
1.14.0
1.13.0
1.12.0
1.11.0
1.10.0
1.9.0
1.8.0
1.7.0
1.6.0
Patch Changes
- da4dbad: Write the product name as Rulvar in prose: package READMEs, npm descriptions, and the documentation site now capitalize the brand. Identifiers keep their exact casing, so package names, the
rulvarbinary,rulvar.config.mjs, the.rulvarstore directory, therulvar.*OTel attributes, and every URL are unchanged. Documentation and metadata only; no runtime behaviour changes.
1.5.2
1.5.1
1.5.0
1.4.0
1.3.2
Patch Changes
- ddef383: Every published package now ships a README, so its npm page states what the package is, how it installs, and where the documentation lives (npm includes README.md in the tarball regardless of the files allowlist, so no manifest changes are involved; @rulvar/compat gains its README on its own next release). Alongside, the repository-level pages are refreshed to the current project state: the root README is rewritten around the never-pay-twice pitch with a runnable quickstart condensation and the full package table, CONTRIBUTING.md lists the complete PR gate set, the examples README drops retired-spec citations for live docs.rulvar.com links and documents the dogfood journal replay, and the pointer README gets the same treatment.
1.3.1
Patch Changes
- 7d1552e: Runtime message strings no longer cite the retired internal specification set: error and warning messages, validation issues, and the CLI help text drop the dangling
docs/NN, section ...references, pointing at https://docs.rulvar.com pages where a pointer earns its place (the CLI help header, tool naming, toolset registries, bare resume). The umbrella package description sheds the naming-contingency note: the unscoped alias is published and owned. Three strings embedded in frozen recordings stay byte-identical on purpose (the no-progress abort reason and two testing-internal recorder strings), as does the byte-locked golden-fold fixture. Test-file comments lose their citations too; test titles are unchanged.
1.3.0
1.2.0
Patch Changes
- 154507b: TSDoc and inline comments no longer cite the retired internal specification set (the pre-docs-site
docs/NN, section ...references). The citations either became links to the public documentation at docs.rulvar.com or were dropped where the comment already carried the rule; traceability markers (DEF-n, XF-nn, FR-nnn, OQ-nn, W-nnn) are untouched. Comment-only change: no runtime behavior, no API shapes, and no runtime message strings were modified; the frozen golden-fold fixture is byte-identical.
1.1.0
1.0.0
0.9.0
0.8.0
0.7.0
Minor Changes
- 4aaf2d5: M6-T03: the determinism rule set with structural JSON diagnostics (docs/06 8.4). Rules: no-bare-date (Date.now and new Date), no-bare-random (Math.random), no-fetch (bare and globalThis.fetch), no-process-env, no-promise-all-over-ctx (Promise.all/allSettled/race/any spawning ctx or bare sandbox calls; ctx.parallel instead), and the duplicate-identical-call advisory (byte-identical ctx.agent/ctx.workflow calls in one function forward-match to one journal entry; opts.key distinguishes deliberate repeats). Locally shadowed globals are never flagged. The flat preset
configs.workflowswires every rule at its intended severity, andtoJsonDiagnosticsprojects lint messages into the machine-readable shape the mode (b) self-repair loop consumes.
0.6.0
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
Minor Changes
- f4e2be9: M0 repo bootstrap (v0.1.0, docs/10-implementation-plan.md section "M0"): monorepo scaffold on the committed toolchain (pnpm 11 workspaces with catalogs, TypeScript 6.0, tsdown, Vitest 4, ESLint 9 flat config, Turborepo 2, changesets fixed mode, npm trusted publishing), the docs/ canon as single source of truth, the L0 contracts skeleton in @rulvar/core, and the vendored dependencies (StandardSchemaV1/StandardJSONSchemaV1 types, the @cfworker/json-schema lineage validator subset, a first-party monotonic ULID). Placeholder scaffolds only: no public API ships in this release.
@rulvar/evals
1.252.0
Patch Changes
- Updated dependencies [3ccb6cf]
- Updated dependencies [52d807f]
- Updated dependencies [517ed00]
- Updated dependencies [a7e589d]
- Updated dependencies [76e95eb]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.251.0
Minor Changes
- ba7e1e1: The shared contract audit lexer (RV4603, the seventh comparison experiment's P2.1). Every hand rolled comparison harness rediscovers the same two counting defects, and the seventh experiment's post audit shipped both: it counted
acceptance.minSpawnedChildren:4, a config property in citation clothing, as a citation occurrence, and recognized zero of the winning answer's 88 requirement ids because they were written as dash led list items instead of the colon form the counter expected; both texts carried the full N48/R24/C16 sets and the report recounted them by hand.lexContractAudit(text, options?)exports that recount as a grammar: the citation shape is the engine's ownDEFAULT_CITATION_PATTERNwith the citation audit's range tail semantics, fenced code strips by default via the sharedstripFencedBlocks, a citation must name a known source file extension (DEFAULT_CITATION_EXTENSIONS) and, under a supplied pure snapshotresolve, must resolve its first line; refused spans land inrejectedwith reasons instead of disappearing. Requirement ids accept the colon, dash and table notations as one vocabulary with per occurrence forms and DISTINCT per family counts. On the seventh experiment's frozen records the lexer reproduces the corrected numbers exactly: 292/276 for the winner with the one property notation rejected, 145/128 for the candidate, 48/24/16 on both sides in both notations. Probes pin the extension gate, the one vocabulary, the fence strip, and the range tail.
Patch Changes
- e7e829c: The negative scenario citation convention (plan 47 B1..B3): a hypothetical is never a line fact. The orchestration guide gains a section with the paste-ready composer block (cite the DEFENSE the scenario attacks, mark the scenario as inference), the profiles guide carries the census evidence the mandate question waited for (sample buys honesty, census buys completeness; the floor still does not require the census), the audit section documents its own surface (
auditScopecensus, the RV4706 output cap guard, the RV4707 truncated unit extension), and regression fixtures pin what the convention buys from the deterministic layers: the genre form is lint silent by design, the convention form lints clean, a moved defense line convicts with line suggestions, and the contract audit lexer keeps every count over the rewrite. No runtime change. - Updated dependencies [e7e829c]
- Updated dependencies [5982be8]
- Updated dependencies [7c58fb2]
- Updated dependencies [b3e465a]
- Updated dependencies [c4e5d6a]
- Updated dependencies [c6fc3da]
- Updated dependencies [c6fc3da]
- Updated dependencies [0ae8b85]
- Updated dependencies [7932936]
- Updated dependencies [7932936]
- Updated dependencies [88da0ed]
- Updated dependencies [06c0e85]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.250.0
Patch Changes
- Updated dependencies [0e240b9]
- Updated dependencies [6fe585e]
- Updated dependencies [c5eb19c]
- Updated dependencies [565c13b]
- Updated dependencies [c6d197b]
- Updated dependencies [c9d9729]
- Updated dependencies [fed9db6]
- Updated dependencies [df9ed76]
- Updated dependencies [3020912]
- Updated dependencies [d8d598d]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.249.0
Patch Changes
- Updated dependencies [8862133]
- Updated dependencies [0d7a717]
- Updated dependencies [e4428bd]
- Updated dependencies [d6873c1]
- Updated dependencies [4092e8d]
- Updated dependencies [e086590]
- Updated dependencies [1411938]
- Updated dependencies [737d1ee]
- Updated dependencies [634f966]
- Updated dependencies [052cc26]
- Updated dependencies [bbae134]
- Updated dependencies [67a8d72]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.248.0
Patch Changes
- Updated dependencies [8d0cd69]
- Updated dependencies [81065e4]
- Updated dependencies [8573f20]
- Updated dependencies [95f6a5e]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.247.0
Patch Changes
- Updated dependencies [1933ecc]
- Updated dependencies [db0a5f0]
- Updated dependencies [b698726]
- Updated dependencies [48348d2]
- Updated dependencies [4cfa1cc]
- Updated dependencies [4b7197a]
- Updated dependencies [5ebc842]
- Updated dependencies [16ff6b9]
- Updated dependencies [0c9941d]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.246.0
Patch Changes
- Updated dependencies [d165b0c]
- Updated dependencies [d59f4a0]
- Updated dependencies [46907ac]
- Updated dependencies [9929ad3]
- Updated dependencies [1790a6a]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.245.0
Minor Changes
- dee6db4: The workflow answers for its own repairs (RV4002, the fifth comparison experiment). The run paid for exactly one repair (a coordination draft rejected by three validators, healed by a sectional resubmission, one more wire at $0.186) and every terminal aggregate answered truthfully for its own stage while no surface answered for the workflow: the independent judge rebuilt the count from the raw transcript and the repair wire's money drowned in 'coordination'. The exported
repairLedgerFromJournalfolds the workflow-wide ledger ({ draft, composition, semantic, total }plus one row per granted repair with its stage, verdict seq, failed validators, spliced sections, and the repair wire's ref and price when the billing lane covered it); the acceptance envelope carriesrepairscomputed by the same fold over the run's own snapshot, so live and post-hoc agree by construction. The draft gate journals its voice (orchestrator_draft_gateon rejection and on the healing sectional acceptance), finish-validation decisions carry theirstageand spliced markers, and the granted repair turn's own wire is stampedphase: 'repair'(ProviderCallRecord.phase), which all three byPhase folds split out of the hosting dispatch's bucket.rulvar cost-auditprints the ledger when the journal proves one, byte parity otherwise; pre-RV4002 journals fold withunstagedVerdictsnamed, a floor, never a guess; clean runs keep every byte (all 61 frozen fixtures verify unchanged). Kit:coordination-draft-repairpins the experiment's exact shape ({ draft: 1, composition: 0, semantic: 0, total: 1 }, the gate decisions, the stamped wire) andsectional-repair-roundpins the semantic round's ledger; four mutation probes pin the wire stamp, the gate's journal voice, the round count, and the CLI line. journal-shape-revision: the wire-levelphasestamp is an additive journal evolution, and the frozen cassettes whose flows contain a refused finish exchange are re-recorded under it. - b85c113: The coverage grade becomes a gate under a declared policy (RV4003, the fifth comparison experiment). The run's claim pass covered 54 of 74 citing sentences, graded itself 'partial' honestly, MET its own declared 0.72 coverage target at 0.7297, and the run still shipped three unsupported citations inside exactly the uncovered fraction: every ratio floor held and none of them binds the grade.
claimConsistency.coveragePolicy: 'strict-final'refuses acceptance typed when the FINAL pass's grade is anything but 'full' (partial, vacuous, critical-uncovered, judge-declined, judge-failed alike), unless the declaredwaiver { principal, reason, expiresAt? }stands: the waived acceptance journals aclaim_coverage_waiveddecision and carriesclaimCoverageWaiveron the envelope verbatim beside the meta, so a non-full grade on a strict run always names who accepted it and why; an expired waiver refuses exactly like none. The default 'observed' keeps every existing byte; the policy requires stage 'final' or 'both', and a waiver without the policy is a ConfigError. Kit:strict-coverage-policydrives both arms (the typed refusal and the journaled waiver); probes pin the gate and the expiry; the orchestration guide names the doctrine ("0 findings" was never "semantically verified" without its denominator) and the doctrine-pin gate now requires it. - bc556e7: The citation entailment audit (RV4004, the fifth comparison experiment): the independent judge's method, internalized. The run's built-in verification judged VALUES (cited-value), TARGETS (citation-targets), and CONSISTENCY (the claim pass, child readings against draft claims), and the shipped answer still carried three citations whose cited lines do not entail the sentences citing them, every one mechanically valid, value-clean, and invisible to a pool that held no reading of those files (20 of 74 citing sentences had no candidates at all; child-against-final pairing can never cover them).
citationAuditruns over the FINAL document: a deterministic stratified sample (per H2 section, seeded from the audited document's own hash, replay-stable, capped), excerpts read through the host's pure snapshot resolver (thecitedValueValidatorchannel; a citation whose first cited line does not resolve is unsupported mechanically), one bounded judge invocation rulingsupported | partial | unsupportedper sampled citation. The envelope carriescitationAuditMetaandcitationFindings;onFound: 'report' | 'fail' | 'repair'decides the consequence, with'repair'riding the RV3307 bounded round (one more composition carrying the findings, a fresh audit from the repaired document's new hash, a configured claim pass rejudging the rewritten document, survivors failing typed; arming it beside the claim round is a ConfigError, one bounded round per run). The declaredjudge.estCostenters the RV4001 acceptance-tail formula on both the runtime gate and preflight (citationAuditmirror on the preflight orchestrator spec), one pass or two, with the round composition and the claim rejudge priced. Kit:citation-entailment-auditdrives the flagship shape (the unsupported citation caught, the supported control clean, the armed fail typed); three probes pin the mechanical unresolved verdict, the fail gate, and the round's re-audit. - 19bcea0: The pre-wire provider intent (RV4006, the fifth comparison experiment's P0.5). Receipts journal after a wire settles, so the wire most exposed at a crash is exactly the one being paid for: between dispatch and receipt, a death leaves money the journal never heard about.
defaults.billingReceipts: 'intent'journals aprovider-intentdecision before every dispatched wire attempt (awaited, the executor ledger's intent-before-effect rule: a failed intent append refuses the dispatch), keyed by dispatch seq, ordinal, and attempt, carrying the serving model, role, and a sha256 request fingerprint; receipts stay awaited as under'awaited'. An intent with neither a receipt row nor a settled terminal covering it is a wire with UNKNOWN outcome: the exportedopenWireIntentsOffold names them, the invoice carries theopenIntentslane (no invented dollars),rulvar cost-auditprints it, and a resume that finds one refuses the blind retry typed untilResumeOptions.acknowledgeOpenWireIntents: trueis passed, which the new segment journals asopen_wire_intents_acknowledged. Dispatch stays at-least-once with attempt binding; the default'async'and'awaited'postures keep every byte. Kit:wire-intent-unknown-outcomedrives the reconstructed crash window through both resume arms; probes pin the quota-arm intent, the resume gate, and the receipt closure.
Patch Changes
- Updated dependencies [b4d47a8]
- Updated dependencies [dee6db4]
- Updated dependencies [b85c113]
- Updated dependencies [bc556e7]
- Updated dependencies [9f11d29]
- Updated dependencies [19bcea0]
- Updated dependencies [60b461c]
- Updated dependencies [61e3a1a]
- Updated dependencies [a156b81]
- Updated dependencies [0bd7045]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.244.0
Minor Changes
- 38d839a:
RunOptions.budgetPolicy: 'segment' | 'immutable-lifetime'(RV3902, the fourth comparison experiment): the regulated posture the docs used to promise by accident is now a real, opt-in invariant. Default'segment'is today's behavior byte for byte. Under'immutable-lifetime'the posture is recorded inRunMetaat genesis (only the non-default is written; the store conformance kit holds stores to the round-trip) and restored on every resume, and a resume carrying ANY applyingResumeOptions.runoverride refuses with a typedConfigErrorbefore ownership, meta writes, or any append, raising and lowering alike; the emptyrun: {}object stays the documented no-op, a bare resume stays a pure replay, and a store that drops the field degrades to'segment'(the door works again), never to an invented refusal. The fault kit gains thebudget-policy-immutablescenario (typed refusal, zero wires, zero durable mutations, bare replay intact); two mutation probes pin the refusal gate and the genesis recording. The source TSDoc sweep retires the lastimmutable after startcomments (engine, budget, termination, orchestrate, plan), and the docs doctrine pins now scandocs/apitoo. - 4fa23e3: The verdict lineage on the acceptance envelope (RV3904, the fourth comparison experiment): the run's terminal read
findings: 0over a lineage whose first judge pass had caught a real contradiction, and only the journal could say so. Under the armed claim repair round,claimConsistencyMetanow carriespasses,firstPassFindings(when passes exceeds 1), andsemanticRepairRounds, so a repaired verdict is distinguishable from a clean first one on the envelope; absent fields mean NOT RECORDED (no round armed, or an older journal), and the mechanicalrepairsUsedkeeps its byte contract untouched. Beside it, the acceptance envelope gainsdeterministicPatches(the RV3801 machine-patch aggregate: accepted decisions, total patches, the last patch's canonical before/after hashes), derived from the same journaled finish decisions the patches live on, so live and resumed envelopes agree by construction. The sectional and deterministic-patch kit scenarios pin the lineage and the aggregate; two mutation probes pin the pass count and the envelope block; the observability guide documents what zero findings does and does not mean. - c894a43:
budget.acceptanceReserve: 'warn' | 'require'(RV3907, the fourth comparison experiment): preflight has long priced the acceptance tail and warned (reserve-line-headroom,orchestrator-working-room), and the experiment's run started anyway with both warnings on record. Under'require'the declared acceptance tail (the heldsynthesisReserveUsd, the claim judge'sestCosttimes one plus the armed semantic repair round, the declaredfinishValidation.estRepairCostUsd, and the armed round's declaredsynthesis.estCostcomposition floor) plus one coordination turn floor must fit the effective cap at exact fill or better, or the run refuses with a typedOrchestratorCapConfigErrorBEFORE the first wire, journaling anacceptance_reserve_refuseddecision that names every term. Undeclared estimates contribute zero, so the gate binds exactly what the host declared; the default'warn'keeps today's behavior byte for byte. The fault kit gainsacceptance-reserve-refusal(typed refusal, zero dispatches, term-by-term decision); boundary tests pin exact fill as admission; one mutation probe pins the gate. - 23fd0e0: The stale-doctrine corpus class and the proactive sectional reminder (RV3909, the fourth comparison experiment). The corpus gains
stale-doctrine-echo: a draft echoing a DOCUMENTED doctrine while the pool holds the diverging source fact, both sides cited, the experiment's decisive failure shape ("immutable after start" echoed from a guide six weeks stale into a pool that never carried the source side); the honest formulation naming the override door is pinned as a test-side control (the source-claim pairing is polarity-blind by design, and the exoneration belongs to the judge, who now holds both sides). The sectional repair round's prompt gains a deterministic evidence-discipline reminder (the experiment's rewritten section birthed two new evidence-grade offenders that the RV3801 patch then healed; a prompt line is cheaper than a healed failure), present only under the sectional block so every other prompt stays byte-identical; the kit's sectional scenario pins the line present in the round and absent from the initial composition. Two mutation probes pin the reminder and the class roster.
Patch Changes
- Updated dependencies [38d839a]
- Updated dependencies [ce13b0f]
- Updated dependencies [4fa23e3]
- Updated dependencies [6841c69]
- Updated dependencies [f56721d]
- Updated dependencies [c894a43]
- Updated dependencies [f6944a3]
- Updated dependencies [23fd0e0]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.243.0
Minor Changes
- 746d1f4: The finish loop performs the evidence-grade prescription host side (RV3801). The third comparison run died fail closed twice on one failure class: sentences in the graded register with no artifact, whose verdict already told the model exactly which sentences to fix and exactly which id to write; the initial composition spent the mechanical pool on it, and the repair round's candidate hit it again with nothing left.
evidenceGradeValidator, with the runtime'srunIdin hand, now attaches structured repair hints to its failure (FinishRepairHint: the offending sentence's exact offsets and bytes, and the prescribed insertion), and the finish loop, when EVERY failure of a string candidate carries hints, applies the edit itself: the id lands inside each offending sentence before its trailing terminator, every other byte stays identical, and the FULL validator set re-judges the patched document. A surviving patch is an accepted verdict with no provider wire and no repair spent; the decision journals it (deterministicRepair: before and after hashes, the patch windows, the healed failures), the healed failures still feed the HOST VALIDATION LESSONS block, and everything short of a surviving patch falls through to the ordinary model repair pool with the original verdict bytes. Masking is excluded by construction: the claim judge rules on the PATCHED document, so an inserted id can satisfy provenance mechanics but never protect a false claim from the semantic pass. The fault kit gainsdeterministic-provenance-patch(the adversarial arc on the real engine: a false positive production claim healed mechanically, then caught semantically, the lesson carried into the round), andvalidator-guidance-conflictnow pins the c3 trap healing in ZERO model repairs with the guidance bytes journaled on the healed verdict. - 009b29c: The convergence hold grows its mechanical leg (RV3802). RV3701 holds the repair round's verdict money and RV3602 gives the round its own mechanical pool, but the one repair turn that pool can grant was funded by nothing: the third comparison run's round entered exactly that turn's price short of certainty. The round now holds a second named leg beside the verdict money from the moment it is admitted, sized from the declared
finishValidation.estRepairCostUsdfirst (a new opt, refused typed unless a nonnegative finite number), else from the run's own observed last mechanical repair window (lastMechanicalRepairCostUsd, a new pure fold over the journal's synthesis candidates, which also gainspanSeqso the pairing never crosses invocations), else zero and inert. The leg joins the projected admission sum and both remainders (repairReserveUsdon the account state and view), a refusal names BOTH legs in its printed arithmetic, and the release is STAGED: the mechanical leg frees at the round invocation's first journaled finish verdict (a repair verdict is about to spend it on the granted turn; an accepted one never needed it), while the verdict leg lives until the judge dispatch as before. The fault kit gainsrepair-round-mechanical-reserve(the ceiling where the round could pay its composition and verdict but not the granted repair: pre dispatch refusal, both clauses named), and two mutation probes hold the admission sum and the staged release. - 1674cbe: The claim repair round is sectional when it can be exact (RV3803). The third comparison run's round regenerated the whole 43k character document to consume findings living in a handful of sentences, inside a tail that was 80.1 percent of the run's wall. The round now plans its repair before dispatching (
sectionalRoundPlan, exported): each judged finding's excerpt is located in the accepted pre-repair document through a collapse-aware scan and owned by the nearest H2 heading above it; when every excerpt locates and the markers are unique, the round's prompt retains the accepted document and asks for ONLY the target sections through the RV808b splice vocabulary, the host splices the resubmitted bodies into the retained document with every other byte identical, and the FULL validator set plus the final judge rule on the spliced whole. Mechanics refusals journal nothing and spend no repair; the model may still resubmit the full document; and every inexact plan (no headings, duplicated markers, an unlocatable excerpt, no finish contract) falls back to the FULL regeneration, byte for byte the historical round. The fault kit gainssectional-repair-round(byte identity of untouched sections, whole-document judging, no mechanical repair spent) andsectional-repair-round-fallback; two mutation probes hold the splice and the fallback. - 4e516f3: The claim corpus gains the three failure classes the third comparison experiment validated (RV3804).
bound-conflation: a draft lists opt-in caps and unconditional guards as one mode (the run's exact shape: the MCP byte and page caps beside the cursor guards), and the pool reading distinguishes the halves for the judge.derived-premise: a derived figure whose premise contradicts the declared input (2,000 slots computed from a 30 minute window where the input declares a 20 minute burst; the honest arithmetic is 1,333).cost-basis: a locally estimated total printed as the provider's bill, against a fact sheet naming the'locally-estimated'basis and the absence of any reconciled statement. Each case is a pure fold through the samepairDraftClaims/pairRunFactClaims/claimCoverageOflayers the orchestrator runs, forms judge-gradeable pairs with both polarities attached, and ships with an honest-formulation negative control that triggers nothing.
Patch Changes
- Updated dependencies [746d1f4]
- Updated dependencies [009b29c]
- Updated dependencies [1674cbe]
- Updated dependencies [bd096bc]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.242.0
Patch Changes
- Updated dependencies [6e3438e]
- Updated dependencies [ba5cf67]
- Updated dependencies [c2d1531]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.241.0
Minor Changes
- 4f832c4: The mechanical repair pool belongs to one composition invocation (RV3602).
finishValidation.maxRepairsused to count non accepted verdicts run wide, so the bounded claim repair round (RV3307) entered with zero mechanical retries whenever the initial composition had spent its own, and under the default bound of one its first regression was final by construction; that arithmetic is how the third comparison run died honest but unconverged with $1.42 of headroom left. The pool now restarts at each composition dispatch: the boundary is the journaled verdict count at dispatch (replay derives the identical index from the identical prefix, no new journal fields), the cycle 73 contract generation rule still applies on top, and validators bound to the coordination loop keep the run wide reading byte for byte, one loop being one invocation. Worst case stays bounded: at most two invocations (the initial and one repair round), each granting at mostmaxRepairsrepair turns; preflight's RV3402 working room term already prices the round at the declared synthesis reserve, which is the host's estimate of exactly one invocation with its repairs, and the RV2504 reserve tail sizing needs no doubling (comments and guide now say so). The fault kit gainsrepair-round-own-pool: the frozen third comparison sequence carried to the convergence the old pool made impossible, verdicts repair/accepted twice withrepairsUsedrestarting at the boundary. - 7452d3d: The bounded repair round keeps the lessons the run already bought (RV3603). The third comparison run's repair round regressed provenance, the exact failure class the initial composition's mechanical loop had fixed 18 seconds and $0.16 earlier, because the round is a fresh invocation with no memory of exchanges it never saw. The round's prompt now carries a
HOST VALIDATION LESSONS:block besideCLAIM CONTRADICTIONS:, folded only from the journaled finish validation failures of the current contract generation (validator names and reasons, deduplicated, journal order), so a resume re derives identical bytes. Present exactly when the prompt already carries judged findings and at least one rejected attempt exists: the initial composition predates any findings and a clean history folds nothing, so every existing prompt stays byte identical. Capped atFINISH_LESSON_CAP_CHARS(2000) with the dropped row count named, never silent. Therepair-round-own-poolkit scenario now also pins the lesson riding the round's prompt and absent from the initial composition's. - a4e22bf: The repair round's terminal names which death occurred (RV3601). The third comparison run's bounded repair round dispatched, paid two wires and produced a candidate its own finish contract rejected, and the terminal read
could not dispatchwithrepairsUsed: 0beside a null judge meta and null findings. A throw carrying theorchestrator_finish_validationsource is now its own class: the message names the dispatch and the host rejection, data carriesroundDispatched: true,repairsUsed: 1, the judge meta beside the findings, and the finish verdict facts verbatim underfinishValidation(the failed validators with reasons,candidateHash,candidateChars, mirrored from the decision the journal already holds; the typed finish failure itself now carries the candidate identity too). The true pre dispatch decline keeps its frame and gains the judge meta plusroundDispatched: false. The engine liftsclaimContradictionsonto RunOutcome, the journaled settle andrun:endbeside the meta, from the acceptance envelope or the typed error data alike, under the same defensive posture as the meta lift; the compact terminal envelope keeps the meta alone, itsfindingscount standing in for the details. The fault kit gainsrepair-round-host-rejectiondriving the arc end to end on the real engine.
Patch Changes
- Updated dependencies [dbcdd24]
- Updated dependencies [7ae7243]
- Updated dependencies [4f832c4]
- Updated dependencies [7452d3d]
- Updated dependencies [a4e22bf]
- Updated dependencies [82df4af]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.240.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.239.0
Minor Changes
- d3568b6: The fault kit drives the post fan in tail arc (RV3403). The 2026-08-12 comparison run settled
ok/completeover a finding its own final judge had named, and the fixes that followed shipped with unit suites but no kit scenario ever drove the arc end to end on the real engine. Three scenarios close that:repair-round-honesty(the final judge finds, the findings ride one more composition, the re-judge clears it, the settled envelope reports the repaired document as the judged one, two compositions and two final judge passes in the journal, the invoice in the same denominator),repair-survivor-refusal(the re-judge still finds: typed failure withrepairsUsed: 1and two distinct document hashes, never a silent ok), andclaim-judge-dead-armed-refusal(a judge that dies on the wire under'fail'and under'repair'fails the run typed with the armed posture named, one composition paid, no round dispatched). Probe: the-kit-actually-drives-the-repair-round.
Patch Changes
- Updated dependencies [74ce99a]
- Updated dependencies [ccd0665]
- Updated dependencies [0c5ce21]
- Updated dependencies [0616934]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.238.0
Patch Changes
- Updated dependencies [cf00947]
- Updated dependencies [c7b9382]
- Updated dependencies [88aea96]
- Updated dependencies [6da8d05]
- Updated dependencies [eae5c4c]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.237.0
Patch Changes
- Updated dependencies [3b987a1]
- Updated dependencies [9d6a279]
- Updated dependencies [49a98f6]
- Updated dependencies [a734ca0]
- Updated dependencies [deb406f]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.236.0
Patch Changes
- Updated dependencies [26306ea]
- Updated dependencies [709b942]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.235.0
Patch Changes
- Updated dependencies [ba4e10d]
- Updated dependencies [e30687f]
- Updated dependencies [172402b]
- Updated dependencies [2ecd787]
- Updated dependencies [e20a5e9]
- Updated dependencies [98c8691]
- Updated dependencies [c70def0]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.234.0
Patch Changes
- Updated dependencies [8420c04]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.233.0
Patch Changes
- Updated dependencies [48b5200]
- Updated dependencies [73bc32b]
- Updated dependencies [e63b743]
- Updated dependencies [ef45da7]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.232.0
Patch Changes
- Updated dependencies [1440410]
- Updated dependencies [6e467f4]
- Updated dependencies [6a58120]
- Updated dependencies [0b14293]
- Updated dependencies [e3bcab2]
- Updated dependencies [b55a0f7]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.231.0
Patch Changes
- Updated dependencies [4eb4b56]
- Updated dependencies [bc8f09e]
- Updated dependencies [ff9b8c2]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.230.0
Patch Changes
- Updated dependencies [e9bf910]
- Updated dependencies [57bfb38]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.229.0
Patch Changes
- Updated dependencies [3370342]
- Updated dependencies [2fb6656]
- Updated dependencies [edce170]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.228.0
Patch Changes
- Updated dependencies [4034fac]
- Updated dependencies [a54b085]
- Updated dependencies [9d0a9be]
- Updated dependencies [be9ef28]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.227.0
Minor Changes
f262e9f: The run's own id becomes an artifact the evidence grade accepts (RV2501).
evidenceGradeValidatordemands that alive-observed,provider billorproduction-provensentence name an artifact IN THAT SENTENCE, andDEFAULT_ARTIFACT_PATTERNonly ever matched apath:linecitation or a ULID behind the literal wordrun. Every other run id was therefore unnameable: the 1.226.0 comparison run carried the idcomparison-rulvar-v12260-aug09-1786272840549, its verdict told the synthesis to state that id, the pattern matched nothing it could write, and the run spent both granted repairs and failed closed on two sentences telling the truth about the run they were part of.FinishValidationInputnow carriesrunId, and the orchestrator runtime supplies it at every gate that judges a finish: the validator-bound finish, the contract draft gate, and theskipWhenDraftValidpre-pass. A sentence carrying that id verbatim as a whole identifier satisfies the grade, and the verdict NAMES the id it wants written, so the repair instruction is executable instead of aspirational while the RV2202 composition warning stands (a run id written beside apath:linecitation is not in the cited window and trades this failure for acited-valueone, so the graded sentence must carry no source citation). The intake is bounded like every sibling: an id shorter than six characters is ignored, because a two character id would satisfy nearly every sentence by accident, the same fail open the empty-pattern guard refuses; the id is credited only as a whole identifier, sox<id>yis never an artifact; and with norunIdsupplied the verdict is byte identical to the historical one. The same defect had a second half in the prompt: the opt-inRUN FACTS:line (RV1503) ends in thelive-observedregister, the composing model is told to reproduce run facts only from it, and the line named no artifact at all, so the engine was steering its own synthesis into a sentence its own default bundle refuses. The line now carriesrunIdin its JSON and readslive-observed by run <id>in the same sentence as the graded phrase, so quoting it faithfully passesevidenceGradeValidatorand, carrying no source citation, passescitedValueValidatorbeside it; a test asserts exactly that over the bytes the engine actually writes, with the id-less contrast asserted as the historical failure. The RUN FACTS line stays folded only from replay-stable material, so a resumed synthesis re-derives identical bytes; hosts that pin synthesis prompt bytes across engine versions should expect this line to have changed. Thevalidator-guidance-conflictfault scenario drives the new arm end to end: its corrected finish now carries the run's OWN id rather than a fabricated ULID, and the scenario asserts the repair exchange names that id verbatim beside the citation-free composition, so the guidance the fault kit gates is the guidance a run can actually execute.f191ff7: Identity spans are not asserted values (RV2502).
citedValueValidatorreads every non-citation inline span in a citing sentence as a value asserted about that citation, and the 1.226.0 comparison run showed the class that rule over-reaches: its synthesis wrote the frozen commit shaf8d9c5131c99c843ed23da22af20651f95377dd0beside source citations, and the verdict demanded the sha appear in the cited source, an impossible repair delivered in the same reason list as three real value fixes; both granted repairs burned and the finish was rejected. A span naming the artefact under review says which commit, run, or release the document is about and asserts nothing about any cited line. Three shapes are now structural and always excluded: a commit sha (12 to 64 hex characters, a floor low enough for every real abbreviation and high enough that ordinary hex literals likedeadbeefstay judged), a release version (1.2.3,v1.2.3, optional prerelease or build tail), and the run's own id when the runtime suppliesrunId, on the same six-character floor the evidence grade uses. Host vocabulary is declared rather than guessed: the newnotValuesoption lists the spans a document writes as identity, verdict words likeconditionally readyamong them, matched whole and case sensitively; a malformed list is aConfigErrorat construction. Nothing else relaxes, and a genuine value the cited line does not carry still fails in the very same sentence as an excused sha.The run-id exclusion makes the shipped bundle self consistent.
evidenceGradeValidatorinstructs a failing model to write this run's id inside the offending sentence (RV2501), and RV2202's warning existed because obeying that beside a citation traded an evidence-grade failure for a cited-value one, the trap that burned both repairs of the third subscription run. The two arms of the grade's reason now each name the composition that is TRUE for them: with the id in hand the graded sentence may carry a citation as well, and without one the older separation advice stands, because there the sibling has no id to recognise. Thevalidator-guidance-conflictfault scenario converges on the direct shape, the run's own id written beside the citation in the graded sentence, which neither validator could accept before.
Patch Changes
- Updated dependencies [f262e9f]
- Updated dependencies [f191ff7]
- Updated dependencies [fbbfbe8]
- Updated dependencies [263b5e8]
- Updated dependencies [db4d56d]
- Updated dependencies [41f93a9]
- Updated dependencies [98c8ca9]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.226.0
Minor Changes
- bef8621: The parity crash shapes become permanent fault-kit gates, and the telemetry target gets its honest boundary (RV2210). Three scenarios, zero paid calls, each driving a branch a parity run died on and asserting the documented typed observable, fail closed.
parity-reserve-line-redemption(RV2101): the coordination turn refused at spent + held synthesis reserve + proposed folds typed'budget-floor'and the held reserve then FUNDS the synthesis whose result rides the partial envelope; the scenario drives the same shape throughmakeOrchestratorWorkflowAND through the PlanRunner extension and demands the identical fold and the identical redeemed result from both, the DEF-7 redemption parity verified rather than assumed.resume-spawn-famine(RV2201): the kill-mid-fan-out journal resumes at the EXACT lifetime spawn cap to the finished dossier, recovered agents re-admitted but never re-counted, no cap decline journaled, only the unsettled workers re-paid.validator-guidance-conflict(RV2202): the c3 trap finish repairs in ONE round because the evidence-grade reason names the composition that cannot trip its cited-value sibling, with the guidance bytes asserted on the repair exchange itself. Docs truths ride along: the evals scenario list catches up (the RV2009 parity gates included), the observability guide gains the postFanInShare targeting rule (on clustered-settle profiles the share's overlap ceiling is the settle spread itself, so targetpostFanIn.coordinationModelMsandfinalCompositionMsabsolutes, with the subscription series' accepted-dossier baseline as the worked example), and the terminal contract names the RV2203 guarantee that failed terminals carry the same lifted facts.
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.225.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.224.0
Patch Changes
- Updated dependencies [4eca1a3]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.223.0
Patch Changes
- Updated dependencies [549aabd]
- Updated dependencies [549aabd]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.222.0
Patch Changes
- Updated dependencies [8326268]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.221.0
Patch Changes
- Updated dependencies [032ce93]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.220.0
Patch Changes
- Updated dependencies [0babe70]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.219.0
Patch Changes
- Updated dependencies [65a4ce7]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.218.0
Patch Changes
- Updated dependencies [088bda6]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.217.0
Patch Changes
- Updated dependencies [ab80b97]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.216.0
Patch Changes
- Updated dependencies [b357f4a]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.215.0
Patch Changes
- Updated dependencies [e1da4c7]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.214.0
Patch Changes
- Updated dependencies [c8af0ec]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.213.0
Patch Changes
- Updated dependencies [61680df]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.212.0
Patch Changes
- Updated dependencies [e6f8516]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.211.0
Minor Changes
- d5a8a36: The third parity rerun's crash shapes become permanent fault-kit gates (RV2009), zero paid calls.
parity-quiescence-deadlockdrives the exact terminal shape in miniature: the coordination turn eats the exposure cap, every worker is refused DRAINED (typedexposure-drained, zero provider attempts, RV2001/RV2002), the root forced-finishes partial (RV1902), and the gate asserts the exhausted terminal, the closed roster,run_settleafter every agent entry, one wire denominator, and no unsettled invoice lane (RV2003/RV2008); any revert reads matched:false.parity-sequential-roster-floordrives the seat-by-seat roster under an unreachable acceptance floor and asserts the FIRST seat's typedroster_floorrefusal with the whole-roster arithmetic journaled and zero paid children (RV2005). The docs truth pass lands the no-silent-exit invariant in the README and the design principles (no path ends the process while a run has no journaled terminal) and extends the observability denominator map with the RV2008 incremental lane and its settled boundary.
Patch Changes
- Updated dependencies [d5a8a36]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.210.0
Patch Changes
- Updated dependencies [c871ddc]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.209.0
Patch Changes
- Updated dependencies [514c7bb]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.208.0
Patch Changes
- Updated dependencies [e7d426f]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.207.0
Patch Changes
- Updated dependencies [99beee2]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.206.0
Patch Changes
- Updated dependencies [ec8e1f1]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.205.0
Patch Changes
- Updated dependencies [6d224da]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.204.0
Patch Changes
- Updated dependencies [efaec9b]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.203.0
Patch Changes
- Updated dependencies [fb08c10]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.202.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.201.0
Patch Changes
- Updated dependencies [7e01189]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.200.0
Patch Changes
- Updated dependencies [e2ddbdf]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.199.0
Patch Changes
- Updated dependencies [29891c6]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.198.0
Patch Changes
- Updated dependencies [c097c96]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.197.0
Minor Changes
- 4d0487e: The four-role benchmark's two defect shapes join the fault-injection kit as permanent gates (RV1905).
benchmark-primary-preflight-paritydrives the exact primary configuration ($6.00 ceiling, $4.50 orchestrator cap, $1.00 synthesis reserve, four workers at estCost $0.62) and matches only when the projection seats 2 of 4 with the synthesis hold and per-row held terms exposed and the roster shortfall namedadmission-below-roster-floor(RV1901).benchmark-recovery-root-exposuredrives the recovery arm's shape on the real engine with scripted adapters and zero provider calls: a root turn refused by the exposure cap beside live gated children parks and completes after a hold releases (RV1902), every child terminal precedesrun_settle(RV1903), and the terminal envelope and the invoice cardinality agree on the wire count (RV1904). Reverting any of the four fixes reportsmatched: falsehere, not only in the unit suites that shipped them.
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.196.0
Patch Changes
- Updated dependencies [ec9c3e3]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.195.0
Patch Changes
- Updated dependencies [5702a70]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.194.0
Patch Changes
- Updated dependencies [360a659]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.193.0
Patch Changes
- Updated dependencies [2bca1d1]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.192.0
Patch Changes
- Updated dependencies [8757601]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.191.0
Minor Changes
- 745387c: Enforceable coverage floors and two new corpus classes (RV1809). The claim pass graded itself honestly (RV1702) but nothing could enforce a floor:
claimConsistency.minimumCoverageRatioandrunFactCoverageRatio(each in(0, 1]) now declare the minimums,onLowCoverage: 'report'(default) stamps the machine-readablelowCoverageblock on the meta with each ratio beside its floor,'fail'fails the run typed BEFORE the judge dispatch exactly likeonUncoveredCritical, the meta additionally carriesrunFactCandidates(the uncapped matched count, so both ratios are computable from the meta alone, live or persisted), and--strictexits nonzero on a stamped block with the ratios printed. The adversarial corpus grows two classes from the nineteenth benchmark:modality-overclaim(a mitigation stated as an unconditional guarantee: the attestation "stops any tool drift" beside the pool reading naming the contract-hash boundary) andscope-ambiguity(child-only totals printed as whole-workflow figures), both forming pairs through the same pure folds.
Patch Changes
- Updated dependencies [745387c]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.190.0
Patch Changes
- Updated dependencies [8e02021]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.189.0
Patch Changes
- Updated dependencies [6a5cc2d]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.188.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.187.0
Patch Changes
- Updated dependencies [c9798ef]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.186.0
Patch Changes
- Updated dependencies [242647e]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.185.0
Patch Changes
- Updated dependencies [1248623]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.184.0
Patch Changes
- Updated dependencies [8a9caca]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.183.0
Patch Changes
- Updated dependencies [dd3767c]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.182.0
Patch Changes
- Updated dependencies [144d026]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.181.0
Minor Changes
- f794c11: The adversarial claim corpus ships as a regression gate (RV1704). The eighteenth comparison benchmark's three worst failures were semantic, and each rode straight past a green mechanical surface: "real models were not run" beside 125 recorded wire requests,
@rulvar/plandescribed through apackages/plannercitation, and a store default inverted in prose. A judge model can only rule on what the folds put in front of it, so the offline regression that matters is the precondition: for every named failure class, the deterministic layers must still form the pair, trigger on the run facts, prioritize the declared claim, and grade the coverage honestly.CLAIM_CORPUSpins that precondition as data, one adversarial case per class (live-fact,package-identity,inverted-default,numeric-range,negation,bounded-coverage), andrunClaimCorpus()executes every case through the same pure folds the orchestrator runs (pairDraftClaims,pairRunFactClaims,claimCoverageOf), no engine and no model, reporting per-case verdicts with the formed pairs attached for judge handoff. The shipped test asserts every case passes, so a change that stops forming any of these pairs fails the suite by case id instead of surfacing in the next paid benchmark. The corpus deliberately does not claim the pairs would be judged correctly: the pool excerpts ride every verdict so a host can adjudicate the semantic half with a real judge on their own budget.
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.180.0
Patch Changes
- Updated dependencies [b124d26]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.179.0
Patch Changes
- Updated dependencies [1a5a85a]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.178.0
Patch Changes
- Updated dependencies [e89f377]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.177.0
Patch Changes
- Updated dependencies [94db8ff]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.176.0
Patch Changes
- Updated dependencies [a74304d]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.175.0
Patch Changes
- Updated dependencies [1999c5d]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.174.0
Patch Changes
- Updated dependencies [aa9a772]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.173.0
Patch Changes
- Updated dependencies [67d27ac]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.172.0
Patch Changes
- Updated dependencies [0d4770b]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.171.0
Patch Changes
- Updated dependencies [f6116b9]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.170.0
Patch Changes
- Updated dependencies [86e4c06]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.169.0
Patch Changes
- Updated dependencies [623b2ae]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.168.0
Patch Changes
- Updated dependencies [ebba79a]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.167.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.166.0
Patch Changes
- Updated dependencies [d8262c3]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.165.0
Patch Changes
- Updated dependencies [6391274]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.164.0
Patch Changes
- Updated dependencies [9f2dda9]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.163.0
Patch Changes
- Updated dependencies [e8d9ada]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.162.0
Patch Changes
- Updated dependencies [2031e82]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.161.0
Patch Changes
- Updated dependencies [d4547b7]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.160.0
Patch Changes
- Updated dependencies [1c6f0d0]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.159.0
Patch Changes
- Updated dependencies [e881c8b]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.158.0
Patch Changes
- Updated dependencies [a266bc7]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.157.0
Patch Changes
- Updated dependencies [1883421]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.156.0
Patch Changes
- Updated dependencies [537144e]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.155.0
Patch Changes
- Updated dependencies [49b08a7]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.154.0
Patch Changes
- Updated dependencies [9259f24]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.153.0
Patch Changes
- Updated dependencies [d8bebcb]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.152.0
Patch Changes
- Updated dependencies [dd6a616]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.151.0
Patch Changes
- Updated dependencies [1de0610]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.150.0
Patch Changes
- Updated dependencies [a331211]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.149.0
Patch Changes
- Updated dependencies [08b4537]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.148.0
Patch Changes
- Updated dependencies [c85dac9]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.147.0
Patch Changes
- Updated dependencies [6367231]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.146.0
Patch Changes
- Updated dependencies [5d9bbc8]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.145.0
Patch Changes
- Updated dependencies [faf7d95]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.144.0
Patch Changes
- Updated dependencies [c11bcd6]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.143.0
Patch Changes
- Updated dependencies [f412169]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.142.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.141.0
Patch Changes
- Updated dependencies [4f12a62]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.140.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.139.0
Minor Changes
- 03a2141: The live budget debits each provider call marginally against the call's own accumulated price (RV1101): a long-context tier crossed by the call's sum that no single mid-stream slice reached now re-prices the whole call live at the crossing slice, exactly the dollars the settled fold records, and a ceiling between the per-slice and tiered readings severs the run instead of settling ok over its own hard cap.
RunBudget.openCallMeterand the optionalBudgetHooks.openCallMetercarry the seam (one meter per provider call, the settled fold's billing basis; the mid-stream deltas and the settle remainder of one call share one accumulation; a marginal debit never credits; the tier still never fires on a run aggregate no single call crossed). The fault kit gains thetier-crossing-live-parityscenario (RV1102), pinning both money paths and the marginal live ladder on the real engine.
Patch Changes
- Updated dependencies [03a2141]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.138.0
Minor Changes
ed0c4fb: Pre-wire continuation reservation, the self-describing fault kit, and the run-id surface (RV1013 + RV1014, PR VII closing the fourteenth plan)
- Pre-wire continuation admission (RV1013, opt-in). Post-hoc settlement is accounting, not admission: a hard provider RPM cap needs each
pause_turncontinuation reserved BEFORE its egress. Withquota: { reserveContinuations: true }the engine admits every provider-side continuation through the new adapter-sideStreamHooksseam (ProviderAdapter.streamgains an optional third parameter; the Anthropic adapter honors it): under a 2-request window the third wire of one absorbed dispatch never leaves and the denial rides the provider-429 machinery verbatim, the main settlement stops re-adding individually admitted segments (the window is never double-counted), and a granted admission whose wire never left is RELEASED back to the window through the new optionalQuotaLimiter.release(reservationId)(implemented bymemoryQuotaLimiter; a release returns exactly what admission consumed, and unknown or expired ids are no-ops). Adapters unaware of the hook keep the documented post-hoc semantics byte for byte, and the default stays post-hoc. The midstream-versus-finish usage confirmation now fires only when a finish CLAIM exists: an error-terminal absorption (a segment denial, a transport cut) no longer manufactures an invariant violation that shadows the real wire error. - The self-describing kit (RV1014).
runFaultInjectionrefuses an emptyonlyselection typed (a gate that runs zero scenarios used to reportallMatched: true), and the report carriesrequestedandselectedcounts so the gate can never quietly shrink. The audit scenario grows the RV1007 arcs (a page-only long-context tier and aNaNscalar are findings, never silent passes), completing kit coverage of every real defect of the fourteenth plan on its real path. - The run-id boundary surface (
assertSafeRunId,MAX_RUN_ID_LENGTH) is now exported from@rulvar/core, so hosts can pre-validate ids beforeengine.run.
- Pre-wire continuation admission (RV1013, opt-in). Post-hoc settlement is accounting, not admission: a hard provider RPM cap needs each
Patch Changes
- Updated dependencies [ed0c4fb]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.137.0
Patch Changes
- Updated dependencies [96f6788]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.136.0
Minor Changes
aa6ca71: A superseded segment refuses green everywhere: typed SupersededError, the distinct settledReason on run:end, and exactly one authoritative successor (RV1009, PR V of the fourteenth plan)
The fencing design swallowed a superseded segment's
LeaseHeldErroron both settlement writes, so a stale segment whose settle bounced off the successor's fence resolvedokwith an unmarkedrun:end: a green terminal that no durable store wrote, exactly the split view the RV907 doctrine forbids.- The stale segment now rejects
handle.resultwith the typedSupersededError(codesuperseded, not retryable,data { runId, runStatus }, cause the fencing rejection): the successor owns settlement, and the authoritative outcome is its settle or the store's run meta, never the stale computation. The meta write is skipped instead of re-proving the fence. run:endrefuses green withsettled: falseand the distinctsettledReason: 'superseded'(an l0-compatible extension), so an event-only consumer can tell a superseded segment from a settlement write failure; the settlement-failure path and every ordinary terminal keep their exact bytes.- A meta-only lease bounce over an already durable settle stays swallowed: the journal records the outcome, and only the projection belongs to the current holder (the takeover no-op contract is unchanged).
- The CLI progress line renders
settled=false (superseded; the successor owns settlement)instead of the resume hint, and the OTel exporter stampsrulvar.run.settled_reasonbeside the refused span status. runFaultInjection(@rulvar/evals) grows the nineteenth scenario,superseded-terminal-honesty: the fenced-out segment must reject typed with the distinct reason and zero settle entries, and the successor must settleokby replay with exactly one settle entry and no second paid call.
- The stale segment now rejects
Patch Changes
- Updated dependencies [aa6ca71]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.135.0
Patch Changes
- Updated dependencies [cf75e22]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.134.0
Minor Changes
cb50ea0: An internally contradictory statement refuses typed at intake, totals decide beside components, and the reconciliation states the settlement-grade predicate first class (RV1005 + RV1006, PR III of the fourteenth plan)
The fourteenth comparison experiment fed
reconcileStatementan export row carryingusd: 100beside a component split summing to 1 and read verdictmatch: each claim sat inside its own tolerance and nothing compared them to each other, because the presence of components suppressed the totals comparison entirely. The same review showed that amatchverdict is a weaker claim than settlement needs: an export can cover every KNOWN row to the cent while a usage-unknown attempt still holds unattributed money.- Intake internal consistency (RV1005): a request row carrying both
usdand acomponentsUsdsplit must have them agree withintotalToleranceUsd, else it refuses with a typedConfigErrornaming the row; an export whose own total contradicts its own components is not evidence. - Totals decide beside components (RV1005): a split's presence no longer suppresses the totals comparison. It decides exactly when both sides' dollar claims cover the same set (every matched export row carries
usdin requests mode; nothing statement-only and every component line claimed in categories mode; no covered model unpriced), so a total drifting beyondtotalToleranceUsdreadsdivergenceeven while every component line sits inside its own tolerance, and a scope mismatch stays the coverage machinery's business instead of manufactured divergence. StatementReconciliation.settleable(RV1006): the settlement-grade composite first class, true exactly when the verdict ismatchAND coverage is complete AND no row settledusageUnknownAND no model went unpriced. A safe consumer no longer assembles that predicate by hand.runFaultInjection(@rulvar/evals) grows the eighteenth scenario,statement-settleable-guard: a REAL run whose first attempt dies before any usage report seeds a genuine usage-unknown ledger row, the clean export over it readsmatchwith complete coverage yetsettleable: false, the clean twin readssettleable: true, and the contradictory row refuses typed at intake. Reverting any of the fixes reportsmatched: falsein the kit.
- Intake internal consistency (RV1005): a request row carrying both
Patch Changes
- Updated dependencies [cb50ea0]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.133.0
Minor Changes
2659f54: A legitimate pause_turn survives the engine end to end, and an invalid continuation cap refuses typed before the first wire (RV1003 + RV1004, PR II of the fourteenth plan)
The fourteenth comparison experiment drove the real Anthropic adapter through the real engine and a legitimate two-segment
pause_turnkilled the run: every segment'smessage_startemitted its own usage mid-stream (5 then 6), the terminal finish carried only the LAST segment's counts, and the engine's midstream-versus-finish invariant read 11 > 6, losing the paid segments from the money. The same experiment fedpauseTurnMaxContinuations: NaNand the cap silently disarmed (continuations > NaNis always false), turning every further continuation into unplanned paid traffic.- The terminal finish now speaks for the WHOLE logical turn (RV1003): the adapter accumulates each absorbed segment's normalized usage (
sumUsage, cache counts and the TTL split included) and the finish carries the sum, so the invariant confirms the per-segment mid-stream reports, the per-call record and the invoice price every paid segment, and the quota window still settles at true wire units. Mid-stream events stay per-segment deltas; a single-segment turn stays byte-identical.TurnMappinggains the segment's ownusage. pauseTurnMaxContinuationsmust be a nonnegative safe integer (RV1004): any other present value (NaN, Infinity, negatives, fractions, strings) refuses with a typedConfigErrorbefore the first wire, instead of silently disarming the continuation bound.runFaultInjection(@rulvar/evals) grows the seventeenth scenario,pause-turn-real-adapter: the two-segment absorption through the REAL adapter and engine must settleokat usage 11/2 with both wire ids on the invoice row and the quota window at 2, and the NaN cap must refuse before any wire. Reverting either fix reportsmatched: falsein the kit.
- The terminal finish now speaks for the WHOLE logical turn (RV1003): the adapter accumulates each absorbed segment's normalized usage (
Patch Changes
- Updated dependencies [2659f54]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.132.0
Minor Changes
2bec904: Live-budget parity for the cache-write TTL split, and the fault kit gates it on the real live path (RV1001 + RV1002, PR I of the fourteenth plan)
The fourteenth comparison experiment reproduced a hard-ceiling breach: a run with
budgetUsd: 4settledokat $4.50, because the mid-stream usage inlet, the reported/remainder fold, and every usage aggregate droppedcacheWrite5mTokens/cacheWrite1hTokens, so the live ledger priced a differentiated cache write at the plain 5m rate ($3.75) while settlement priced the split ($4.50). The two money paths now read one provider usage identically:- The mid-stream cleaner and the finish remainder carry the TTL split to the live debit, so the layer-3 ceiling holds against the same dollars settlement records; a ceiling between the unsplit and split readings severs the run instead of letting it settle
okover the ceiling. @rulvar/coreexportssumUsage, the canonical usage adder: aggregates (the run outcome, the settled ledger fold, the budget telemetry,reduceInvocationTablebuckets) keep the split they were billed under, and an undifferentiated side's writes count as the 5m share so mixed aggregates stay canonical under the split-sum invariant.- Mid-stream TTL counts the finish total does not confirm are a usage-invariant violation, loud like every other telemetry anomaly; per-field catch-up over a shifted attribution only ever overcharges, never credits.
runFaultInjection(@rulvar/evals) grows a sixteenth scenario,ttl-live-budget-parity: a mid-stream differentiated write against the real engine must debit live and settle to the same $4.50, keep the split on the aggregate, and refuse to settleokunder a $4 ceiling. Reverting the fix reportsmatched: falsein the kit, not only in the unit suite that shipped it.
- The mid-stream cleaner and the finish remainder carry the TTL split to the live debit, so the layer-3 ceiling holds against the same dollars settlement records; a ceiling between the unsplit and split readings severs the run instead of letting it settle
Patch Changes
- Updated dependencies [2bec904]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.131.0
Minor Changes
256cae1: The thirteenth plan's probes become permanent gates, and the three moneys get their vocabulary (RV909, RV910; closes the thirteenth plan).
runFaultInjectiongrows eight fail-closed scenarios driving the plan's fixed defects end to end on the real engine, zero provider calls and zero keys:nan-statement-refusal(unsummable statement dollars refuse typed at reconciliation intake, never verdictmatchover NaN totals),token-mismatch-divergence(provider-reported counts that disagree with our recorded usage decide the verdict even when the dollars agree, withtokenComparison: 'informational'still the declared opt-out),audit-missing-field-finding(the documented-rates comparator fails closed in both directions),anthropic-1h-priced(the shipped Anthropic table prices the 1h cache-write share at the documented 2x-input premium under its pinnedpricingVersion, on the per-call reconciliation ledger where the TTL split lives),pause-turn-units(continuations absorbed into one dispatch settle at true wire units across the quota window, the invoice row's segment set, and the all-or-nothing statement join, with a partial segment set readingpartial-coverage, neverno-overlap),pre-admission-count-refusal(a spawn the budget could never admit refuses before thecountTokensegress, so the full child prompt never leaves the process),forced-finish-completion(a budget-capped adaptive orchestration settlesokwith the honest completion envelope mirrored onto the outcome), andsettlement-terminal-honesty(a failed settlement write rejects typed withsettled: falseonrun:end; the healed resume re-settles by replay with zero live calls). Reverting any of the fixes now reportsmatched: falsein the kit, not only in the unit suite that shipped the fix. To reach those surfaces@rulvar/evalsgains@rulvar/openai,@rulvar/anthropic, and@rulvar/planas dependencies.@rulvar/corepublishescompareRates(with itsDocumentedRatesinput type), the both-directions documented-rates comparator the weekly audit runs: moved from the audit script to a published home so the kit can drive it as a gate, with the script importing the same function from dist inside its entrypoint exactly like the seeds, one source of truth. And the pricing docs now name the three moneys of one run in one place: recorded money (settled history under thepricingVersionpins its own settles wrote, the numberCostReport,rulvar inspect, and the invoice's pinned rows show), the docs estimate (repricing at the current table, whatpreflightEstimateprojects and the invoice prints past the pins), and the provider bill (established only byreconcileStatementover saved exports, never by a dashboard headline), plus the rate-update order: audit, then release, then new pinned runs.
Patch Changes
- Updated dependencies [256cae1]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.130.0
Patch Changes
- Updated dependencies [d6bec7a]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.129.0
Patch Changes
- Updated dependencies [1612439]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.128.0
Patch Changes
- Updated dependencies [27c4e38]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.127.0
Patch Changes
- Updated dependencies [b3b1805]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.126.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.125.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.124.0
Minor Changes
- 37fd1f2: The twelfth plan's closing trio (RV809, RV810, RV811). The tool budget extension gains
coverEvidenceDeficit: with an evidence contract declared, the extension grants at a tool-turn boundary whenever the remaining call budget cannot cover the declared floor's outstanding deficit, under the same money, progress, and maxExtensions gates, so a limited child at 7 of 11 entries converts headroom into the missing evidence BEFORE the cap instead of dumping through the reserved tail; the journaled grant decision carriestrigger: 'evidence-deficit'and the announcement names the exact deficit. Canonical Usage gains the optional cache-write TTL split (cacheWrite5mTokensandcacheWrite1hTokens, invariant: the split sums tocacheWriteTokens);priceUsdOfbills the 1h share atcacheWrite1hUsdPerMTokwith everything unclaimed at the plain write rate (byte-identical arithmetic without a split), sanitize repairs broken splits with 1h priority (never an undercharge), and the Anthropic adapter fills the split from thecache_creationbreakdown when it agrees with the flat total. @rulvar/evals gains the fault-injection kit:runFaultInjectiondrives the never-observed-live fail-closed branches (in-flight-exposure refusal, duplicate quota rule, torn and glued JSONL tails, the settle-boundary crash resume, pricing rotation with an uncovered tail, unknown provider id) on the real engine offline, verifies each documented typed observable fail closed, and leaves experiment-grade artifacts.
Patch Changes
- Updated dependencies [37fd1f2]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.123.0
Patch Changes
- Updated dependencies [5c46468]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.122.0
Patch Changes
- Updated dependencies [8cf45c5]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.121.0
Patch Changes
- Updated dependencies [3d67d41]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.120.0
Patch Changes
- Updated dependencies [d630c9e]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.119.0
Patch Changes
- Updated dependencies [1e4ff3c]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.118.0
Patch Changes
- Updated dependencies [f8341a3]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.117.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.116.0
Patch Changes
- Updated dependencies [a213878]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.115.0
Patch Changes
- Updated dependencies [63642ae]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.114.0
Patch Changes
- Updated dependencies [5759731]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.113.0
Patch Changes
- Updated dependencies [a60807a]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.112.0
Patch Changes
- Updated dependencies [00ae55b]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.111.0
Patch Changes
- Updated dependencies [fd25169]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.110.0
Patch Changes
- Updated dependencies [58afdb5]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.109.0
Patch Changes
- Updated dependencies [85b1d39]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.108.0
Patch Changes
- Updated dependencies [affa3d4]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.107.0
Patch Changes
- Updated dependencies [9f5f6f6]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.106.0
Patch Changes
- Updated dependencies [9a4ce49]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.105.0
Patch Changes
- Updated dependencies [531dc88]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.104.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.103.0
Patch Changes
- Updated dependencies [f2b809e]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.102.0
Patch Changes
- Updated dependencies [3eb6515]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.101.0
Patch Changes
- Updated dependencies [51b215c]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.100.0
Patch Changes
- Updated dependencies [9785bea]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.99.1
Patch Changes
- Updated dependencies [ef08d73]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.99.0
Patch Changes
- Updated dependencies [9e00888]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.98.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.97.0
Patch Changes
- Updated dependencies [5c3b453]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.96.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.95.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.94.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.93.0
Patch Changes
- Updated dependencies [c62150a]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.92.0
Patch Changes
- Updated dependencies [351d1f5]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.91.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.90.0
Patch Changes
- Updated dependencies [9603940]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.89.0
Patch Changes
- Updated dependencies [f18b671]
- Updated dependencies [f18b671]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.88.0
Patch Changes
- Updated dependencies [3b339d9]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.87.0
Patch Changes
- Updated dependencies [c4c02b1]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.86.0
Patch Changes
- Updated dependencies [2f71894]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.85.0
Patch Changes
- Updated dependencies [6932a9f]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.84.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.83.0
Minor Changes
- ca9cf6c: The deep review of the eval package (cycle 81), three fail-closed gaps in the measurement-to-belief pipeline.
runSweepMatrixno longer mints a claim from a cell containing a target that settled neither ok nor exhausted: an 'error', 'cancelled', or 'suspended' target is a measurement artifact, and a passRate deflated by a provider failure or a host cancellation could previously commit a false weakness through the eval-committer gate; such runs are now counted in the newnonOkRunscell field and suppress the claim exactly likeexhaustedRuns.runValueCheckpointmarks a cell or criterioncontaminatedwhen either A/B arm carried a measurement artifact (an envelope refusal, an incomplete row, a non-ok target): the arms are not comparable, the verdict can never pass, and criterion 1 fails withcontaminatedCellsreported; previously an envelope drained by the baseline left an empty refused treatment arm (n 0, cost 0) that mechanically beat any baseline under the cheaper-at-equal-quality branch, passing the gate on nothing.runBenchmarkends a series monotonically on a target-run envelope refusal (report.refusal, every completed repeat preserved) instead of throwing away the paid evidence, mirroring the eval suite's refusal contract; judge refusals keep rejecting their own run as 'judge:refused'. Also:renderCheckpointReportcounts recommended cells in its criterion 1 denominator instead of all cells (neutral cells are excluded from the majority), contaminated cells render marked, and the missing-rung error names the tier that is actually absent.
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.82.0
Patch Changes
- Updated dependencies [9cc5d66]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.81.2
Patch Changes
- Updated dependencies [296885b]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.81.1
Patch Changes
- Updated dependencies [c030982]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.81.0
Patch Changes
- Updated dependencies [ce4c392]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.80.0
Patch Changes
- Updated dependencies [262e397]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.79.0
Patch Changes
- Updated dependencies [85956ab]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.78.0
Patch Changes
- Updated dependencies [941b6e1]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.77.0
Patch Changes
- Updated dependencies [6aba271]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.76.0
Patch Changes
- Updated dependencies [22cba47]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.75.1
Patch Changes
- Updated dependencies [82bc0f0]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.75.0
Patch Changes
- Updated dependencies [c486de8]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.74.0
Patch Changes
- Updated dependencies [d94beab]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.73.0
Patch Changes
- Updated dependencies [3e95bd1]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.72.0
Patch Changes
- Updated dependencies [662e9e0]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.71.0
Patch Changes
- Updated dependencies [20d02e0]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.70.1
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.70.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.69.0
Patch Changes
- Updated dependencies [b21a681]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.68.0
Patch Changes
- Updated dependencies [b227874]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.67.0
Patch Changes
- Updated dependencies [8e6006d]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.66.0
Patch Changes
- Updated dependencies [1b8987e]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.65.0
Patch Changes
- Updated dependencies [0b6b859]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.64.0
Patch Changes
- Updated dependencies [991f9b5]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.63.0
Patch Changes
- Updated dependencies [8a28aed]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.62.0
Patch Changes
- Updated dependencies [fca5fd1]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.61.0
Patch Changes
- Updated dependencies [b4c1f1f]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.60.0
Patch Changes
- Updated dependencies [59bbeaa]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.59.4
Patch Changes
- Updated dependencies [c49d7a1]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.59.3
Patch Changes
- Updated dependencies [deaef36]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.59.2
Patch Changes
- Updated dependencies [dd0e10f]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.59.1
Patch Changes
- Updated dependencies [c127770]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.59.0
Patch Changes
- Updated dependencies [615dc90]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.58.0
Patch Changes
- Updated dependencies [4fa35ce]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.57.0
Patch Changes
- Updated dependencies [5897232]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.56.0
Patch Changes
- Updated dependencies [f26dba0]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.55.0
Patch Changes
- Updated dependencies [e9b005b]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.54.0
Patch Changes
- Updated dependencies [3f6bc03]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.53.0
Patch Changes
- Updated dependencies [b821bd1]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.52.0
Patch Changes
- Updated dependencies [e138df9]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.51.0
Minor Changes
11bf944: The reproducible benchmark kit (RV-213):
runBenchmark(engine, spec, options)turns one workflow into a citable measurement series and enforces the distinction a hand-rolled loop silently skips: a run that finished is not yet a run that counts.- Each of the spec's
repeatsruns sequentially and is verified by the replay-strict gate before it may score: a dry-run resume must replay it with zero misses and reruns, reproduce the journaled settle status and theoutputHashdigest, and raise zero workflow-provenance determinism warnings across the live and replayed streams. A non-reproducible run (a result mixing in bareMath.random(), an output JCS cannot hash, a diverged replay) lands in its record with machine-readablerejectedReasonsand stays out of the series. - Percentiles (
min/p50/p90/max/mean, nearest-rank, no interpolation) are computed over SCORED runs only for wall time, cost, and any named per-run metric extractor, and are absent entirely when nothing scored: the kit never fabricates a series. Wall time comes from each run's ownrun:start/run:endevent timestamps; the kit reads no clock. - Graders reuse the eval contract unchanged (golden, rubric, and LLM-judge graders compose as-is; judge runs stay journaled, budgeted, VCR-recordable, and blind: the judge sees the output and the rubric, never a system label, ordinal, or runId). A failing grader rejects the run; judge budget events normalize to
judge:refused/judge:exhaustedrejections with the spend counted. - The report carries every run's full record (runId for independent
rulvar replayre-verification, verification verdict with both digests, dispatch and invocation counts, per-run metrics), honest totals (totalCostUsdincludes rejected work), and aBenchmarkFingerprint: Node version, platform, arch, resolved rulvar package versions, the first run's start timestamp, and host-suppliedlabels(commit, pricing snapshot, corpus hash, cache series). The kit never shells out or guesses identity. SpendEnvelopecomposes exactly like the eval runners: every target and judge run authorizes its ceiling before starting; a target refusal throws typed, a judge refusal rejects that run.
- Each of the spec's
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.50.0
Patch Changes
- Updated dependencies [e39a885]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.49.0
Patch Changes
- Updated dependencies [bab7b2c]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.48.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.47.0
Patch Changes
- Updated dependencies [a3687fe]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.46.0
Patch Changes
- Updated dependencies [865e7bf]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.45.0
Patch Changes
- Updated dependencies [b96305d]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.44.1
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.44.0
Patch Changes
- Updated dependencies [299f7d2]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.43.0
Patch Changes
- Updated dependencies [71b7181]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.42.0
Patch Changes
- Updated dependencies [9b70f27]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.41.0
Patch Changes
- Updated dependencies [be589ec]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.40.0
Patch Changes
- Updated dependencies [cf33550]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.39.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.38.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.37.0
Patch Changes
- Updated dependencies [e6b1481]
- Updated dependencies [e6b1481]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.36.0
Minor Changes
- 101795b: Validate the CAS rebase
attemptsofcommitEvalMeasuredandflipStaleOnCanaryDriftas positive integers before the first store read (v1.35.0 review P2). Unvalidated, NaN or a nonpositive count skipped the loop entirely and surfaced the genericunreachableError instead of a typed refusal, while a fraction over ran by an attempt.
Patch Changes
- Updated dependencies [101795b]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.35.0
Patch Changes
- Updated dependencies [d4ac3bf]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.34.0
Patch Changes
- Updated dependencies [f1505ec]
- Updated dependencies [f1505ec]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.33.0
Patch Changes
- Updated dependencies [3f0f5e8]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.32.0
Patch Changes
- Updated dependencies [e366d64]
- Updated dependencies [e366d64]
- Updated dependencies [e366d64]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.31.0
Patch Changes
- Updated dependencies [df6b8f8]
- Updated dependencies [df6b8f8]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.30.0
Patch Changes
- Updated dependencies [87ce985]
- Updated dependencies [87ce985]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.29.0
Minor Changes
621d566: Validate eval thresholds before they can classify anything (v1.28.0 review P2).
rubricGradernow throws a typedConfigErrorat construction whenpassThresholdis not a finite fraction in [0, 1]; previously a negative threshold made every zero score verdict pass.runSweepMatrixvalidates its effective thresholds beforeengineFor, envelope reservation, or any provider and store activity: both bands must be finite fractions in [0, 1] withweaknessstrictly belowstrength, so the bands stay ordered and the uninformative mid band exists. Previously a reversed or out of range configuration turned a failing cell (pass rate 0) into a committed strength claim, which a connected ModelKnowledge store would then feed into routing as false knowledge.
Patch Changes
- Updated dependencies [621d566]
- Updated dependencies [621d566]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.28.0
Patch Changes
- Updated dependencies [d98eb0b]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.27.0
Patch Changes
- Updated dependencies [884a433]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.26.0
Patch Changes
- Updated dependencies [a4fc757]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.25.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.24.1
Patch Changes
- Updated dependencies [0bb14db]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.24.0
Patch Changes
- Updated dependencies [2b033e8]
- Updated dependencies [2b033e8]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.23.0
Minor Changes
1f9c272: PlanRunner spawn telemetry, the missing evals export, and the conformance kit's new meta field (v1.22.0 review P2-5, P2-6, P1-2).
@rulvar/plan: PlanRunner journals every admission INSIDE a carrying entry (decomposition rows in escalation decisions, ladder-verdict respawns, reuse and graft links, revision admissions) and emitted nospawn:admitted/spawn:rejectedat all; a live PlanRunner run with admitted roots showed an event count of zero. Every embedded admission row now announces through one formatter, identically on the live path and on replay absorb, withreplayed: trueon recovered rows,entryRefon the journaled carrying entry, andagentTyperesolved from the landed specs.@rulvar/evals:agentTypeRuleHoldsjoins the package root next torungRuleHolds, exactly as the v1.21.0 changelog had already announced; a public-API test now imports the checkpoint quartet from the root. The evals guide gains a full measured-value checkpoint section (ladder/pool/cell/arm vocabulary, both criteria, the vacuous-pass guard, cost discipline, a runnable example).@rulvar/store-conformance: the meta round-trip case now also pins the new optionalRunMeta.segmentsfield, which the engine bumps durably at every resume to keep eventseq/spanIdunique per run.
Patch Changes
- Updated dependencies [1f9c272]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.22.0
Patch Changes
- Updated dependencies [77b554f]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.21.0
Patch Changes
- Updated dependencies [7ee42a0]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.20.0
Patch Changes
- 9367030:
SpendEnveloperejects amounts at or above 2^49 micro-USD (about $562,949,953.42). The 4-ULP representation-noise window grows with magnitude and reaches half a micro-USD at that boundary, where the nearest integer stops being unique: a ceil debit could snap DOWN and admit an aggregate whose raw requests sum above the ceiling (the v1.19.0 review reproduced a sub-micro overshoot at a $570M cap). Out-of-domain caps and ceilings now throw a typedConfigErrorthat debits nothing. The class documents the exact input interpretation (a double within the noise window of an integer micro value IS that integer) and the honest raw-double bound (at most half a micro per admitted amount, the finest distinction double precision carries at the top of the domain); boundary and adversarial ULP-neighbor properties pin both. - Updated dependencies [9367030]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.19.0
Patch Changes
- 8cc9a9c:
SpendEnvelopedirected rounding survives dollar magnitudes and rejects out-of-domain amounts. The previous conservative-rounding fix snapped to the nearest integer micro-USD within a RELATIVE 1e-6 tolerance, which already reaches half a micro at $0.50 and turns directed rounding into round-to-nearest: two $0.5000004 authorizations (true sum $1.0000008) both fit a $1 cap, a $0.5000006 cap admitted a $0.500001 debit, and aNumber.MAX_VALUEcap overflowed toInfinitymicro where every authorization is admitted andremainingUsdisNaN. The snap window now scales with the ULP ofusd * 1e6, so only genuine IEEE-754 representation noise snaps (0.1 + 0.2 against a 0.3 envelope stays a fit) while real sub-micro fractions keep the conservative floor (caps) or ceil (debits), and after conversion both the cap and every ceiling must be safe integers in micro-USD (at most $9007199254.740991), rejected otherwise with a typedConfigErrorthat debits nothing. Property tests now cover dollar magnitudes and the domain edges. - Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.18.0
Minor Changes
943962d:
SpendEnvelopeis now provably conservative at the representation boundary. Nearest rounding on both the cap and the debits let any positive ceiling below $0.0000005 round to a zero debit, admitting an unbounded number of authorizations pastmaxTotalUsd. Accounting stays integer micro-USD, but the cap now converts down (floor), every debit converts up (ceil, minimum one micro-USD), and amaxTotalUsdbelow $0.000001 is rejected as aConfigError, so for any admitted sequence the sum of the original ceilings can never exceedmaxTotalUsdand no positive ceiling ever debits zero. Amounts that are integer micro-USD up to float noise stay exact (0.1 + 0.2 against 0.3 remains a fit). Migration: an envelope constructed with a sub-micro cap now throws instead of admitting everything, and sub-micro ceilings now consume a full micro-USD each.943962d: Sweep and suite reports are now monotone: paid evidence survives every budget refusal. Previously
runSweepMatrixcaught the envelope'sSweepBudgetErroraround a whole cell and replaced it with an emptyenvelopeExhaustedrow, erasing already completed targets and their cost; a judge refused by the envelope erased the paid successful target the same way; and a judge run that hit its own per-run ceiling threwEvalJudgeErrorout of the entire matrix, losing every accumulated cell.Now:
runEvalSuitereturns partial results withplannedN,completedN, and a typedrefusalmarker instead of throwing when the envelope refuses a target; a judge budget event (per-run ceiling exhaustion or envelope refusal) normalizes into the owningEvalCaseResultasincomplete: { reason: 'judge-exhausted' | 'judge-refused' }with the failing judge run's actual cost counted, while non-budget grader errors still throw;SweepCellReportgainsplannedN,judgeIncompleteRuns,incompleteReason, andrefusedRunLabel, and any incomplete cell (n < plannedN, exhausted targets, unfinished judges, or an envelope refusal) emits no claim;runCanaryrecords an envelope-refused probe asstatus: 'refused'and keeps walking, so completed probe evidence survives andallOkstays the drift-flip gate;EvalJudgeErrorcarriescostUsd. Thekb sweephuman renderer prints incomplete cells explicitly (INCOMPLETE: envelope refused ... after N of M case(s), unfinished-judge counts, refused-probe counts) instead of pretending nothing ran.Migration:
runSweepMatrixandrunEvalSuiteno longer throwSweepBudgetErrorfor refused targets or judges; readEvalSuiteResult.refusal,EvalCaseResult.incomplete, and the new cell fields instead. Cells now always carryplannedN.
Patch Changes
- Updated dependencies [943962d]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.17.0
Minor Changes
7909b6b: Budget surfaces for sweeps and the canary (the v1.16.2 review P1-2).
- New
SpendEnvelope(maxTotalUsd): the debit-only aggregate bound over a whole sweep. Every target, judge, and canary run authorizes its immutable per-run ceiling against it BEFORE starting (integer micro-USD accounting, so exact fits pass); a refusal throws the newSweepBudgetErrorbefore any provider work, and authorizations are never returned, not on completion, not on replay, not on CAS retries. runEvalCase,runEvalSuite, andrunSweepMatrixacceptenvelope; an envelope requires the matching per-run ceiling (budgetUsd, andjudgeBudgetUsdonce a grader judges), because an unbounded run under an aggregate envelope would be unaccountable.- Sweep cells now separate measurement from budget artifacts: a cell the envelope refused reports
envelopeExhausted, a cell whose target runs hit their own ceiling reportsexhaustedRuns, and neither emits a claim, so a budget-starved measurement can never become a false weakness belief about the model. - New
runCanary(engine, probes, { budgetUsd?, envelope? })returns{ fingerprint, allOk, probes }: each probe run carries the optional immutable ceiling, andallOkis the drift-flip gate, because a non-okprobe fingerprints differently without the model having drifted.canaryFingerprintstays exported (now accepting the same options) for fingerprint-only callers.
- New
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.16.2
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.16.1
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
1.16.0
Patch Changes
- Updated dependencies [5f76cf2]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.15.0
Patch Changes
- Updated dependencies [4aee1f3]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.14.0
Patch Changes
- Updated dependencies [6073226]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.13.0
Patch Changes
- Updated dependencies [c28c4c0]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.12.0
Patch Changes
- Updated dependencies [46edcc0]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.11.0
Patch Changes
- Updated dependencies [0c70c5e]
- Updated dependencies [0c70c5e]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.10.0
Patch Changes
- Updated dependencies [0e8d78e]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.9.0
Patch Changes
- Updated dependencies [7577f8e]
- Updated dependencies [3a53383]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.8.0
Patch Changes
- Updated dependencies [25724b5]
- Updated dependencies [57ea1de]
- Updated dependencies [7884ec5]
- Updated dependencies [52db30d]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.7.0
Patch Changes
- Updated dependencies [45285aa]
- Updated dependencies [2f20d1d]
- Updated dependencies [22f65a8]
- Updated dependencies [2ddfa29]
- Updated dependencies [2abd9c2]
- Updated dependencies [1c1175d]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.6.0
Patch Changes
- da4dbad: Write the product name as Rulvar in prose: package READMEs, npm descriptions, and the documentation site now capitalize the brand. Identifiers keep their exact casing, so package names, the
rulvarbinary,rulvar.config.mjs, the.rulvarstore directory, therulvar.*OTel attributes, and every URL are unchanged. Documentation and metadata only; no runtime behaviour changes. - Updated dependencies [da4dbad]
- Updated dependencies [487da86]
- Updated dependencies [df416fc]
- Updated dependencies [a737810]
- Updated dependencies [9eb66b4]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.5.2
Patch Changes
- Updated dependencies [54936a0]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.5.1
Patch Changes
- Updated dependencies [6c6d56f]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.5.0
Patch Changes
- Updated dependencies [4fba3c7]
- Updated dependencies [8655c0f]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.4.0
Patch Changes
- Updated dependencies [c4f563d]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.3.2
Patch Changes
- ddef383: Every published package now ships a README, so its npm page states what the package is, how it installs, and where the documentation lives (npm includes README.md in the tarball regardless of the files allowlist, so no manifest changes are involved; @rulvar/compat gains its README on its own next release). Alongside, the repository-level pages are refreshed to the current project state: the root README is rewritten around the never-pay-twice pitch with a runnable quickstart condensation and the full package table, CONTRIBUTING.md lists the complete PR gate set, the examples README drops retired-spec citations for live docs.rulvar.com links and documents the dogfood journal replay, and the pointer README gets the same treatment.
- Updated dependencies [ddef383]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.3.1
Patch Changes
- 7d1552e: Runtime message strings no longer cite the retired internal specification set: error and warning messages, validation issues, and the CLI help text drop the dangling
docs/NN, section ...references, pointing at https://docs.rulvar.com pages where a pointer earns its place (the CLI help header, tool naming, toolset registries, bare resume). The umbrella package description sheds the naming-contingency note: the unscoped alias is published and owned. Three strings embedded in frozen recordings stay byte-identical on purpose (the no-progress abort reason and two testing-internal recorder strings), as does the byte-locked golden-fold fixture. Test-file comments lose their citations too; test titles are unchanged. - Updated dependencies [7d1552e]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.3.0
Patch Changes
- Updated dependencies [7d1a287]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.2.0
Patch Changes
- 5ac56b4: Criterion 2 of the measured-value checkpoint gains the quality branch per the founder's OQ-09 amendment (2026-07-12): the card-informed arm passes by matching the baseline pass rate at no more than 105 percent of its cost, OR by beating it by at least 15 points at no more than 115 percent. The reopened gate measured plus 40 and plus 20 points at 107.9 and 106.6 percent: the baseline fails cheaply, so the flat cost bar tightened exactly when the card won on quality. The vacuous-pass guard stands unchanged; the rule now lives in the exported agentTypeRuleHolds next to rungRuleHolds.
- 154507b: TSDoc and inline comments no longer cite the retired internal specification set (the pre-docs-site
docs/NN, section ...references). The citations either became links to the public documentation at docs.rulvar.com or were dropped where the comment already carried the rule; traceability markers (DEF-n, XF-nn, FR-nnn, OQ-nn, W-nnn) are untouched. Comment-only change: no runtime behavior, no API shapes, and no runtime message strings were modified; the frozen golden-fold fixture is byte-identical. - Updated dependencies [3bfaec0]
- Updated dependencies [890f42c]
- Updated dependencies [154507b]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.1.0
Minor Changes
- 00f1ab5: M12-T01: the measured-value checkpoint harness (docs/05, section "Phases and placement"; the OQ-09 criteria).
runValueCheckpointexecutes the M12 gate as two A/B experiments under one fixed pool: criterion 1 (rung selection) runs every eval case per (ladder, taskClass) cell at the ladder's default start tier versus the tier recommended bycompileVerifiedLayerover the store's claims, judging each recommended cell by the OQ-09 rule (equal-or-better pass rate at 90 percent of the cost, or five points better at cost) with unrecommended cells neutral for the majority but included in the pooled aggregate; criterion 2 (agentType selection) runs the same orchestrate-role cases with and without the knowledge store and requires the card-informed arm to match or beat the baseline pass rate within 105 percent of its cost. The checkpoint passes only when both hold;renderCheckpointReportproduces the docs-ready record, and an unmeasured criterion 2 honestly counts as failed. The fixed mixed corpus (extraction, code-edit, judging; a seeded LCG keeps it byte-stable; the seed/eval split prevents leakage into the treatment arm) and the budget-guarded live Anthropic runner ship as repo scripts.
Patch Changes
- 63b2c01: Two defects the first live M12 checkpoint run surfaced. The Anthropic capability table lacked a Haiku 4.5 entry, so the dated id fell through to the current-generation default and the adapter sent adaptive thinking, which that model rejects with a live 400 (every haiku run died at zero cost):
claude-haiku-4-5(and its dated snapshots by the prefix rule) now resolves to the enabled-budget thinking form with real haiku pricing, meaning the default wire omits thinking entirely. And the checkpoint's criterion 2 could pass vacuously when both arms scored zero at zero cost (zero satisfies "at least equal at no more cost"): the card-informed arm must now win something real (nonzero n and pass rate) before the criterion can hold. - 42050b5: The checkpoint's orchestrated arms take their own suite options (
orchestratedSuite, defaulting tosuite): the third live run showed the shared per-case budget starving the orchestrator cap math (a $0.10 run ceiling cannot host the default finalize reserve, so every orchestrate-role run died at OrchestratorCapConfigError before the first model call, at zero cost). - Updated dependencies [d16b04a]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.0.0
Minor Changes
6649e5f: M11-T01: the eval-committer identity activates eval-measured claims (docs/05, sections "Data model" and "Commit discipline", amended with the dedicated
eval-committerGateRecord variant, distinct from the v2-reserved eval-confirmed proposal auto-gate).- Commit validation is now GATE-DRIVEN and the coherence square is schema-enforced in both directions: an eval-committer-gated op MUST carry class eval-measured, author kind eval-pipeline, and the metrics block; a human-gated op MUST NOT carry any of the three (a human-authored op with metrics keeps rejecting). Observational data never carries metrics and never auto-promotes.
@rulvar/evalsships the pipeline side:evalMeasuredClaim(the docs/05 TTL table applied by polarity: strength 90 days, weakness 30) andcommitEvalMeasuredwith the documented CAS-rebase recipe against any ModelKnowledgeStore.
eaacdeb: M11-T02: matrix sweeps (docs/05, section "Grounding and decay").
runSweepMatrixmeasures a FIXED pool (workflow x model x taskClass; sweep volume is never authorized by proposal volume) through the ordinary engine, sequentially in declaration order for deterministic cassette consumption, and aggregates per (model, taskClass) cell.- Threshold-crossing cells emit eval-measured claims (strength at or above 0.9, weakness at or below 0.5 by default; the mid band emits nothing): typed statement templates, metrics {passRate, n, graderId}, EvidenceRef eval reports with the case ids, confidence from n, the docs/05 TTL table from observedAt, and deterministic report-scoped claim ids.
- With a store given, claims commit through the eval-committer identity (the M11-T01 gate); the sweep e2e records against fake adapters and replays hermetically from the cassette with zero live calls, byte-identical reports.
01d6b2d: M11-T04: modelEpoch capture and the canary fingerprint (docs/05, section "Grounding and decay"; OQ-06 CLOSED with the committed design).
- Core:
modelEpochOf/capsHashOfbuild the honestly coarse epoch signal (registry version, pricing version, caps hash; silent alias re-pointing stays a documented uncaught case absent probes). The ClaimOp union gainsmark_stale(docs/05 amended): section 6 requires status stale at fingerprint drift and the closed op set could not produce it; active flips to stale, already-stale is an idempotent noop, terminals never revive. - Evals:
canaryFingerprint(engine, probes)runs the FIXED caller-versioned probe set sequentially through the ordinary engine and hashes NFC-normalized, whitespace-collapsed outputs (the probe count prefixes the hash so probe-set edits never collide with drift).flipStaleOnCanaryDriftflips the model's active eval-measured claims whose recorded fingerprint differs, in one CAS-rebased command; claims without a baseline stay untouched. Sweeps stamp the epoch per pool member viamodelEpochFor.
- Core:
e679c6e: M9-T02: the @rulvar/evals base (docs/09 section 7; docs/11 "Eval CI"; FR-5xx). First real public surface of @rulvar/evals, built strictly on the public APIs (L6).
EvalCase = { workflow, args, graders[] }exactly as documented, withrunEvalCaseandrunEvalSuiterunners: the target workflow runs as its own journaled run; latency is derived from run:start and run:end event timestamps (no separate measurement channel); duplicate workflow names disambiguate by ordinal.- Three grader families:
goldenGrader(deep JSON equality with diff evidence),rubricGrader(named pure criteria, per-criterion verdicts, fraction score against a pass threshold), andjudgeGrader(an LLM verdict against a schema). The judge runs THROUGH the engine viaGraderContext.judgeas an ordinary journaled, budgeted invocation, so judge calls are VCR-recordable and eval CI replays them deterministically with zero live calls. @rulvar/evals ships NO default judge model: weak judge defaults are forbidden by the router quality floors, somodelis required. Judge invocations are skipped deterministically when the target run did not settle ok. runEvalMatrixcompares configuration cells (profile vs profile, cheap workers vs premium, reviewer on or off): each cell supplies its own engine and the report carries pass-rate, cost, and latency per cell from the existing usage and cost fields. No failure clustering, no vector dependency (EXC registry).- Acceptance held in-suite: a suite recorded through the VCR adapters replays byte-deterministically (latency excluded as the one wall-clock measurement) from the cassette under onMiss 'throw', and the cassette carries its hashVersion header (DEF-6).
Patch Changes
- Updated dependencies [0e0b569]
- Updated dependencies [b28b7a3]
- Updated dependencies [b53a89e]
- Updated dependencies [4454175]
- Updated dependencies [6599ca8]
- Updated dependencies [6649e5f]
- Updated dependencies [fd2f83b]
- Updated dependencies [01d6b2d]
- Updated dependencies [9a20dbb]
- Updated dependencies [0fbe7ea]
- Updated dependencies [ebe0abc]
- Updated dependencies [a3079d0]
- Updated dependencies [807d1f9]
- Updated dependencies [596a39b]
- Updated dependencies [464ab6e]
- @rulvar/[email protected]
- @rulvar/[email protected]
0.9.0
Patch Changes
- Updated dependencies [84f94d4]
- Updated dependencies [65c7b2c]
- Updated dependencies [a2a3243]
- Updated dependencies [ebc8101]
- @rulvar/[email protected]
- @rulvar/[email protected]
0.8.0
Patch Changes
- Updated dependencies [85d55cf]
- Updated dependencies [b88c9e3]
- Updated dependencies [f3c4613]
- Updated dependencies [a41c20f]
- Updated dependencies [f4e70be]
- Updated dependencies [75d1646]
- Updated dependencies [0627413]
- Updated dependencies [55c0f87]
- Updated dependencies [fd33871]
- Updated dependencies [e70e7f4]
- Updated dependencies [bc9c903]
- @rulvar/[email protected]
- @rulvar/[email protected]
0.7.0
Patch Changes
- Updated dependencies [fd1d06c]
- Updated dependencies [6fcf296]
- Updated dependencies [dcc97a9]
- Updated dependencies [434dc83]
- Updated dependencies [03173c1]
- Updated dependencies [11c0afc]
- Updated dependencies [10b45f1]
- @rulvar/[email protected]
- @rulvar/[email protected]
0.6.0
Patch Changes
- Updated dependencies [fa05007]
- Updated dependencies [9234dc8]
- Updated dependencies [638d9a1]
- Updated dependencies [644512c]
- Updated dependencies [8a41656]
- Updated dependencies [02f7f7a]
- @rulvar/[email protected]
- @rulvar/[email protected]
0.5.0
Patch Changes
- Updated dependencies [ac274f4]
- Updated dependencies [5735d92]
- Updated dependencies [46ca98e]
- Updated dependencies [8ae129e]
- Updated dependencies [d1c4525]
- Updated dependencies [b840aba]
- @rulvar/[email protected]
- @rulvar/[email protected]
0.4.0
Patch Changes
- Updated dependencies [dfe03b5]
- Updated dependencies [d2089a7]
- Updated dependencies [3f60234]
- Updated dependencies [f668890]
- Updated dependencies [16d7aa6]
- Updated dependencies [6513ce8]
- Updated dependencies [7dad493]
- Updated dependencies [2bbf180]
- @rulvar/[email protected]
- @rulvar/[email protected]
0.3.0
Patch Changes
- Updated dependencies [43444f6]
- Updated dependencies [279881b]
- Updated dependencies [9fd0966]
- Updated dependencies [24ebadf]
- Updated dependencies [a1b35d3]
- Updated dependencies [18a5821]
- @rulvar/[email protected]
- @rulvar/[email protected]
0.2.0
Patch Changes
- Updated dependencies [c24228d]
- Updated dependencies [c50871e]
- Updated dependencies [1af8fb9]
- Updated dependencies [1fe0249]
- Updated dependencies [5c4fc32]
- @rulvar/[email protected]
- @rulvar/[email protected]
0.1.0
Minor Changes
- f4e2be9: M0 repo bootstrap (v0.1.0, docs/10-implementation-plan.md section "M0"): monorepo scaffold on the committed toolchain (pnpm 11 workspaces with catalogs, TypeScript 6.0, tsdown, Vitest 4, ESLint 9 flat config, Turborepo 2, changesets fixed mode, npm trusted publishing), the docs/ canon as single source of truth, the L0 contracts skeleton in @rulvar/core, and the vendored dependencies (StandardSchemaV1/StandardJSONSchemaV1 types, the @cfworker/json-schema lineage validator subset, a first-party monotonic ULID). Placeholder scaffolds only: no public API ships in this release.
Patch Changes
- Updated dependencies [f4e2be9]
- @rulvar/[email protected]
- @rulvar/[email protected]
@rulvar/executor
1.252.0
Patch Changes
- Updated dependencies [3ccb6cf]
- Updated dependencies [52d807f]
- Updated dependencies [517ed00]
- Updated dependencies [a7e589d]
- Updated dependencies [76e95eb]
- @rulvar/[email protected]
1.251.0
Patch Changes
- Updated dependencies [e7e829c]
- Updated dependencies [5982be8]
- Updated dependencies [7c58fb2]
- Updated dependencies [b3e465a]
- Updated dependencies [c4e5d6a]
- Updated dependencies [c6fc3da]
- Updated dependencies [c6fc3da]
- Updated dependencies [0ae8b85]
- Updated dependencies [7932936]
- Updated dependencies [7932936]
- Updated dependencies [88da0ed]
- Updated dependencies [06c0e85]
- @rulvar/[email protected]
1.250.0
Patch Changes
- Updated dependencies [0e240b9]
- Updated dependencies [6fe585e]
- Updated dependencies [c5eb19c]
- Updated dependencies [565c13b]
- Updated dependencies [c6d197b]
- Updated dependencies [c9d9729]
- Updated dependencies [fed9db6]
- Updated dependencies [df9ed76]
- Updated dependencies [3020912]
- Updated dependencies [d8d598d]
- @rulvar/[email protected]
1.249.0
Patch Changes
- Updated dependencies [8862133]
- Updated dependencies [0d7a717]
- Updated dependencies [e4428bd]
- Updated dependencies [d6873c1]
- Updated dependencies [4092e8d]
- Updated dependencies [e086590]
- Updated dependencies [1411938]
- Updated dependencies [737d1ee]
- Updated dependencies [634f966]
- Updated dependencies [052cc26]
- Updated dependencies [bbae134]
- @rulvar/[email protected]
1.248.0
Patch Changes
- Updated dependencies [8d0cd69]
- Updated dependencies [81065e4]
- Updated dependencies [8573f20]
- Updated dependencies [95f6a5e]
- @rulvar/[email protected]
1.247.0
Minor Changes
- b698726: The first-party surface attests, and the floor loses its holes (RV4204, the sixth comparison experiment). Before this, only
mcp()and the AI SDK bridge exposeddescribeRegulatedPosture(), sounrecognized >= 1on nearly every real regulated compile and a zero-blind-spot floor was unsatisfiable by construction; and the floor checked toolset attestation only ondefaults.profiles, accepted legacy contract-only pins that pass authority drift silently, and never walked the executors at all. Now:anthropic()andopenai()attest their egress (official, acustom-base-urlwhose ORIGIN enters the hashed posture map, or apreconstructed-clientnamed honestly) plus the caps pagination bound;subprocessExecutor()andcontainerExecutor()attest their ledger, env allowlist, resolved ceilings, and isolation seam;compileRegulatedProfilewalksengine.executorsand the sandbox runner beside adapters and toolsets, wraps attested executors sorun()re-judges the posture at use (the RV4102 seam), refuses a regulated executor without aToolEffectLedgerby field name, refuses legacy contract-only pins (re-record withattestToolset()), and arms the new engine-widedefaults.requireToolsetAttestation, under which a spawn resolving a non-empty toolset with no pin binding it refuses typed at spawn time (the per-call-tools hole the profile pins could not see). The opt-inconstruction: 'require-recognized'compile floor turns the unrecognized count into a typed refusal naming the blind constructions, satisfiable now that the first-party surface attests.
Patch Changes
- Updated dependencies [1933ecc]
- Updated dependencies [db0a5f0]
- Updated dependencies [b698726]
- Updated dependencies [48348d2]
- Updated dependencies [4cfa1cc]
- Updated dependencies [4b7197a]
- Updated dependencies [5ebc842]
- Updated dependencies [16ff6b9]
- Updated dependencies [0c9941d]
- @rulvar/[email protected]
1.246.0
Patch Changes
- Updated dependencies [d165b0c]
- Updated dependencies [d59f4a0]
- Updated dependencies [46907ac]
- Updated dependencies [9929ad3]
- Updated dependencies [1790a6a]
- @rulvar/[email protected]
1.245.0
Patch Changes
- Updated dependencies [b4d47a8]
- Updated dependencies [dee6db4]
- Updated dependencies [b85c113]
- Updated dependencies [bc556e7]
- Updated dependencies [9f11d29]
- Updated dependencies [19bcea0]
- Updated dependencies [60b461c]
- Updated dependencies [61e3a1a]
- Updated dependencies [a156b81]
- Updated dependencies [0bd7045]
- @rulvar/[email protected]
1.244.0
Patch Changes
- Updated dependencies [38d839a]
- Updated dependencies [ce13b0f]
- Updated dependencies [4fa23e3]
- Updated dependencies [6841c69]
- Updated dependencies [f56721d]
- Updated dependencies [c894a43]
- Updated dependencies [f6944a3]
- Updated dependencies [23fd0e0]
- @rulvar/[email protected]
1.243.0
Patch Changes
- Updated dependencies [746d1f4]
- Updated dependencies [009b29c]
- Updated dependencies [1674cbe]
- Updated dependencies [bd096bc]
- @rulvar/[email protected]
1.242.0
Patch Changes
- Updated dependencies [6e3438e]
- Updated dependencies [ba5cf67]
- Updated dependencies [c2d1531]
- @rulvar/[email protected]
1.241.0
Patch Changes
- Updated dependencies [dbcdd24]
- Updated dependencies [7ae7243]
- Updated dependencies [4f832c4]
- Updated dependencies [7452d3d]
- Updated dependencies [a4e22bf]
- Updated dependencies [82df4af]
- @rulvar/[email protected]
1.240.0
Patch Changes
- @rulvar/[email protected]
1.239.0
Patch Changes
- Updated dependencies [74ce99a]
- Updated dependencies [ccd0665]
- Updated dependencies [0c5ce21]
- Updated dependencies [0616934]
- @rulvar/[email protected]
1.238.0
Patch Changes
- Updated dependencies [cf00947]
- Updated dependencies [c7b9382]
- Updated dependencies [88aea96]
- Updated dependencies [6da8d05]
- Updated dependencies [eae5c4c]
- @rulvar/[email protected]
1.237.0
Patch Changes
- Updated dependencies [9d6a279]
- Updated dependencies [49a98f6]
- Updated dependencies [a734ca0]
- Updated dependencies [deb406f]
- @rulvar/[email protected]
1.236.0
Patch Changes
- Updated dependencies [26306ea]
- Updated dependencies [709b942]
- @rulvar/[email protected]
1.235.0
Patch Changes
- Updated dependencies [ba4e10d]
- Updated dependencies [172402b]
- Updated dependencies [2ecd787]
- Updated dependencies [e20a5e9]
- Updated dependencies [98c8691]
- Updated dependencies [c70def0]
- @rulvar/[email protected]
1.234.0
Patch Changes
- Updated dependencies [8420c04]
- @rulvar/[email protected]
1.233.0
Patch Changes
- Updated dependencies [48b5200]
- Updated dependencies [73bc32b]
- Updated dependencies [e63b743]
- Updated dependencies [ef45da7]
- @rulvar/[email protected]
1.232.0
Patch Changes
- Updated dependencies [1440410]
- Updated dependencies [6e467f4]
- Updated dependencies [0b14293]
- Updated dependencies [e3bcab2]
- Updated dependencies [b55a0f7]
- @rulvar/[email protected]
1.231.0
Patch Changes
- Updated dependencies [4eb4b56]
- Updated dependencies [bc8f09e]
- Updated dependencies [ff9b8c2]
- @rulvar/[email protected]
1.230.0
Patch Changes
- Updated dependencies [e9bf910]
- Updated dependencies [57bfb38]
- @rulvar/[email protected]
1.229.0
Patch Changes
- Updated dependencies [3370342]
- Updated dependencies [2fb6656]
- Updated dependencies [edce170]
- @rulvar/[email protected]
1.228.0
Patch Changes
- Updated dependencies [4034fac]
- Updated dependencies [a54b085]
- Updated dependencies [9d0a9be]
- Updated dependencies [be9ef28]
- @rulvar/[email protected]
1.227.0
Patch Changes
- Updated dependencies [f262e9f]
- Updated dependencies [f191ff7]
- Updated dependencies [fbbfbe8]
- Updated dependencies [263b5e8]
- Updated dependencies [db4d56d]
- Updated dependencies [41f93a9]
- Updated dependencies [98c8ca9]
- @rulvar/[email protected]
1.226.0
Patch Changes
- @rulvar/[email protected]
1.225.0
Patch Changes
- @rulvar/[email protected]
1.224.0
Patch Changes
- Updated dependencies [4eca1a3]
- @rulvar/[email protected]
1.223.0
Patch Changes
- Updated dependencies [549aabd]
- Updated dependencies [549aabd]
- @rulvar/[email protected]
1.222.0
Patch Changes
- Updated dependencies [8326268]
- @rulvar/[email protected]
1.221.0
Patch Changes
- Updated dependencies [032ce93]
- @rulvar/[email protected]
1.220.0
Patch Changes
- Updated dependencies [0babe70]
- @rulvar/[email protected]
1.219.0
Patch Changes
- Updated dependencies [65a4ce7]
- @rulvar/[email protected]
1.218.0
Patch Changes
- Updated dependencies [088bda6]
- @rulvar/[email protected]
1.217.0
Patch Changes
- Updated dependencies [ab80b97]
- @rulvar/[email protected]
1.216.0
Patch Changes
- Updated dependencies [b357f4a]
- @rulvar/[email protected]
1.215.0
Patch Changes
- Updated dependencies [e1da4c7]
- @rulvar/[email protected]
1.214.0
Patch Changes
- Updated dependencies [c8af0ec]
- @rulvar/[email protected]
1.213.0
Patch Changes
- Updated dependencies [61680df]
- @rulvar/[email protected]
1.212.0
Patch Changes
- Updated dependencies [e6f8516]
- @rulvar/[email protected]
1.211.0
Patch Changes
- Updated dependencies [d5a8a36]
- @rulvar/[email protected]
1.210.0
Patch Changes
- Updated dependencies [c871ddc]
- @rulvar/[email protected]
1.209.0
Patch Changes
- Updated dependencies [514c7bb]
- @rulvar/[email protected]
1.208.0
Patch Changes
- Updated dependencies [e7d426f]
- @rulvar/[email protected]
1.207.0
Patch Changes
- Updated dependencies [99beee2]
- @rulvar/[email protected]
1.206.0
Patch Changes
- Updated dependencies [ec8e1f1]
- @rulvar/[email protected]
1.205.0
Patch Changes
- Updated dependencies [6d224da]
- @rulvar/[email protected]
1.204.0
Patch Changes
- Updated dependencies [efaec9b]
- @rulvar/[email protected]
1.203.0
Patch Changes
- Updated dependencies [fb08c10]
- @rulvar/[email protected]
1.202.0
Patch Changes
- @rulvar/[email protected]
1.201.0
Patch Changes
- Updated dependencies [7e01189]
- @rulvar/[email protected]
1.200.0
Patch Changes
- Updated dependencies [e2ddbdf]
- @rulvar/[email protected]
1.199.0
Patch Changes
- Updated dependencies [29891c6]
- @rulvar/[email protected]
1.198.0
Patch Changes
- Updated dependencies [c097c96]
- @rulvar/[email protected]
1.197.0
Patch Changes
- @rulvar/[email protected]
1.196.0
Patch Changes
- Updated dependencies [ec9c3e3]
- @rulvar/[email protected]
1.195.0
Patch Changes
- Updated dependencies [5702a70]
- @rulvar/[email protected]
1.194.0
Patch Changes
- Updated dependencies [360a659]
- @rulvar/[email protected]
1.193.0
Patch Changes
- Updated dependencies [2bca1d1]
- @rulvar/[email protected]
1.192.0
Patch Changes
- Updated dependencies [8757601]
- @rulvar/[email protected]
1.191.0
Patch Changes
- Updated dependencies [745387c]
- @rulvar/[email protected]
1.190.0
Patch Changes
- Updated dependencies [8e02021]
- @rulvar/[email protected]
1.189.0
Patch Changes
- Updated dependencies [6a5cc2d]
- @rulvar/[email protected]
1.188.0
Patch Changes
- @rulvar/[email protected]
1.187.0
Patch Changes
- Updated dependencies [c9798ef]
- @rulvar/[email protected]
1.186.0
Patch Changes
- Updated dependencies [242647e]
- @rulvar/[email protected]
1.185.0
Patch Changes
- Updated dependencies [1248623]
- @rulvar/[email protected]
1.184.0
Patch Changes
- Updated dependencies [8a9caca]
- @rulvar/[email protected]
1.183.0
Patch Changes
- Updated dependencies [dd3767c]
- @rulvar/[email protected]
1.182.0
Patch Changes
- Updated dependencies [144d026]
- @rulvar/[email protected]
1.181.0
Patch Changes
- @rulvar/[email protected]
1.180.0
Patch Changes
- Updated dependencies [b124d26]
- @rulvar/[email protected]
1.179.0
Patch Changes
- Updated dependencies [1a5a85a]
- @rulvar/[email protected]
1.178.0
Patch Changes
- @rulvar/[email protected]
1.177.0
Patch Changes
- Updated dependencies [94db8ff]
- @rulvar/[email protected]
1.176.0
Patch Changes
- Updated dependencies [a74304d]
- @rulvar/[email protected]
1.175.0
Patch Changes
- Updated dependencies [1999c5d]
- @rulvar/[email protected]
1.174.0
Patch Changes
- Updated dependencies [aa9a772]
- @rulvar/[email protected]
1.173.0
Patch Changes
- Updated dependencies [67d27ac]
- @rulvar/[email protected]
1.172.0
Patch Changes
- Updated dependencies [0d4770b]
- @rulvar/[email protected]
1.171.0
Patch Changes
- Updated dependencies [f6116b9]
- @rulvar/[email protected]
1.170.0
Patch Changes
- Updated dependencies [86e4c06]
- @rulvar/[email protected]
1.169.0
Patch Changes
- Updated dependencies [623b2ae]
- @rulvar/[email protected]
1.168.0
Patch Changes
- Updated dependencies [ebba79a]
- @rulvar/[email protected]
1.167.0
Patch Changes
- @rulvar/[email protected]
1.166.0
Patch Changes
- Updated dependencies [d8262c3]
- @rulvar/[email protected]
1.165.0
Patch Changes
- Updated dependencies [6391274]
- @rulvar/[email protected]
1.164.0
Patch Changes
- Updated dependencies [9f2dda9]
- @rulvar/[email protected]
1.163.0
Patch Changes
e8d9ada: Report the import bundle's reference closure, serve verify-only journal reads, and close the documentation gaps the benchmark named (RV1511, RV1512, RV1513). The sixth and final PR of the eighteenth plan.
The import closure report (RV1511). The intake validated shapes, namespaces, and the runId, but nothing held the ENTRIES' own references against the blobs the bundle carries: a torn bundle imported whole and the missing transcript surfaced only when something later read it.
importRunnow returns{ unresolvedRefs }, every transcript, checkpoint, artifact, and workflow-source ref the entries (and meta) name that no bundle blob resolves; the default stays permissive (retention and checkpoint pruning legitimately drop blobs their entries still name) and the report makes the gap visible, whilerequireClosure: truerefuses typed BEFORE any write. A duplicate blob ref refuses always: last-write-wins over transcript bytes is a torn or edited bundle, never a valid export.The verify-only load (RV1512). The A1 salvage model repairs a torn trailing line ON LOAD, which is right for an owner about to append and wrong for an auditor: a verification read that rewrites the artifact it verifies destroys the evidence of the tear.
JsonlFileStore({ repairOnLoad: false })serves the salvageable records without touching the file, andrulvar runs audit --no-load-repairopens the default store that way (contradicting--repairis refused typed).The documentation debts (RV1513). The README package count now matches its own table (seventeen names, the unscoped pointer included);
@rulvar/executorships a README and LICENSE like every sibling; the package reference names the eval framework's real dependencies; and the isolated-executor guide gains "What the ledger is NOT", the explicit denial list (not an outbox, not authorization, not exactly-once, not always on) for exactly the facts the seventeenth comparison run's dossier inverted while citing the sources that state them.Updated dependencies [e8d9ada]
- @rulvar/[email protected]
1.162.0
Patch Changes
- Updated dependencies [2031e82]
- @rulvar/[email protected]
1.161.0
Patch Changes
- Updated dependencies [d4547b7]
- @rulvar/[email protected]
1.160.0
Patch Changes
- Updated dependencies [1c6f0d0]
- @rulvar/[email protected]
1.159.0
Patch Changes
- Updated dependencies [e881c8b]
- @rulvar/[email protected]
1.158.0
Patch Changes
- Updated dependencies [a266bc7]
- @rulvar/[email protected]
1.157.0
Patch Changes
- Updated dependencies [1883421]
- @rulvar/[email protected]
1.156.0
Patch Changes
- Updated dependencies [537144e]
- @rulvar/[email protected]
1.155.0
Patch Changes
- Updated dependencies [49b08a7]
- @rulvar/[email protected]
1.154.0
Patch Changes
- Updated dependencies [9259f24]
- @rulvar/[email protected]
1.153.0
Patch Changes
- Updated dependencies [d8bebcb]
- @rulvar/[email protected]
1.152.0
Patch Changes
- Updated dependencies [dd6a616]
- @rulvar/[email protected]
1.151.0
Patch Changes
- Updated dependencies [1de0610]
- @rulvar/[email protected]
1.150.0
Patch Changes
- Updated dependencies [a331211]
- @rulvar/[email protected]
1.149.0
Patch Changes
- Updated dependencies [08b4537]
- @rulvar/[email protected]
1.148.0
Patch Changes
- Updated dependencies [c85dac9]
- @rulvar/[email protected]
1.147.0
Patch Changes
- Updated dependencies [6367231]
- @rulvar/[email protected]
1.146.0
Patch Changes
- Updated dependencies [5d9bbc8]
- @rulvar/[email protected]
1.145.0
Patch Changes
- @rulvar/[email protected]
1.144.0
Patch Changes
- Updated dependencies [c11bcd6]
- @rulvar/[email protected]
1.143.0
Patch Changes
- Updated dependencies [f412169]
- @rulvar/[email protected]
1.142.0
Patch Changes
- @rulvar/[email protected]
1.141.0
Patch Changes
- Updated dependencies [4f12a62]
- @rulvar/[email protected]
1.140.0
Patch Changes
- @rulvar/[email protected]
1.139.0
Patch Changes
- Updated dependencies [03a2141]
- @rulvar/[email protected]
1.138.0
Patch Changes
- Updated dependencies [ed0c4fb]
- @rulvar/[email protected]
1.137.0
Patch Changes
- Updated dependencies [96f6788]
- @rulvar/[email protected]
1.136.0
Patch Changes
- Updated dependencies [aa6ca71]
- @rulvar/[email protected]
1.135.0
Patch Changes
- Updated dependencies [cf75e22]
- @rulvar/[email protected]
1.134.0
Patch Changes
- @rulvar/[email protected]
1.133.0
Patch Changes
- @rulvar/[email protected]
1.132.0
Patch Changes
- Updated dependencies [2bec904]
- @rulvar/[email protected]
1.131.0
Patch Changes
- Updated dependencies [256cae1]
- @rulvar/[email protected]
1.130.0
Patch Changes
- Updated dependencies [d6bec7a]
- @rulvar/[email protected]
1.129.0
Patch Changes
- Updated dependencies [1612439]
- @rulvar/[email protected]
1.128.0
Patch Changes
- Updated dependencies [27c4e38]
- @rulvar/[email protected]
1.127.0
Patch Changes
- Updated dependencies [b3b1805]
- @rulvar/[email protected]
1.126.0
Patch Changes
- @rulvar/[email protected]
1.125.0
Patch Changes
- @rulvar/[email protected]
1.124.0
Patch Changes
- Updated dependencies [37fd1f2]
- @rulvar/[email protected]
1.123.0
Patch Changes
- Updated dependencies [5c46468]
- @rulvar/[email protected]
1.122.0
Patch Changes
- Updated dependencies [8cf45c5]
- @rulvar/[email protected]
1.121.0
Patch Changes
- Updated dependencies [3d67d41]
- @rulvar/[email protected]
1.120.0
Patch Changes
- Updated dependencies [d630c9e]
- @rulvar/[email protected]
1.119.0
Patch Changes
- Updated dependencies [1e4ff3c]
- @rulvar/[email protected]
1.118.0
Patch Changes
- Updated dependencies [f8341a3]
- @rulvar/[email protected]
1.117.0
Patch Changes
- @rulvar/[email protected]
1.116.0
Patch Changes
- Updated dependencies [a213878]
- @rulvar/[email protected]
1.115.0
Patch Changes
- Updated dependencies [63642ae]
- @rulvar/[email protected]
1.114.0
Patch Changes
- Updated dependencies [5759731]
- @rulvar/[email protected]
1.113.0
Minor Changes
- a60807a: The pricing composition's second half names itself, and the effect-ledger quarantine is byte-true (RV706, RV707).
InvoicePricingProvenancegains optionalcurrentPricingVersion: on composed exports it is the version of the caller's current table, the one that priced everything pastpinnedThroughSeq(on current-table exports, the whole fold), so an invoice folded across a rotation now names both halves of the composition where the pinned segments already declared theirs;rulvar invoiceandrulvar inspectfill it from the configured table and extend their text suffix topins composed with the current table (v-a, v-b; current v-live), byte for byte unchanged when the config declares no version. The executor ledger's torn-tail quarantine row now carriesbytesBase64andsha256of the exact torn bytes alongside the lossybytesstring kept for old readers (two different byte tails used to collapse into one indistinguishable row), and the repair's parseable decision is made on the bytes, strict UTF-8 beforeJSON.parse: the lossy decode could make a fragment with invalid bytes inside a string literal parse, and the repair then terminated a line of invalid bytes in place, manufacturing exactly the corruption the fail-closed scan refuses.
Patch Changes
- Updated dependencies [a60807a]
- @rulvar/[email protected]
1.112.0
Patch Changes
- Updated dependencies [00ae55b]
- @rulvar/[email protected]
1.111.0
Patch Changes
- Updated dependencies [fd25169]
- @rulvar/[email protected]
1.110.0
Patch Changes
- Updated dependencies [58afdb5]
- @rulvar/[email protected]
1.109.0
Patch Changes
- Updated dependencies [85b1d39]
- @rulvar/[email protected]
1.108.0
Patch Changes
- Updated dependencies [affa3d4]
- @rulvar/[email protected]
1.107.0
Patch Changes
- Updated dependencies [9f5f6f6]
- @rulvar/[email protected]
1.106.0
Patch Changes
- Updated dependencies [9a4ce49]
- @rulvar/[email protected]
1.105.0
Patch Changes
- Updated dependencies [531dc88]
- @rulvar/[email protected]
1.104.0
Minor Changes
3edecd8: Make the effect ledger's tail repair mutually exclusive across processes and its scan fail closed on every malformed line (RV606, RV607).
Repair exclusion (RV606): the destructive half of the torn-tail repair (truncate plus quarantine) now runs under a sidecar
<path>.repair-locktaken withO_EXCL, and the ledger file is re-read AFTER the lock is held, so a writer never truncates by a boundary computed from a stale read. A waiter polls; a lock whose mtime is further than ten seconds from now (either direction, so a skewed clock cannot pin the file) is presumed abandoned by a crashed holder and stolen, and ownership is re-verified immediately before the truncate. Two writer processes meeting on one torn file previously could erase each other's confirmed intents: the slower instance truncated at its stale boundary, cutting away the faster instance's quarantine and any rows appended after it. A clean file is still returned untouched, byte for byte, without the lock ever existing. The considered alternative, an append-only repair that terminates the fragment in place and quarantines it without truncating, was rejected because it turns the fragment into an unparseable interior line: a repaired file must stay readable by EVERY reader version, and pre-1.104 scans fail closed on exactly that construction. The writer contract is now stated publicly onjsonlEffectLedgerand in the guide: prefer one writer per path (aneffects.<worker>.jsonlper worker process, merged at reconciliation), and when writers do meet on one local path, the repair lock makes the meeting cost duplicated effort at worst, never a truncated confirmed row.Fail-closed scan (RV607):
loadEffectLedgernow decodes every physical line withTextDecoder('utf-8', { fatal: true })and validates the shape before anything dereferences it: the phase must be exactlyintent,outcome, ortorn, and every required field of that phase must carry its type (extra fields still pass through). Invalid UTF-8, non-object JSON (null,42,"str", arrays), a missing or mistyped required field, and an unknown phase are allCorruptLedgerLines: the default scan throws the typedLedgerCorruptionError, and{ tolerateCorrupt: true }returns the same lines as data and never leaks a rawTypeError(anullline used to pierce both modes as one). An unterminated tail that fails to decode or parse remains the tolerated, namedtornTail; an unterminated line that PARSES but fails the shape is corruption, because a torn prefix of the writer's own flat record can never parse, so such a line is foreign, not a crash artifact.Migration note: scans that previously resolved while silently skipping malformed rows (a replacement-character key entering reconciliation as genuine, an unknown phase erasing an orphan, primitives vanishing) now surface them: the default mode throws
LedgerCorruptionErrorwhere it previously returned a partial result or leaked aTypeError. Hosts that hit the new refusal on an existing file should triage with{ tolerateCorrupt: true }, which reports each offending line's number, byte offset, and sha256. Rows written byjsonlEffectLedgeritself are unaffected: every line the writer emits passes the validation it now demands.
Patch Changes
- @rulvar/[email protected]
1.103.0
Patch Changes
- Updated dependencies [f2b809e]
- @rulvar/[email protected]
1.102.0
Patch Changes
- Updated dependencies [3eb6515]
- @rulvar/[email protected]
1.101.0
Patch Changes
- Updated dependencies [51b215c]
- @rulvar/[email protected]
1.100.0
Patch Changes
- Updated dependencies [9785bea]
- @rulvar/[email protected]
1.99.1
Patch Changes
- Updated dependencies [ef08d73]
- @rulvar/[email protected]
1.99.0
Patch Changes
- Updated dependencies [9e00888]
- @rulvar/[email protected]
1.98.0
Patch Changes
- @rulvar/[email protected]
1.97.0
Patch Changes
- Updated dependencies [5c3b453]
- @rulvar/[email protected]
1.96.0
Minor Changes
89fd032: Attempt-exact effect-ledger identity, torn-tail repair, and workdir cleanup on a failed audit write (RV501/RV502/RV503, the two ninth-experiment P0s plus their P1 neighbor).
RV501: every reference-executor dispatch now mints a unique
attemptId, written into the intent row and copied verbatim onto the same attempt's outcome row, andloadEffectLedgerpairs the two phases exactly: an outcome of ANY class resolves only its own attempt (rows written before the id shipped pair by the legacy(idempotencyKey, startedAt)join). This deliberately changesorphanedIntentsin the conservative direction: a sibling retry's outcome no longer clears an older attempt whose effect may already have applied, so files that previously scanned clean can now (correctly) report orphans. Closing the logical idempotency key belongs to the host reconciler, against the effect provider's receipt. A SIGKILL test drives the real crash window against the built package.RV502: before its first append,
jsonlEffectLedgerrepairs a torn tail left by a crashed predecessor: a complete record missing only its newline is terminated in place; an unparseable fragment is truncated and quarantined verbatim as a{"phase":"torn"}line (surfaced astornArtifacts), so an append can never glue onto torn bytes and hide the next valid record.loadEffectLedgernow tolerates and NAMES a live unterminated trailing fragment (tornTail) but fails closed on an unparseable interior line with a typedLedgerCorruptionError(line numbers, byte offsets, sha256 hashes); pass{ tolerateCorrupt: true }to receive those lines ascorruptdata for triage. Previously both records vanished silently after an append over a torn tail, and interior corruption was skipped without a signal.RV503: the outcome record write and the workdir removal are now nested, so the ephemeral workdir never survives the dispatch even when the audit write fails, and a rejected
ledger.recordsurfaces as a typedExecutorErrorwith codeledger(naming the dispatch failure too when both broke) instead of an untyped rejection that leaked the directory.
Patch Changes
- @rulvar/[email protected]
1.95.0
Patch Changes
- @rulvar/[email protected]
1.94.0
Patch Changes
- @rulvar/[email protected]
1.93.0
Patch Changes
- Updated dependencies [c62150a]
- @rulvar/[email protected]
1.92.0
Patch Changes
- 351d1f5: Honest ledger outcomes for dispatches that never ran. A failure between the intent point and the spawn (a credentials mint that throws, a sandbox launcher that throws, cancellation mid-mint) used to ledger
outcome: 'ok'with a null exit code even though nothing was dispatched. Both reference executors now default the outcome toerrorand setokat exactly one place, the successful protocol return, so every unclassified throw ledgers as the error it is. All previously classified paths (spawn failure, timeout, abort, output cap, non-zero exit, protocol violation, success) keep byte-identical records. - Updated dependencies [351d1f5]
- @rulvar/[email protected]
1.91.0
Minor Changes
- f93f5ca: Two-phase intent protocol for external effects (RV404, the eighth-experiment review, variant a). A
ToolEffectLedgerthat implements the new optionalintentmethod opts into the capability: both reference executors durably record the intent (idempotency key, tool,argsHash, runId, spanId, workdir, the attempt'sstartedAt) strictly BEFORE the external effect is dispatched and the outcomerecordafter it, so a host crash between the effect and the outcome row leaves an orphan intent, the mandatory reconciliation signal, instead of an untracked effect. A failed intent write refuses the dispatch with the new typedledgererror code; a ledger without the method keeps the historical single-record contract byte for byte. Ships the durable JSONL reference (jsonlEffectLedger,loadEffectLedgerwithorphanedIntentsprecomputed, a torn trailing line skipped), the two-phasememoryEffectLedgerupgrade withintents(), the conformance scenario e13 (a simulated kill between the phases must leave the orphan intent, recorded before the effect), and the documented host reconciliation contract. Full outbox, business authorization, and monetary reconciliation remain host obligations built on the ledger, not inside it.
Patch Changes
- @rulvar/[email protected]
1.90.0
Patch Changes
- Updated dependencies [9603940]
- @rulvar/[email protected]
1.89.0
Patch Changes
- Updated dependencies [f18b671]
- Updated dependencies [f18b671]
- @rulvar/[email protected]
1.88.0
Patch Changes
- Updated dependencies [3b339d9]
- @rulvar/[email protected]
1.87.0
Patch Changes
- Updated dependencies [c4c02b1]
- @rulvar/[email protected]
1.86.0
Patch Changes
- Updated dependencies [2f71894]
- @rulvar/[email protected]
1.85.0
Patch Changes
- Updated dependencies [6932a9f]
- @rulvar/[email protected]
1.84.0
Patch Changes
- @rulvar/[email protected]
1.83.0
Patch Changes
- @rulvar/[email protected]
1.82.0
Patch Changes
- Updated dependencies [9cc5d66]
- @rulvar/[email protected]
1.81.2
Patch Changes
- Updated dependencies [296885b]
- @rulvar/[email protected]
1.81.1
Patch Changes
- c030982: The side-effect ledger records the outcome a dispatch actually had: a tool whose stdout violates the result protocol (non-JSON output from a clean exit) now ledgers
errorinstead ofok, in both the subprocess and container executors, and the executor conformance kit pins it as check e12. In@rulvar/core,stripFencedBlockscloses fences in CRLF text (a trailing carriage return no longer keeps a fence open and swallows the rest of the document), whichfencedCode: 'excluded'validators andheadingStructureValidatorinherit. Docs drift closed alongside: the package count, tables, and dependency graphs catch up to@rulvar/executorand@rulvar/store-postgres, the durability page reflects the shipped data protection hooks instead of denying them, and the architecture page no longer claims only the in-process executor exists. - Updated dependencies [c030982]
- @rulvar/[email protected]
1.81.0
Patch Changes
- Updated dependencies [ce4c392]
- @rulvar/[email protected]
1.80.0
Patch Changes
- Updated dependencies [262e397]
- @rulvar/[email protected]
1.79.0
Patch Changes
- Updated dependencies [85956ab]
- @rulvar/[email protected]
1.78.0
Patch Changes
- Updated dependencies [941b6e1]
- @rulvar/[email protected]
1.77.0
Patch Changes
- Updated dependencies [6aba271]
- @rulvar/[email protected]
1.76.0
Patch Changes
- Updated dependencies [22cba47]
- @rulvar/[email protected]
1.75.1
Patch Changes
- Updated dependencies [82bc0f0]
- @rulvar/[email protected]
1.75.0
Patch Changes
- Updated dependencies [c486de8]
- @rulvar/[email protected]
1.74.0
Patch Changes
- Updated dependencies [d94beab]
- @rulvar/[email protected]
1.73.0
Patch Changes
- Updated dependencies [3e95bd1]
- @rulvar/[email protected]
1.72.0
Patch Changes
- Updated dependencies [662e9e0]
- @rulvar/[email protected]
1.71.0
Patch Changes
- Updated dependencies [20d02e0]
- @rulvar/[email protected]
1.70.1
Patch Changes
- @rulvar/[email protected]
1.70.0
Patch Changes
- @rulvar/[email protected]
1.69.0
Patch Changes
- Updated dependencies [b21a681]
- @rulvar/[email protected]
1.68.0
Patch Changes
- Updated dependencies [b227874]
- @rulvar/[email protected]
1.67.0
Patch Changes
- Updated dependencies [8e6006d]
- @rulvar/[email protected]
1.66.0
Patch Changes
- Updated dependencies [1b8987e]
- @rulvar/[email protected]
1.65.0
Patch Changes
- Updated dependencies [0b6b859]
- @rulvar/[email protected]
1.64.0
Patch Changes
- Updated dependencies [991f9b5]
- @rulvar/[email protected]
1.63.0
Patch Changes
- Updated dependencies [8a28aed]
- @rulvar/[email protected]
1.62.0
Patch Changes
- Updated dependencies [fca5fd1]
- @rulvar/[email protected]
1.61.0
Patch Changes
- Updated dependencies [b4c1f1f]
- @rulvar/[email protected]
1.60.0
Patch Changes
- Updated dependencies [59bbeaa]
- @rulvar/[email protected]
1.59.4
Patch Changes
- Updated dependencies [c49d7a1]
- @rulvar/[email protected]
1.59.3
Patch Changes
- Updated dependencies [deaef36]
- @rulvar/[email protected]
1.59.2
Patch Changes
- Updated dependencies [dd0e10f]
- @rulvar/[email protected]
1.59.1
Patch Changes
- Updated dependencies [c127770]
- @rulvar/[email protected]
1.59.0
Minor Changes
- 615dc90: RV-216: the isolated tool executor, the last open item in the improvement plan. In-process tools are ordinary function calls with full host capabilities (an execution convenience, never a sandbox for hostile or model-generated code); this release adds an official out-of-process executor contract so a tool whose input is untrusted cannot reach host capabilities. (1) THE SEAM in
@rulvar/core: aToolExecutorProviderSPI, registered on the engine ascreateEngine({ executors: { subprocess, container } }). A tool declaringexecutor: 'subprocess'or'container'(previously a hard "only inprocess in v1" rejection) dispatches through the matching provider instead of running itsexecuteclosure; an unregistered tag is a typed ConfigError at spawn time, before any provider or model call. The dispatch mints the tool span exactly like an inprocess call and derives a stable idempotency key (a pure function of runId, tool name, and canonical args) so a side-effecting tool can fold an at-least-once retry into effectively-once; the tag never enterstoolsetHash, so opting a tool into isolation does not change run identity, and inprocess dispatch stays byte-identical. (2) THE REFERENCE ADAPTERS in the new@rulvar/executorpackage:subprocessExecutorruns the tool in a child process with a REPLACED environment (host credentials scrubbed; the usual exfiltration path removed), a fresh ephemeral working directory per call, per-call short-lived credentials, a hard timeout that escalates SIGTERM to SIGKILL, and a bounded output capture, plus asandboxlauncher hook where bwrap/firejail/sandbox-exec plug in for filesystem and network isolation;containerExecutorruns it in a one-shot container with the network dropped (--network none), the root filesystem read-only, memory/CPU/pid caps, and all Linux capabilities dropped, which is where the strong isolation the subprocess adapter cannot promise on its own actually holds (a microVM adapter implements the same seam).subprocessTooldefines a tool that dispatches through them; aToolEffectLedgerrecords every dispatch (idempotency key, tool, argsHash, workdir, outcome) so a host can bind an approval to the effect it authorized. (3) THE CONFORMANCE KIT:executorConformanceis the executable shared-contract battery any command-based executor must pass, foremost the gate the epic exists for, a hostile tool cannot read the host's ambient credentials; the subprocess reference passes all of it, and the container reference additionally proves the network and filesystem isolation against a real runtime. New guide page: https://docs.rulvar.com/guide/isolated-executor.
Patch Changes
- Updated dependencies [615dc90]
- @rulvar/[email protected]
@rulvar/openai
1.252.0
Patch Changes
- Updated dependencies [3ccb6cf]
- Updated dependencies [52d807f]
- Updated dependencies [517ed00]
- Updated dependencies [a7e589d]
- Updated dependencies [76e95eb]
- @rulvar/[email protected]
1.251.0
Patch Changes
- Updated dependencies [e7e829c]
- Updated dependencies [5982be8]
- Updated dependencies [7c58fb2]
- Updated dependencies [b3e465a]
- Updated dependencies [c4e5d6a]
- Updated dependencies [c6fc3da]
- Updated dependencies [c6fc3da]
- Updated dependencies [0ae8b85]
- Updated dependencies [7932936]
- Updated dependencies [7932936]
- Updated dependencies [88da0ed]
- Updated dependencies [06c0e85]
- @rulvar/[email protected]
1.250.0
Patch Changes
- Updated dependencies [0e240b9]
- Updated dependencies [6fe585e]
- Updated dependencies [c5eb19c]
- Updated dependencies [565c13b]
- Updated dependencies [c6d197b]
- Updated dependencies [c9d9729]
- Updated dependencies [fed9db6]
- Updated dependencies [df9ed76]
- Updated dependencies [3020912]
- Updated dependencies [d8d598d]
- @rulvar/[email protected]
1.249.0
Minor Changes
- 67a8d72: The Sol rates follow the documented page. The fresh contract classification dispatched for the plan-44 release gate caught a real drift: the provider's model page for gpt-5.6-sol now documents input 4, output 20, cache read 0.4, cache write 5 USD per MTok against the seeded 5 / 30 / 0.5 / 6.25. Per the rates audit's own doctrine (a confirmed rate change ships as its own changeset, never an automatic rewrite), the seed row and the derived
OPENAI_PRICINGtable move to the page's numbers under the distinctpricingVersion: 'openai-2026-08-23', withratesVerifiedAt: '2026-08-23'on Sol and itsgpt-5.6alias (Terra and Luna keep their 2026-07-31 verification). Runs recorded before this release overstated Sol spend relative to the cut, never under; the distinct version string surfaces the revision on resume instead of silently reinterpreting past spend. Sol's previous rates were billing-confirmed by the 2026-07-30 statement reconciliation; the new rates await theirs over a future export.
Patch Changes
- Updated dependencies [8862133]
- Updated dependencies [0d7a717]
- Updated dependencies [e4428bd]
- Updated dependencies [d6873c1]
- Updated dependencies [4092e8d]
- Updated dependencies [e086590]
- Updated dependencies [1411938]
- Updated dependencies [737d1ee]
- Updated dependencies [634f966]
- Updated dependencies [052cc26]
- Updated dependencies [bbae134]
- @rulvar/[email protected]
1.248.0
Patch Changes
- Updated dependencies [8d0cd69]
- Updated dependencies [81065e4]
- Updated dependencies [8573f20]
- Updated dependencies [95f6a5e]
- @rulvar/[email protected]
1.247.0
Minor Changes
- b698726: The first-party surface attests, and the floor loses its holes (RV4204, the sixth comparison experiment). Before this, only
mcp()and the AI SDK bridge exposeddescribeRegulatedPosture(), sounrecognized >= 1on nearly every real regulated compile and a zero-blind-spot floor was unsatisfiable by construction; and the floor checked toolset attestation only ondefaults.profiles, accepted legacy contract-only pins that pass authority drift silently, and never walked the executors at all. Now:anthropic()andopenai()attest their egress (official, acustom-base-urlwhose ORIGIN enters the hashed posture map, or apreconstructed-clientnamed honestly) plus the caps pagination bound;subprocessExecutor()andcontainerExecutor()attest their ledger, env allowlist, resolved ceilings, and isolation seam;compileRegulatedProfilewalksengine.executorsand the sandbox runner beside adapters and toolsets, wraps attested executors sorun()re-judges the posture at use (the RV4102 seam), refuses a regulated executor without aToolEffectLedgerby field name, refuses legacy contract-only pins (re-record withattestToolset()), and arms the new engine-widedefaults.requireToolsetAttestation, under which a spawn resolving a non-empty toolset with no pin binding it refuses typed at spawn time (the per-call-tools hole the profile pins could not see). The opt-inconstruction: 'require-recognized'compile floor turns the unrecognized count into a typed refusal naming the blind constructions, satisfiable now that the first-party surface attests.
Patch Changes
- Updated dependencies [1933ecc]
- Updated dependencies [db0a5f0]
- Updated dependencies [b698726]
- Updated dependencies [48348d2]
- Updated dependencies [4cfa1cc]
- Updated dependencies [4b7197a]
- Updated dependencies [5ebc842]
- Updated dependencies [16ff6b9]
- Updated dependencies [0c9941d]
- @rulvar/[email protected]
1.246.0
Patch Changes
- Updated dependencies [d165b0c]
- Updated dependencies [d59f4a0]
- Updated dependencies [46907ac]
- Updated dependencies [9929ad3]
- Updated dependencies [1790a6a]
- @rulvar/[email protected]
1.245.0
Patch Changes
- Updated dependencies [b4d47a8]
- Updated dependencies [dee6db4]
- Updated dependencies [b85c113]
- Updated dependencies [bc556e7]
- Updated dependencies [9f11d29]
- Updated dependencies [19bcea0]
- Updated dependencies [60b461c]
- Updated dependencies [61e3a1a]
- Updated dependencies [a156b81]
- Updated dependencies [0bd7045]
- @rulvar/[email protected]
1.244.0
Patch Changes
- Updated dependencies [38d839a]
- Updated dependencies [ce13b0f]
- Updated dependencies [4fa23e3]
- Updated dependencies [6841c69]
- Updated dependencies [f56721d]
- Updated dependencies [c894a43]
- Updated dependencies [f6944a3]
- Updated dependencies [23fd0e0]
- @rulvar/[email protected]
1.243.0
Patch Changes
- Updated dependencies [746d1f4]
- Updated dependencies [009b29c]
- Updated dependencies [1674cbe]
- Updated dependencies [bd096bc]
- @rulvar/[email protected]
1.242.0
Patch Changes
- Updated dependencies [6e3438e]
- Updated dependencies [ba5cf67]
- Updated dependencies [c2d1531]
- @rulvar/[email protected]
1.241.0
Patch Changes
- Updated dependencies [dbcdd24]
- Updated dependencies [7ae7243]
- Updated dependencies [4f832c4]
- Updated dependencies [7452d3d]
- Updated dependencies [a4e22bf]
- Updated dependencies [82df4af]
- @rulvar/[email protected]
1.240.0
Patch Changes
- @rulvar/[email protected]
1.239.0
Patch Changes
- Updated dependencies [74ce99a]
- Updated dependencies [ccd0665]
- Updated dependencies [0c5ce21]
- Updated dependencies [0616934]
- @rulvar/[email protected]
1.238.0
Patch Changes
- Updated dependencies [cf00947]
- Updated dependencies [c7b9382]
- Updated dependencies [88aea96]
- Updated dependencies [6da8d05]
- Updated dependencies [eae5c4c]
- @rulvar/[email protected]
1.237.0
Patch Changes
- Updated dependencies [9d6a279]
- Updated dependencies [49a98f6]
- Updated dependencies [a734ca0]
- Updated dependencies [deb406f]
- @rulvar/[email protected]
1.236.0
Patch Changes
- Updated dependencies [26306ea]
- Updated dependencies [709b942]
- @rulvar/[email protected]
1.235.0
Patch Changes
- Updated dependencies [ba4e10d]
- Updated dependencies [172402b]
- Updated dependencies [2ecd787]
- Updated dependencies [e20a5e9]
- Updated dependencies [98c8691]
- Updated dependencies [c70def0]
- @rulvar/[email protected]
1.234.0
Patch Changes
- Updated dependencies [8420c04]
- @rulvar/[email protected]
1.233.0
Patch Changes
- Updated dependencies [48b5200]
- Updated dependencies [73bc32b]
- Updated dependencies [e63b743]
- Updated dependencies [ef45da7]
- @rulvar/[email protected]
1.232.0
Patch Changes
- Updated dependencies [1440410]
- Updated dependencies [6e467f4]
- Updated dependencies [0b14293]
- Updated dependencies [e3bcab2]
- Updated dependencies [b55a0f7]
- @rulvar/[email protected]
1.231.0
Patch Changes
- Updated dependencies [4eb4b56]
- Updated dependencies [bc8f09e]
- Updated dependencies [ff9b8c2]
- @rulvar/[email protected]
1.230.0
Patch Changes
- Updated dependencies [e9bf910]
- Updated dependencies [57bfb38]
- @rulvar/[email protected]
1.229.0
Patch Changes
- Updated dependencies [3370342]
- Updated dependencies [2fb6656]
- Updated dependencies [edce170]
- @rulvar/[email protected]
1.228.0
Patch Changes
- Updated dependencies [4034fac]
- Updated dependencies [a54b085]
- Updated dependencies [9d0a9be]
- Updated dependencies [be9ef28]
- @rulvar/[email protected]
1.227.0
Patch Changes
- Updated dependencies [f262e9f]
- Updated dependencies [f191ff7]
- Updated dependencies [fbbfbe8]
- Updated dependencies [263b5e8]
- Updated dependencies [db4d56d]
- Updated dependencies [41f93a9]
- Updated dependencies [98c8ca9]
- @rulvar/[email protected]
1.226.0
Patch Changes
- @rulvar/[email protected]
1.225.0
Patch Changes
- @rulvar/[email protected]
1.224.0
Patch Changes
- Updated dependencies [4eca1a3]
- @rulvar/[email protected]
1.223.0
Patch Changes
- Updated dependencies [549aabd]
- Updated dependencies [549aabd]
- @rulvar/[email protected]
1.222.0
Patch Changes
- Updated dependencies [8326268]
- @rulvar/[email protected]
1.221.0
Patch Changes
- Updated dependencies [032ce93]
- @rulvar/[email protected]
1.220.0
Patch Changes
- Updated dependencies [0babe70]
- @rulvar/[email protected]
1.219.0
Patch Changes
- Updated dependencies [65a4ce7]
- @rulvar/[email protected]
1.218.0
Patch Changes
- Updated dependencies [088bda6]
- @rulvar/[email protected]
1.217.0
Patch Changes
- Updated dependencies [ab80b97]
- @rulvar/[email protected]
1.216.0
Patch Changes
- Updated dependencies [b357f4a]
- @rulvar/[email protected]
1.215.0
Patch Changes
- Updated dependencies [e1da4c7]
- @rulvar/[email protected]
1.214.0
Patch Changes
- Updated dependencies [c8af0ec]
- @rulvar/[email protected]
1.213.0
Patch Changes
- Updated dependencies [61680df]
- @rulvar/[email protected]
1.212.0
Patch Changes
- Updated dependencies [e6f8516]
- @rulvar/[email protected]
1.211.0
Patch Changes
- Updated dependencies [d5a8a36]
- @rulvar/[email protected]
1.210.0
Patch Changes
- Updated dependencies [c871ddc]
- @rulvar/[email protected]
1.209.0
Patch Changes
- Updated dependencies [514c7bb]
- @rulvar/[email protected]
1.208.0
Minor Changes
- e7d426f: First-class prompt-cache policy (RV2006).
ChatRequest.cacheHintexisted and the Anthropic adapter compiled it intocache_control, but nothing in the core ever populated it: the third parity rerun's workers re-paid the full input rate on every turn of their ~550k-token contexts (cacheReadTokens 0across the run), and the $6 envelope sized on OpenAI's implicit server cache was incomparable on Anthropic. The agent loop now compiles the hint on every tool-cycle turn: breakpoints after tools, after system, and after the deepest message, sliding with the history. Default ON exactly where the adapter declares the newModelCaps.promptCaching: 'explicit'(the Anthropic adapter does); OpenAI declares'implicit'and undeclared adapters get byte-identical requests. Configure withdefaults.cache,AgentProfile.cache, or per-callopts.cache(CachePolicy { mode?: 'auto' | 'off'; ttl?: '5m' | '1h' }), call over profile over engine. Billing note: on cache-capable Anthropic models this changes the wire requests of every loop turn to carry cache breakpoints, typically cutting long-cycle input cost several-fold (cached reads bill at a tenth of the input rate);CostReportcache accounting is unchanged, the hint never enters identity or journals, and@rulvar/testing'srequestHashstrips it so existing cassettes replay byte for byte.
Patch Changes
- Updated dependencies [e7d426f]
- @rulvar/[email protected]
1.207.0
Patch Changes
- Updated dependencies [99beee2]
- @rulvar/[email protected]
1.206.0
Patch Changes
- Updated dependencies [ec8e1f1]
- @rulvar/[email protected]
1.205.0
Patch Changes
- Updated dependencies [6d224da]
- @rulvar/[email protected]
1.204.0
Patch Changes
- Updated dependencies [efaec9b]
- @rulvar/[email protected]
1.203.0
Patch Changes
- Updated dependencies [fb08c10]
- @rulvar/[email protected]
1.202.0
Patch Changes
- @rulvar/[email protected]
1.201.0
Patch Changes
- Updated dependencies [7e01189]
- @rulvar/[email protected]
1.200.0
Patch Changes
- Updated dependencies [e2ddbdf]
- @rulvar/[email protected]
1.199.0
Patch Changes
- Updated dependencies [29891c6]
- @rulvar/[email protected]
1.198.0
Patch Changes
- Updated dependencies [c097c96]
- @rulvar/[email protected]
1.197.0
Patch Changes
- @rulvar/[email protected]
1.196.0
Patch Changes
- Updated dependencies [ec9c3e3]
- @rulvar/[email protected]
1.195.0
Patch Changes
- Updated dependencies [5702a70]
- @rulvar/[email protected]
1.194.0
Patch Changes
- Updated dependencies [360a659]
- @rulvar/[email protected]
1.193.0
Patch Changes
- Updated dependencies [2bca1d1]
- @rulvar/[email protected]
1.192.0
Patch Changes
- Updated dependencies [8757601]
- @rulvar/[email protected]
1.191.0
Patch Changes
- Updated dependencies [745387c]
- @rulvar/[email protected]
1.190.0
Patch Changes
- Updated dependencies [8e02021]
- @rulvar/[email protected]
1.189.0
Patch Changes
- Updated dependencies [6a5cc2d]
- @rulvar/[email protected]
1.188.0
Patch Changes
- @rulvar/[email protected]
1.187.0
Patch Changes
- Updated dependencies [c9798ef]
- @rulvar/[email protected]
1.186.0
Patch Changes
- Updated dependencies [242647e]
- @rulvar/[email protected]
1.185.0
Patch Changes
- Updated dependencies [1248623]
- @rulvar/[email protected]
1.184.0
Patch Changes
- Updated dependencies [8a9caca]
- @rulvar/[email protected]
1.183.0
Patch Changes
- Updated dependencies [dd3767c]
- @rulvar/[email protected]
1.182.0
Patch Changes
- Updated dependencies [144d026]
- @rulvar/[email protected]
1.181.0
Patch Changes
- @rulvar/[email protected]
1.180.0
Minor Changes
- b124d26: Statement reconciliation is core, with a fail-closed intake for raw exports and a fixed adapter contract matrix (RV1703).
reconcileStatementwas provider-neutral from birth, typing only against the invoice and the pricing SPI, but it lived in@rulvar/openaiand forced Anthropic-only consumers into an OpenAI dependency for a join that never touched OpenAI code; the eighteenth comparison benchmark graded provider readiness "conditionally ready" partly on exactly this asymmetry. The module now lives in@rulvar/coreand the historical@rulvar/openaiimport paths keep serving the identical functions as re-exports, so no consumer rebuild or import rewrite is forced. New beside it:statementFromRows({ kind, rows, map })normalizes a raw keyed export (a parsed CSV, a JSON download) into aProviderStatementunder one explicitStatementColumnMap, deliberately shipping no per-provider schema knowledge; every mapped cell validates fail-closed with the row index and column name (non-numeric dollars, fractional or negative token counts, empty response ids, unknown component names all refuse typed), absent cells omit their field, and a requests row left with no dollars, no component split, and no usage refuses, because a row without evidence cannot reconcile anything. The providers guide now fixes the per-adapter billing contract in one matrix: what each adapter surface contributes to the join (continuation absorption and the any-id-of-the-set rule forpause_turndispatches, the one-response-id-per-wire contract of the Responses API, the coverage posture for compatible endpoints and the AI SDK bridge), so reconciliation readiness is a documented contract per adapter instead of an inference.
Patch Changes
- Updated dependencies [b124d26]
- @rulvar/[email protected]
1.179.0
Patch Changes
- Updated dependencies [1a5a85a]
- @rulvar/[email protected]
1.178.0
Patch Changes
- @rulvar/[email protected]
1.177.0
Patch Changes
- Updated dependencies [94db8ff]
- @rulvar/[email protected]
1.176.0
Patch Changes
- Updated dependencies [a74304d]
- @rulvar/[email protected]
1.175.0
Patch Changes
- Updated dependencies [1999c5d]
- @rulvar/[email protected]
1.174.0
Patch Changes
- Updated dependencies [aa9a772]
- @rulvar/[email protected]
1.173.0
Patch Changes
- Updated dependencies [67d27ac]
- @rulvar/[email protected]
1.172.0
Patch Changes
- Updated dependencies [0d4770b]
- @rulvar/[email protected]
1.171.0
Patch Changes
- Updated dependencies [f6116b9]
- @rulvar/[email protected]
1.170.0
Patch Changes
- Updated dependencies [86e4c06]
- @rulvar/[email protected]
1.169.0
Patch Changes
- Updated dependencies [623b2ae]
- @rulvar/[email protected]
1.168.0
Patch Changes
- Updated dependencies [ebba79a]
- @rulvar/[email protected]
1.167.0
Patch Changes
- @rulvar/[email protected]
1.166.0
Patch Changes
- Updated dependencies [d8262c3]
- @rulvar/[email protected]
1.165.0
Patch Changes
- Updated dependencies [6391274]
- @rulvar/[email protected]
1.164.0
Patch Changes
- Updated dependencies [9f2dda9]
- @rulvar/[email protected]
1.163.0
Patch Changes
- Updated dependencies [e8d9ada]
- @rulvar/[email protected]
1.162.0
Patch Changes
- Updated dependencies [2031e82]
- @rulvar/[email protected]
1.161.0
Patch Changes
- Updated dependencies [d4547b7]
- @rulvar/[email protected]
1.160.0
Patch Changes
- Updated dependencies [1c6f0d0]
- @rulvar/[email protected]
1.159.0
Patch Changes
- Updated dependencies [e881c8b]
- @rulvar/[email protected]
1.158.0
Patch Changes
- Updated dependencies [a266bc7]
- @rulvar/[email protected]
1.157.0
Patch Changes
- Updated dependencies [1883421]
- @rulvar/[email protected]
1.156.0
Patch Changes
- Updated dependencies [537144e]
- @rulvar/[email protected]
1.155.0
Patch Changes
- Updated dependencies [49b08a7]
- @rulvar/[email protected]
1.154.0
Patch Changes
- Updated dependencies [9259f24]
- @rulvar/[email protected]
1.153.0
Patch Changes
- Updated dependencies [d8bebcb]
- @rulvar/[email protected]
1.152.0
Patch Changes
- Updated dependencies [dd6a616]
- @rulvar/[email protected]
1.151.0
Patch Changes
- Updated dependencies [1de0610]
- @rulvar/[email protected]
1.150.0
Patch Changes
- Updated dependencies [a331211]
- @rulvar/[email protected]
1.149.0
Patch Changes
- Updated dependencies [08b4537]
- @rulvar/[email protected]
1.148.0
Patch Changes
- Updated dependencies [c85dac9]
- @rulvar/[email protected]
1.147.0
Patch Changes
- Updated dependencies [6367231]
- @rulvar/[email protected]
1.146.0
Patch Changes
- Updated dependencies [5d9bbc8]
- @rulvar/[email protected]
1.145.0
Minor Changes
- faf7d95: An affirmatively declared empty claim is not settlement evidence (RV1201). A per-request statement row whose
usageorcomponentsUsdwas an object with no figures used to read verdictmatchwith complete coverage andsettleable: trueon the object's mere presence, exactly the false settlement-grade evidence the sixteenth experiment's judge reproduced as R1:{usage:{}}and{componentsUsd:{}}both settled. The intake now refuses such a row with a typedConfigErrornaming the row and the empty field, at the same fail-closed gate that already refuses non-finite dollars, malformed token counts, and self-contradicting rows. The documented partial-declaration model is unchanged: a row declaring only itsresponseIdstill joins the coverage set, because presence is coverage, not a figure claim; and a single declared figure (one token count, one component line) remains evidence exactly as before.
Patch Changes
- @rulvar/[email protected]
1.144.0
Patch Changes
- Updated dependencies [c11bcd6]
- @rulvar/[email protected]
1.143.0
Patch Changes
- Updated dependencies [f412169]
- @rulvar/[email protected]
1.142.0
Patch Changes
- @rulvar/[email protected]
1.141.0
Patch Changes
- Updated dependencies [4f12a62]
- @rulvar/[email protected]
1.140.0
Patch Changes
- @rulvar/[email protected]
1.139.0
Patch Changes
- Updated dependencies [03a2141]
- @rulvar/[email protected]
1.138.0
Patch Changes
- Updated dependencies [ed0c4fb]
- @rulvar/[email protected]
1.137.0
Patch Changes
- Updated dependencies [96f6788]
- @rulvar/[email protected]
1.136.0
Patch Changes
- Updated dependencies [aa6ca71]
- @rulvar/[email protected]
1.135.0
Patch Changes
- Updated dependencies [cf75e22]
- @rulvar/[email protected]
1.134.0
Minor Changes
cb50ea0: An internally contradictory statement refuses typed at intake, totals decide beside components, and the reconciliation states the settlement-grade predicate first class (RV1005 + RV1006, PR III of the fourteenth plan)
The fourteenth comparison experiment fed
reconcileStatementan export row carryingusd: 100beside a component split summing to 1 and read verdictmatch: each claim sat inside its own tolerance and nothing compared them to each other, because the presence of components suppressed the totals comparison entirely. The same review showed that amatchverdict is a weaker claim than settlement needs: an export can cover every KNOWN row to the cent while a usage-unknown attempt still holds unattributed money.- Intake internal consistency (RV1005): a request row carrying both
usdand acomponentsUsdsplit must have them agree withintotalToleranceUsd, else it refuses with a typedConfigErrornaming the row; an export whose own total contradicts its own components is not evidence. - Totals decide beside components (RV1005): a split's presence no longer suppresses the totals comparison. It decides exactly when both sides' dollar claims cover the same set (every matched export row carries
usdin requests mode; nothing statement-only and every component line claimed in categories mode; no covered model unpriced), so a total drifting beyondtotalToleranceUsdreadsdivergenceeven while every component line sits inside its own tolerance, and a scope mismatch stays the coverage machinery's business instead of manufactured divergence. StatementReconciliation.settleable(RV1006): the settlement-grade composite first class, true exactly when the verdict ismatchAND coverage is complete AND no row settledusageUnknownAND no model went unpriced. A safe consumer no longer assembles that predicate by hand.runFaultInjection(@rulvar/evals) grows the eighteenth scenario,statement-settleable-guard: a REAL run whose first attempt dies before any usage report seeds a genuine usage-unknown ledger row, the clean export over it readsmatchwith complete coverage yetsettleable: false, the clean twin readssettleable: true, and the contradictory row refuses typed at intake. Reverting any of the fixes reportsmatched: falsein the kit.
- Intake internal consistency (RV1005): a request row carrying both
Patch Changes
- @rulvar/[email protected]
1.133.0
Patch Changes
- @rulvar/[email protected]
1.132.0
Patch Changes
- Updated dependencies [2bec904]
- @rulvar/[email protected]
1.131.0
Patch Changes
- Updated dependencies [256cae1]
- @rulvar/[email protected]
1.130.0
Patch Changes
- Updated dependencies [d6bec7a]
- @rulvar/[email protected]
1.129.0
Patch Changes
- Updated dependencies [1612439]
- @rulvar/[email protected]
1.128.0
Minor Changes
27c4e38: pause_turn continuations become accounted wire units (RV905, the thirteenth experiment's fifth release risk). The Anthropic adapter absorbs server-side turn pauses by re-sending, making up to six wire requests inside ONE core dispatch; until now the request quota window, the provider call record, and the invoice row all saw one, and a per-request provider statement matched one segment while the rest read statement-only.
The adapter's finish metadata now names the whole segment set (
providerMetadata.anthropic.wireRequests = { count, responseIds }); the provider call record and the invoice row carrywireResponseIds; and the quota reconciliation settles the reservation against the TRUE wire request count. TheQuotaLimiter.reconcileSPI gains an optionalactual.requestsargument, honored by all three reference limiters through one shared arithmetic (quotaActualRequestsDelta), so a window that admitted one request per reservation now reflects what the provider's own RPM meter saw; a settlement only ever adds, never denies retroactively, and implementations written against the two-argument form remain valid.reconcileStatementjoins a multi-wire invoice row by ANY id of its segment set, all-or-nothing: a partially delivered segment set readspartial-coveragewith its delivered segments never counted as statement-only (and neverno-overlapwhen segments touched our data), and provider-reported token counts compare as the SUM over the segments against the dispatch's recorded usage. Single-wire dispatches carry none of the new fields and stay byte-identical, journals and events included.
Patch Changes
- Updated dependencies [27c4e38]
- @rulvar/[email protected]
1.127.0
Patch Changes
- Updated dependencies [b3b1805]
- @rulvar/[email protected]
1.126.0
Minor Changes
e5e9526: Fail-closed statement reconciliation (RV903, the thirteenth experiment's two false-match probes):
reconcileStatementnow refuses at intake, with a typedConfigErrornaming the row and field, any statement number that cannot be evidence: non-finite or negative dollars (usdand everycomponentsUsdentry, requests and categories alike), non-integer or negative provider-reported token counts, and non-finite or negative tolerances. Before this, a request row withusd: NaNflowed through the totals,Math.abs(NaN) > toleranceevaluated false, and a corrupted export readverdict: 'match'with NaNstatementUsdanddeltaUsd; negative amounts are refused too, because credits and adjustments are not per-request billing evidence and a negative row could mask a rate divergence of its own size.Provider-reported token counts now decide the verdict by default: our recorded counts are the provider's own wire-reported numbers, so an export that disagrees with them describes a different request than the wire served, and any token mismatch reads as
divergenceeven when the dollars agree (the second probe:verdict: 'match'besidetokenMismatches: 1). The newtokenComparison: 'informational'option restores the pre-v1.126 dollar-only verdict for exports whose token semantics legitimately differ from the wire's; the mismatch count andtokenMismatchSamplereport either way. Reports for clean exports are byte-identical to v1.125.0.
Patch Changes
- @rulvar/[email protected]
1.125.0
Minor Changes
109e9fa: Pricing-table truth: the Anthropic 1h cache-write premium is seeded, the rates audit fails closed on documented rates the seed never declared, and the OpenAI Terra/Luna price cut ships as a versioned revision (RV901, RV902, RV911; the thirteenth experiment's underpricing probes).
@rulvar/anthropicseeds now carry all five published pricing columns:cacheWrite1hUsdPerMToklands on every priced row at the documented 2x base input (Fable 5 $20, Opus 4.8/4.7/4.6 $10, Sonnet 5 $4 under the introductory price, Sonnet 4.6 $6, Haiku 4.5 $2), under the newpricingVersionanthropic-2026-07-31. v1.124.0 taught the wire to fill the canonical 5m/1h split andpriceUsdOfto bill the 1h share at the premium, but the seed never declared the rate, so a million Sonnet 5 1h write tokens priced at the 5m $2.50 instead of the documented $4.00: an underpricing a budget ceiling then failed to bound. A usage with no split still folds the whole write count at the 5m rate, byte for byte as before; the stale caps comment claiming the canonical Usage cannot distinguish 1h writes is retired.scripts/rates-audit.mjs(the weekly documented-rates drift audit) now compares seed and page in BOTH directions: a billable page rate the seed never declared is a finding, not a silent skip. The old one-directional rule rested on the 1h premium being unbillable; that rationale died with the Usage split, and the audit printingmatchfor Sonnet 5 while the page showed a 1h column the seed lacked is exactly how the underpricing hid. The pinning test is flipped to the fail-closed behavior.@rulvar/openaipicks up the provider's 2026-07-30 price cut, docs-verified per model page on 2026-07-31 after the live audit caught the drift: Terra to $2 input / $12 output / $0.20 cached input / $2.50 cache write (0.8x across the board) and Luna to $0.20 / $1.20 / $0.02 / $0.25 (0.2x), both keeping the family's long-context tier, under the newpricingVersionopenai-2026-07-31. Sol is unchanged and additionally remains billing-confirmed by the 2026-07-30 statement reconciliation; the new Terra and Luna rates are docs-verified only until the next reconciliation over a saved export. Runs recorded underopenai-2026-07-18-r2overstated Terra/Luna spend relative to the cut, never under, and a resumed run surfaces the rotation as explicit pricing drift instead of silently reinterpreting recorded spend. Every re-verified row now stampsratesVerifiedAt: '2026-07-31'.
Patch Changes
- @rulvar/[email protected]
1.124.0
Patch Changes
- Updated dependencies [37fd1f2]
- @rulvar/[email protected]
1.123.0
Patch Changes
- Updated dependencies [5c46468]
- @rulvar/[email protected]
1.122.0
Patch Changes
- Updated dependencies [8cf45c5]
- @rulvar/[email protected]
1.121.0
Minor Changes
- 3d67d41: Rate provenance made checkable (RV807, RV813, RV814). The pricing row grows
ratesVerifiedAt(SPI), the ISO date it was last verified against the provider's documented rates or, stronger, its billing categories: the shipped seeds stamp it (the GPT-5.6 family reads2026-07-30, the day the statement reconciliation confirmed those rates against the provider's own per-component billing categories to the cent; the pre-5.6 OpenAI rows keep their2026-07-18docs verification; every Anthropic row was re-verified against the documented table on2026-07-30). The date is surfaced wherever a dollar is consumed:preflightEstimatecopies it onto each spawn report andrulvar preflightrendersratesVerified=<date>with its age on the spawn line; the settle pin journals it with the rest of the applied row so it survives any later table rewrite; andrulvar invoiceprints arates verified:line naming each priced model's date and age, pinned rows first, current table past them; the twelfth run's founder read the invoice doubting the rates and nothing said the seed was 12 days stale. The doctrine ships with the mechanism: seeds bound ceilings conservatively, billing truth is established only byreconcileStatementover saved exports, and a confirmed divergence corrects the seed in its own release with a changeset, never a silent rewrite. Enforcement rides two new gates: a weekly documented-rates audit (scripts/rates-audit.mjsin the live contract workflow) re-fetches exactly the pages the seed comments cite, compares every rate, write premium, and long-context tier, and opens an issue on drift or on a page that stops extracting, and a README release-table gate (scripts/readme-release-shas.mjs, in CI) requires every cited squash SHA to be an ancestor of HEAD, catching the v1.109.0 row that pointed at an object no branch contained for eleven releases (now corrected to the real squash58afdb5).
Patch Changes
- Updated dependencies [3d67d41]
- @rulvar/[email protected]
1.120.0
Patch Changes
- Updated dependencies [d630c9e]
- @rulvar/[email protected]
1.119.0
Patch Changes
- Updated dependencies [1e4ff3c]
- @rulvar/[email protected]
1.118.0
Minor Changes
- f8341a3: Provider statement reconciliation as a machine (RV812, the twelfth experiment's billing lesson). The run's billing question (a dashboard headline of 4.45 then 4.77 USD against the settled 7.304885) was closed by hand with screenshots; nothing in the system could close it. Now
@rulvar/openaiexportsreconcileStatement(invoice, statement, { pricingOf }): it joins the machine-readable invoice against a NORMALIZED provider export, per-request rows by response id or per-model per-component category totals (the Spend categories shape), and refuses a headline aggregate typed, because an eventually consistent dashboard total is not evidence. The report carries response-id coverage (a partially delivered export reads aspartial-coverage, never as false divergence: component deltas fold over the covered subset only), per-component deltas per serving model, and the implied actual rate of every component beside our effective rate over the same token base, so a real divergence NAMES the rate-card line that moved with the rate the provider actually applied. Unpriced models and usage-unknown rows are declared apart, never folded or silent; verdicts arematch,divergence,partial-coverage,no-overlap. Backing it,@rulvar/coreexportspriceComponentsOf(pricing, usage): the four billing components (uncached input, output, cached input, cache writes) with token bases and dollars, decomposed with exactly the settled fold's arithmetic;priceUsdOfis now defined as the sum of those four terms in the historical order, byte for byte the same number, so the reconciliation and the settled fold can never disagree about what a usage costs. Validated against the real twelfth-run artifacts offline: the founder's eight dashboard categories reconcile tomatchwith every delta under 0.0005 (3-decimal rounding), response-id coverage reads 120 of 120, a 100-row truncation reads partial coverage with zero divergence, and a synthetically distorted write rate namesgpt-5.6-terra cache-writewith implied 2.5 USD/MTok against effective 3.125.
Patch Changes
- Updated dependencies [f8341a3]
- @rulvar/[email protected]
1.117.0
Patch Changes
- @rulvar/[email protected]
1.116.0
Patch Changes
- Updated dependencies [a213878]
- @rulvar/[email protected]
1.115.0
Patch Changes
- Updated dependencies [63642ae]
- @rulvar/[email protected]
1.114.0
Patch Changes
- Updated dependencies [5759731]
- @rulvar/[email protected]
1.113.0
Patch Changes
- Updated dependencies [a60807a]
- @rulvar/[email protected]
1.112.0
Patch Changes
- Updated dependencies [00ae55b]
- @rulvar/[email protected]
1.111.0
Patch Changes
- Updated dependencies [fd25169]
- @rulvar/[email protected]
1.110.0
Patch Changes
- Updated dependencies [58afdb5]
- @rulvar/[email protected]
1.109.0
Patch Changes
- Updated dependencies [85b1d39]
- @rulvar/[email protected]
1.108.0
Patch Changes
- Updated dependencies [affa3d4]
- @rulvar/[email protected]
1.107.0
Patch Changes
- Updated dependencies [9f5f6f6]
- @rulvar/[email protected]
1.106.0
Patch Changes
- Updated dependencies [9a4ce49]
- @rulvar/[email protected]
1.105.0
Patch Changes
- Updated dependencies [531dc88]
- @rulvar/[email protected]
1.104.0
Patch Changes
- @rulvar/[email protected]
1.103.0
Patch Changes
- Updated dependencies [f2b809e]
- @rulvar/[email protected]
1.102.0
Patch Changes
- Updated dependencies [3eb6515]
- @rulvar/[email protected]
1.101.0
Patch Changes
- Updated dependencies [51b215c]
- @rulvar/[email protected]
1.100.0
Patch Changes
- Updated dependencies [9785bea]
- @rulvar/[email protected]
1.99.1
Patch Changes
- ef08d73: Guarantee matrix and exactly-once claim hygiene (RV508); no runtime behavior changes. The isolated-executor guide now carries the guarantee matrix stating flatly who provides what: the library's layers give at-least-once execution with attempt binding and intent-before-effect, exactly-once effect execution is promised by NO library layer, and what IS exactly-once is pay and replay (the never-pay-twice invariant). The two claims the ninth comparison experiment's judge caught are rewritten to the precise statements ("each ran once" became attempt counting under a stable idempotency key; the approvals guide now says continuation is a run-level guarantee, not an effect-level one, with the at-least-once window named);
ctx.stepdocs state the same window for effectful steps; aResolutionBynote says the field records a channel, never a verified principal (identity, signatures, and separation of duties are host IAM). The worker header now points at the shippedSqliteQuotaLimiterandPostgresQuotaLimiterinstead of denying that cross-process limiters exist. A new docs-lint sentinel forbids "exactly once" claims in the hand-written docs and in package source comments outside a vetted (file, heading anchor) allowlist (the durability pay doctrine and the guarantee matrix), and every remaining occurrence in doc prose and source comments was rewritten to the precise wording; string literals are deliberately out of scope (tool descriptions enter the toolset hash). - Updated dependencies [ef08d73]
- @rulvar/[email protected]
1.99.0
Patch Changes
- Updated dependencies [9e00888]
- @rulvar/[email protected]
1.98.0
Patch Changes
- @rulvar/[email protected]
1.97.0
Patch Changes
- Updated dependencies [5c3b453]
- @rulvar/[email protected]
1.96.0
Patch Changes
- @rulvar/[email protected]
1.95.0
Patch Changes
- @rulvar/[email protected]
1.94.0
Patch Changes
- @rulvar/[email protected]
1.93.0
Patch Changes
- Updated dependencies [c62150a]
- @rulvar/[email protected]
1.92.0
Patch Changes
- Updated dependencies [351d1f5]
- @rulvar/[email protected]
1.91.0
Patch Changes
- @rulvar/[email protected]
1.90.0
Patch Changes
- Updated dependencies [9603940]
- @rulvar/[email protected]
1.89.0
Minor Changes
- f18b671: Provider-id provenance parity across every adapter path (RV401, the eighth comparison experiment). The AI SDK bridge now ships the flat
responseIdthe core reconciliation record reads, beside the nestedresponseobject it always emitted, and an error finish carries the accumulated response metadata and warnings on the error event instead of dropping them (retained parts stay deliberately absent there: a failed turn is discarded, never re-injected). The core agent loop captures provider metadata from error events and falls back to the AI SDK's nestedresponse.idshape when a third-party adapter ships only that, with the flat first-class form winning when both are present. The OpenAI adapter attaches the failed response's id to itsresponse.failederror event, so a billed failure reconciles against the provider statement exactly like an ok row. End-to-end tests pin a bridged engine run whose per-call reconciliation records carry ids on the success, retry, and billed-failure paths alike.
Patch Changes
- Updated dependencies [f18b671]
- Updated dependencies [f18b671]
- @rulvar/[email protected]
1.88.0
Patch Changes
- Updated dependencies [3b339d9]
- @rulvar/[email protected]
1.87.0
Patch Changes
- Updated dependencies [c4c02b1]
- @rulvar/[email protected]
1.86.0
Patch Changes
- Updated dependencies [2f71894]
- @rulvar/[email protected]
1.85.0
Patch Changes
- Updated dependencies [6932a9f]
- @rulvar/[email protected]
1.84.0
Patch Changes
- @rulvar/[email protected]
1.83.0
Patch Changes
- @rulvar/[email protected]
1.82.0
Patch Changes
- Updated dependencies [9cc5d66]
- @rulvar/[email protected]
1.81.2
Patch Changes
- Updated dependencies [296885b]
- @rulvar/[email protected]
1.81.1
Patch Changes
- Updated dependencies [c030982]
- @rulvar/[email protected]
1.81.0
Patch Changes
- Updated dependencies [ce4c392]
- @rulvar/[email protected]
1.80.0
Patch Changes
- Updated dependencies [262e397]
- @rulvar/[email protected]
1.79.0
Patch Changes
- Updated dependencies [85956ab]
- @rulvar/[email protected]
1.78.0
Patch Changes
- Updated dependencies [941b6e1]
- @rulvar/[email protected]
1.77.0
Patch Changes
- Updated dependencies [6aba271]
- @rulvar/[email protected]
1.76.0
Patch Changes
- Updated dependencies [22cba47]
- @rulvar/[email protected]
1.75.1
Patch Changes
- Updated dependencies [82bc0f0]
- @rulvar/[email protected]
1.75.0
Minor Changes
- c486de8: The provider output floor and the finish arguments second chance (the v1.74 comparison review, P0.1 + P1.5).
ModelCaps.minOutputTokensPerTurndeclares the smallest request output cap the provider accepts (OpenAI Responses: 16; absent means one), and the layer-2b budget clamp never dispatches below it: the last-gasp turn goes out AT the floor instead of one token, a remainder that cannot buy the floor is refused as a typedBudgetExhaustedErrorwith zero wire calls, and a configured per-turn cap below the floor is aConfigError;preflightEstimatereports that configuration as the error findingoutput-cap-below-provider-minimum. Tool arguments an adapter delivered as the parse-failure wrapper{__unparsed: raw}now get one deterministic second chance before the schema rejection: a strict re-parse, then one bounded normalization (markdown fence, first balanced object, raw control characters escaped inside string literals); a recovered object that passes the tool schema executes as if it had parsed on the wire, with a warn log naming the pass, and replay or resume recovers identically with nothing journaled. The OpenAI wire re-projects an unparseable call as the ORIGINAL raw arguments string instead of the wrapper JSON, so a model no longer learns to imitate{"__unparsed": ...}from its own rewritten history. Both wires drop unsafe-integerx-ratelimitvalues instead of normalizing 400 digits intoInfinity.FakeAdaptergainscapsOverridesso offline tests can drive caps-declared behavior like the floor.
Patch Changes
- Updated dependencies [c486de8]
- @rulvar/[email protected]
1.74.0
Minor Changes
- d94beab: Quota drift telemetry and the honest zero (the v1.71 experiment review, P0.5 resized + P1.4). The experiment declared 12M TPM over a provider-real 1M, the local limiter went quiet, and seven live 429s followed with nothing recording the mismatch. Now: both wire adapters parse the provider's x-ratelimit headers on every real 429 into normalized per-minute limits (
WireError.data.reportedLimits; the openai wire also gains the raw bucket capture the anthropic wire already had), the loop remembers them per (provider, model) as live telemetry, and the opt-inquota.declaredRules(the SAME rule array preflight takes) makes the engine journal aquota_driftdecision plus a warn log whenever a binding declared cap EXCEEDS the provider-reported one, per invocation and dimension, with anthropic's split input and output windows summed against a combined declared tokensPerMinute. Purely observational, synthetic limiter denials never count, and without declaredRules journals and events stay byte identical. On the invoice, anunconfirmedrow that recorded zero usage on every counter now carriesusageUnknown: true(export-levelusageUnknownRowscount, CLIusage-unknownmarker): the zeros mean "nothing recorded", never "the provider metered nothing"; derived at export time, no journal shape change.
Patch Changes
- Updated dependencies [d94beab]
- @rulvar/[email protected]
1.73.0
Patch Changes
- Updated dependencies [3e95bd1]
- @rulvar/[email protected]
1.72.0
Patch Changes
- Updated dependencies [662e9e0]
- @rulvar/[email protected]
1.71.0
Patch Changes
- Updated dependencies [20d02e0]
- @rulvar/[email protected]
1.70.1
Patch Changes
- @rulvar/[email protected]
1.70.0
Patch Changes
- @rulvar/[email protected]
1.69.0
Patch Changes
- Updated dependencies [b21a681]
- @rulvar/[email protected]
1.68.0
Patch Changes
- Updated dependencies [b227874]
- @rulvar/[email protected]
1.67.0
Patch Changes
- Updated dependencies [8e6006d]
- @rulvar/[email protected]
1.66.0
Patch Changes
- Updated dependencies [1b8987e]
- @rulvar/[email protected]
1.65.0
Patch Changes
- Updated dependencies [0b6b859]
- @rulvar/[email protected]
1.64.0
Patch Changes
- Updated dependencies [991f9b5]
- @rulvar/[email protected]
1.63.0
Patch Changes
- Updated dependencies [8a28aed]
- @rulvar/[email protected]
1.62.0
Patch Changes
- Updated dependencies [fca5fd1]
- @rulvar/[email protected]
1.61.0
Patch Changes
- Updated dependencies [b4c1f1f]
- @rulvar/[email protected]
1.60.0
Patch Changes
- Updated dependencies [59bbeaa]
- @rulvar/[email protected]
1.59.4
Patch Changes
- Updated dependencies [c49d7a1]
- @rulvar/[email protected]
1.59.3
Patch Changes
- Updated dependencies [deaef36]
- @rulvar/[email protected]
1.59.2
Patch Changes
- Updated dependencies [dd0e10f]
- @rulvar/[email protected]
1.59.1
Patch Changes
- Updated dependencies [c127770]
- @rulvar/[email protected]
1.59.0
Patch Changes
- Updated dependencies [615dc90]
- @rulvar/[email protected]
1.58.0
Patch Changes
- Updated dependencies [4fa35ce]
- @rulvar/[email protected]
1.57.0
Patch Changes
- Updated dependencies [5897232]
- @rulvar/[email protected]
1.56.0
Patch Changes
- Updated dependencies [f26dba0]
- @rulvar/[email protected]
1.55.0
Patch Changes
- Updated dependencies [e9b005b]
- @rulvar/[email protected]
1.54.0
Patch Changes
- Updated dependencies [3f6bc03]
- @rulvar/[email protected]
1.53.0
Patch Changes
- Updated dependencies [b821bd1]
- @rulvar/[email protected]
1.52.0
Patch Changes
- Updated dependencies [e138df9]
- @rulvar/[email protected]
1.51.0
Patch Changes
- @rulvar/[email protected]
1.50.0
Patch Changes
- Updated dependencies [e39a885]
- @rulvar/[email protected]
1.49.0
Patch Changes
- Updated dependencies [bab7b2c]
- @rulvar/[email protected]
1.48.0
Patch Changes
- @rulvar/[email protected]
1.47.0
Patch Changes
- Updated dependencies [a3687fe]
- @rulvar/[email protected]
1.46.0
Patch Changes
- Updated dependencies [865e7bf]
- @rulvar/[email protected]
1.45.0
Patch Changes
- Updated dependencies [b96305d]
- @rulvar/[email protected]
1.44.1
Patch Changes
- @rulvar/[email protected]
1.44.0
Patch Changes
- Updated dependencies [299f7d2]
- @rulvar/[email protected]
1.43.0
Patch Changes
- Updated dependencies [71b7181]
- @rulvar/[email protected]
1.42.0
Patch Changes
- Updated dependencies [9b70f27]
- @rulvar/[email protected]
1.41.0
Patch Changes
- Updated dependencies [be589ec]
- @rulvar/[email protected]
1.40.0
Patch Changes
- Updated dependencies [cf33550]
- @rulvar/[email protected]
1.39.0
Patch Changes
- @rulvar/[email protected]
1.38.0
Patch Changes
- @rulvar/[email protected]
1.37.0
Patch Changes
- Updated dependencies [e6b1481]
- Updated dependencies [e6b1481]
- @rulvar/[email protected]
1.36.0
Patch Changes
- Updated dependencies [101795b]
- @rulvar/[email protected]
1.35.0
Patch Changes
- Updated dependencies [d4ac3bf]
- @rulvar/[email protected]
1.34.0
Patch Changes
- Updated dependencies [f1505ec]
- @rulvar/[email protected]
1.33.0
Patch Changes
- @rulvar/[email protected]
1.32.0
Patch Changes
- @rulvar/[email protected]
1.31.0
Patch Changes
- df6b8f8:
Retry-Afteraccepts HTTP optional whitespace padding only. ECMAScripttrim()removed far more than the OWS production (space and horizontal tab), so values padded with newline, carriage return, vertical tab, form feed, or NBSP were honored as delays despite the documented exact delta seconds grammar; a real HTTP transport rejects most of those octets, but an injected SDK client or a mock does not. Both first party adapters now match/^[\t ]*([0-9]+)[\t ]*$/and fall back to the computed policy backoff for every other form.- @rulvar/[email protected]
1.30.0
Patch Changes
- 87ce985: Parse
Retry-Afterunder the exact RFC delta seconds grammar (v1.29.0 review P3). Published 1.29.0 usedNumber(header), which accepted far more than the documented delta seconds form: an empty or whitespace header became a 0 ms delay (an instant retry instead of the policy backoff), and hex (0x10), exponent (1e3), decimal (1.5), and signed (+3) forms were honored as delays. The value must now be a nonempty run of decimal digits after optional whitespace; every other form (the HTTP date included) omitsretryAfterMsso the engine's computed backoff applies, and a huge digit run still clamps to the Node timer maximum. - Updated dependencies [87ce985]
- @rulvar/[email protected]
1.29.0
Minor Changes
621d566: Make the retry and failover backoff interruptible and validate every provider supplied retry delay (v1.28.0 review P1 and P2).
The retry engine now races its backoff wait against the host cancel signal (which the run deadline also drives) and the budget ceiling signal: an abort wakes the wait immediately, settles through the canonical aborted outcome (
cancelledorexhausted, with every already recorded usage kept), and forbids every further dispatch, including the one behind a keyed limiter queue, so an adapter that ignores its signal can no longer be re entered after an abort. Previously a provider suppliedretryAfterMsarmed an uninterruptible sleep: a cancel, a crossed deadline, and a crossed budget ceiling all waited out the full backoff and the adapter was dispatched again. The injectedretry.sleep(ms)test hook keeps its signature; a hook that loses the race is abandoned without an unhandled rejection, and the native timer path clears its timer so an abandoned long backoff never pins the event loop.retryDelayMsis now the defensive boundary the docs promise: only a finite nonnegative providerretryAfterMsreplaces the computed delay, anything else (NaN, Infinity, a negative) is ignored as adapter noise, and every returned delay is a finite nonnegative integer clamped to the Node timer maximum, so a malformed or huge value can never arm an instant or overflowing timer. Both first party adapters stop emitting unvalidatedRetry-Afterparses: an unparsable header (the HTTP date form included) omitsretryAfterMsentirely instead of producing NaN (which also broke theWireError.dataJson invariant by serializing to null), and a huge but finite value is clamped. ThemapAnthropicStreamTSDoc now states precisely how a truncated stream is reported (thefinishedflag on the return value, with the adapter synthesizing the terminal error).Four frozen fixture cassettes are refrozen for this release (the hashVersion-bump refreeze ceremony applies; hashVersion itself is unchanged and existing journals replay identically): in three cap freeze scenarios the main orchestrator entry now honestly settles cancelled at the cap instead of paying one more ordinary turn whose result the forced finish machinery discarded anyway, and one scenario loses a post abort wait suspension that can no longer be dispatched. Entry identities, keys, and every other row are byte identical.
Patch Changes
- Updated dependencies [621d566]
- @rulvar/[email protected]
1.28.0
Minor Changes
- d98eb0b: Enforce the terminal stream contract end to end (v1.27.0 deep E2E review P1 and P2). The runtime now fails closed when an adapter stream drains without a terminal
finishorerrorevent: the partial turn becomes a retryable transport fault that feeds the ordinary retry and failover machinery instead of settling asokwith truncated text, and a requested abort (cancel, budget ceiling, idle severance) remains a clean end with no fabricated provider error. Consumption stops at the first terminal event, so events afterfinishcan no longer mutate the value, revise the authoritative bill, or trigger tool execution. The first party adapters enforce the same contract at the wire: the Chat Completions mapper no longer synthesizesfinish: stopwhen the stream is cut before afinish_reason(usage the provider did report is still forwarded, half assembled tool calls are dropped), the Responses mapper fails closed on EOF without a response terminal event, and the Anthropic adapter surfaces a read cut beforemessage_stopas a retryable transport error and no longer converts a caller requested abort duringmessages.create()into a terminal error.mapResponsesStreamandmapChatCompletionsStreamaccept an optionalsignalso a requested abort keeps ending the stream without a terminal event. The VCRrecordwrapper now commits its cassette row even when the consumer stops reading at the terminal event (the engine always does now); adapter middleware must not rely on being drained past the terminal. The committedcombined-loop-descentcatalog cassette is refrozen because stopping consumption at the terminal shifts the deterministic interleaving of two parallel plan children by one scheduler turn; entry content, keys, and the actualhashVersionare unchanged, journals recorded under earlier versions replay unchanged, and this changeset carries the frozen fixture gate's hashVersion-bump ceremony token only to unlock that refreeze.
Patch Changes
- Updated dependencies [d98eb0b]
- @rulvar/[email protected]
1.27.0
Patch Changes
- Updated dependencies [884a433]
- @rulvar/[email protected]
1.26.0
Patch Changes
- Updated dependencies [a4fc757]
- @rulvar/[email protected]
1.25.0
Patch Changes
- @rulvar/[email protected]
1.24.1
Patch Changes
- Updated dependencies [0bb14db]
- @rulvar/[email protected]
1.24.0
Patch Changes
- Updated dependencies [2b033e8]
- @rulvar/[email protected]
1.23.0
Patch Changes
- Updated dependencies [1f9c272]
- @rulvar/[email protected]
1.22.0
Patch Changes
- Updated dependencies [77b554f]
- @rulvar/[email protected]
1.21.0
Minor Changes
- 7ee42a0: Canonical reasoning effort
maxnow reaches the wire unchanged on every GPT-5.6 sibling: Terra and Luna join Sol withwireMaxEffort: true, each verified live (a max-effort Responses call returns 200 with the effort echoed, and the API's own 400 validator enumeratesmaxamong the supported values), closing the silent quality downgrade of the v1.20.0 review P2-3. Pre-5.6 families and unknown models keep the safe, visible downmap toxhigh. The adapter also declaresusageSemantics: 'openai-cache-subsets-v2', stamped onto usage-bearing journal entries so the cache-accounting semantics ride the journal alongside the numbers, and new exportsundoV1190CacheDoubleCountandauditV1190CacheJournalprovide the exact opt-in sidecar inversion for journals recorded by v1.19.0, whose adapter double-counted cache writes (v1.20.0 review P1/P2-2). Numeric hygiene stays with the core boundary validator by design; the normalizer maps wire shape only.
Patch Changes
- Updated dependencies [7ee42a0]
- @rulvar/[email protected]
1.20.0
Patch Changes
- 9367030: Cache detail tokens are subsets of the full input, never additions. On the OpenAI wire
input_tokens/prompt_tokensis already the complete prompt count;cached_tokensandcache_write_tokensclassify parts of it. The v1.19.0 normalizer added cache writes on top of the full count, double-billing every written token at the base rate plus the 1.25x premium (a 73.6 percent overreport on the review's live cache scenario) and inflating budget debits, which could prematurely exhaust run, agent, and child ceilings. Both the Responses and the Chat Completions paths now pass the provider's full count through untouched and clamp impossible telemetry conservatively (nonnegative, reads keep priority, reads plus writes never exceed the input) instead of rejecting paid evidence. Verified against the live wire: identical prompts report the sameinput_tokenswhether the details show a write or a read, andtotal_tokensequals input plus output; a new opt-in live contract test pins exactly that. - Updated dependencies [9367030]
- @rulvar/[email protected]
1.19.0
Patch Changes
- 8cc9a9c: Three cost-accounting corrections against the official OpenAI materials. Prompt cache writes are now accounted: GPT-5.6 and later report
input_tokens_details.cache_write_tokens(Responses) andprompt_tokens_details.cache_write_tokens(Chat Completions) separately from the base prompt count, billed at 1.25x the uncached input rate; the adapter previously pinnedcacheWriteTokensto 0, so the premium never entered cost or the budget guard. Writes now joininputTokens(the canonical Usage invariant: the full prompt), mirroring the Anthropic adapter's mapping, with one usage emission per response.response.failednow emits the failed response's paid usage before the error termination and classifiesresponse.error.codecanonically:rate_limit_exceededretries as a rate limit,server_errorand timeout-class codes retry as transport faults, validation/policy/auth and unknown codes stay non-retryable (fail closed); previously the branch dropped usage entirely and pinnedretryable: false. The pre-5.6 price rows had gone stale after the provider's price cut and are corrected:gpt-5.55/30 (cached 0.5),gpt-5.5-pro30/180 (no cached-input rate published; the row omits the field rather than fabricating a discount or a zero),gpt-5.42.5/15 (cached 0.25),gpt-5.4-mini0.75/4.5 (cached 0.075).OPENAI_PRICING.pricingVersionbumps toopenai-2026-07-18-r2so a resumed run that priced under the stale rows surfaces the drift instead of silently reinterpreting past spend. - Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- @rulvar/[email protected]
1.18.0
Minor Changes
- 943962d: Exact GPT-5.6 Terra and Luna capability and pricing rows, and a safe snapshot grammar. The seed table previously carried only Sol and the
gpt-5.6alias, and the general prefix matcher let the alias capture the sibling models:gpt-5.6-lunaandgpt-5.6-terrawere silently priced as Sol (5x on Luna), which is worse than no price at all. Terra ($2.5/$15 per MTok, cache read $0.25, cache write $3.125) and Luna ($1/$6, cache read $0.1, cache write $1.25) now have their own rows with the family's long-context tier (strictly above 272K input: 2x input, 1.5x output), both exported throughOPENAI_PRICINGunderpricingVersionopenai-2026-07-18. Prefix inheritance is restricted to the documented dated-snapshot grammar<exact model>-YYYY-MM-DD; any other unknown sibling or suffix now resolves to conservative unpriced caps so its usage lands inCostReport.unpricedinstead of a fabricated total. Canonical reasoning effortmaxis now sent on the wire unchanged for Sol (OpenAiModelInfo.wireMaxEffort); other models keep the documented lossy downmap toxhigh, still recorded inproviderMetadata.openai.effortDownmapped.
Patch Changes
- Updated dependencies [943962d]
- @rulvar/[email protected]
1.17.0
Patch Changes
- @rulvar/[email protected]
1.16.2
Patch Changes
- @rulvar/[email protected]
1.16.1
Patch Changes
- @rulvar/[email protected]
1.16.0
Patch Changes
- @rulvar/[email protected]
1.15.0
Minor Changes
- 4aee1f3: Production auth surface (v1.14 review P2-2). New
sdkOptionsonOpenAiAdapterOptionsforwards official SDK construction options verbatim,maxRetriesexcluded from the type (OpenAiSdkOptions) and forced to 0:workloadIdentityfederation included, plusfetch,timeout, anddefaultHeaders. Theclientoption now accepts the officialOpenAIinstance directly under strict TypeScript, no casts, alongside the structuralOpenAiClientLikemock; an injected client with SDK autoretries enabled (maxRetries !== 0) is rejected with a typedConfigError, as areclientcombined with construction options, duplicated fields, and theapiKeyplussdkOptions.workloadIdentityconflict, all before any network I/O. A synthetic workload-identity test covers the full path: one token exchange, one Responses API request under the short-lived bearer, canonical finish.
Patch Changes
- @rulvar/[email protected]
1.14.0
Patch Changes
- @rulvar/[email protected]
1.13.0
Patch Changes
- @rulvar/[email protected]
1.12.0
Patch Changes
- Updated dependencies [46edcc0]
- @rulvar/[email protected]
1.11.0
Patch Changes
- Updated dependencies [0c70c5e]
- @rulvar/[email protected]
1.10.0
Patch Changes
- Updated dependencies [0e8d78e]
- @rulvar/[email protected]
1.9.0
Minor Changes
7577f8e: Correct the Anthropic fallback pricing to the official table and export versioned price tables from both first-party adapters.
The
ANTHROPIC_MODELSseed rows had never been audited against the published price list and overcharged every current Claude model: Fable 5 was seeded at exactly 2x the official rate (20/100 vs 10/50 per MTok, cache rates likewise), Opus 4.8 at 12/60 vs 5/25, Opus 4.7 at 10/50 vs 5/25, and Opus 4.6 at 15/75 vs 5/25. Claude Sonnet 5 now carries its introductory price (2/10, in effect through 2026-08-31); Haiku 4.5 and Sonnet 4.6 were already correct. Cost reports for affected models drop accordingly, and budget ceilings admit roughly twice the work they previously rejected.New exports
ANTHROPIC_PRICING(anthropic-2026-07-16) andOPENAI_PRICING(openai-2026-07-16) publish the seed rows as versionedPriceTables forcreateEngine({ pricing }), so runs journal a concrete pricing version instead ofunpricedand price revisions become explicit table updates.createTestEnginegained apricingpassthrough for testing against a versioned table.
Patch Changes
- Updated dependencies [3a53383]
- @rulvar/[email protected]
1.8.0
Patch Changes
- Updated dependencies [25724b5]
- Updated dependencies [57ea1de]
- Updated dependencies [7884ec5]
- Updated dependencies [52db30d]
- @rulvar/[email protected]
1.7.0
Patch Changes
- Updated dependencies [45285aa]
- Updated dependencies [2f20d1d]
- Updated dependencies [22f65a8]
- Updated dependencies [2ddfa29]
- Updated dependencies [2abd9c2]
- Updated dependencies [1c1175d]
- @rulvar/[email protected]
1.6.0
Minor Changes
df416fc: Correct and extend model pricing: GPT-5.6 entries, long-context tiers, no fabricated prices, no double-charged cache.
Pricinggains optional long-contexttiers(PricingTier): the highest threshold strictly below the full prompt re-prices the entire request, input-side rates (cache included) scaling byinputMultiplierand the output rate byoutputMultiplier. Existing linear rows are untouched.@rulvar/openaiseedsgpt-5.6-soland itsgpt-5.6alias with the official caps and pricing (1,050,000 context, 128,000 max output, $5/$0.50/$30 per MTok, $6.25 cache write, 2x input and 1.5x output above 272K input tokens). Previously the unknown-model fallback silently priced them as gpt-5.4.- Unknown model ids in both first-class adapters keep conservative transport caps but no longer receive a fabricated price row: their usage surfaces in
CostReport.unpricedand a USD ceiling warns that it cannot bound them. Provide a versionedcreateEngine({ pricing })row for hosted models the tables do not know yet. priceUsdOfno longer double-charges cache tokens: under the Usage invariantinputTokensis the full prompt, so the input rate now bills only the uncached remainder while cache reads and writes bill at their own rates (a row without cache rates bills them at the input rate). Cache-heavy runs previously over-attributed cost by the full input rate on every cached token.- Admission reserve estimation routes through the same
priceUsdOf, so estimates and settled costs share one formula, tiers included. - Model id resolution picks the longest matching table prefix, so a dated
gpt-5.5-pro-...snapshot resolves to the pro entry, never the shortergpt-5.5sibling.
886d065: Make the first-class adapters genuinely streaming: every canonical event is yielded AS its provider event is consumed.
Both adapters (and
openaiCompatible) buffered the complete canonical event stream in an internal array and yielded it only after the provider response finished. Consequences fixed by this change:agent:streamwas never live; the stream-idle watchdog saw zero events during healthy generation, so any turn longer thanstreamIdleTimeoutMs(default 120s) was falsely severed as idle and retried; a budget or external abort lost ALL partial usage (the journal recorded zero for tokens the provider billed); and every delta of a long response was retained in memory.mapAnthropicStream,mapResponsesStream, andmapChatCompletionsStreamare now async generators: they yield eachChatEventas the corresponding provider event is consumed, with the consumer's pull as the only pacing (natural backpressure, no queue, no detached work). The Anthropic mapper's return value carries the accumulatedpause_turnstate;TurnMappingno longer has the redundanteventsarray field. Callers of the old callback signatures (emitparameter) must switch to iterating the generator.- Adapter behavior is preserved: canonical id mapping, thinking/reasoning retention,
pause_turncontinuation and its cap (each segment now streams live before the continuation dispatches), tool argument assembly, typed refusals and errors, exactly one canonical terminal event, the degraded Chat Completions path (visible inproviderMetadata.openai.degradedPath), abort propagation, usage normalization, and SDK autoretries disabled. - New regression tests with gated fake SDK clients prove the first
stream().next()resolves before the provider terminal exists, aborts reach the in-flight provider iterable after the first delta, a paused consumer causes zero read-ahead (lock-step pulls),pause_turnsegment deltas arrive before the continuation request, and exactly one terminal event survives.
Patch Changes
- da4dbad: Write the product name as Rulvar in prose: package READMEs, npm descriptions, and the documentation site now capitalize the brand. Identifiers keep their exact casing, so package names, the
rulvarbinary,rulvar.config.mjs, the.rulvarstore directory, therulvar.*OTel attributes, and every URL are unchanged. Documentation and metadata only; no runtime behaviour changes. - Updated dependencies [da4dbad]
- Updated dependencies [487da86]
- Updated dependencies [df416fc]
- Updated dependencies [a737810]
- Updated dependencies [9eb66b4]
- @rulvar/[email protected]
1.5.2
Patch Changes
- Updated dependencies [54936a0]
- @rulvar/[email protected]
1.5.1
Patch Changes
- Updated dependencies [6c6d56f]
- @rulvar/[email protected]
1.5.0
Patch Changes
- Updated dependencies [4fba3c7]
- Updated dependencies [8655c0f]
- @rulvar/[email protected]
1.4.0
Patch Changes
- Updated dependencies [c4f563d]
- @rulvar/[email protected]
1.3.2
Patch Changes
- ddef383: Every published package now ships a README, so its npm page states what the package is, how it installs, and where the documentation lives (npm includes README.md in the tarball regardless of the files allowlist, so no manifest changes are involved; @rulvar/compat gains its README on its own next release). Alongside, the repository-level pages are refreshed to the current project state: the root README is rewritten around the never-pay-twice pitch with a runnable quickstart condensation and the full package table, CONTRIBUTING.md lists the complete PR gate set, the examples README drops retired-spec citations for live docs.rulvar.com links and documents the dogfood journal replay, and the pointer README gets the same treatment.
- Updated dependencies [ddef383]
- @rulvar/[email protected]
1.3.1
Patch Changes
- 7d1552e: Runtime message strings no longer cite the retired internal specification set: error and warning messages, validation issues, and the CLI help text drop the dangling
docs/NN, section ...references, pointing at https://docs.rulvar.com pages where a pointer earns its place (the CLI help header, tool naming, toolset registries, bare resume). The umbrella package description sheds the naming-contingency note: the unscoped alias is published and owned. Three strings embedded in frozen recordings stay byte-identical on purpose (the no-progress abort reason and two testing-internal recorder strings), as does the byte-locked golden-fold fixture. Test-file comments lose their citations too; test titles are unchanged. - Updated dependencies [7d1552e]
- @rulvar/[email protected]
1.3.0
Patch Changes
- Updated dependencies [7d1a287]
- @rulvar/[email protected]
1.2.0
Patch Changes
- 154507b: TSDoc and inline comments no longer cite the retired internal specification set (the pre-docs-site
docs/NN, section ...references). The citations either became links to the public documentation at docs.rulvar.com or were dropped where the comment already carried the rule; traceability markers (DEF-n, XF-nn, FR-nnn, OQ-nn, W-nnn) are untouched. Comment-only change: no runtime behavior, no API shapes, and no runtime message strings were modified; the frozen golden-fold fixture is byte-identical. - Updated dependencies [3bfaec0]
- Updated dependencies [890f42c]
- Updated dependencies [154507b]
- @rulvar/[email protected]
1.1.0
Patch Changes
- Updated dependencies [d16b04a]
- @rulvar/[email protected]
1.0.0
Patch Changes
- Updated dependencies [0e0b569]
- Updated dependencies [b28b7a3]
- Updated dependencies [b53a89e]
- Updated dependencies [4454175]
- Updated dependencies [6599ca8]
- Updated dependencies [6649e5f]
- Updated dependencies [fd2f83b]
- Updated dependencies [01d6b2d]
- Updated dependencies [9a20dbb]
- Updated dependencies [0fbe7ea]
- Updated dependencies [ebe0abc]
- Updated dependencies [a3079d0]
- Updated dependencies [596a39b]
- Updated dependencies [464ab6e]
- @rulvar/[email protected]
0.9.0
Patch Changes
- Updated dependencies [84f94d4]
- Updated dependencies [65c7b2c]
- Updated dependencies [a2a3243]
- Updated dependencies [ebc8101]
- @rulvar/[email protected]
0.8.0
Patch Changes
- Updated dependencies [85d55cf]
- Updated dependencies [b88c9e3]
- Updated dependencies [f3c4613]
- Updated dependencies [a41c20f]
- Updated dependencies [f4e70be]
- Updated dependencies [75d1646]
- Updated dependencies [0627413]
- Updated dependencies [55c0f87]
- Updated dependencies [fd33871]
- Updated dependencies [e70e7f4]
- Updated dependencies [bc9c903]
- @rulvar/[email protected]
0.7.0
Patch Changes
- Updated dependencies [fd1d06c]
- Updated dependencies [6fcf296]
- Updated dependencies [dcc97a9]
- Updated dependencies [434dc83]
- Updated dependencies [03173c1]
- Updated dependencies [11c0afc]
- @rulvar/[email protected]
0.6.0
Patch Changes
- Updated dependencies [fa05007]
- Updated dependencies [9234dc8]
- Updated dependencies [644512c]
- Updated dependencies [8a41656]
- Updated dependencies [02f7f7a]
- @rulvar/[email protected]
0.5.0
Minor Changes
ac274f4: M4-T01 role protocol completion. The full trigger protocol for the six invocation roles lands in
@rulvar/core(model/roles.ts):- Extract necessity is completed per docs/04 section 8.3: a separate final structured-output invocation fires when a schema is set AND (routing directs extract to a different model OR the loop model's required tier cannot ride a tools-available turn OR finalize is routed). The required-tier rule is new: a
forced-tooltier pins toolChoice toemit_resultand cannot ride while the agent's tools must remain available, so such agents now pay one separate extract call instead of silently losing tool access. Agents without tools keep the M1 single-shot behavior byte for byte. - The finalize role fires for the first time: only when configured in routing and only for tool-bearing agents, as one synthesis invocation with toolChoice
'none'over the full transcript after tools stop. Its text is the output for schema-less calls; with a schema the separate extract runs over the transcript including the synthesis. - A separate extract invocation over a tool-bearing transcript now carries the agent's tool contracts (both providers reject tool-use history without tool definitions) with toolChoice pinned to
'none'or toemit_resultper tier. - Both adapters map
toolChoice: 'none'to the provider's explicit none choice with the tools param present instead of dropping tools from the request. createTestEngineno longer routesfinalizeby default: the routing key is the firing opt-in, and the old default would have summoned a synthesis call for every tool-bearing test agent. Tests that want finalize route it explicitly.
Identity is untouched: extract and finalize resolutions never enter the spawn content key, and existing journals replay unchanged.
- Extract necessity is completed per docs/04 section 8.3: a separate final structured-output invocation fires when a schema is set AND (routing directs extract to a different model OR the loop model's required tier cannot ride a tools-available turn OR finalize is routed). The required-tier rule is new: a
5735d92: M4-T02 HistoryProjector. Cross-provider history projection lands in
@rulvar/core(model/projector.ts) and the retention pipeline that feeds it:projectHistoryprojects the canonical history into a target provider's view: provider-raw parts ride if and only if the target adapter's provider family matches the part's provider; everything else passes through untouched. The agent loop projects EVERY outgoing request (loop turns, finalize, extract), so per-role provider mixing inside one agent yields a valid wire history on each side.- Retention transport: adapters ship a turn's blocks-to-retain in stream order via
finish.providerMetadata[<adapter id>].retainedParts; the runtime lifts them into provider-raw parts at the HEAD of the turn's canonical assistant message.@rulvar/anthropicships thinking and redacted_thinking blocks (signatures intact, pause_turn continuations included);@rulvar/openaiships reasoning items with their encrypted_content. Retained blocks now actually reach the canonical history, survive checkpoints, and echo byte-exact to their own provider on every subsequent turn. ProviderAdaptergains an optionalproviderfield: the provider family for provider-raw matching (default = adapter id). The first-class adapters declare 'anthropic' and 'openai';openaiCompatiblegateways declare 'openai' whatever their custom id, so same-family adapters share retained blocks and projections.
Identity is untouched: projection state never enters content keys, and adapters that ship no retention payload (FakeAdapter included) produce byte-identical histories.
Patch Changes
- Updated dependencies [ac274f4]
- Updated dependencies [5735d92]
- Updated dependencies [46ca98e]
- Updated dependencies [8ae129e]
- Updated dependencies [d1c4525]
- Updated dependencies [b840aba]
- @rulvar/[email protected]
0.4.0
Minor Changes
f668890: M3-T05 worktree isolation and M3-T06 openaiCompatible. GitWorktreeProvider implements the IsolationProvider seam: acquire creates a detached worktree from HEAD or a given ref (non-git host is a typed ConfigError), tools receive cwd inside the tree, collect() snapshots changed files and a binary patch, dispose removes the tree with keepOnError retention under the shared maxPinnedWorktrees cap (default 4). ctx.agent resolves isolation call-over-profile into spawn identity, stores the collected patch in TranscriptStore, and surfaces it as a kind 'patch' Artifact on AgentResult.artifacts and the terminal journal entry, so replays reconstruct artifacts with zero live calls; applying the patch stays with the caller. isolation 'readonly' is accepted as a declaration (its compiled deny rule ships with risk presets in M5).
@rulvar/openai gains openaiCompatible({ id, baseURL, apiKey?, caps? }) for Ollama, vLLM, and gateways: the Chat Completions dialect by construction, explicit ids so several endpoints coexist (duplicate id stays a ConfigError at createEngine), and the most conservative caps when unprobed (prompt-tier structured output, no parallel tools, no pricing; supplied caps merge over the floor).
Patch Changes
- Updated dependencies [dfe03b5]
- Updated dependencies [d2089a7]
- Updated dependencies [3f60234]
- Updated dependencies [f668890]
- Updated dependencies [16d7aa6]
- Updated dependencies [6513ce8]
- Updated dependencies [7dad493]
- Updated dependencies [2bbf180]
- @rulvar/[email protected]
0.3.0
Patch Changes
- Updated dependencies [43444f6]
- Updated dependencies [279881b]
- Updated dependencies [9fd0966]
- Updated dependencies [24ebadf]
- Updated dependencies [a1b35d3]
- Updated dependencies [18a5821]
- @rulvar/[email protected]
0.2.0
Minor Changes
- 527c9b4: M1-T12/T13: the two first-class adapters on the July 2026 surfaces. @rulvar/anthropic: adaptive thinking, the output_config umbrella (effort passthrough including max, native json_schema format), strict tools, cache_control compilation from cacheHint (deepest-4 kept), thinking-block retention with provider-granularity projection, pause_turn absorption without synthetic user messages, the full stop-reason table with typed refusal stop details, count_tokens, capabilities-bearing refreshCaps, retry-after/x-ratelimit/529 signaling, SDK autoretries disabled, usage normalization under the Usage invariant. @rulvar/openai: Responses API with manual item replay only (store false, encrypted reasoning echoed verbatim; previous_response_id/Conversations rejected as ConfigError), flattened strict function tools, text.format json_schema, the typed SSE catalog mapped to ChatEvent, the Chat Completions degraded path (visible via providerMetadata), effort mapping with the documented lossy max-to-xhigh downmap and provider none via providerOptions only, usage normalization.
Patch Changes
- Updated dependencies [c24228d]
- Updated dependencies [c50871e]
- Updated dependencies [1af8fb9]
- Updated dependencies [1fe0249]
- Updated dependencies [5c4fc32]
- @rulvar/[email protected]
0.1.0
Minor Changes
- f4e2be9: M0 repo bootstrap (v0.1.0, docs/10-implementation-plan.md section "M0"): monorepo scaffold on the committed toolchain (pnpm 11 workspaces with catalogs, TypeScript 6.0, tsdown, Vitest 4, ESLint 9 flat config, Turborepo 2, changesets fixed mode, npm trusted publishing), the docs/ canon as single source of truth, the L0 contracts skeleton in @rulvar/core, and the vendored dependencies (StandardSchemaV1/StandardJSONSchemaV1 types, the @cfworker/json-schema lineage validator subset, a first-party monotonic ULID). Placeholder scaffolds only: no public API ships in this release.
Patch Changes
- Updated dependencies [f4e2be9]
- @rulvar/[email protected]
@rulvar/plan
1.252.0
Patch Changes
- Updated dependencies [3ccb6cf]
- Updated dependencies [52d807f]
- Updated dependencies [517ed00]
- Updated dependencies [a7e589d]
- Updated dependencies [76e95eb]
- @rulvar/[email protected]
1.251.0
Patch Changes
- Updated dependencies [e7e829c]
- Updated dependencies [5982be8]
- Updated dependencies [7c58fb2]
- Updated dependencies [b3e465a]
- Updated dependencies [c4e5d6a]
- Updated dependencies [c6fc3da]
- Updated dependencies [c6fc3da]
- Updated dependencies [0ae8b85]
- Updated dependencies [7932936]
- Updated dependencies [7932936]
- Updated dependencies [88da0ed]
- Updated dependencies [06c0e85]
- @rulvar/[email protected]
1.250.0
Patch Changes
- Updated dependencies [0e240b9]
- Updated dependencies [6fe585e]
- Updated dependencies [c5eb19c]
- Updated dependencies [565c13b]
- Updated dependencies [c6d197b]
- Updated dependencies [c9d9729]
- Updated dependencies [fed9db6]
- Updated dependencies [df9ed76]
- Updated dependencies [3020912]
- Updated dependencies [d8d598d]
- @rulvar/[email protected]
1.249.0
Patch Changes
- Updated dependencies [8862133]
- Updated dependencies [0d7a717]
- Updated dependencies [e4428bd]
- Updated dependencies [d6873c1]
- Updated dependencies [4092e8d]
- Updated dependencies [e086590]
- Updated dependencies [1411938]
- Updated dependencies [737d1ee]
- Updated dependencies [634f966]
- Updated dependencies [052cc26]
- Updated dependencies [bbae134]
- @rulvar/[email protected]
1.248.0
Patch Changes
- Updated dependencies [8d0cd69]
- Updated dependencies [81065e4]
- Updated dependencies [8573f20]
- Updated dependencies [95f6a5e]
- @rulvar/[email protected]
1.247.0
Patch Changes
- Updated dependencies [1933ecc]
- Updated dependencies [db0a5f0]
- Updated dependencies [b698726]
- Updated dependencies [48348d2]
- Updated dependencies [4cfa1cc]
- Updated dependencies [4b7197a]
- Updated dependencies [5ebc842]
- Updated dependencies [16ff6b9]
- Updated dependencies [0c9941d]
- @rulvar/[email protected]
1.246.0
Patch Changes
- Updated dependencies [d165b0c]
- Updated dependencies [d59f4a0]
- Updated dependencies [46907ac]
- Updated dependencies [9929ad3]
- Updated dependencies [1790a6a]
- @rulvar/[email protected]
1.245.0
Patch Changes
- Updated dependencies [b4d47a8]
- Updated dependencies [dee6db4]
- Updated dependencies [b85c113]
- Updated dependencies [bc556e7]
- Updated dependencies [9f11d29]
- Updated dependencies [19bcea0]
- Updated dependencies [60b461c]
- Updated dependencies [61e3a1a]
- Updated dependencies [a156b81]
- Updated dependencies [0bd7045]
- @rulvar/[email protected]
1.244.0
Patch Changes
- Updated dependencies [38d839a]
- Updated dependencies [ce13b0f]
- Updated dependencies [4fa23e3]
- Updated dependencies [6841c69]
- Updated dependencies [f56721d]
- Updated dependencies [c894a43]
- Updated dependencies [f6944a3]
- Updated dependencies [23fd0e0]
- @rulvar/[email protected]
1.243.0
Patch Changes
- Updated dependencies [746d1f4]
- Updated dependencies [009b29c]
- Updated dependencies [1674cbe]
- Updated dependencies [bd096bc]
- @rulvar/[email protected]
1.242.0
Patch Changes
- Updated dependencies [6e3438e]
- Updated dependencies [ba5cf67]
- Updated dependencies [c2d1531]
- @rulvar/[email protected]
1.241.0
Patch Changes
- Updated dependencies [dbcdd24]
- Updated dependencies [7ae7243]
- Updated dependencies [4f832c4]
- Updated dependencies [7452d3d]
- Updated dependencies [a4e22bf]
- Updated dependencies [82df4af]
- @rulvar/[email protected]
1.240.0
Patch Changes
- @rulvar/[email protected]
1.239.0
Patch Changes
- Updated dependencies [74ce99a]
- Updated dependencies [ccd0665]
- Updated dependencies [0c5ce21]
- Updated dependencies [0616934]
- @rulvar/[email protected]
1.238.0
Patch Changes
- Updated dependencies [cf00947]
- Updated dependencies [c7b9382]
- Updated dependencies [88aea96]
- Updated dependencies [6da8d05]
- Updated dependencies [eae5c4c]
- @rulvar/[email protected]
1.237.0
Patch Changes
- Updated dependencies [9d6a279]
- Updated dependencies [49a98f6]
- Updated dependencies [a734ca0]
- Updated dependencies [deb406f]
- @rulvar/[email protected]
1.236.0
Patch Changes
- Updated dependencies [26306ea]
- Updated dependencies [709b942]
- @rulvar/[email protected]
1.235.0
Minor Changes
- e30687f: The resume config identity (RV3203). The profile registry hash frozen in
termination.init(profile names mapped to ladder lengths) is now recomputed on every PlanRunner resume: a mismatch refuses the resumed run typed BEFORE any model call, because ladders are live values the journal cannot rebuild and "the journal wins" is not honorable for them;PlanRunnerOptions.profileDrift: 'warn'downgrades the refusal to thetermination:config-driftevent for a deliberate registry change. The frozen dollar vector (runBudgetUsdCeiling,orchestratorCapUsd,finalizeReserveUsd) rides the same drift report; journals from before v1.8 stored zeros there and skip the comparison, journals from before the registry hash shipped skip the identity check entirely, and a resume under the original profiles is byte identical. - 2ecd787: The extension finish gate (RV3202).
OrchestratorExtensiongainsfinishGate?(), consulted FIRST on every ordinary coordination finish: a refusal returns as the finish tool's typed error result (nothing journals, no repair spent), so the model resolves the named blockers and finishes again; the forced-finalization and synthesis finishes are never gated. PlanRunner implements it:finishis now refused while any plan node is ready or running, with the stragglers named, because quiescence participation alone gated only wakes and a root could settle a bare ok while the exit barrier cancelled a running node.allowEarlyFinish: truerestores the old behavior deliberately. Runs without an extension finish gate are byte identical. journal-shape-revision: the oscillation-freeze cassette re-recorded for the gate's live path (the scripted finish over the still-running frozen-signature node is now refused typed, and the scenario closes the straggler deliberately before finishing); already-journaled entries replay verbatim, so existing journals stay valid.
Patch Changes
- Updated dependencies [ba4e10d]
- Updated dependencies [172402b]
- Updated dependencies [2ecd787]
- Updated dependencies [e20a5e9]
- Updated dependencies [98c8691]
- Updated dependencies [c70def0]
- @rulvar/[email protected]
1.234.0
Patch Changes
- Updated dependencies [8420c04]
- @rulvar/[email protected]
1.233.0
Patch Changes
- Updated dependencies [48b5200]
- Updated dependencies [73bc32b]
- Updated dependencies [e63b743]
- Updated dependencies [ef45da7]
- @rulvar/[email protected]
1.232.0
Patch Changes
- Updated dependencies [1440410]
- Updated dependencies [6e467f4]
- Updated dependencies [0b14293]
- Updated dependencies [e3bcab2]
- Updated dependencies [b55a0f7]
- @rulvar/[email protected]
1.231.0
Patch Changes
- Updated dependencies [4eb4b56]
- Updated dependencies [bc8f09e]
- Updated dependencies [ff9b8c2]
- @rulvar/[email protected]
1.230.0
Patch Changes
- Updated dependencies [e9bf910]
- Updated dependencies [57bfb38]
- @rulvar/[email protected]
1.229.0
Patch Changes
- Updated dependencies [3370342]
- Updated dependencies [2fb6656]
- Updated dependencies [edce170]
- @rulvar/[email protected]
1.228.0
Patch Changes
- Updated dependencies [4034fac]
- Updated dependencies [a54b085]
- Updated dependencies [9d0a9be]
- Updated dependencies [be9ef28]
- @rulvar/[email protected]
1.227.0
Patch Changes
- Updated dependencies [f262e9f]
- Updated dependencies [f191ff7]
- Updated dependencies [fbbfbe8]
- Updated dependencies [263b5e8]
- Updated dependencies [db4d56d]
- Updated dependencies [41f93a9]
- Updated dependencies [98c8ca9]
- @rulvar/[email protected]
1.226.0
Patch Changes
- @rulvar/[email protected]
1.225.0
Patch Changes
- @rulvar/[email protected]
1.224.0
Patch Changes
- Updated dependencies [4eca1a3]
- @rulvar/[email protected]
1.223.0
Patch Changes
- Updated dependencies [549aabd]
- Updated dependencies [549aabd]
- @rulvar/[email protected]
1.222.0
Patch Changes
- Updated dependencies [8326268]
- @rulvar/[email protected]
1.221.0
Patch Changes
- Updated dependencies [032ce93]
- @rulvar/[email protected]
1.220.0
Patch Changes
- Updated dependencies [0babe70]
- @rulvar/[email protected]
1.219.0
Patch Changes
- Updated dependencies [65a4ce7]
- @rulvar/[email protected]
1.218.0
Patch Changes
- Updated dependencies [088bda6]
- @rulvar/[email protected]
1.217.0
Patch Changes
- Updated dependencies [ab80b97]
- @rulvar/[email protected]
1.216.0
Patch Changes
- Updated dependencies [b357f4a]
- @rulvar/[email protected]
1.215.0
Patch Changes
- Updated dependencies [e1da4c7]
- @rulvar/[email protected]
1.214.0
Patch Changes
- Updated dependencies [c8af0ec]
- @rulvar/[email protected]
1.213.0
Patch Changes
- Updated dependencies [61680df]
- @rulvar/[email protected]
1.212.0
Patch Changes
- Updated dependencies [e6f8516]
- @rulvar/[email protected]
1.211.0
Patch Changes
- Updated dependencies [d5a8a36]
- @rulvar/[email protected]
1.210.0
Patch Changes
- Updated dependencies [c871ddc]
- @rulvar/[email protected]
1.209.0
Patch Changes
- Updated dependencies [514c7bb]
- @rulvar/[email protected]
1.208.0
Patch Changes
- Updated dependencies [e7d426f]
- @rulvar/[email protected]
1.207.0
Patch Changes
- Updated dependencies [99beee2]
- @rulvar/[email protected]
1.206.0
Patch Changes
- Updated dependencies [ec8e1f1]
- @rulvar/[email protected]
1.205.0
Patch Changes
- Updated dependencies [6d224da]
- @rulvar/[email protected]
1.204.0
Patch Changes
- Updated dependencies [efaec9b]
- @rulvar/[email protected]
1.203.0
Patch Changes
- Updated dependencies [fb08c10]
- @rulvar/[email protected]
1.202.0
Patch Changes
- @rulvar/[email protected]
1.201.0
Patch Changes
- Updated dependencies [7e01189]
- @rulvar/[email protected]
1.200.0
Patch Changes
- Updated dependencies [e2ddbdf]
- @rulvar/[email protected]
1.199.0
Patch Changes
- Updated dependencies [29891c6]
- @rulvar/[email protected]
1.198.0
Patch Changes
- Updated dependencies [c097c96]
- @rulvar/[email protected]
1.197.0
Patch Changes
- @rulvar/[email protected]
1.196.0
Patch Changes
- Updated dependencies [ec9c3e3]
- @rulvar/[email protected]
1.195.0
Patch Changes
- Updated dependencies [5702a70]
- @rulvar/[email protected]
1.194.0
Patch Changes
- Updated dependencies [360a659]
- @rulvar/[email protected]
1.193.0
Patch Changes
- Updated dependencies [2bca1d1]
- @rulvar/[email protected]
1.192.0
Patch Changes
- Updated dependencies [8757601]
- @rulvar/[email protected]
1.191.0
Patch Changes
- Updated dependencies [745387c]
- @rulvar/[email protected]
1.190.0
Patch Changes
- Updated dependencies [8e02021]
- @rulvar/[email protected]
1.189.0
Patch Changes
- Updated dependencies [6a5cc2d]
- @rulvar/[email protected]
1.188.0
Patch Changes
- @rulvar/[email protected]
1.187.0
Patch Changes
- Updated dependencies [c9798ef]
- @rulvar/[email protected]
1.186.0
Patch Changes
- Updated dependencies [242647e]
- @rulvar/[email protected]
1.185.0
Patch Changes
- Updated dependencies [1248623]
- @rulvar/[email protected]
1.184.0
Patch Changes
- Updated dependencies [8a9caca]
- @rulvar/[email protected]
1.183.0
Patch Changes
- Updated dependencies [dd3767c]
- @rulvar/[email protected]
1.182.0
Patch Changes
- Updated dependencies [144d026]
- @rulvar/[email protected]
1.181.0
Patch Changes
- @rulvar/[email protected]
1.180.0
Patch Changes
- Updated dependencies [b124d26]
- @rulvar/[email protected]
1.179.0
Patch Changes
- Updated dependencies [1a5a85a]
- @rulvar/[email protected]
1.178.0
Minor Changes
- e89f377: Package truth is now a gate, not a hope (RV1701). The eighteenth comparison benchmark's strongest documentation-class failure was package identity conflation: a due-diligence dossier described
@rulvar/planwith a citation intopackages/planner, and nothing mechanical objected. The docs cannot stop a reader's model from confusing two names, but they can refuse to ship a byte that gets the universe wrong themselves. Docs lint check 12 now enforces four layers against build artifacts rather than prose: every@rulvar/<name>token in every page must name a real workspace package; every import, require, export-from, and dynamic-import specifier in a ts/js fence must resolve to a real exports-map subpath of its package; every named root import in a fence must be a symbol the package's committed dts rollup actually exports, which turnsimport { planRunner } from '@rulvar/planner'into a lint failure instead of a shipped falsehood; and the versioning page's fixed-group list, its spelled-out size, and both package tables stay in set equality with.changeset/config.jsonand the manifests. The completeness layer had teeth on its first run: the installation guide's "full package list" had silently dropped@rulvar/store-postgresand@rulvar/executor; both rows are restored. The pointer narrative now tells the caret truth: a fresh install ofrulvar@Xresolves the newest umbrella release of X's major (X or newer, never older), so the bare name is a front door, not a pinning surface; pin@rulvar/rulvarexactly when you need one exact version. The CommonJS consumer path the installation guide documents is now proven on packed artifacts: the install smoke gains a.cjsconsumer thatrequire()s the umbrella and the pointer on the packed tarballs and assertsimport()serves the same module instance. And the two npm descriptions disambiguate each other in both directions:@rulvar/planreplans during the run and names@rulvar/planneras the package it is not;@rulvar/plannerplans before the run and names@rulvar/planthe same way.
Patch Changes
- @rulvar/[email protected]
1.177.0
Patch Changes
- Updated dependencies [94db8ff]
- @rulvar/[email protected]
1.176.0
Patch Changes
- Updated dependencies [a74304d]
- @rulvar/[email protected]
1.175.0
Patch Changes
- Updated dependencies [1999c5d]
- @rulvar/[email protected]
1.174.0
Patch Changes
- Updated dependencies [aa9a772]
- @rulvar/[email protected]
1.173.0
Patch Changes
- Updated dependencies [67d27ac]
- @rulvar/[email protected]
1.172.0
Patch Changes
- Updated dependencies [0d4770b]
- @rulvar/[email protected]
1.171.0
Patch Changes
- Updated dependencies [f6116b9]
- @rulvar/[email protected]
1.170.0
Patch Changes
- Updated dependencies [86e4c06]
- @rulvar/[email protected]
1.169.0
Patch Changes
- Updated dependencies [623b2ae]
- @rulvar/[email protected]
1.168.0
Patch Changes
- Updated dependencies [ebba79a]
- @rulvar/[email protected]
1.167.0
Patch Changes
- @rulvar/[email protected]
1.166.0
Patch Changes
- Updated dependencies [d8262c3]
- @rulvar/[email protected]
1.165.0
Patch Changes
- Updated dependencies [6391274]
- @rulvar/[email protected]
1.164.0
Patch Changes
- Updated dependencies [9f2dda9]
- @rulvar/[email protected]
1.163.0
Patch Changes
- Updated dependencies [e8d9ada]
- @rulvar/[email protected]
1.162.0
Patch Changes
- Updated dependencies [2031e82]
- @rulvar/[email protected]
1.161.0
Patch Changes
- Updated dependencies [d4547b7]
- @rulvar/[email protected]
1.160.0
Patch Changes
- Updated dependencies [1c6f0d0]
- @rulvar/[email protected]
1.159.0
Patch Changes
- Updated dependencies [e881c8b]
- @rulvar/[email protected]
1.158.0
Patch Changes
- Updated dependencies [a266bc7]
- @rulvar/[email protected]
1.157.0
Patch Changes
- Updated dependencies [1883421]
- @rulvar/[email protected]
1.156.0
Patch Changes
- Updated dependencies [537144e]
- @rulvar/[email protected]
1.155.0
Patch Changes
- Updated dependencies [49b08a7]
- @rulvar/[email protected]
1.154.0
Patch Changes
- Updated dependencies [9259f24]
- @rulvar/[email protected]
1.153.0
Patch Changes
- Updated dependencies [d8bebcb]
- @rulvar/[email protected]
1.152.0
Patch Changes
- Updated dependencies [dd6a616]
- @rulvar/[email protected]
1.151.0
Patch Changes
- Updated dependencies [1de0610]
- @rulvar/[email protected]
1.150.0
Patch Changes
- Updated dependencies [a331211]
- @rulvar/[email protected]
1.149.0
Patch Changes
- Updated dependencies [08b4537]
- @rulvar/[email protected]
1.148.0
Patch Changes
- Updated dependencies [c85dac9]
- @rulvar/[email protected]
1.147.0
Patch Changes
- Updated dependencies [6367231]
- @rulvar/[email protected]
1.146.0
Patch Changes
- Updated dependencies [5d9bbc8]
- @rulvar/[email protected]
1.145.0
Patch Changes
- @rulvar/[email protected]
1.144.0
Patch Changes
- Updated dependencies [c11bcd6]
- @rulvar/[email protected]
1.143.0
Patch Changes
- Updated dependencies [f412169]
- @rulvar/[email protected]
1.142.0
Patch Changes
- @rulvar/[email protected]
1.141.0
Patch Changes
- Updated dependencies [4f12a62]
- @rulvar/[email protected]
1.140.0
Patch Changes
- @rulvar/[email protected]
1.139.0
Patch Changes
- Updated dependencies [03a2141]
- @rulvar/[email protected]
1.138.0
Patch Changes
- Updated dependencies [ed0c4fb]
- @rulvar/[email protected]
1.137.0
Patch Changes
- Updated dependencies [96f6788]
- @rulvar/[email protected]
1.136.0
Patch Changes
- Updated dependencies [aa6ca71]
- @rulvar/[email protected]
1.135.0
Patch Changes
- Updated dependencies [cf75e22]
- @rulvar/[email protected]
1.134.0
Patch Changes
- @rulvar/[email protected]
1.133.0
Patch Changes
- @rulvar/[email protected]
1.132.0
Patch Changes
- Updated dependencies [2bec904]
- @rulvar/[email protected]
1.131.0
Patch Changes
- Updated dependencies [256cae1]
- @rulvar/[email protected]
1.130.0
Patch Changes
- Updated dependencies [d6bec7a]
- @rulvar/[email protected]
1.129.0
Patch Changes
- Updated dependencies [1612439]
- @rulvar/[email protected]
1.128.0
Patch Changes
- Updated dependencies [27c4e38]
- @rulvar/[email protected]
1.127.0
Patch Changes
- Updated dependencies [b3b1805]
- @rulvar/[email protected]
1.126.0
Patch Changes
- @rulvar/[email protected]
1.125.0
Patch Changes
- @rulvar/[email protected]
1.124.0
Patch Changes
- Updated dependencies [37fd1f2]
- @rulvar/[email protected]
1.123.0
Patch Changes
- Updated dependencies [5c46468]
- @rulvar/[email protected]
1.122.0
Patch Changes
- Updated dependencies [8cf45c5]
- @rulvar/[email protected]
1.121.0
Patch Changes
- Updated dependencies [3d67d41]
- @rulvar/[email protected]
1.120.0
Patch Changes
- Updated dependencies [d630c9e]
- @rulvar/[email protected]
1.119.0
Patch Changes
- Updated dependencies [1e4ff3c]
- @rulvar/[email protected]
1.118.0
Patch Changes
- Updated dependencies [f8341a3]
- @rulvar/[email protected]
1.117.0
Patch Changes
- @rulvar/[email protected]
1.116.0
Patch Changes
- Updated dependencies [a213878]
- @rulvar/[email protected]
1.115.0
Patch Changes
- Updated dependencies [63642ae]
- @rulvar/[email protected]
1.114.0
Patch Changes
- Updated dependencies [5759731]
- @rulvar/[email protected]
1.113.0
Patch Changes
- Updated dependencies [a60807a]
- @rulvar/[email protected]
1.112.0
Patch Changes
- Updated dependencies [00ae55b]
- @rulvar/[email protected]
1.111.0
Patch Changes
- Updated dependencies [fd25169]
- @rulvar/[email protected]
1.110.0
Patch Changes
- Updated dependencies [58afdb5]
- @rulvar/[email protected]
1.109.0
Patch Changes
- Updated dependencies [85b1d39]
- @rulvar/[email protected]
1.108.0
Patch Changes
- Updated dependencies [affa3d4]
- @rulvar/[email protected]
1.107.0
Patch Changes
- Updated dependencies [9f5f6f6]
- @rulvar/[email protected]
1.106.0
Patch Changes
- Updated dependencies [9a4ce49]
- @rulvar/[email protected]
1.105.0
Patch Changes
- Updated dependencies [531dc88]
- @rulvar/[email protected]
1.104.0
Patch Changes
- @rulvar/[email protected]
1.103.0
Patch Changes
- Updated dependencies [f2b809e]
- @rulvar/[email protected]
1.102.0
Patch Changes
- Updated dependencies [3eb6515]
- @rulvar/[email protected]
1.101.0
Patch Changes
- Updated dependencies [51b215c]
- @rulvar/[email protected]
1.100.0
Patch Changes
- Updated dependencies [9785bea]
- @rulvar/[email protected]
1.99.1
Patch Changes
- ef08d73: Guarantee matrix and exactly-once claim hygiene (RV508); no runtime behavior changes. The isolated-executor guide now carries the guarantee matrix stating flatly who provides what: the library's layers give at-least-once execution with attempt binding and intent-before-effect, exactly-once effect execution is promised by NO library layer, and what IS exactly-once is pay and replay (the never-pay-twice invariant). The two claims the ninth comparison experiment's judge caught are rewritten to the precise statements ("each ran once" became attempt counting under a stable idempotency key; the approvals guide now says continuation is a run-level guarantee, not an effect-level one, with the at-least-once window named);
ctx.stepdocs state the same window for effectful steps; aResolutionBynote says the field records a channel, never a verified principal (identity, signatures, and separation of duties are host IAM). The worker header now points at the shippedSqliteQuotaLimiterandPostgresQuotaLimiterinstead of denying that cross-process limiters exist. A new docs-lint sentinel forbids "exactly once" claims in the hand-written docs and in package source comments outside a vetted (file, heading anchor) allowlist (the durability pay doctrine and the guarantee matrix), and every remaining occurrence in doc prose and source comments was rewritten to the precise wording; string literals are deliberately out of scope (tool descriptions enter the toolset hash). - Updated dependencies [ef08d73]
- @rulvar/[email protected]
1.99.0
Patch Changes
- Updated dependencies [9e00888]
- @rulvar/[email protected]
1.98.0
Patch Changes
- @rulvar/[email protected]
1.97.0
Patch Changes
- Updated dependencies [5c3b453]
- @rulvar/[email protected]
1.96.0
Patch Changes
- @rulvar/[email protected]
1.95.0
Patch Changes
- @rulvar/[email protected]
1.94.0
Patch Changes
- @rulvar/[email protected]
1.93.0
Patch Changes
- Updated dependencies [c62150a]
- @rulvar/[email protected]
1.92.0
Patch Changes
- Updated dependencies [351d1f5]
- @rulvar/[email protected]
1.91.0
Patch Changes
- @rulvar/[email protected]
1.90.0
Patch Changes
- Updated dependencies [9603940]
- @rulvar/[email protected]
1.89.0
Patch Changes
- Updated dependencies [f18b671]
- Updated dependencies [f18b671]
- @rulvar/[email protected]
1.88.0
Patch Changes
- Updated dependencies [3b339d9]
- @rulvar/[email protected]
1.87.0
Patch Changes
- Updated dependencies [c4c02b1]
- @rulvar/[email protected]
1.86.0
Patch Changes
- Updated dependencies [2f71894]
- @rulvar/[email protected]
1.85.0
Patch Changes
- Updated dependencies [6932a9f]
- @rulvar/[email protected]
1.84.0
Patch Changes
- @rulvar/[email protected]
1.83.0
Patch Changes
- @rulvar/[email protected]
1.82.0
Patch Changes
- Updated dependencies [9cc5d66]
- @rulvar/[email protected]
1.81.2
Patch Changes
- Updated dependencies [296885b]
- @rulvar/[email protected]
1.81.1
Patch Changes
- Updated dependencies [c030982]
- @rulvar/[email protected]
1.81.0
Patch Changes
- Updated dependencies [ce4c392]
- @rulvar/[email protected]
1.80.0
Patch Changes
- Updated dependencies [262e397]
- @rulvar/[email protected]
1.79.0
Patch Changes
- Updated dependencies [85956ab]
- @rulvar/[email protected]
1.78.0
Patch Changes
- Updated dependencies [941b6e1]
- @rulvar/[email protected]
1.77.0
Patch Changes
- Updated dependencies [6aba271]
- @rulvar/[email protected]
1.76.0
Patch Changes
- Updated dependencies [22cba47]
- @rulvar/[email protected]
1.75.1
Patch Changes
- Updated dependencies [82bc0f0]
- @rulvar/[email protected]
1.75.0
Patch Changes
- Updated dependencies [c486de8]
- @rulvar/[email protected]
1.74.0
Patch Changes
- Updated dependencies [d94beab]
- @rulvar/[email protected]
1.73.0
Patch Changes
- Updated dependencies [3e95bd1]
- @rulvar/[email protected]
1.72.0
Patch Changes
- Updated dependencies [662e9e0]
- @rulvar/[email protected]
1.71.0
Patch Changes
- Updated dependencies [20d02e0]
- @rulvar/[email protected]
1.70.1
Patch Changes
- @rulvar/[email protected]
1.70.0
Patch Changes
- @rulvar/[email protected]
1.69.0
Patch Changes
- Updated dependencies [b21a681]
- @rulvar/[email protected]
1.68.0
Patch Changes
- Updated dependencies [b227874]
- @rulvar/[email protected]
1.67.0
Patch Changes
- Updated dependencies [8e6006d]
- @rulvar/[email protected]
1.66.0
Patch Changes
- Updated dependencies [1b8987e]
- @rulvar/[email protected]
1.65.0
Patch Changes
- Updated dependencies [0b6b859]
- @rulvar/[email protected]
1.64.0
Patch Changes
- Updated dependencies [991f9b5]
- @rulvar/[email protected]
1.63.0
Patch Changes
- Updated dependencies [8a28aed]
- @rulvar/[email protected]
1.62.0
Patch Changes
- Updated dependencies [fca5fd1]
- @rulvar/[email protected]
1.61.0
Patch Changes
- Updated dependencies [b4c1f1f]
- @rulvar/[email protected]
1.60.0
Patch Changes
- Updated dependencies [59bbeaa]
- @rulvar/[email protected]
1.59.4
Patch Changes
- Updated dependencies [c49d7a1]
- @rulvar/[email protected]
1.59.3
Patch Changes
- Updated dependencies [deaef36]
- @rulvar/[email protected]
1.59.2
Patch Changes
- Updated dependencies [dd0e10f]
- @rulvar/[email protected]
1.59.1
Patch Changes
- Updated dependencies [c127770]
- @rulvar/[email protected]
1.59.0
Patch Changes
- Updated dependencies [615dc90]
- @rulvar/[email protected]
1.58.0
Patch Changes
- Updated dependencies [4fa35ce]
- @rulvar/[email protected]
1.57.0
Patch Changes
- Updated dependencies [5897232]
- @rulvar/[email protected]
1.56.0
Patch Changes
- Updated dependencies [f26dba0]
- @rulvar/[email protected]
1.55.0
Patch Changes
- Updated dependencies [e9b005b]
- @rulvar/[email protected]
1.54.0
Patch Changes
- Updated dependencies [3f6bc03]
- @rulvar/[email protected]
1.53.0
Patch Changes
- Updated dependencies [b821bd1]
- @rulvar/[email protected]
1.52.0
Patch Changes
- Updated dependencies [e138df9]
- @rulvar/[email protected]
1.51.0
Patch Changes
- @rulvar/[email protected]
1.50.0
Patch Changes
- Updated dependencies [e39a885]
- @rulvar/[email protected]
1.49.0
Patch Changes
- Updated dependencies [bab7b2c]
- @rulvar/[email protected]
1.48.0
Patch Changes
- @rulvar/[email protected]
1.47.0
Patch Changes
- Updated dependencies [a3687fe]
- @rulvar/[email protected]
1.46.0
Patch Changes
- Updated dependencies [865e7bf]
- @rulvar/[email protected]
1.45.0
Patch Changes
- Updated dependencies [b96305d]
- @rulvar/[email protected]
1.44.1
Patch Changes
- @rulvar/[email protected]
1.44.0
Patch Changes
- Updated dependencies [299f7d2]
- @rulvar/[email protected]
1.43.0
Patch Changes
- Updated dependencies [71b7181]
- @rulvar/[email protected]
1.42.0
Patch Changes
- Updated dependencies [9b70f27]
- @rulvar/[email protected]
1.41.0
Patch Changes
- Updated dependencies [be589ec]
- @rulvar/[email protected]
1.40.0
Patch Changes
- Updated dependencies [cf33550]
- @rulvar/[email protected]
1.39.0
Patch Changes
- @rulvar/[email protected]
1.38.0
Patch Changes
- @rulvar/[email protected]
1.37.0
Patch Changes
- Updated dependencies [e6b1481]
- Updated dependencies [e6b1481]
- @rulvar/[email protected]
1.36.0
Minor Changes
- 101795b: Make the guards fallback
'fail-run'a real failure policy (v1.35.0 review P2). After the journaled guard verdict the PlanRunner terminates the orchestration withFailRunError(data.source: 'plan_guards',data.verdictRef) through the new extension terminate capability: no further model turn is consulted, the run ends with outcomeerror, and a resume re folds the verdict at boot and rolls the same failure forward with zero model calls.reject-revisionandfinish-with-partialkeep their historical steer to finish behavior.
Patch Changes
- Updated dependencies [101795b]
- @rulvar/[email protected]
1.35.0
Minor Changes
- d4ac3bf: Validate
RevisionGuardslimits at construction (v1.34.0 review P2-3). The streak and oscillation limits must be positive integers, the stall replan cap a nonnegative integer, andmaxAbandonedNetUsdFractiona fraction in (0, 1]; anything else, NaN included, is a typedConfigErrorbefore any revision is judged. Unvalidated, a NaN limit inverted the machinery: the dropped and oscillation guards tripped immediately while the stall cap never tripped at all.
Patch Changes
- Updated dependencies [d4ac3bf]
- @rulvar/[email protected]
1.34.0
Patch Changes
- Updated dependencies [f1505ec]
- @rulvar/[email protected]
1.33.0
Patch Changes
- @rulvar/[email protected]
1.32.0
Patch Changes
- @rulvar/[email protected]
1.31.0
Patch Changes
- @rulvar/[email protected]
1.30.0
Patch Changes
- Updated dependencies [87ce985]
- @rulvar/[email protected]
1.29.0
Patch Changes
- Updated dependencies [621d566]
- @rulvar/[email protected]
1.28.0
Patch Changes
- Updated dependencies [d98eb0b]
- @rulvar/[email protected]
1.27.0
Patch Changes
- Updated dependencies [884a433]
- @rulvar/[email protected]
1.26.0
Patch Changes
- Updated dependencies [a4fc757]
- @rulvar/[email protected]
1.25.0
Patch Changes
- @rulvar/[email protected]
1.24.1
Patch Changes
- Updated dependencies [0bb14db]
- @rulvar/[email protected]
1.24.0
Patch Changes
- Updated dependencies [2b033e8]
- @rulvar/[email protected]
1.23.0
Minor Changes
1f9c272: PlanRunner spawn telemetry, the missing evals export, and the conformance kit's new meta field (v1.22.0 review P2-5, P2-6, P1-2).
@rulvar/plan: PlanRunner journals every admission INSIDE a carrying entry (decomposition rows in escalation decisions, ladder-verdict respawns, reuse and graft links, revision admissions) and emitted nospawn:admitted/spawn:rejectedat all; a live PlanRunner run with admitted roots showed an event count of zero. Every embedded admission row now announces through one formatter, identically on the live path and on replay absorb, withreplayed: trueon recovered rows,entryRefon the journaled carrying entry, andagentTyperesolved from the landed specs.@rulvar/evals:agentTypeRuleHoldsjoins the package root next torungRuleHolds, exactly as the v1.21.0 changelog had already announced; a public-API test now imports the checkpoint quartet from the root. The evals guide gains a full measured-value checkpoint section (ladder/pool/cell/arm vocabulary, both criteria, the vacuous-pass guard, cost discipline, a runnable example).@rulvar/store-conformance: the meta round-trip case now also pins the new optionalRunMeta.segmentsfield, which the engine bumps durably at every resume to keep eventseq/spanIdunique per run.
Patch Changes
- Updated dependencies [1f9c272]
- @rulvar/[email protected]
1.22.0
Patch Changes
- Updated dependencies [77b554f]
- @rulvar/[email protected]
1.21.0
Patch Changes
- Updated dependencies [7ee42a0]
- @rulvar/[email protected]
1.20.0
Patch Changes
- Updated dependencies [9367030]
- @rulvar/[email protected]
1.19.0
Minor Changes
- 8cc9a9c:
orchestrate(engine, goal, opts?, runOptions?)andorchestratePlanned(engine, goal, opts?, runOptions?)accept the created run'sRunOptionsas an optional fourth argument, threaded verbatim toengine.run.runOptions.budgetUsdis the ROOT hard ceiling over the whole tree (the orchestrator and every child), immutable after start and frozen intoRunMeta, whileopts.budgetonly shapes the orchestrator's own sub-account inside that ceiling; the two layers were previously conflatable, and the canonical shortcuts could not set a root ceiling (or signal, runId, limits, deadline) at all without dropping toengine.run(makeOrchestratorWorkflow(goal, opts), undefined, runOptions). Purely additive; existing calls are unchanged, and a call withoutrunOptionsstill starts an UNCAPPED run, which the docs now state explicitly.
Patch Changes
- Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- @rulvar/[email protected]
1.18.0
Patch Changes
- Updated dependencies [943962d]
- @rulvar/[email protected]
1.17.0
Patch Changes
- @rulvar/[email protected]
1.16.2
Patch Changes
- @rulvar/[email protected]
1.16.1
Patch Changes
- @rulvar/[email protected]
1.16.0
Patch Changes
- @rulvar/[email protected]
1.15.0
Patch Changes
- @rulvar/[email protected]
1.14.0
Patch Changes
- @rulvar/[email protected]
1.13.0
Patch Changes
- @rulvar/[email protected]
1.12.0
Patch Changes
- Updated dependencies [46edcc0]
- @rulvar/[email protected]
1.11.0
Patch Changes
- Updated dependencies [0c70c5e]
- @rulvar/[email protected]
1.10.0
Patch Changes
- Updated dependencies [0e8d78e]
- @rulvar/[email protected]
1.9.0
Patch Changes
- Updated dependencies [3a53383]
- @rulvar/[email protected]
1.8.0
Minor Changes
7884ec5: PlanRunner plan admission is now atomic with child dispatch admission (the v1.7.0 follow-up review's P1). Previously a
plan_reviseop could be journaled asadmit(consuming its spawn unit) and only then havescheduleReady's dispatch rejected by the engine budget, stranding the node ready forever, losing theplan:revisedevent, and burning the orchestrator budget with no worker output.- An
add_taskop whose resolved profileestCostcannot fit the effective child ceiling (rung-resolvedmaxCostUsd, elsebudgetUsd) is bounced at rebase time with the new typed reasonreserve_exceeds_budgetnaming the child account, requested and resolved reserve, ceiling, and minimum correction. No plan state changes and no spawn unit is consumed; theplan_revisetool result carries the reason verbatim. - The read-only admission branch now projects the SAME reserve the dispatch layer will commit (estimate clamped by the explicit child budget only), plus the pending reserves of earlier ops in the same revision, so every embedded admit of one batch is dispatchable under the snapshot it was decided on. The dynamic
spawn_agentpath passes the profile estimate into admission for the same reason. - Layer 1 (ctx.agent) clamps its committed reserve to the tightest
child-allowanceaccount headroom on the chain (a plan node's own sub-account, actx.workflowchild ceiling): an allowance already bounds the child's lifetime spend, so an estimate above it clamps instead of denying, which is what makes "admit implies dispatchable" hold by construction. The run root and orchestrator cap are never clamped against; their headroom is shared money that projected admission keeps protecting. plan:revisedandtermination:debitnow emit strictly after the durable revision append and before the scheduling effects, so a scheduling fault cannot erase an applied revision from the event stream.- The residual class (facts that genuinely changed between admit and dispatch, e.g. the engine lifetime spawn cap) lands the node terminally
failedthrough a journaledplan.decisionwith the new origin/causedispatch-rejected; other ready nodes still dispatch and the run proceeds.
Acceptance tests cover the review's live shape (profile
estCost0.015 againstbudgetUsd0.01), the positive control, resume idempotence, the containment path, and an admit-implies-dispatchable property grid over estimates, budgets, ceilings, flat reserves, and prior commitments.- An
52db30d:
termination.initnow freezes the ACTUAL orchestrator budget dollars instead of zeros, closing the journal-contract gap the v1.7.0 follow-up review found: the budgets guide documentsorchestratorCapUsdandfinalizeReserveUsdas frozen in the same limits vector as the counters, but PlanRunner journals stored0for both and only the laterorchestrator_budget_reservedecision carried the real values.- The engine resolves the effective cap and finalize reserve strictly before extension boot and exposes them on
OrchestratorExtensionIO(orchestratorCapUsd,finalizeReserveUsd); PlanRunner writes them intotermination.init. - On resume the cap dollars are now recovered from the frozen
orchestrator_budget_reservedecision instead of being re-derived from live options (DEF-2 config-drift-resume: the journal wins). A diverging livecapUsd/capFraction/finalizeReserveUsdemitstermination:config-driftand is never honored. - Journals recorded before this release (zeros in
termination.init) replay unchanged: the fold reads the init entry by kind, and the reserve decision remains their authority. - The reserve-decision presence guard is now scoped to the orchestrate call, so nested capped orchestrations each journal their own freeze.
The frozen cassette catalog is re-recorded (the init limits vector and its content key change); hashVersion stays 2, and the fixture lock refresh carries the required hashVersion-bump token.
- The engine resolves the effective cap and finalize reserve strictly before extension boot and exposes them on
Patch Changes
- Updated dependencies [25724b5]
- Updated dependencies [57ea1de]
- Updated dependencies [7884ec5]
- Updated dependencies [52db30d]
- @rulvar/[email protected]
1.7.0
Patch Changes
- Updated dependencies [45285aa]
- Updated dependencies [2f20d1d]
- Updated dependencies [22f65a8]
- Updated dependencies [2ddfa29]
- Updated dependencies [2abd9c2]
- Updated dependencies [1c1175d]
- @rulvar/[email protected]
1.6.0
Patch Changes
- da4dbad: Write the product name as Rulvar in prose: package READMEs, npm descriptions, and the documentation site now capitalize the brand. Identifiers keep their exact casing, so package names, the
rulvarbinary,rulvar.config.mjs, the.rulvarstore directory, therulvar.*OTel attributes, and every URL are unchanged. Documentation and metadata only; no runtime behaviour changes. - Updated dependencies [da4dbad]
- Updated dependencies [487da86]
- Updated dependencies [df416fc]
- Updated dependencies [a737810]
- Updated dependencies [9eb66b4]
- @rulvar/[email protected]
1.5.2
Patch Changes
- Updated dependencies [54936a0]
- @rulvar/[email protected]
1.5.1
Patch Changes
- Updated dependencies [6c6d56f]
- @rulvar/[email protected]
1.5.0
Patch Changes
- Updated dependencies [4fba3c7]
- Updated dependencies [8655c0f]
- @rulvar/[email protected]
1.4.0
Patch Changes
- Updated dependencies [c4f563d]
- @rulvar/[email protected]
1.3.2
Patch Changes
- ddef383: Every published package now ships a README, so its npm page states what the package is, how it installs, and where the documentation lives (npm includes README.md in the tarball regardless of the files allowlist, so no manifest changes are involved; @rulvar/compat gains its README on its own next release). Alongside, the repository-level pages are refreshed to the current project state: the root README is rewritten around the never-pay-twice pitch with a runnable quickstart condensation and the full package table, CONTRIBUTING.md lists the complete PR gate set, the examples README drops retired-spec citations for live docs.rulvar.com links and documents the dogfood journal replay, and the pointer README gets the same treatment.
- Updated dependencies [ddef383]
- @rulvar/[email protected]
1.3.1
Patch Changes
- 7d1552e: Runtime message strings no longer cite the retired internal specification set: error and warning messages, validation issues, and the CLI help text drop the dangling
docs/NN, section ...references, pointing at https://docs.rulvar.com pages where a pointer earns its place (the CLI help header, tool naming, toolset registries, bare resume). The umbrella package description sheds the naming-contingency note: the unscoped alias is published and owned. Three strings embedded in frozen recordings stay byte-identical on purpose (the no-progress abort reason and two testing-internal recorder strings), as does the byte-locked golden-fold fixture. Test-file comments lose their citations too; test titles are unchanged. - Updated dependencies [7d1552e]
- @rulvar/[email protected]
1.3.0
Minor Changes
- 7d1a287: ModelKnowledge phase 3, first slice (M12-T02, unlocked by the passed measured-value checkpoint): the kb_propose orchestrator tool and the quarantined modelObservations write path. PlanRunner registers kb_propose on explicit opt-in (PlanRunnerOptions.kbPropose, like any opt-in tool); its payload is tier-relative (the orchestrator never names a model) and the engine resolves the tier against the referenced lineage's declared ladder into the concrete KbProposal subject, validates that the tier has a journaled attempt and that evidence refs resolve to this run's decision entries, and journals the proposal as the observation_add ledger.op through the single-writer path. Quarantine is absolute: the ack is entryRef only, ledger_read withholds observation content behind a count (byte-stable for observation-free renders), worker prompts never see it, and nothing can commit during a run (the runtime handle has no write path by API shape); proposals reach the human gate only through the post-run LedgerExport. Core exports KbProposal, KbProposalTrigger and the typed model-free proposalStatement template. The kb-propose-quarantine cassette joins the frozen catalog (61 IDs).
Patch Changes
- Updated dependencies [7d1a287]
- @rulvar/[email protected]
1.2.0
Patch Changes
- 154507b: TSDoc and inline comments no longer cite the retired internal specification set (the pre-docs-site
docs/NN, section ...references). The citations either became links to the public documentation at docs.rulvar.com or were dropped where the comment already carried the rule; traceability markers (DEF-n, XF-nn, FR-nnn, OQ-nn, W-nnn) are untouched. Comment-only change: no runtime behavior, no API shapes, and no runtime message strings were modified; the frozen golden-fold fixture is byte-identical. - Updated dependencies [3bfaec0]
- Updated dependencies [890f42c]
- Updated dependencies [154507b]
- @rulvar/[email protected]
1.1.0
Patch Changes
- Updated dependencies [d16b04a]
- @rulvar/[email protected]
1.0.0
Minor Changes
0e0b569: M10 entry: the render budgets of docs/06 Appendix A are committed (the TBD-before-M10 rule) and wired as engine defaults; OQ-04 (the renderBudget measure) closes on the CHARACTER measure.
- WakeDigest: 400 chars per outputSummary row, one exported constant (
WAKE_SUMMARY_RENDER_BUDGET_CHARS) now serving both the distillation cap (adopted unchanged, the value frozen into every cassette since M6) and the digest render default ofrenderBudgetChars, which stays overridable per orchestration. - ledger_read render: 65536 chars over the serialized view via the new pure
boundLedgerRender(exported withLEDGER_RENDER_BUDGET_CHARS): over budget, rows drop deterministically oldest-first (auto-derived joins before authored sections, the mission brief slices last) and every drop renders as a FLAGGED discrepancy line. The section caps stay the primary bound, so under default termination limits the belt never engages; all frozen fixtures are byte-identical. - KB card: 4096 chars, committed in docs and consumed by the M10-T03 card renderer.
- WakeDigest: 400 chars per outputSummary row, one exported constant (
4454175: M10-T03: the ModelKnowledge read path (docs/05, sections "Read path" and "Security"). kb_pinned and kb_repinned land, the card renders, and the whole feature is store-gated: an engine without
stores.modelKnowledgewrites no kb entries at all, so every existing journal and cassette stays byte-stable (zero added awaits on the off path).createEngineacceptsstores.modelKnowledge; the runtime holds ONLY thecurrent()handle (commit is physically absent inside runs).- One read at run admission for orchestrate-role runs: the engine filters claims (active, unexpired, reachable through the run's declared ladders after the role-floor filter) and journals
kb_pinned { version, hash, cardText }with the card bytes EMBEDDED, strictly before the first orchestrator turn. Resume and replay read the entry bytes and never touch the live store. - A fresh
kb_repinnedlands on every wait_for_events wake under the same filtering rules against a FRESH store read, so expired, stale, and archived claims never steer spawns after pauses; a mid-run store commit affects only subsequent pins. modelKnowledgeCard: deterministic, two-layer, tier-relative, 4096-char budget (oldest notes withhold behind an explicit marker). The verified layer compiles EXCLUSIVELY from eval-measured claims (empty in phase 1) with the one-rung clamp; editorial notes render dated and explicitly marked, never compiled into a tier; the orchestrator never sees model names. The card docks into the spawn tool description beside the profile card.- OQ-11 closes: editorial notes render for every taskClass with no self-description suppression (the nameless tier-relative render already blunts the feared bias).
- Two catalog cassettes (docs/09, new section 6.11): kb-pin-replay and kb-repin-expiry, recorded offline over a deterministic stub store with time-stable dates; the cassette-catalog CI job runs them.
6599ca8: M10-T05: the taskClass binding interim rule becomes the phase-1 resolution (docs/05, section "Phases and placement"; docs/14 OQ-12 CLOSED). The classification source is author declaration: the optional
taskClasson AgentProfile, TaskSpec, and spawn_agent params; absence means unclassified and stores no literal string anywhere. Card recommendations never apply to unclassified spawns (in phase 1 no recommendation application exists at all; the M11 compiler inherits the rule as normative).- The plan dispatch now forwards the declared TaskSpec.taskClass onto the ExtensionDispatchSpec, completing the substrate: a declared class journals inside the spawn-admission decision (spawn_agent path) and the plan.revision spec of record (PlanRunner path), so M11 matrix sweeps and the recommendation compiler slice attempts by class from journals alone.
- Byte-neutral: journals without declared classes are unchanged; floors stay profile-driven per docs/04.
0fbe7ea: M9-T04 (part 1): the DEF-2 and DEF-3 catalog rows deferred at M7 (docs/09 sections 6.2 and 6.3; docs/10 M9 row "Complete catalog green in one CI run"), plus the producers and liveness fixes the rows exposed.
- Nine new frozen cassettes with public runners and byte-for-byte replay tests: combined-loop-descent, config-drift-resume, class-storm-single-turn, oscillation-bounded, race-timeout-vs-live (DEF-2); respawn-preserves-counter, reworded-lessons-collide, stall-streak-classes-and-pinning, legacy-journal-resume (DEF-3). The class and race rows additionally round-trip their frozen bytes through BOTH reference stores (JsonlFileStore and SqliteStore) with identical loads, per the store-independence rule.
@rulvar/plan: the class-level escalation decision producer lands (docs/07 6.5): two or more same-kind reports resolved by ONE revision merge into ONE escalation-decision entry with per-lineagedebitsrows and resolvedBy 'class'; a denied per-lineage debit degrades the group to single-target decisions so denial semantics stay per report. The folds already consumed this form; single-target behavior and all existing cassette bytes are unchanged.@rulvar/plan:termination:config-driftnow actually fires on resume when a live termination knob diverges from the journaledtermination.init(the journal wins, the divergence is reported per field; docs/07 11.2). Events are never journaled, so frozen cassettes are unaffected.@rulvar/plan: aretryescalation decision re-opens the node AND clears its stale dispatch handle; previously the re-opened node sat ready forever while the scheduler skipped it (the re-dispatch liveness gap behind Flavor B defaultDecision retry).@rulvar/plan:lesson_addkeys once (docs/07 9.2): a repeated add with the same content key acks the recorded lesson instead of appending a duplicate; re-executed-turn recovery is unchanged.@rulvar/core: an extension dispatch whose agent dies BEFORE its root entry lands now surfaces the underlying failure loudly to the dispatching caller instead of hanging the dispatch await forever (the pre-root cousin of the stale-writer liveness rule). Healthy paths and replays are byte- and timing-identical.- Known residual, unchanged: repeated Flavor B suspensions on ONE re-opened node dedup onto the first suspension's decision key; the recorded cassettes route around it and the at-cap immediate-resolution flavor rows stay with M9-T04's later parts.
ebe0abc: M9-T04 (part 2): the six DEF-5 catalog cassettes (docs/09 section 6.5; docs/03 section 9), plus the reuse-producer completions the rows forced.
- Six new frozen cassettes with public runners and byte-for-byte replay tests: oscillation-full-reuse (escalated-terminal donor, shared full link, by-ref root, reclaimedUsdAtLink carries the donor spend), graft-partial-subtree (a three-rung limit ladder severed mid-top-rung grafts exclusively; the completed rung attempts forward-match through the scope alias and only the interrupted rung reruns live, exactly once), crash-between-link-and-root (cut strictly between the durable node.link and the by-ref root; the resume rolls forward with zero repayment), oscillation-guard-trip (the third re-add at maxOscillationsPerKey 2 rejects osc_guard with the embedded verdict and the run closes non-HITL), worktree-disposed-degrade (an unpinned worktree graft donor degrades to a fresh admit with DedupNote graft_unsafe; reuse_full stays allowed for a worktree donor with a terminal root), claim-exclusivity-and-chain (two identical adds in ONE revision: the first grafts exclusively, the second degrades donor_active; the severed grafted node becomes the chain head and the third add drains the chain transitively; oscillationCount reaches 2).
@rulvar/core(docs/03 9.3/9.6 producer completions, folds and bytes of existing journals unchanged): evaluateReuse now skips exclusively-claimed donors (first-wins) and degrades to a fresh admit with the documenteddonor_activereason when every candidate is captured; a severed grafted node inherits its captured link's chain (ancestry plus chain-tail graft eligibility), so the next add links to the chain head and drains transitively; agent dispatch roots record their resolved isolation (value.isolation, only when not 'none') so the DedupIndex worktree rules can read it from the journal.@rulvar/plan: exclusive captures are first-wins WITHIN one revision too: the second identical add of the same revision degrades todonor_activeinstead of double-claiming the donor.- All fifteen M9 cassettes re-record byte-identically under the double-run agreement; the nine part-1 fixtures are untouched by the producer changes. fixtures.sha256 covers 50 frozen files.
a3079d0: M9-T04 (part 3): the six DEF-8 catalog cassettes plus the DEF-7 reserve-survives-run-exhaustion row (docs/09 sections 6.7 and 6.8), with the roll-forward and reserve producers the rows exposed.
- Seven new frozen cassettes with public runners and byte-for-byte replay tests: revise-racing-defaultDecision (the mandatory stale-wake trio dropping dep_already_resolved with blockingRef, node_escalated, node_already_done in ONE revision), crash-after-append-before-effects (the pre-effects kill point; both children spawn live exactly once on resume and the request-only cancel lands on the redispatched branch), amend-vs-running-then-cancel-add, intra-revision-self-conflict (sequential intra-revision semantics), bad-base-streak-terminates (three fabricated-base all-dropped entries then the non-HITL guards fallback), park-races-child-completion (parkRequested extinguished by the child-result transition, no park retention), and reserve-survives-run-exhaustion (adds that would invade the committed finalize reserve drop admission_denied inside the revision outcomes; the forced finish executes FROM the reserve and closes the run ok).
@rulvar/plan: the idempotent plan_revise recovery path now also re-lands request-only cancels and parks by aborting the redispatched mid-flight branch; previously the crash-after-append-before-effects roll-forward left the cancelled branch running forever.@rulvar/plan: an accepted escalation resolution records the node's done reference (doneRefs), so a later waive_dep against the resolved dependency drops dep_already_resolved with the blockingRef pointing at the resolving reference, exactly like a child-result transition.@rulvar/core: the forced finish now RELEASES the finalize reserve as it begins (releaseFinalizeReserve): the reserve stops subtracting from the admission remainder at the moment it is being spent, or the finalize agent could never draw the money reserved for it under a tight run ceiling. Admissions stay frozen past the cap, so nothing else can take it. Cap behavior under unlimited ceilings (all existing cassettes) is byte-identical.- All 22 M9 cassettes re-record byte-identically under the double-run agreement; fixtures.sha256 covers 57 frozen files.
Patch Changes
- Updated dependencies [0e0b569]
- Updated dependencies [b28b7a3]
- Updated dependencies [b53a89e]
- Updated dependencies [4454175]
- Updated dependencies [6599ca8]
- Updated dependencies [6649e5f]
- Updated dependencies [fd2f83b]
- Updated dependencies [01d6b2d]
- Updated dependencies [9a20dbb]
- Updated dependencies [0fbe7ea]
- Updated dependencies [ebe0abc]
- Updated dependencies [a3079d0]
- Updated dependencies [596a39b]
- Updated dependencies [464ab6e]
- @rulvar/[email protected]
0.9.0
Minor Changes
f920013: M8-T03: the multi-process seam soak and the queue-failover-during-forced-finish cassette (the DEF-7 final cassette; docs/09 sections 6.9 and 6.10; docs/10 section 3.9 exit criteria).
@rulvar/plan: the publicrunQueueFailoverDuringForcedFinishcassette runner: worker A loses its lease strictly between the cap decision and the final wake; worker B reclaims with a bumped fencing epoch and rolls the forced finish forward. The stale writer's appends are rejected and invisible, exactly one cap decision exists, finalization is paid once. The LeasableStore is injected (QueueFailoverDeps.makeStore) so the package stays core-only; the replay test and the record script supply the reference SqliteStore.@rulvar/cli: the multi-process-fencing-soak harness: two workers over one SqliteStore file with kill/failover across the suspension, plan-revision, and forced-finish boundaries; every round asserts zero split-brain and zero double pay. Worker hardening: a failed renew now frees the concurrency slot immediately (a stale run whose landings all reject may never settle; fencing, not the stale process's cooperation, protects the journal).- Repo:
cassettes/queue-failover-during-forced-finish.jsonrecorded and frozen (double-run agreement;scripts/record-m8-cassettes.mjs); the queue-mode limitation stays documented (no distributed cross-process rate limiter, EXC-14/OQ-17).
Patch Changes
- Updated dependencies [84f94d4]
- Updated dependencies [65c7b2c]
- Updated dependencies [a2a3243]
- Updated dependencies [ebc8101]
- @rulvar/[email protected]
0.8.0
Minor Changes
85d55cf: The v0.8.0 BREAKING release notes (M7 adaptive orchestration full; the flagged BREAKING minor of the pre-1.0 convention, docs/12 registry).
BREAKING: the unified
AdmitVerdictunion is extended with the reuse verdicts (reuse_full,admit_graft) and the new reject codes (termination_exhausted,ladder_exceeds_frozen,lineage_exhausted,lineage_busy,osc_guard) (DEF-5). How it fails: exhaustive switches over the verdict kind or reject code in custom shells and admission SPI extensions stop compiling. Migration: add branches for the new arms; reject-code switches should route unknown codes to their generic-denial path.BREAKING: reuse-by-reference is the DEFAULT (DEF-5). A byte-identical
add_taskafter a cancel or abandon no longer re-executes the subtree: the result returns by reference (reuse_full) or continues from the paid prefix (admit_graft). How it fails: changed semantics; runs that relied on re-execution against a changed world observe referenced results instead. This is the only intentional change of visible semantics in the pre-1.0 line. Migration: setreuse.enabled: falseon the admission config, orfresh: trueon the specificadd_task.BREAKING: the config key
maxEscalationsPerNodeis renamed tomaxEscalationsPerLogicalTask(XF-10): escalations count per logical task across respawns via the lineage chain. How it fails: a typedConfigErrornaming the new key rejects the old one. Migration: rename the key; the default stays 2.BREAKING: the plan-size-scaled revision budget option is removed without deprecation (DEF-2).
maxRevisionsPerRunis an absolute, non-replenishable counter (default 32) debited by exactly 1 per journaledplan_revise; nothing increments it. How it fails: the removed option is rejected at config validation. Migration: sizemaxRevisionsPerRundirectly.BREAKING:
plan_reviseresult and error schemas widen (rebase outcomes, embedded admissions,revisionUnitsRemaining) andWakeDigestgains the MANDATORYterminationfield besideplanHash,budget, andreuse(DEF-2/DEF-8). How it fails: schemaHash and toolsetHash of orchestrator scopes change, so VCR cassettes recorded over orchestrator turns invalidate. Migration: re-record affected cassettes; consumers of the digest type add the new mandatory blocks (all-zero outside PlanRunner).BREAKING: B0, the run budget ceiling, is immutable after start (DEF-2): no API, including HITL decisions, can top it up. How it fails: code that mutated the run budget mid-run or expected an HITL top-up hits a typed runtime error; overshoot stays bounded by one turn per in-flight agent. Migration: size the ceiling at start; use the orchestrator cap and the finalize reserve (DEF-7) for graceful degradation instead of top-ups.
BREAKING: PlanRunner requires a resolvable orchestrator cap (DEF-7).
orchestratePlannedwith no run USD ceiling and no explicitbudget.capUsd, or witheffectiveCap < finalizeReserve, refuses to start with a typedOrchestratorCapConfigErrorbefore any LLM call. Migration: passbudget: { capUsd }(or run under a USD ceiling and rely oncapFraction, default 0.2; up to 1.0 opts out explicitly with a telemetry warning).712a28e: M7-T01: the plan scope substrate.
TaskPlanas engine-owned typed data (docs/07 3.1):PlanNodewith the exact canonical field list, the closedPlanNodeStatusmachine with immutable terminal statuses (doneis immutable by construction) enforced byassertPlanTransitionraising the typedPlanInvariantError; pure derivationsdepsSatisfied,recomputePlanReadiness(dependency satisfaction is derived in the fold, never a record), andwouldCreateDepCyclefor the rewire_deps atomicity rule.planHash(docs/07 3.4): sha256 over the RFC 8785 canonical projection of PlanState through the frozen hashVersion 2 deriver, nodes sorted by NodeId, deps sorted in the hash, plus the guard fold counters revisionCount and droppedRevisionStreak;assertPlanHeadraisesPlanInvariantErroron a fold-head mismatch; golden hashes are frozen in tests.PlanWriteLock(docs/07 3.2, XF-07): the in-process FIFO mutex serializing ONLY plan-scope appends, never a substitute for the ResolutionArbiter. The single sequential scope constantPLAN_SCOPEis'plan'. The temporaryM0_SCAFFOLDmarker is removed now that the package's first real API has landed.c8d88e7: M7-T04: plan.revision, plan.decision, and the committed rebase algorithm (DEF-8).
task-spec.ts: the typedTaskSpec/TaskSpecPatchof docs/07 4.1 withpromptSpecHashOfand patch application.plan-entries.ts: the two plan-mutating entry payloads (PlanRevisionValuewith base/requestedOps/outcomes/assignedNodeIds/admissions/planHash chain/rationale plus the DEF-2 extensions;PlanDecisionValuewith the closedEnginePlanOpset), content keys per docs/07 3.3 (rationale never keys), and THE single applierapplyPlanEntry: replay consumes recorded outcomes (the APPLIED diff), never re-runs rebase, verifies the planHash chain under each entry's own hashVersion and raises the typedReplayPlanHashMismatchat the exact entry; bad_base entries leave the hashed state byte-identical while lengthening the guard-side streak (effectiveDroppedStreak); terminal set_node_status transitions extinguish pending park/cancel flags and record doneRefs for waive blockingRef.rebase.ts: the committed algorithm (base validation against the recorded WakeDigest pair, conflicts evaluated ONLY against the fold head, sequential intra-revision application, per-op applied | transformed | dropped with the complete closed conflict table and reason codes, engine-computed cancel cascades excluding done, embedded add/unpark admissions, lineage-at-head checks, the DEF-5 dedup transform hook, and the DEF-7 plan_frozen row). Every row of the conflict table is exercised by the table-driven test matrix; the revise-racing-defaultDecision cassette shape asserts the exact dropped trio with blockingRef.a41c20f: M7-T05: PlanRunner scheduling and toolset. Core gains the PUBLIC orchestrator extension seam (docs/02 section 4 seam-sufficiency: orchestration packages build exclusively from the public API):
OrchestrateOptions.extensionhosts anOrchestratorExtensionwith boot strictly before the orchestrator's first agent entry, extension tools appended to the mode (c) toolset, an activity hook running after every child settlement strictly before wake evaluation, quiescence participation (nothing running AND nothing ready), digest extras, wake observation, prompt lines, and anOrchestratorExtensionIOexposing total-order appends into extension-owned scopes, the journal snapshot, the single admission point, explicit-scope child dispatch through the ordinary ctx.agent path (plan/NodeId sub-accounts open beside the orchestrator account), settled lookups, cancel, ULID minting, and telemetry.outputSchemaRef/toolsetRefnow RESOLVE against the newdefaults.schemasanddefaults.toolsetsengine registries (unknown names stay typed tool errors);TerminationAccount.bindDeniedWriterbinds I/O onto fold-rebuilt accounts. @rulvar/plan shipsplanRunner(options)andorchestratePlanned(engine, goal, opts): boot writestermination.init(frozen limits with kMax and the profile-registry snapshot hash) strictly before the first scheduling entry and binds the account into admission; plan_view renders the pinned pure fold (plan state, per-node LineageStats, the TerminationAccount snapshot) at the last delivered WakeDigest, with digestSeq 0 seeded as the empty-plan bootstrap snapshot; plan_revise (normative docs/07 4.7 schema) debits one revisionUnit per journaled revision (underflow writes termination.denied first), evaluates the committed rebase at the fold head, appends ONE plan.revision strictly before effects, schedules newly-ready nodes under plan/NodeId scopes, lands cancel requests, re-issues idempotently on re-executed turns (roll-forward), and emits plan:revised plus termination:debit; the engine (never the model) schedules ready nodes and journals ready-to-running and terminal transitions as plan.decision entries whose terminal transitions extinguish pending flags; quiescence completes (nothing running and nothing ready). The end-to-end revise-mid-run shape and a full crash-resume with zero live calls and no duplicate entries are covered by integration tests against the public engine API.51b062a: M7-T06: RevisionGuards, the oscillation detector, and hysteresis (docs/07 3.8). New
guards.ts: the non-HITL terminating guard state machine whose every verdict is a journaled decision entry (decisionType 'guard-verdict') written strictly BEFORE its effects, with replay rebuilding state from journaled verdicts. The droppedRevisionStreak detector consumeseffectiveDroppedStreak(the hashed counter plus trailing bad_base entries) and fires the configured fallback (reject-revision | finish-with-partial | fail-run; default finish-with-partial, droppedRevisionLimit default 3) exactly once: further plan_revise calls are rejected with a typed tool error instructing a finish with the partial result, and the fourth revision after a three-bad-base streak journals nothing and debits nothing. The oscillation detector keys on approachSigCoarse ACROSS LogicalTaskId boundaries: a re-add after a severing cancel counts one oscillation, the per-key limit (2, the Appendix A osc_guard default) freezes the signature with a journaled verdict plus a guard:oscillation event, and frozen re-adds reject at admission with the embedded osc_guard verdict (dropped admission_denied in the revision entry); guard counters are fed from the plan fold itself, identically live and on replay, so freeze thresholds never shift across a resume (fired-but-unjournaled verdicts roll forward at boot, deduplicated by content key). Stall detection emits stall:detected per (lineage, streak) with the hard per-run stall replan cap journaling its own verdict; hysteresis stays structural (park/cancel against running nodes land only as boundary flags, so nearly-done children are never killed mid-turn). plan_view now renders the guards block (engaged fallback, frozen signatures, stall replans used).f4e70be: M7-T07: reuse-by-reference (DEF-5). Core: new
journal/reuse.tswith the richDonorRef(replacing the M6 seq placeholder inside the closed AdmitVerdict union),GraftBoot,DedupNote,ReuseConfig,NodeLinkValueand its content identity (nodeLinkKeyover {kind, spawnKey, donorScope, targetNodeId}), theDedupIndexpure fold (severed roots become donor candidates when their pre-abandon effective status is not error, memoized failures excluded, exclusive claims resolve first-wins, plan-node scopes sweep their own branch payments, unpinned worktree donors degrade),evaluateReusewith the four-outcome verdict table (reuse_full | admit_graft | fresh-with-note | reject osc_guard at the link count), and the abandoned-spend ledger fold (abandonedUsd/reclaimedUsd/netLostUsd, per-key oscillation counts). The kernel matcher gains scope-prefix aliasing (docs/03 9.5):registerAliasmerges donor-scope candidates into the target scope in journal order at every nested level, and the alias disposition bypasses the abandon overlay so donor entries regain their pre-abandon status ONLY through the alias (the standalone old scope stays skipped); a dangling donor root through the alias IS the graft frontier (rerun-dangling continues from the donor checkpoint).AbandonAttemptcarries logicalTaskId (XF-04); the extension IO gainsabandonBranch,registerAlias, andpriceUsd. Plan: PlanRunner wires the DedupIndex at the fold head under the PlanWriteLock into the rebase dedup hook (transforms embed the verdict, the donor descriptor, and the placement into the revision entry), applies the per-SpawnKey osc_guard rejection, attaches DedupNotes to fresh admits, compiles applied cancel_task (and cancel-landed) into severing abandon entries with lineage attribution, lands node.link entries and by-ref roots in the mandatory write order with idempotent roll-forward, registers aliases (rebuilt by fold at boot), completes full-linked nodes by reference through an engine decision instead of a dispatch, debits a spawnUnit per reuse link, and renders the abandoned-spend view in plan_view (pinned) and the WakeDigest extras;PlanRunnerOptions.reusecarries the docs/03 9.9 config.75d1646: M7-T08: park and unpark. Core: the internal boot-checkpoint channel lets a FRESH dispatch boot from a retained transcript checkpoint (
ExtensionDispatchSpec.bootCheckpointRef; dangling redispatch checkpoints take precedence), serving park/unpark continuation and the DEF-5 graft boot. Plan: newpark.tswith thePinLedgerfold (live pins counted from abandon entries carrying retainWorktree, park pinning and DEF-5 retention SHAREmaxPinnedWorktrees, default 4),parkDispositionOf(checkpoints always retained; worktrees pinned only under capacity, overflow keeps the checkpoint but drops the tree), andunparkPlacementOf(continuation from the retained checkpoint; restart when no checkpoint exists or a worktree-isolated node lost its tree: silent resume against a fresh tree is impossible). PlanRunner lands parks at the turn boundary: a park-requested running child is aborted, thepark-landedplan.decision transitions running to parked carrying the checkpoint anchor (set_node_status gains the optional checkpointRef field, applied by the fold), the branch is severed with retainCheckpoint plus retainWorktree per the pin disposition, the dispatch slot frees for the unpark, and node:parked emits. unpark_task applies with the embedded admission: a previously dispatched branch is a lineage rebirth (relation 'unpark-restart' continuing the node's LTID), while a never-started parked node resumes scheduling without consuming an attempt; the unparked dispatch boots fromcheckpointRefFor(runId, anchor)on the continuation path and restarts otherwise. The park-unpark integration test drives the full shape deterministically (one paid tool turn, park inside the second turn, unpark continuation whose booted history carries the paid turn) plus the pin-cap overflow and placement rows as units.5ed23d5: M7-T09: RunLedger (docs/07, section 9). New
ledger.ts: the CLOSED authored op vocabulary (brief_setonce per run,fact_add/fact_supersede,lesson_addkeyed by (logicalTaskId, approachSig),observation_add),foldLedgeras a pure fold ofledger.opentries joined to the journal task table (auto-derived revisionHistory, taskDigests, worldDelta; journal-vs-ledger contradictions render as flagged discrepancies, never as truth), single-writer discipline (foreign-scope ops ignored and flagged), Appendix A section caps (64 facts, 32 lessons, 16 observations) vialedgerCapViolation, compaction sufficiency vialedgerSufficiency, and the draft-versionedexportLedger(ledgerExportVersion: 'draft-1'). PlanRunner gainsledger_appendandledger_read: appends are journaled effect entries of kindledger.opin the orchestrator scope with content-derived keys, idempotent on re-execution (a journaled op acks with the recorded ref and skips validation, so re-executed turns never spuriously reject); alesson_addwhose key matches no journaled attempt of that logical task rejects as a typed tool error;ledger_readis pinned to the delivered-wake seq exactly likeplan_view, so a re-executed wake turn renders byte-identical ledger bytes and fold-global counters never enter the transcript.0627413: M7-T10: ModelLadder full (docs/07 section 10; docs/04 section 12; FR-119/FR-313). Core: ladders now RESOLVE through the chain (
canonicalizeLaddervalidates the declaration once, FR-119 undeclared-judge-rung ConfigError included, and resolves every rung's effort explicitly;ladderRungChoiceyields the concrete per-rung ModelChoice; a higher concrete layer shadows a lower ladder and vice versa; a ladder that WINS wire resolution stays a typed ConfigError since rung attempts always carry a concrete override).ladderLengthOfreads the normative declaration points (profilemodel: { ladder }or the loop-role routing entry).foldTerminationdebits the rung RESPAWN's embedded admission on raising ladder verdicts (docs/07 11.3 b). New per-engine mechanical gate registrydefaults.gates(MechanicalGateProfileover AgentResult.artifacts). The extension seam gainsio.random(journaled ctx.random for spot-checks),io.gates, and dispatch fieldsmodel(the concrete rung resolution entering the attempt's identity hash),memoizeOutcome, and inlineschemafor the engine-synthesized judge. Plan: newladder.tsplus the PlanRunner ladder driver: rung attempts are ordinary agent scopes on the concrete rung model with rung caps binding (tier N+1 = new content key = one live attempt, all sharing the LTID via relationrung-retryregistered from the raising verdict'snextAttempt); triggers classify typed (error, limit, schema-exhausted, no-progress first-class via the abort class, verify-failed from gates only); acceptance gates run per ok attempt in declaration order with journaledgate-verdictdecisions (mechanical registry profiles, judge on a declared rung >= the executing rung or explicit override with a forced verdict schema and derived identity, spot-check selection strictly via the journaled draw); every ladder verdict is a decision entry computed once live and recovered by content key, so folds consume only journaled values; a denied respawn writestermination.deniedstrictly before the fallback lands; an ok attempt whose acceptance fails with no raise left landsfailed, neverdone. Mid-flight resume redispatches running nodes through forward matching (dangling attempts continue, settled ones replay instantly): the half-escalated-ladder shape resumes without repaying completed rungs, proven by the truncated-journal test.55c0f87: M7-T11: EscalationProtocol completion (docs/07 section 6; DEF-2/3/4). Core: Flavor B now REQUIRES an explicit
deadlineMs(the knob has no engine default per the frozen Appendix A row; a flavor B spawn without it is a typed ConfigError before any LLM call); SpawnRecord captures the dispatch's escalation flavor and the WakeDigest escalations block reports it (a flavor B report reaching the digest is already decided by the DEF-4 winner). Plan: newescalation.tswith the authoritativeescalation-decisionentry contract (decide-once per report by content key;countsAgainstLimitderived from the report kind, XF-06; the counting debit atomic with the append embeddingescalationUnitsAfter; a DENIED debit writestermination.deniedstrictly before and flips the entry tocapExceededwithcountsAgainstLimit: false, so the cap yields the flagged decision plus the final report, never a bare limit, and the folds stay replay-strict). PlanRunner completes the decision flow: thecancel_taskrevision transform on an escalated node lands the verdictcanceldecision, theresolve_escalationplan.decision (originescalation-live), and the severing abandon strictly after the revision append; a settled Flavor B suspension's DEF-4 winner (timeoutdefaultDecisionbytimeout, a live decision, or a class fan-out) is absorbed into the authoritative entry (originsescalation-default/escalation-class) and the fate applies through the single applier (retry re-opens the node in place with the journaledamendedPrompt/startTierhonored at re-dispatch, accept closes the paid partial result done, cancel closes cancelled, decompose leaves the node escalated while the proposed children enter throughspawn_admittedops with FRESH lineages and embedded admissions debiting spawn units through the decision entry).fd33871: M7-T12: orchestrator cap and finalize reserve (DEF-7; docs/07 section 12). BREAKING for PlanRunner runs (v0.8.0 registry, docs/12):
orchestratePlannednow REQUIRES a resolvable orchestrator cap; a run with no USD ceiling and no explicitbudget.capUsd, or witheffectiveCap < finalizeReserve, refuses to start with a typedOrchestratorCapConfigErrorBEFORE the first LLM call and before any journal entries (an uncapped orchestrator was precisely the defect;capFractionup to 1.0 opts out explicitly).effectiveCapUsd = min(capUsd, capFraction x runCeiling), default fraction 0.2. The engine writes ONEorchestrator_budget_reservedecision entry strictly aftertermination.initand strictly before the orchestrator's first agent entry, freezing the cap and the finalize reserve (explicit, orfinalizeTurnsx the deterministic per-turn estimate) in absolute dollars, recovered by content key on resume and never re-evaluated. The reserve registers on the orchestrator account AND the run root (kept separate from committedReserve; the admission block checks add it), so no spawn ever eats the finalization money. At the pre-wake soft boundary (orchSpent + turnEstimate > effectiveCap - finalizeReserve) the engine writes exactly ONEorchestrator_budget_capdecision strictly before any effects (an in-flight latch closes the wake-ordinal race): the plan freezes for adaptation but not for work (the rebase contextfrozenflag drops every opplan_frozenwhile admitted nodes run to completion), all wake triggers except quiescence disarm, and the orchestrator unwinds to the reserved FINAL wake: a fresh agent entry on the restricted single-finishtoolset with afinalizeTurnslimit, paid from the reserve; success yields outcomeokwithforcedFinishmarked in the CostReport. If the final finish fails,orchestrator_finalize_fallbackjournals and the engine SYNTHESIZES a deterministic partial result by pure fold with zero LLM calls; the run endsexhaustedwith the non-null partial (RunOutcome.valuenow survives exhaustion). Every digest carries theWakeBudgetBlock(run and orchestrator spend, cap, reserve, the epsilon-floored orchestrator share,softWarningat 0.8) withorchestrator:budgettelemetry at each wake boundary and at the cap;CostReport.orchestratorpopulates spentUsd, wakes, forcedFinish, and reserveUsedUsd for H-OrchShare.e70e7f4: M7-T13: the FINAL normative WakeDigest in ONE coordinated schema change (docs/07 section 5; XF-08/XF-12, inside the frozen hashVersion-2 identity rules).
WakeDigestnow declares every block first-class:digestSeq,planHash(emission-time plan hash, empty outside PlanRunner),coversToOrdinal,completedDigestsordered by spawn ordinal,escalations(with the Flavor BdeadlineAt), the MANDATORYterminationsnapshot (DEF-2, contributed by the PlanRunner extension as a pure fold), the MANDATORYbudgetblock (WakeBudgetBlock, DEF-7), and thereusestats (the AbandonedSpendView shape, DEF-5). Runs without the PlanRunner extension ship all-zero blocks (emptyDigestBlocks), mirroring the CostReport convention. The digest render is bounded deterministically: the newrenderBudgetCharsoption clamps each TaskDigestoutputSummaryby CHARACTERS (the model-independent interim measure; the tokenizer choice stays the docs/14 open question, the numeric default TBD before M10). Pinning semantics are unchanged: the digest is part of the wake snapshot and a re-executed turn reads identical bytes.bc9c903: M7-T14: the M7 gating cassettes and the remaining metric wiring (docs/09 sections "Metrics" and "Mandatory defect cassette catalog"). Thirteen frozen cassettes record the round-2 set (revise-mid-run, crash-during-revision, park-unpark, oscillation-freeze, half-escalated-ladder, budget-denied-rung), the DEF-7 set minus queue-failover (cap-freeze-then-finish, crash-between-cap-and-effects, finalize-fallback-synthesized, escalation-storm-frozen), and representative DEF-2/DEF-3 rows (revision-exhaustion, rung-retry-lineage, decompose-mints-children), each double-run at record time and replayed byte-for-byte in CI through the new public
@rulvar/plancassette runners with deterministic journal normalization (ULIDs, content hashes, wall clock, spans, and refs collapse to first-appearance placeholders). Metric events:orchestrator:wokenow carriesplanHash,coversToOrdinal, andrenderSize(the deterministic character measure of the delivered digest, the wake-render-size metric); the escalated landing emitsescalation:raisedwith the report kind, the lineage attribution,agentType(the escalation-rate slice), andcostToDateUsd; the abandoned/reclaimed/netLost USD view rides every digest through the T13 reuse block andledger:opplusspawn:*events already feed ledger-ops-per-spawn.
Patch Changes
- Updated dependencies [85d55cf]
- Updated dependencies [b88c9e3]
- Updated dependencies [f3c4613]
- Updated dependencies [a41c20f]
- Updated dependencies [f4e70be]
- Updated dependencies [75d1646]
- Updated dependencies [0627413]
- Updated dependencies [55c0f87]
- Updated dependencies [fd33871]
- Updated dependencies [e70e7f4]
- Updated dependencies [bc9c903]
- @rulvar/[email protected]
0.7.0
Patch Changes
- Updated dependencies [fd1d06c]
- Updated dependencies [6fcf296]
- Updated dependencies [dcc97a9]
- Updated dependencies [434dc83]
- Updated dependencies [03173c1]
- Updated dependencies [11c0afc]
- @rulvar/[email protected]
0.6.0
Patch Changes
- Updated dependencies [fa05007]
- Updated dependencies [9234dc8]
- Updated dependencies [644512c]
- Updated dependencies [8a41656]
- Updated dependencies [02f7f7a]
- @rulvar/[email protected]
0.5.0
Patch Changes
- Updated dependencies [ac274f4]
- Updated dependencies [5735d92]
- Updated dependencies [46ca98e]
- Updated dependencies [8ae129e]
- Updated dependencies [d1c4525]
- Updated dependencies [b840aba]
- @rulvar/[email protected]
0.4.0
Patch Changes
- Updated dependencies [dfe03b5]
- Updated dependencies [d2089a7]
- Updated dependencies [3f60234]
- Updated dependencies [f668890]
- Updated dependencies [16d7aa6]
- Updated dependencies [6513ce8]
- Updated dependencies [7dad493]
- Updated dependencies [2bbf180]
- @rulvar/[email protected]
0.3.0
Patch Changes
- Updated dependencies [43444f6]
- Updated dependencies [279881b]
- Updated dependencies [9fd0966]
- Updated dependencies [24ebadf]
- Updated dependencies [a1b35d3]
- Updated dependencies [18a5821]
- @rulvar/[email protected]
0.2.0
Patch Changes
- Updated dependencies [c24228d]
- Updated dependencies [c50871e]
- Updated dependencies [1af8fb9]
- Updated dependencies [1fe0249]
- Updated dependencies [5c4fc32]
- @rulvar/[email protected]
0.1.0
Minor Changes
- f4e2be9: M0 repo bootstrap (v0.1.0, docs/10-implementation-plan.md section "M0"): monorepo scaffold on the committed toolchain (pnpm 11 workspaces with catalogs, TypeScript 6.0, tsdown, Vitest 4, ESLint 9 flat config, Turborepo 2, changesets fixed mode, npm trusted publishing), the docs/ canon as single source of truth, the L0 contracts skeleton in @rulvar/core, and the vendored dependencies (StandardSchemaV1/StandardJSONSchemaV1 types, the @cfworker/json-schema lineage validator subset, a first-party monotonic ULID). Placeholder scaffolds only: no public API ships in this release.
Patch Changes
- Updated dependencies [f4e2be9]
- @rulvar/[email protected]
@rulvar/planner
1.252.0
Patch Changes
- Updated dependencies [3ccb6cf]
- Updated dependencies [52d807f]
- Updated dependencies [517ed00]
- Updated dependencies [a7e589d]
- Updated dependencies [76e95eb]
1.251.0
Patch Changes
- Updated dependencies [e7e829c]
- Updated dependencies [5982be8]
- Updated dependencies [7c58fb2]
- Updated dependencies [b3e465a]
- Updated dependencies [c4e5d6a]
- Updated dependencies [c6fc3da]
- Updated dependencies [c6fc3da]
- Updated dependencies [0ae8b85]
- Updated dependencies [7932936]
- Updated dependencies [7932936]
- Updated dependencies [88da0ed]
- Updated dependencies [06c0e85]
1.250.0
Patch Changes
- Updated dependencies [0e240b9]
- Updated dependencies [6fe585e]
- Updated dependencies [c5eb19c]
- Updated dependencies [565c13b]
- Updated dependencies [c6d197b]
- Updated dependencies [c9d9729]
- Updated dependencies [fed9db6]
- Updated dependencies [df9ed76]
- Updated dependencies [3020912]
- Updated dependencies [d8d598d]
1.249.0
Patch Changes
- Updated dependencies [8862133]
- Updated dependencies [0d7a717]
- Updated dependencies [e4428bd]
- Updated dependencies [d6873c1]
- Updated dependencies [4092e8d]
- Updated dependencies [e086590]
- Updated dependencies [1411938]
- Updated dependencies [737d1ee]
- Updated dependencies [634f966]
- Updated dependencies [052cc26]
- Updated dependencies [bbae134]
1.248.0
Patch Changes
- Updated dependencies [8d0cd69]
- Updated dependencies [81065e4]
- Updated dependencies [8573f20]
- Updated dependencies [95f6a5e]
1.247.0
Patch Changes
- Updated dependencies [1933ecc]
- Updated dependencies [db0a5f0]
- Updated dependencies [b698726]
- Updated dependencies [48348d2]
- Updated dependencies [4cfa1cc]
- Updated dependencies [4b7197a]
- Updated dependencies [5ebc842]
- Updated dependencies [16ff6b9]
- Updated dependencies [0c9941d]
1.246.0
Patch Changes
- Updated dependencies [d165b0c]
- Updated dependencies [d59f4a0]
- Updated dependencies [46907ac]
- Updated dependencies [9929ad3]
- Updated dependencies [1790a6a]
1.245.0
Patch Changes
- Updated dependencies [b4d47a8]
- Updated dependencies [dee6db4]
- Updated dependencies [b85c113]
- Updated dependencies [bc556e7]
- Updated dependencies [9f11d29]
- Updated dependencies [19bcea0]
- Updated dependencies [60b461c]
- Updated dependencies [61e3a1a]
- Updated dependencies [a156b81]
- Updated dependencies [0bd7045]
1.244.0
Patch Changes
- Updated dependencies [38d839a]
- Updated dependencies [ce13b0f]
- Updated dependencies [4fa23e3]
- Updated dependencies [6841c69]
- Updated dependencies [f56721d]
- Updated dependencies [c894a43]
- Updated dependencies [f6944a3]
- Updated dependencies [23fd0e0]
1.243.0
Patch Changes
- Updated dependencies [746d1f4]
- Updated dependencies [009b29c]
- Updated dependencies [1674cbe]
- Updated dependencies [bd096bc]
1.242.0
Patch Changes
- Updated dependencies [6e3438e]
- Updated dependencies [ba5cf67]
- Updated dependencies [c2d1531]
1.241.0
Patch Changes
- Updated dependencies [dbcdd24]
- Updated dependencies [7ae7243]
- Updated dependencies [4f832c4]
- Updated dependencies [7452d3d]
- Updated dependencies [a4e22bf]
- Updated dependencies [82df4af]
1.240.0
Patch Changes
1.239.0
Patch Changes
- Updated dependencies [74ce99a]
- Updated dependencies [ccd0665]
- Updated dependencies [0c5ce21]
- Updated dependencies [0616934]
1.238.0
Patch Changes
- Updated dependencies [cf00947]
- Updated dependencies [c7b9382]
- Updated dependencies [88aea96]
- Updated dependencies [6da8d05]
- Updated dependencies [eae5c4c]
1.237.0
Patch Changes
- Updated dependencies [9d6a279]
- Updated dependencies [49a98f6]
- Updated dependencies [a734ca0]
- Updated dependencies [deb406f]
1.236.0
Patch Changes
- Updated dependencies [26306ea]
- Updated dependencies [709b942]
1.235.0
Patch Changes
- Updated dependencies [ba4e10d]
- Updated dependencies [172402b]
- Updated dependencies [2ecd787]
- Updated dependencies [e20a5e9]
- Updated dependencies [98c8691]
- Updated dependencies [c70def0]
1.234.0
Patch Changes
- Updated dependencies [8420c04]
1.233.0
Patch Changes
- Updated dependencies [48b5200]
- Updated dependencies [73bc32b]
- Updated dependencies [e63b743]
- Updated dependencies [ef45da7]
1.232.0
Patch Changes
- Updated dependencies [1440410]
- Updated dependencies [6e467f4]
- Updated dependencies [0b14293]
- Updated dependencies [e3bcab2]
- Updated dependencies [b55a0f7]
1.231.0
Patch Changes
- Updated dependencies [4eb4b56]
- Updated dependencies [bc8f09e]
- Updated dependencies [ff9b8c2]
1.230.0
Patch Changes
- Updated dependencies [e9bf910]
- Updated dependencies [57bfb38]
1.229.0
Patch Changes
- Updated dependencies [3370342]
- Updated dependencies [2fb6656]
- Updated dependencies [edce170]
1.228.0
Patch Changes
- Updated dependencies [4034fac]
- Updated dependencies [a54b085]
- Updated dependencies [9d0a9be]
- Updated dependencies [be9ef28]
1.227.0
Patch Changes
- Updated dependencies [f262e9f]
- Updated dependencies [f191ff7]
- Updated dependencies [fbbfbe8]
- Updated dependencies [263b5e8]
- Updated dependencies [db4d56d]
- Updated dependencies [41f93a9]
- Updated dependencies [98c8ca9]
1.226.0
Patch Changes
1.225.0
Patch Changes
1.224.0
Patch Changes
- Updated dependencies [4eca1a3]
1.223.0
Patch Changes
- Updated dependencies [549aabd]
- Updated dependencies [549aabd]
1.222.0
Patch Changes
- Updated dependencies [8326268]
1.221.0
Patch Changes
- Updated dependencies [032ce93]
1.220.0
Patch Changes
- Updated dependencies [0babe70]
1.219.0
Patch Changes
- Updated dependencies [65a4ce7]
1.218.0
Patch Changes
- Updated dependencies [088bda6]
1.217.0
Patch Changes
- Updated dependencies [ab80b97]
1.216.0
Patch Changes
- Updated dependencies [b357f4a]
1.215.0
Patch Changes
- Updated dependencies [e1da4c7]
1.214.0
Patch Changes
- Updated dependencies [c8af0ec]
1.213.0
Patch Changes
- Updated dependencies [61680df]
1.212.0
Patch Changes
- Updated dependencies [e6f8516]
1.211.0
Patch Changes
- Updated dependencies [d5a8a36]
1.210.0
Patch Changes
- Updated dependencies [c871ddc]
1.209.0
Patch Changes
- Updated dependencies [514c7bb]
1.208.0
Patch Changes
- Updated dependencies [e7d426f]
1.207.0
Patch Changes
- Updated dependencies [99beee2]
1.206.0
Patch Changes
- Updated dependencies [ec8e1f1]
1.205.0
Patch Changes
- Updated dependencies [6d224da]
1.204.0
Patch Changes
- Updated dependencies [efaec9b]
1.203.0
Patch Changes
- Updated dependencies [fb08c10]
1.202.0
Patch Changes
1.201.0
Patch Changes
- Updated dependencies [7e01189]
1.200.0
Patch Changes
- Updated dependencies [e2ddbdf]
1.199.0
Patch Changes
- Updated dependencies [29891c6]
1.198.0
Patch Changes
- Updated dependencies [c097c96]
1.197.0
Patch Changes
1.196.0
Patch Changes
- Updated dependencies [ec9c3e3]
1.195.0
Patch Changes
- Updated dependencies [5702a70]
1.194.0
Patch Changes
- Updated dependencies [360a659]
1.193.0
Patch Changes
- Updated dependencies [2bca1d1]
1.192.0
Patch Changes
- Updated dependencies [8757601]
1.191.0
Patch Changes
- Updated dependencies [745387c]
1.190.0
Patch Changes
- Updated dependencies [8e02021]
1.189.0
Patch Changes
- Updated dependencies [6a5cc2d]
1.188.0
Patch Changes
1.187.0
Patch Changes
- Updated dependencies [c9798ef]
1.186.0
Patch Changes
- Updated dependencies [242647e]
1.185.0
Patch Changes
- Updated dependencies [1248623]
1.184.0
Patch Changes
- Updated dependencies [8a9caca]
1.183.0
Patch Changes
- Updated dependencies [dd3767c]
1.182.0
Patch Changes
- Updated dependencies [144d026]
1.181.0
Patch Changes
1.180.0
Patch Changes
- Updated dependencies [b124d26]
1.179.0
Patch Changes
- Updated dependencies [1a5a85a]
1.178.0
Minor Changes
- e89f377: Package truth is now a gate, not a hope (RV1701). The eighteenth comparison benchmark's strongest documentation-class failure was package identity conflation: a due-diligence dossier described
@rulvar/planwith a citation intopackages/planner, and nothing mechanical objected. The docs cannot stop a reader's model from confusing two names, but they can refuse to ship a byte that gets the universe wrong themselves. Docs lint check 12 now enforces four layers against build artifacts rather than prose: every@rulvar/<name>token in every page must name a real workspace package; every import, require, export-from, and dynamic-import specifier in a ts/js fence must resolve to a real exports-map subpath of its package; every named root import in a fence must be a symbol the package's committed dts rollup actually exports, which turnsimport { planRunner } from '@rulvar/planner'into a lint failure instead of a shipped falsehood; and the versioning page's fixed-group list, its spelled-out size, and both package tables stay in set equality with.changeset/config.jsonand the manifests. The completeness layer had teeth on its first run: the installation guide's "full package list" had silently dropped@rulvar/store-postgresand@rulvar/executor; both rows are restored. The pointer narrative now tells the caret truth: a fresh install ofrulvar@Xresolves the newest umbrella release of X's major (X or newer, never older), so the bare name is a front door, not a pinning surface; pin@rulvar/rulvarexactly when you need one exact version. The CommonJS consumer path the installation guide documents is now proven on packed artifacts: the install smoke gains a.cjsconsumer thatrequire()s the umbrella and the pointer on the packed tarballs and assertsimport()serves the same module instance. And the two npm descriptions disambiguate each other in both directions:@rulvar/planreplans during the run and names@rulvar/planneras the package it is not;@rulvar/plannerplans before the run and names@rulvar/planthe same way.
Patch Changes
1.177.0
Patch Changes
- Updated dependencies [94db8ff]
1.176.0
Patch Changes
- Updated dependencies [a74304d]
1.175.0
Patch Changes
- Updated dependencies [1999c5d]
1.174.0
Patch Changes
- Updated dependencies [aa9a772]
1.173.0
Patch Changes
- Updated dependencies [67d27ac]
1.172.0
Patch Changes
- Updated dependencies [0d4770b]
1.171.0
Patch Changes
- Updated dependencies [f6116b9]
1.170.0
Patch Changes
- Updated dependencies [86e4c06]
1.169.0
Patch Changes
- Updated dependencies [623b2ae]
1.168.0
Patch Changes
- Updated dependencies [ebba79a]
1.167.0
Patch Changes
1.166.0
Patch Changes
- Updated dependencies [d8262c3]
1.165.0
Patch Changes
- Updated dependencies [6391274]
1.164.0
Patch Changes
- Updated dependencies [9f2dda9]
1.163.0
Patch Changes
- Updated dependencies [e8d9ada]
1.162.0
Patch Changes
- Updated dependencies [2031e82]
1.161.0
Patch Changes
- Updated dependencies [d4547b7]
1.160.0
Patch Changes
- Updated dependencies [1c6f0d0]
1.159.0
Patch Changes
- Updated dependencies [e881c8b]
1.158.0
Patch Changes
- Updated dependencies [a266bc7]
1.157.0
Patch Changes
- Updated dependencies [1883421]
1.156.0
Patch Changes
- Updated dependencies [537144e]
1.155.0
Patch Changes
- Updated dependencies [49b08a7]
1.154.0
Patch Changes
- Updated dependencies [9259f24]
1.153.0
Patch Changes
- Updated dependencies [d8bebcb]
1.152.0
Patch Changes
- Updated dependencies [dd6a616]
1.151.0
Patch Changes
- Updated dependencies [1de0610]
1.150.0
Patch Changes
- Updated dependencies [a331211]
1.149.0
Patch Changes
- Updated dependencies [08b4537]
1.148.0
Patch Changes
- Updated dependencies [c85dac9]
1.147.0
Patch Changes
- Updated dependencies [6367231]
1.146.0
Patch Changes
- Updated dependencies [5d9bbc8]
1.145.0
Patch Changes
1.144.0
Patch Changes
- Updated dependencies [c11bcd6]
1.143.0
Patch Changes
- Updated dependencies [f412169]
1.142.0
Patch Changes
1.141.0
Patch Changes
- Updated dependencies [4f12a62]
1.140.0
Patch Changes
1.139.0
Patch Changes
- Updated dependencies [03a2141]
1.138.0
Patch Changes
- Updated dependencies [ed0c4fb]
1.137.0
Patch Changes
- Updated dependencies [96f6788]
1.136.0
Patch Changes
- Updated dependencies [aa6ca71]
1.135.0
Patch Changes
- Updated dependencies [cf75e22]
1.134.0
Patch Changes
1.133.0
Patch Changes
1.132.0
Patch Changes
- Updated dependencies [2bec904]
1.131.0
Patch Changes
- Updated dependencies [256cae1]
1.130.0
Patch Changes
- Updated dependencies [d6bec7a]
1.129.0
Patch Changes
- Updated dependencies [1612439]
1.128.0
Patch Changes
- Updated dependencies [27c4e38]
1.127.0
Patch Changes
- Updated dependencies [b3b1805]
1.126.0
Patch Changes
1.125.0
Patch Changes
1.124.0
Patch Changes
- Updated dependencies [37fd1f2]
1.123.0
Patch Changes
- Updated dependencies [5c46468]
1.122.0
Patch Changes
- Updated dependencies [8cf45c5]
1.121.0
Patch Changes
- Updated dependencies [3d67d41]
1.120.0
Patch Changes
- Updated dependencies [d630c9e]
1.119.0
Patch Changes
- Updated dependencies [1e4ff3c]
1.118.0
Patch Changes
- Updated dependencies [f8341a3]
1.117.0
Patch Changes
1.116.0
Patch Changes
- Updated dependencies [a213878]
1.115.0
Patch Changes
- Updated dependencies [63642ae]
1.114.0
Patch Changes
- Updated dependencies [5759731]
1.113.0
Patch Changes
- Updated dependencies [a60807a]
1.112.0
Patch Changes
- Updated dependencies [00ae55b]
1.111.0
Patch Changes
- Updated dependencies [fd25169]
1.110.0
Patch Changes
- Updated dependencies [58afdb5]
1.109.0
Patch Changes
- Updated dependencies [85b1d39]
1.108.0
Patch Changes
- Updated dependencies [affa3d4]
1.107.0
Patch Changes
- Updated dependencies [9f5f6f6]
1.106.0
Patch Changes
- Updated dependencies [9a4ce49]
1.105.0
Patch Changes
- Updated dependencies [531dc88]
1.104.0
Patch Changes
1.103.0
Patch Changes
- Updated dependencies [f2b809e]
1.102.0
Patch Changes
- Updated dependencies [3eb6515]
1.101.0
Patch Changes
- Updated dependencies [51b215c]
1.100.0
Patch Changes
- Updated dependencies [9785bea]
1.99.1
Patch Changes
- Updated dependencies [ef08d73]
1.99.0
Patch Changes
- Updated dependencies [9e00888]
1.98.0
Patch Changes
1.97.0
Patch Changes
- Updated dependencies [5c3b453]
1.96.0
Patch Changes
1.95.0
Patch Changes
1.94.0
Patch Changes
1.93.0
Patch Changes
- Updated dependencies [c62150a]
1.92.0
Patch Changes
- Updated dependencies [351d1f5]
1.91.0
Patch Changes
1.90.0
Patch Changes
- Updated dependencies [9603940]
1.89.0
Patch Changes
- Updated dependencies [f18b671]
- Updated dependencies [f18b671]
1.88.0
Patch Changes
- Updated dependencies [3b339d9]
1.87.0
Patch Changes
- Updated dependencies [c4c02b1]
1.86.0
Patch Changes
- Updated dependencies [2f71894]
1.85.0
Minor Changes
6932a9f: Three fail-closed fixes from the cycle 83 sweep, plus the dependency refresh.
Engine. A typed error thrown out of
ProviderAdapter.stream()now keeps its own class instead of being laundered into a retryable transport fault. AConfigError(a bridged model id that does not match the wrapped model, an unsupported role, a namespaced option contradicting a canonical field) used to be retried through the whole backoff ladder and then trigger transport failover, so a misconfigured primary silently served the run from a fallback model the caller never asked for while the real fault vanished behind a generic message. Typed errors that ARE retryable by class (a lost lease) keep retrying exactly as before, and an untyped throw is still a retryable transport fault.Planner sandbox. The realm scrub replaced
Date.nowandMath.random, which left three ambient sources open: a barenew Date()never consultsDate.now(V8 reads the system clock directly),performance.now()is a second live clock, and WebCrypto (crypto.randomUUID(),crypto.getRandomValues()) is raw entropy. Those are the first idioms a machine-written script reaches for, and each silently produced a run that could not reproduce on replay. All of them now draw from the same seeded stream: zero-argumentnew Date()andDate()take the logical clock,performance.now()is that clock minus the segment base,crypto.randomUUID()is the journaled uuid shim, andcrypto.getRandomValues()fills from the seed. Passing a timestamp or a date string toDatestays a pure conversion.Server. A tracked run whose segment REJECTS instead of settling (the genesis ownership boot refusing a run another process owns, a withheld settlement whose durable write failed) was reported as
runningfor the life of the process, its SSE connections never closed, and neither retention nor the settled cap could release it.GET /runs/:idnow answersstatus: "error"with the typed wire error, connected streams close with a comment naming the failure, a late subscriber gets that comment instead of an empty stream, and the tracked run becomes eligible for retention like any other terminal run.Dependencies.
@anthropic-ai/sdkmoves to^0.115.0(the only shipped floor its caret was blocking); in-range minors refresh across the workspace. The four majors stay held: eslint 10 and@eslint/js10,@types/node26 against the Node 22.12 floor, and TypeScript 7. The tsdown resolution is pinned at 0.22.3 because it generates the frozen.d.tsartifacts, including the published@rulvar/compattarball that must repack byte identical.
Patch Changes
- Updated dependencies [6932a9f]
1.84.0
Patch Changes
1.83.0
Patch Changes
1.82.0
Patch Changes
- Updated dependencies [9cc5d66]
1.81.2
Patch Changes
- Updated dependencies [296885b]
1.81.1
Patch Changes
- Updated dependencies [c030982]
1.81.0
Patch Changes
- Updated dependencies [ce4c392]
1.80.0
Patch Changes
- Updated dependencies [262e397]
1.79.0
Patch Changes
- Updated dependencies [85956ab]
1.78.0
Patch Changes
- Updated dependencies [941b6e1]
1.77.0
Patch Changes
- Updated dependencies [6aba271]
1.76.0
Patch Changes
- Updated dependencies [22cba47]
1.75.1
Patch Changes
- Updated dependencies [82bc0f0]
1.75.0
Patch Changes
- Updated dependencies [c486de8]
1.74.0
Patch Changes
- Updated dependencies [d94beab]
1.73.0
Patch Changes
- Updated dependencies [3e95bd1]
1.72.0
Patch Changes
- Updated dependencies [662e9e0]
1.71.0
Patch Changes
- Updated dependencies [20d02e0]
1.70.1
Patch Changes
1.70.0
Patch Changes
1.69.0
Patch Changes
- Updated dependencies [b21a681]
1.68.0
Patch Changes
- Updated dependencies [b227874]
1.67.0
Patch Changes
- Updated dependencies [8e6006d]
1.66.0
Patch Changes
- Updated dependencies [1b8987e]
1.65.0
Patch Changes
- Updated dependencies [0b6b859]
1.64.0
Patch Changes
- Updated dependencies [991f9b5]
1.63.0
Patch Changes
- Updated dependencies [8a28aed]
1.62.0
Patch Changes
- Updated dependencies [fca5fd1]
1.61.0
Patch Changes
- Updated dependencies [b4c1f1f]
1.60.0
Patch Changes
- Updated dependencies [59bbeaa]
1.59.4
Patch Changes
- Updated dependencies [c49d7a1]
1.59.3
Patch Changes
- Updated dependencies [deaef36]
1.59.2
Patch Changes
- Updated dependencies [dd0e10f]
1.59.1
Patch Changes
- Updated dependencies [c127770]
1.59.0
Patch Changes
- Updated dependencies [615dc90]
1.58.0
Patch Changes
- Updated dependencies [4fa35ce]
1.57.0
Patch Changes
- Updated dependencies [5897232]
1.56.0
Patch Changes
- Updated dependencies [f26dba0]
1.55.0
Patch Changes
- Updated dependencies [e9b005b]
1.54.0
Patch Changes
- Updated dependencies [3f6bc03]
1.53.0
Patch Changes
- Updated dependencies [b821bd1]
1.52.0
Patch Changes
- Updated dependencies [e138df9]
1.51.0
Patch Changes
1.50.0
Patch Changes
- Updated dependencies [e39a885]
1.49.0
Patch Changes
- Updated dependencies [bab7b2c]
1.48.0
Patch Changes
1.47.0
Patch Changes
- Updated dependencies [a3687fe]
1.46.0
Patch Changes
- Updated dependencies [865e7bf]
1.45.0
Patch Changes
- Updated dependencies [b96305d]
1.44.1
Patch Changes
1.44.0
Patch Changes
- Updated dependencies [299f7d2]
1.43.0
Patch Changes
- Updated dependencies [71b7181]
1.42.0
Patch Changes
- Updated dependencies [9b70f27]
1.41.0
Patch Changes
- Updated dependencies [be589ec]
1.40.0
Patch Changes
- Updated dependencies [cf33550]
1.39.0
Minor Changes
0cff035: Close the dynamic code generation parity gap in the planner sandbox dialect (v1.38.0 review P2-CODEGEN-PARITY).
compileScriptand therulvar/no-code-generationESLint rule now share one AST policy (scanDialect), so both reach the same decision for every statically visible constructor reconstruction form:.constructor,["constructor"], a computed key that folds to the constant,{ constructor: x }destructuring, andReflect.get(fn, "constructor"). The previous regex compile gate matched only the dotted form, so a bracket or computed key passed compile while the linter flagged some of them; moving to an AST also drops the regex false positives, where a property merely namedeval,Function, orconstructorwas wrongly rejected.A key assembled only at runtime (
fn[parts.join("")]) cannot be decided statically without rejecting every dynamic property access, so the worker realm now neutralizes the constructor reconstruction path at runtime by replacing theconstructorslot on all four Function family prototypes with a thrower. A script that compiles clean can no longer reach the Function constructor through a dynamic key.The planner and orchestration docs are corrected to state the exact boundary: the dialect rejects the statically visible forms and the worker neutralizes the runtime path, but a worker in the same process shares its intrinsics with the code it runs and remains a determinism and blast radius boundary, not a hostile code wall.
Patch Changes
- Updated dependencies [0cff035]
1.38.0
Minor Changes
- 3e2d591: Reject dynamic code generation in the planner sandbox dialect (v1.37.0 review SEC-P2).
compileScriptbannedimportbut noteval, theFunctionconstructor, or.constructoraccess, so a machine script could reach the Function constructor and compile a dynamic import the literal scan never saw, recovering the import allowlist and, throughnode:child_process, arbitrary host capability at run statusok.compileScriptnow rejectseval,Function, and.constructor(diagnostic idsno-eval,no-function-constructor,no-constructor-access); a newrulvar/no-code-generationESLint rule carries the same ban into theworkflowspreset and the self repair loop; and the worker additionally unbindsevalandFunctionas defense in depth. This keeps the import allowlist meaningful and the dialect consistent. It is not a hostile code boundary, which the sandbox has never claimed to be: JavaScript intrinsics can still reconstruct the constructors, so the docs continue to call the sandbox a determinism and blast radius boundary, not a security one.
Patch Changes
- Updated dependencies [3e2d591]
1.37.0
Patch Changes
- Updated dependencies [e6b1481]
- Updated dependencies [e6b1481]
1.36.0
Minor Changes
- 101795b: Validate
PlanOptions.repairRoundsas a nonnegative integer before the runId derivation, the store lookup, and any provider dispatch (v1.35.0 review P2). Unvalidated, NaN produced zero drafts with anafter NaN draftsrejection, a fraction over ran by a draft, andInfinityturned the self repair limiter into an unbounded paid loop.
Patch Changes
- Updated dependencies [101795b]
1.35.0
Minor Changes
- d4ac3bf: Validate
WorkerSandboxRunnerresource ceilings at construction (v1.34.0 review P2-2, P2-3).timeoutMsmust be an integer between 1 and 2147483647 ms, the Node timer maximum: a larger value used to clamp to a 1 ms timer and kill a trivial worker immediately withsandbox_limit.memoryMbmust be a positive integer. Anything else, NaN included, is a typedConfigErrorbefore any worker exists.
Patch Changes
- Updated dependencies [d4ac3bf]
1.34.0
Patch Changes
- Updated dependencies [f1505ec]
1.33.0
Patch Changes
1.32.0
Patch Changes
1.31.0
Patch Changes
1.30.0
Patch Changes
- Updated dependencies [87ce985]
1.29.0
Patch Changes
- Updated dependencies [621d566]
1.28.0
Patch Changes
- Updated dependencies [d98eb0b]
1.27.0
Patch Changes
- Updated dependencies [884a433]
1.26.0
Patch Changes
- a4fc757:
SqliteStoreimplements the exact lookup capability (getMetaas a primary key query) and narrowsstatus,statuses, andnamein SQL over the JSON payload behind new expression indexes (created idempotently, so existing database files gain them on the next open), so a selectivelistRunsreads only the matching rows instead of decoding the whole catalog; the tags containment check stays in JS over the reduced set with unchanged semantics. The conformance kit checks thegenesisround trip, that astatusesfilter never drops a matching meta (supersets stay allowed), and that a store exposinggetMetaagrees withlistRunsand resolvesundefinedfor a missing run. The planner's deterministic plan lookup reads one meta through the capability instead of scanning the catalog. - Updated dependencies [a4fc757]
1.25.0
Minor Changes
- 74851ed:
WorkerSandboxRunnernow launches its worker with an explicitexecArgv(default[]) instead of inheriting the host'sprocess.execArgv. Host-only launch flags used to reach the file-entry worker and kill a correct compiled workflow before its first sandbox operation:--input-type=module(present whenever the host itself runs as ESM from stdin or--eval) is rejected for file entries, and an inherited--evalcarried the host's whole source text into the worker's options. The same compiled workflow now behaves identically whether the host runs from a file, from stdin, or via--eval. Hosts that need loader, coverage, or instrumentation flags inside the worker opt in through the newWorkerSandboxRunnerOptions.execArgv, which is passed to the worker verbatim.
Patch Changes
1.24.1
Patch Changes
- Updated dependencies [0bb14db]
1.24.0
Minor Changes
2b033e8: Fix the API card's semantic contract for
tools,model, androuting(the v1.23.0 review P2-1 and P2-2). The card now teaches that string entries oftoolsare registered TOOLSET names (exactly the set the profile card prints), never agent profile names, matching the runtime resolver that rejects unknown names with a typed ConfigError before any provider call. Themodelandroutingbullets now say to normally omit both: the host's profiles and routing decide models, the profile card never names any (model secrecy is a design invariant), and the escape hatch is explicitly conditioned on the goal text itself supplying allowed refs; the false phrase "a model ref from the profile card" is gone. A ConfigError now also stays typed (code: 'config') across the sandbox worker boundary instead of degrading to a generic error, so a compiled script that misuses a profile name intoolssettles with the typed pre-call outcome and zero provider calls.The card text is an identity input of plan operations, so the frozen planner cassettes are re-recorded under the hashVersion-bump token ceremony (the derivation itself is unchanged; CURRENT_HASH_VERSION stays 2).
Patch Changes
- Updated dependencies [2b033e8]
1.23.0
Minor Changes
1f9c272: The API card now tells the planner the truth about identical calls and the complete sanctioned option set (v1.22.0 review P2-4). The card claimed identical calls "journal as ONE result"; the ordinal semantics have always been the opposite: every call journals as its own operation, identical calls share a content key but take sequential ordinals, and repeats always run. The card now states exactly that, plus why a distinguishing
keystill matters (it binds each result to its call by identity instead of position across script edits). The agent opts line is now GENERATED from the runtime allowlist (SANDBOX_AGENT_OPT_KEYS, newly exported from@rulvar/core), which also surfaces the three options the hand-maintained list had silently dropped:routing,memoizeOutcome, andreplay, each with a one-line explanation the model can act on. A parity test pins the card to the runtime allowlist in both directions.Identity note (hashVersion-bump ceremony): the card text is an input of the planner operation's content key, so the frozen
planner-self-repaircassette is re-recorded under the new prompt bytes. The key DERIVATION andCURRENT_HASH_VERSIONare unchanged; committed journals recorded under the old card replay byte-exact, and only a freshplan()call sees the new prompt identity.
Patch Changes
- Updated dependencies [1f9c272]
1.22.0
Patch Changes
- Updated dependencies [77b554f]
1.21.0
Patch Changes
- Updated dependencies [7ee42a0]
1.20.0
Patch Changes
- Updated dependencies [9367030]
1.19.0
Patch Changes
- Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
1.18.0
Patch Changes
- Updated dependencies [943962d]
1.17.0
Patch Changes
1.16.2
Patch Changes
1.16.1
Patch Changes
1.16.0
Patch Changes
1.15.0
Patch Changes
1.14.0
Patch Changes
1.13.0
Patch Changes
- c28c4c0: Export
RunPlannedOptionsfrom the package barrel (v1.12 follow-up review, P2). The interface appears in the publicrunPlannedsignature but was missing from the explicit type export list ofindex.ts, so a named type import from@rulvar/plannerfailed with TS2459 and the generated API docs rendered the name as unlinked text with no interface page. Runtime behavior is unchanged. The docs build now escalates any TypeDoc referenced-but-not-included warning outside a frozen baseline of pre-existing internal helper types, so a public type missing from its barrel fails CI instead of shipping.
1.12.0
Minor Changes
- 46edcc0: Budget-safe planner APIs (v1.11 follow-up review, P2).
PlanOptions.runcarries run options for the planning conversation itself (budgetUsd,limits,deadlineAt,signal; the runId stays goal-derived and is not overridable): they apply at GENESIS, wherebudgetUsdfreezes as the planning run's immutable ceiling B0, recorded in RunMeta. A laterplan()of the same goal resumes the existing journal under its RECORDED ceiling: a differing explicitbudgetUsdemits aRULVAR_PLAN_BUDGET_DRIFTwarning and never tops up or replaces the frozen value. When the ceiling cannot fit the next draft,plan()throwsScriptRejectedwhose data carriesstatus: 'exhausted'and the typedbudget_exhaustederror, with zero over-ceiling provider calls and the planning journal intact.runPlanned(engine, goal, args, options)gainsRunPlannedOptions { plan?, run? }:planbounds (and fully parameterizes) the planning leg,runis passed toengine.runverbatim as the execution leg's own independent RunOptions. Existing calls stay source-compatible; the bare forms without options remain UNBOUNDED and are now documented as such, with the bounded form shown first in the planner and orchestration-modes guides.
Patch Changes
- Updated dependencies [46edcc0]
1.11.0
Patch Changes
- Updated dependencies [0c70c5e]
1.10.0
Patch Changes
- Updated dependencies [0e8d78e]
1.9.0
Patch Changes
- Updated dependencies [3a53383]
1.8.0
Patch Changes
- Updated dependencies [25724b5]
- Updated dependencies [57ea1de]
- Updated dependencies [7884ec5]
- Updated dependencies [52db30d]
1.7.0
Patch Changes
- Updated dependencies [45285aa]
- Updated dependencies [2f20d1d]
- Updated dependencies [22f65a8]
- Updated dependencies [2ddfa29]
- Updated dependencies [2abd9c2]
- Updated dependencies [1c1175d]
1.6.0
Patch Changes
- da4dbad: Write the product name as Rulvar in prose: package READMEs, npm descriptions, and the documentation site now capitalize the brand. Identifiers keep their exact casing, so package names, the
rulvarbinary,rulvar.config.mjs, the.rulvarstore directory, therulvar.*OTel attributes, and every URL are unchanged. Documentation and metadata only; no runtime behaviour changes. - Updated dependencies [da4dbad]
- Updated dependencies [487da86]
- Updated dependencies [df416fc]
- Updated dependencies [a737810]
- Updated dependencies [9eb66b4]
1.5.2
Patch Changes
- Updated dependencies [54936a0]
1.5.1
Patch Changes
- Updated dependencies [6c6d56f]
1.5.0
Patch Changes
- Updated dependencies [4fba3c7]
- Updated dependencies [8655c0f]
1.4.0
Patch Changes
- Updated dependencies [c4f563d]
1.3.2
Patch Changes
- ddef383: Every published package now ships a README, so its npm page states what the package is, how it installs, and where the documentation lives (npm includes README.md in the tarball regardless of the files allowlist, so no manifest changes are involved; @rulvar/compat gains its README on its own next release). Alongside, the repository-level pages are refreshed to the current project state: the root README is rewritten around the never-pay-twice pitch with a runnable quickstart condensation and the full package table, CONTRIBUTING.md lists the complete PR gate set, the examples README drops retired-spec citations for live docs.rulvar.com links and documents the dogfood journal replay, and the pointer README gets the same treatment.
- Updated dependencies [ddef383]
1.3.1
Patch Changes
- 7d1552e: Runtime message strings no longer cite the retired internal specification set: error and warning messages, validation issues, and the CLI help text drop the dangling
docs/NN, section ...references, pointing at https://docs.rulvar.com pages where a pointer earns its place (the CLI help header, tool naming, toolset registries, bare resume). The umbrella package description sheds the naming-contingency note: the unscoped alias is published and owned. Three strings embedded in frozen recordings stay byte-identical on purpose (the no-progress abort reason and two testing-internal recorder strings), as does the byte-locked golden-fold fixture. Test-file comments lose their citations too; test titles are unchanged. - Updated dependencies [7d1552e]
1.3.0
Patch Changes
- Updated dependencies [7d1a287]
1.2.0
Patch Changes
- 154507b: TSDoc and inline comments no longer cite the retired internal specification set (the pre-docs-site
docs/NN, section ...references). The citations either became links to the public documentation at docs.rulvar.com or were dropped where the comment already carried the rule; traceability markers (DEF-n, XF-nn, FR-nnn, OQ-nn, W-nnn) are untouched. Comment-only change: no runtime behavior, no API shapes, and no runtime message strings were modified; the frozen golden-fold fixture is byte-identical. - Updated dependencies [3bfaec0]
- Updated dependencies [890f42c]
- Updated dependencies [154507b]
1.1.0
Patch Changes
- Updated dependencies [d16b04a]
1.0.0
Patch Changes
- Updated dependencies [0e0b569]
- Updated dependencies [b28b7a3]
- Updated dependencies [b53a89e]
- Updated dependencies [4454175]
- Updated dependencies [6599ca8]
- Updated dependencies [6649e5f]
- Updated dependencies [fd2f83b]
- Updated dependencies [01d6b2d]
- Updated dependencies [9a20dbb]
- Updated dependencies [0fbe7ea]
- Updated dependencies [ebe0abc]
- Updated dependencies [a3079d0]
- Updated dependencies [596a39b]
- Updated dependencies [464ab6e]
0.9.0
Patch Changes
- Updated dependencies [84f94d4]
- Updated dependencies [65c7b2c]
- Updated dependencies [a2a3243]
- Updated dependencies [ebc8101]
0.8.0
Patch Changes
- Updated dependencies [85d55cf]
- Updated dependencies [b88c9e3]
- Updated dependencies [f3c4613]
- Updated dependencies [a41c20f]
- Updated dependencies [f4e70be]
- Updated dependencies [75d1646]
- Updated dependencies [0627413]
- Updated dependencies [55c0f87]
- Updated dependencies [fd33871]
- Updated dependencies [e70e7f4]
- Updated dependencies [bc9c903]
0.7.0
Minor Changes
- dc1c182: M6-T01: compileScript and the CompiledWorkflow surface.
compileScript(source, { allowImports })validates planner-generated source (syntax over the exact sandbox global set; import/require/export scanning with a literal-specifier allowlist defaulting to none) and compiles it into the coreCompiledWorkflowdata form (errorPolicy 'lenient'); any violation throws the typedScriptRejectedcarrying machine-readableScriptDiagnostic[]for the plan() self-repair loop. ExportsSANDBOX_GLOBALS(the docs/06 8.2 curated list) andscriptDiagnosticsOf. The closure Workflow and CompiledWorkflow forms stay mutually unassignable by type. - fd1d06c: M6-T02: WorkerSandboxRunner and the sandbox contract.
@rulvar/plannergainsWorkerSandboxRunner(accepts CompiledWorkflow ONLY; worker_threads with the exact curated 12-global scope; timeoutMs 300000 / memoryMb 512 breaches terminate the worker with the new typedSandboxError, codesandbox_limit). Core gains the public host half,createSandboxBridge: proxied primitives (agent, step, workflow, awaitExternal, parallel, pipeline, phase, budget) served against the canonical run ctx with worker thunks executing under host-allocated scope tokens; the worker's SYNC seeded now/random/uuid (and the Date.now/Math.random replacements) mirror-journal as ordinary kindrandentries with match-first resume semantics; a busy-state protocol keeps suspension and quiescence behavior identical to in-process runs.createEnginegainsrunners.sandbox;engine.run/engine.resumeaccept CompiledWorkflow, persist the source blob plus workflowSourceRef/workflowHash at start, andresume(runId)with no workflow rehydrates the hash-pinned source (a differing supplied source is a typed ConfigError). NewFileTranscriptStoremakes compiled runs resumable across processes. The sandbox dialect exposes asyncbudget.spent()/remaining(); import/fetch/process are absent from the worker scope. - 6fcf296: M6-T04: profileCard and the API card. Core gains
profileCard(profiles): the one agent vocabulary both orchestration modes speak, feeding the planner prompt (mode b) and spawn_agent agentType guidance (mode c) with IDENTICAL text; pure function of the registry, sorted, byte-stable, rendering only model-agnostic fields (name, description, tool names, taskClass, estCost, escalation opt-in; models are never named). The planner gainsapiCard(): the byte-stable card teaching exactly the curated 12-global sandbox dialect (schema literals only, tools by profile name, onError throw|null, async budget, no imports, the opts.key repeat rule) with usage patterns distilled from the examples corpus. - dcc97a9: M6-T05: the plan agent and the self-repair loop (mode b).
plan(engine, goal, { model?, profiles?, repairRounds? })asks a planner model under roleplanto write a script against the API card plus the engine's profile card, lints it (eslint-plugin-rulvar preset + compileScript), self-repairs up to repairRounds (default 3) from the machine-readable JSON diagnostics, and returns{ source, workflow, lint }. The planner conversation is an ordinary journaled run with a goal-derived deterministic runId, so re-planning the same goal replays the unchanged prefix free; exhausting the rounds throws a typed ScriptRejected carrying the last diagnostics.runPlanned(engine, goal, args?)composes plan-then-sandbox-run (async by amendment). Core gainsAgentOpts.role('loop' | 'plan' | 'orchestrate', the primary invocation role threading through resolution, effort defaults, floors, cost buckets, and events) and the narrowEngine.profileCard(names?)accessor rendering the registered profiles through the public API. - 10b45f1: M6-T11: the rulvar plan command and the M6 gating cassettes.
rulvar plan "<goal>" [--dry-run](the canonical grammar) loads @rulvar/planner DYNAMICALLY (the CLI's static dependency stays @rulvar/core; a missing install is a clear error), plans against the host-config engine, prints the accepted script plus its advisory diagnostics, and runs it in the worker sandbox unless --dry-run. The three docs/09 6.10 gating cassettes are recorded on the FakeAdapter and committed under the frozen-fixture lock with exported scenario builders shared by the recorder script and the replay tests: sandbox-determinism (two fresh runs of one CompiledWorkflow produce byte-identical normalized journals matching the cassette), planner-self-repair (the failing draft round-trips through the JSON-diagnostics repair, re-planning from the committed journal is free, and the accepted script executes deterministically in the sandbox), and orchestrator-crash-resume (the committed pre-crash journal plus boundary checkpoints resume with zero re-paid spawns, no duplicate spawn decisions, and byte-stable handles).
Patch Changes
- Updated dependencies [fd1d06c]
- Updated dependencies [4aaf2d5]
- Updated dependencies [6fcf296]
- Updated dependencies [dcc97a9]
- Updated dependencies [434dc83]
- Updated dependencies [03173c1]
- Updated dependencies [11c0afc]
0.6.0
Patch Changes
- Updated dependencies [fa05007]
- Updated dependencies [9234dc8]
- Updated dependencies [644512c]
- Updated dependencies [8a41656]
- Updated dependencies [02f7f7a]
0.5.0
Patch Changes
- Updated dependencies [ac274f4]
- Updated dependencies [5735d92]
- Updated dependencies [46ca98e]
- Updated dependencies [8ae129e]
- Updated dependencies [d1c4525]
- Updated dependencies [b840aba]
0.4.0
Patch Changes
- Updated dependencies [dfe03b5]
- Updated dependencies [d2089a7]
- Updated dependencies [3f60234]
- Updated dependencies [f668890]
- Updated dependencies [16d7aa6]
- Updated dependencies [6513ce8]
- Updated dependencies [7dad493]
- Updated dependencies [2bbf180]
0.3.0
Patch Changes
- Updated dependencies [43444f6]
- Updated dependencies [279881b]
- Updated dependencies [9fd0966]
- Updated dependencies [24ebadf]
- Updated dependencies [a1b35d3]
- Updated dependencies [18a5821]
0.2.0
Patch Changes
- Updated dependencies [c24228d]
- Updated dependencies [c50871e]
- Updated dependencies [1af8fb9]
- Updated dependencies [1fe0249]
- Updated dependencies [5c4fc32]
0.1.0
Minor Changes
- f4e2be9: M0 repo bootstrap (v0.1.0, docs/10-implementation-plan.md section "M0"): monorepo scaffold on the committed toolchain (pnpm 11 workspaces with catalogs, TypeScript 6.0, tsdown, Vitest 4, ESLint 9 flat config, Turborepo 2, changesets fixed mode, npm trusted publishing), the docs/ canon as single source of truth, the L0 contracts skeleton in @rulvar/core, and the vendored dependencies (StandardSchemaV1/StandardJSONSchemaV1 types, the @cfworker/json-schema lineage validator subset, a first-party monotonic ULID). Placeholder scaffolds only: no public API ships in this release.
Patch Changes
- Updated dependencies [f4e2be9]
@rulvar/rulvar
1.252.0
Patch Changes
- Updated dependencies [3ccb6cf]
- Updated dependencies [52d807f]
- Updated dependencies [517ed00]
- Updated dependencies [a7e589d]
- Updated dependencies [76e95eb]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.251.0
Patch Changes
- Updated dependencies [e7e829c]
- Updated dependencies [5982be8]
- Updated dependencies [7c58fb2]
- Updated dependencies [b3e465a]
- Updated dependencies [c4e5d6a]
- Updated dependencies [c6fc3da]
- Updated dependencies [c6fc3da]
- Updated dependencies [0ae8b85]
- Updated dependencies [7932936]
- Updated dependencies [7932936]
- Updated dependencies [88da0ed]
- Updated dependencies [06c0e85]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.250.0
Patch Changes
- Updated dependencies [0e240b9]
- Updated dependencies [6fe585e]
- Updated dependencies [c5eb19c]
- Updated dependencies [565c13b]
- Updated dependencies [c6d197b]
- Updated dependencies [c9d9729]
- Updated dependencies [fed9db6]
- Updated dependencies [df9ed76]
- Updated dependencies [3020912]
- Updated dependencies [d8d598d]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.249.0
Patch Changes
- Updated dependencies [8862133]
- Updated dependencies [0d7a717]
- Updated dependencies [e4428bd]
- Updated dependencies [d6873c1]
- Updated dependencies [4092e8d]
- Updated dependencies [e086590]
- Updated dependencies [1411938]
- Updated dependencies [737d1ee]
- Updated dependencies [634f966]
- Updated dependencies [052cc26]
- Updated dependencies [bbae134]
- Updated dependencies [67a8d72]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.248.0
Patch Changes
- Updated dependencies [8d0cd69]
- Updated dependencies [81065e4]
- Updated dependencies [8573f20]
- Updated dependencies [95f6a5e]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.247.0
Patch Changes
- Updated dependencies [1933ecc]
- Updated dependencies [db0a5f0]
- Updated dependencies [b698726]
- Updated dependencies [48348d2]
- Updated dependencies [4cfa1cc]
- Updated dependencies [4b7197a]
- Updated dependencies [5ebc842]
- Updated dependencies [16ff6b9]
- Updated dependencies [0c9941d]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.246.0
Patch Changes
- Updated dependencies [d165b0c]
- Updated dependencies [d59f4a0]
- Updated dependencies [46907ac]
- Updated dependencies [9929ad3]
- Updated dependencies [1790a6a]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.245.0
Patch Changes
- Updated dependencies [b4d47a8]
- Updated dependencies [dee6db4]
- Updated dependencies [b85c113]
- Updated dependencies [bc556e7]
- Updated dependencies [9f11d29]
- Updated dependencies [19bcea0]
- Updated dependencies [60b461c]
- Updated dependencies [61e3a1a]
- Updated dependencies [a156b81]
- Updated dependencies [0bd7045]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.244.0
Patch Changes
- Updated dependencies [38d839a]
- Updated dependencies [ce13b0f]
- Updated dependencies [4fa23e3]
- Updated dependencies [6841c69]
- Updated dependencies [f56721d]
- Updated dependencies [c894a43]
- Updated dependencies [f6944a3]
- Updated dependencies [23fd0e0]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.243.0
Patch Changes
- Updated dependencies [746d1f4]
- Updated dependencies [009b29c]
- Updated dependencies [1674cbe]
- Updated dependencies [bd096bc]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.242.0
Patch Changes
- Updated dependencies [6e3438e]
- Updated dependencies [ba5cf67]
- Updated dependencies [c2d1531]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.241.0
Patch Changes
- Updated dependencies [dbcdd24]
- Updated dependencies [7ae7243]
- Updated dependencies [4f832c4]
- Updated dependencies [7452d3d]
- Updated dependencies [a4e22bf]
- Updated dependencies [82df4af]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.240.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.239.0
Patch Changes
- Updated dependencies [74ce99a]
- Updated dependencies [ccd0665]
- Updated dependencies [0c5ce21]
- Updated dependencies [0616934]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.238.0
Patch Changes
- Updated dependencies [cf00947]
- Updated dependencies [c7b9382]
- Updated dependencies [88aea96]
- Updated dependencies [6da8d05]
- Updated dependencies [eae5c4c]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.237.0
Patch Changes
- Updated dependencies [3b987a1]
- Updated dependencies [9d6a279]
- Updated dependencies [49a98f6]
- Updated dependencies [a734ca0]
- Updated dependencies [deb406f]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.236.0
Patch Changes
- Updated dependencies [26306ea]
- Updated dependencies [709b942]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.235.0
Patch Changes
- Updated dependencies [ba4e10d]
- Updated dependencies [172402b]
- Updated dependencies [2ecd787]
- Updated dependencies [e20a5e9]
- Updated dependencies [98c8691]
- Updated dependencies [c70def0]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.234.0
Patch Changes
- Updated dependencies [8420c04]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.233.0
Patch Changes
- Updated dependencies [48b5200]
- Updated dependencies [73bc32b]
- Updated dependencies [e63b743]
- Updated dependencies [ef45da7]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.232.0
Patch Changes
- Updated dependencies [1440410]
- Updated dependencies [6e467f4]
- Updated dependencies [6a58120]
- Updated dependencies [0b14293]
- Updated dependencies [e3bcab2]
- Updated dependencies [b55a0f7]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.231.0
Patch Changes
- Updated dependencies [4eb4b56]
- Updated dependencies [bc8f09e]
- Updated dependencies [ff9b8c2]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.230.0
Patch Changes
- Updated dependencies [e9bf910]
- Updated dependencies [57bfb38]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.229.0
Patch Changes
- Updated dependencies [3370342]
- Updated dependencies [2fb6656]
- Updated dependencies [edce170]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.228.0
Patch Changes
- Updated dependencies [4034fac]
- Updated dependencies [a54b085]
- Updated dependencies [9d0a9be]
- Updated dependencies [be9ef28]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.227.0
Patch Changes
- Updated dependencies [f262e9f]
- Updated dependencies [f191ff7]
- Updated dependencies [fbbfbe8]
- Updated dependencies [263b5e8]
- Updated dependencies [db4d56d]
- Updated dependencies [41f93a9]
- Updated dependencies [98c8ca9]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.226.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.225.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.224.0
Patch Changes
- Updated dependencies [4eca1a3]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.223.0
Patch Changes
- Updated dependencies [549aabd]
- Updated dependencies [549aabd]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.222.0
Patch Changes
- Updated dependencies [8326268]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.221.0
Patch Changes
- Updated dependencies [032ce93]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.220.0
Patch Changes
- Updated dependencies [0babe70]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.219.0
Patch Changes
- Updated dependencies [65a4ce7]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.218.0
Patch Changes
- Updated dependencies [088bda6]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.217.0
Patch Changes
- Updated dependencies [ab80b97]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.216.0
Patch Changes
- Updated dependencies [b357f4a]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.215.0
Patch Changes
- Updated dependencies [e1da4c7]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.214.0
Patch Changes
- Updated dependencies [c8af0ec]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.213.0
Patch Changes
- Updated dependencies [61680df]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.212.0
Patch Changes
- Updated dependencies [e6f8516]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.211.0
Patch Changes
- Updated dependencies [d5a8a36]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.210.0
Patch Changes
- Updated dependencies [c871ddc]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.209.0
Patch Changes
- Updated dependencies [514c7bb]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.208.0
Patch Changes
- Updated dependencies [e7d426f]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.207.0
Patch Changes
- Updated dependencies [99beee2]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.206.0
Patch Changes
- Updated dependencies [ec8e1f1]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.205.0
Patch Changes
- Updated dependencies [6d224da]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.204.0
Patch Changes
- Updated dependencies [efaec9b]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.203.0
Patch Changes
- Updated dependencies [fb08c10]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.202.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.201.0
Patch Changes
- Updated dependencies [7e01189]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.200.0
Patch Changes
- Updated dependencies [e2ddbdf]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.199.0
Patch Changes
- Updated dependencies [29891c6]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.198.0
Patch Changes
- Updated dependencies [c097c96]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.197.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.196.0
Patch Changes
- Updated dependencies [ec9c3e3]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.195.0
Patch Changes
- Updated dependencies [5702a70]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.194.0
Patch Changes
- Updated dependencies [360a659]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.193.0
Patch Changes
- Updated dependencies [2bca1d1]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.192.0
Patch Changes
- Updated dependencies [8757601]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.191.0
Patch Changes
- Updated dependencies [745387c]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.190.0
Patch Changes
- Updated dependencies [8e02021]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.189.0
Patch Changes
- Updated dependencies [6a5cc2d]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.188.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.187.0
Patch Changes
- Updated dependencies [c9798ef]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.186.0
Patch Changes
- Updated dependencies [242647e]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.185.0
Patch Changes
- Updated dependencies [1248623]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.184.0
Patch Changes
- Updated dependencies [8a9caca]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.183.0
Patch Changes
- Updated dependencies [dd3767c]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.182.0
Patch Changes
- Updated dependencies [144d026]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.181.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.180.0
Patch Changes
- Updated dependencies [b124d26]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.179.0
Patch Changes
- Updated dependencies [1a5a85a]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.178.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.177.0
Patch Changes
- Updated dependencies [94db8ff]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.176.0
Patch Changes
- Updated dependencies [a74304d]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.175.0
Patch Changes
- Updated dependencies [1999c5d]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.174.0
Patch Changes
- Updated dependencies [aa9a772]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.173.0
Patch Changes
- Updated dependencies [67d27ac]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.172.0
Patch Changes
- Updated dependencies [0d4770b]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.171.0
Patch Changes
- Updated dependencies [f6116b9]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.170.0
Patch Changes
- Updated dependencies [86e4c06]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.169.0
Patch Changes
- Updated dependencies [623b2ae]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.168.0
Patch Changes
- Updated dependencies [ebba79a]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.167.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.166.0
Patch Changes
- Updated dependencies [d8262c3]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.165.0
Patch Changes
- Updated dependencies [6391274]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.164.0
Patch Changes
- Updated dependencies [9f2dda9]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.163.0
Patch Changes
- Updated dependencies [e8d9ada]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.162.0
Patch Changes
- Updated dependencies [2031e82]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.161.0
Patch Changes
- Updated dependencies [d4547b7]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.160.0
Patch Changes
- Updated dependencies [1c6f0d0]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.159.0
Patch Changes
- Updated dependencies [e881c8b]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.158.0
Patch Changes
- Updated dependencies [a266bc7]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.157.0
Patch Changes
- Updated dependencies [1883421]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.156.0
Patch Changes
- Updated dependencies [537144e]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.155.0
Patch Changes
- Updated dependencies [49b08a7]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.154.0
Patch Changes
- Updated dependencies [9259f24]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.153.0
Patch Changes
- Updated dependencies [d8bebcb]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.152.0
Patch Changes
- Updated dependencies [dd6a616]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.151.0
Patch Changes
- Updated dependencies [1de0610]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.150.0
Patch Changes
- Updated dependencies [a331211]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.149.0
Patch Changes
- Updated dependencies [08b4537]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.148.0
Patch Changes
- Updated dependencies [c85dac9]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.147.0
Patch Changes
- Updated dependencies [6367231]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.146.0
Patch Changes
- Updated dependencies [5d9bbc8]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.145.0
Patch Changes
- Updated dependencies [faf7d95]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.144.0
Patch Changes
- Updated dependencies [c11bcd6]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.143.0
Patch Changes
- Updated dependencies [f412169]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.142.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.141.0
Patch Changes
- Updated dependencies [4f12a62]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.140.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.139.0
Patch Changes
- Updated dependencies [03a2141]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.138.0
Patch Changes
- Updated dependencies [ed0c4fb]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.137.0
Patch Changes
- Updated dependencies [96f6788]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.136.0
Patch Changes
- Updated dependencies [aa6ca71]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.135.0
Patch Changes
- Updated dependencies [cf75e22]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.134.0
Patch Changes
- Updated dependencies [cb50ea0]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.133.0
Patch Changes
- Updated dependencies [2659f54]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.132.0
Patch Changes
- Updated dependencies [2bec904]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.131.0
Patch Changes
- Updated dependencies [256cae1]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.130.0
Patch Changes
- Updated dependencies [d6bec7a]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.129.0
Patch Changes
- Updated dependencies [1612439]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.128.0
Patch Changes
- Updated dependencies [27c4e38]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.127.0
Patch Changes
- Updated dependencies [b3b1805]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.126.0
Patch Changes
- Updated dependencies [e5e9526]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.125.0
Patch Changes
- Updated dependencies [109e9fa]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.124.0
Patch Changes
- Updated dependencies [37fd1f2]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.123.0
Patch Changes
- Updated dependencies [5c46468]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.122.0
Patch Changes
- Updated dependencies [8cf45c5]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.121.0
Patch Changes
- Updated dependencies [3d67d41]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.120.0
Patch Changes
- Updated dependencies [d630c9e]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.119.0
Patch Changes
- Updated dependencies [1e4ff3c]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.118.0
Patch Changes
- Updated dependencies [f8341a3]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.117.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.116.0
Patch Changes
- Updated dependencies [a213878]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.115.0
Patch Changes
- Updated dependencies [63642ae]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.114.0
Patch Changes
- Updated dependencies [5759731]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.113.0
Patch Changes
- Updated dependencies [a60807a]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.112.0
Patch Changes
- Updated dependencies [00ae55b]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.111.0
Patch Changes
- Updated dependencies [fd25169]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.110.0
Patch Changes
- Updated dependencies [58afdb5]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.109.0
Patch Changes
- Updated dependencies [85b1d39]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.108.0
Patch Changes
- Updated dependencies [affa3d4]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.107.0
Patch Changes
- Updated dependencies [9f5f6f6]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.106.0
Patch Changes
- Updated dependencies [9a4ce49]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.105.0
Patch Changes
- Updated dependencies [531dc88]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.104.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.103.0
Patch Changes
- Updated dependencies [f2b809e]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.102.0
Patch Changes
- Updated dependencies [3eb6515]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.101.0
Patch Changes
- Updated dependencies [51b215c]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.100.0
Patch Changes
- Updated dependencies [9785bea]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.99.1
Patch Changes
- Updated dependencies [ef08d73]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.99.0
Patch Changes
- Updated dependencies [9e00888]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.98.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.97.0
Patch Changes
- Updated dependencies [5c3b453]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.96.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.95.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.94.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.93.0
Patch Changes
- Updated dependencies [c62150a]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.92.0
Patch Changes
- Updated dependencies [351d1f5]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.91.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.90.0
Patch Changes
- Updated dependencies [9603940]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.89.0
Patch Changes
- Updated dependencies [f18b671]
- Updated dependencies [f18b671]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.88.0
Patch Changes
- Updated dependencies [3b339d9]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.87.0
Patch Changes
- Updated dependencies [c4c02b1]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.86.0
Patch Changes
- Updated dependencies [2f71894]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.85.0
Patch Changes
- Updated dependencies [6932a9f]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.84.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.83.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.82.0
Patch Changes
- Updated dependencies [9cc5d66]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.81.2
Patch Changes
- Updated dependencies [296885b]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.81.1
Patch Changes
- Updated dependencies [c030982]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.81.0
Patch Changes
- Updated dependencies [ce4c392]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.80.0
Patch Changes
- Updated dependencies [262e397]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.79.0
Patch Changes
- Updated dependencies [85956ab]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.78.0
Patch Changes
- Updated dependencies [941b6e1]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.77.0
Patch Changes
- Updated dependencies [6aba271]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.76.0
Patch Changes
- Updated dependencies [22cba47]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.75.1
Patch Changes
- Updated dependencies [82bc0f0]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.75.0
Patch Changes
- Updated dependencies [c486de8]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.74.0
Patch Changes
- Updated dependencies [d94beab]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.73.0
Patch Changes
- Updated dependencies [3e95bd1]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.72.0
Patch Changes
- Updated dependencies [662e9e0]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.71.0
Patch Changes
- Updated dependencies [20d02e0]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.70.1
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.70.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.69.0
Patch Changes
- Updated dependencies [b21a681]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.68.0
Patch Changes
- Updated dependencies [b227874]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.67.0
Patch Changes
- Updated dependencies [8e6006d]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.66.0
Patch Changes
- Updated dependencies [1b8987e]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.65.0
Patch Changes
- Updated dependencies [0b6b859]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.64.0
Patch Changes
- Updated dependencies [991f9b5]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.63.0
Patch Changes
- Updated dependencies [8a28aed]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.62.0
Patch Changes
- Updated dependencies [fca5fd1]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.61.0
Patch Changes
- Updated dependencies [b4c1f1f]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.60.0
Patch Changes
- Updated dependencies [59bbeaa]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.59.4
Patch Changes
- Updated dependencies [c49d7a1]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.59.3
Patch Changes
- Updated dependencies [deaef36]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.59.2
Patch Changes
- Updated dependencies [dd0e10f]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.59.1
Patch Changes
- Updated dependencies [c127770]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.59.0
Patch Changes
- Updated dependencies [615dc90]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.58.0
Patch Changes
- Updated dependencies [4fa35ce]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.57.0
Patch Changes
- Updated dependencies [5897232]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.56.0
Patch Changes
- Updated dependencies [f26dba0]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.55.0
Patch Changes
- Updated dependencies [e9b005b]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.54.0
Patch Changes
- Updated dependencies [3f6bc03]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.53.0
Patch Changes
- Updated dependencies [b821bd1]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.52.0
Patch Changes
- Updated dependencies [e138df9]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.51.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.50.0
Patch Changes
- Updated dependencies [e39a885]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.49.0
Patch Changes
- Updated dependencies [bab7b2c]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.48.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.47.0
Patch Changes
- Updated dependencies [a3687fe]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.46.0
Patch Changes
- Updated dependencies [865e7bf]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.45.0
Patch Changes
- Updated dependencies [b96305d]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.44.1
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.44.0
Patch Changes
- Updated dependencies [299f7d2]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.43.0
Patch Changes
- Updated dependencies [71b7181]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.42.0
Patch Changes
- Updated dependencies [9b70f27]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.41.0
Patch Changes
- Updated dependencies [be589ec]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.40.0
Patch Changes
- Updated dependencies [cf33550]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.39.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.38.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.37.0
Patch Changes
- Updated dependencies [e6b1481]
- Updated dependencies [e6b1481]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.36.0
Patch Changes
- Updated dependencies [101795b]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.35.0
Patch Changes
- Updated dependencies [d4ac3bf]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.34.0
Patch Changes
- Updated dependencies [f1505ec]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.33.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.32.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.31.0
Patch Changes
- Updated dependencies [df6b8f8]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.30.0
Patch Changes
- Updated dependencies [87ce985]
- Updated dependencies [87ce985]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.29.0
Patch Changes
- Updated dependencies [621d566]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.28.0
Patch Changes
- Updated dependencies [d98eb0b]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.27.0
Patch Changes
- Updated dependencies [884a433]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.26.0
Patch Changes
- Updated dependencies [a4fc757]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.25.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.24.1
Patch Changes
- Updated dependencies [0bb14db]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.24.0
Patch Changes
- Updated dependencies [2b033e8]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.23.0
Patch Changes
1f9c272: The renderers' remaining unsanitized paths and the malformed-event gaps (v1.22.0 review P2-2, P2-3).
progress(): the error text surfaced when the SOURCE fails (a rejectedRunHandle.result, a rejectedPromise<RunHandle>, a throwing iterable) went to the sink raw; a crafted rejection could inject ANSI, forge lines, and leak a key-shaped fragment. Every catch path now routes through one helper that secret-masks FIRST (the thrown value never crossed the event masking boundary) and terminal-sanitizes second; lines mode prints the notice as its own sanitized line instead of dropping it.- Malformed recognized events from a raw iterable can no longer stop a view: every dynamic field in the
progress()reducer, its lines formatter,renderProgress, and the CLIrenderEventLineis read through typed guards (a hostile object with a throwingtoStringincluded), a backstop catch skips a bad event with a bounded diagnostic carrying no untrusted data, and the stream continues. The v1.22.0 claim of full defensive reads was narrower in reality (agent:streamwithoutdeltaorphase:startwithoutphasestopped the raw-iterable view); it is true now and pinned by a table-driven test over every consumed type. posIntOptionwording: a below-minimum value CLAMPS to the minimum (only non-finite values fall back to the default); the JSDoc said "falls back" for both.@rulvar/clibuild config migrates the deprecated tsdownexternaloption todeps.neverBundle; the packed dist keeps the companion specifiers external, byte-for-same behavior.
Updated dependencies [1f9c272]
Updated dependencies [1f9c272]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.22.0
Patch Changes
- 77b554f: Harden the terminal progress renderers (v1.21.0 review). Both
progress(its lines mode and the tty state, plus thetitleoption) and the minimalrenderProgressnow pass every untrusted field through the sharedsanitizeTerminalTextsanitizer, so control characters and ANSI escape sequences in provider/tool/log strings can no longer clear the screen, recolor to forge text, or inject extra lines (P2-1).progressgeometry and timing options are normalized to finite positive integers: a non-finite or below-minimumfps,width,maxRows,sink.columns, orsink.rowsfalls back instead of breaking the clip or creating a NaN-interval timer, the width clip now holds every rendered line strictly under the terminal width for every width (including 1 to 3), and a NaN or backward clock reading renders a zero timer rather thanNaN(P3-2). The clock JSDoc is corrected toperformance.now, and every dynamic field is read defensively so a recognized event missing a required field degrades a row instead of stopping the view. - Updated dependencies [77b554f]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.21.0
Minor Changes
- 7ee42a0: New live terminal progress view:
progress(source, options)renders a claude-workflows-style tree over the WorkflowEvent stream with one row per agent (status glyph, running timer, token counts, USD), per-role sub-timings when one call spans several invocation phases, the run header with spend against the ceiling, banners for pending approvals and externals, and a final summary including the per-role dollar split fromRunOutcome.cost.byRole. Accepts aRunHandle(subscribes viaon(), leavinghandle.eventsfree), a promise of one, or a raw event iterable (the gapless resume path). TTY mode repaints in place at a bounded rate; pipes and CI degrade to append-only lines;NO_COLOR, injectable sink and clock, and stderr-only output keep it deterministic and clean. The minimalrenderProgressis unchanged.
Patch Changes
- Updated dependencies [7ee42a0]
- Updated dependencies [7ee42a0]
- Updated dependencies [7ee42a0]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.20.0
Patch Changes
- Updated dependencies [9367030]
- Updated dependencies [9367030]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.19.0
Patch Changes
- Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.18.0
Minor Changes
- 943962d:
recommendedDefaults.floorsnow admitsopenai:gpt-5.6-soland its published exact aliasopenai:gpt-5.6for theorchestrateandplanroles. The allowlists had fallen behind the product recommendation: the rulvar.com quickstart routes the orchestrator at Sol, but a configuration combining that recommendation with the recommended floors was rejected before any provider call with a quality-floor violation. The weaker family siblings Terra and Luna stay deliberately floored out of the control-plane roles; worker roles (loop,extract) remain unfloored.
Patch Changes
- Updated dependencies [943962d]
- Updated dependencies [943962d]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.17.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.16.2
Patch Changes
- Updated dependencies [9f07130]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.16.1
Patch Changes
- Updated dependencies [fac1ecc]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.16.0
Patch Changes
- Updated dependencies [5f76cf2]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.15.0
Patch Changes
- Updated dependencies [4aee1f3]
- Updated dependencies [4aee1f3]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.14.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.13.0
Patch Changes
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.12.0
Patch Changes
- Updated dependencies [46edcc0]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.11.0
Patch Changes
- Updated dependencies [0c70c5e]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.10.0
Patch Changes
- Updated dependencies [0e8d78e]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.9.0
Patch Changes
- Updated dependencies [7577f8e]
- Updated dependencies [3a53383]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.8.0
Patch Changes
- Updated dependencies [25724b5]
- Updated dependencies [57ea1de]
- Updated dependencies [7884ec5]
- Updated dependencies [52db30d]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.7.0
Patch Changes
- Updated dependencies [45285aa]
- Updated dependencies [2f20d1d]
- Updated dependencies [22f65a8]
- Updated dependencies [2ddfa29]
- Updated dependencies [2abd9c2]
- Updated dependencies [1c1175d]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.6.0
Patch Changes
- da4dbad: Write the product name as Rulvar in prose: package READMEs, npm descriptions, and the documentation site now capitalize the brand. Identifiers keep their exact casing, so package names, the
rulvarbinary,rulvar.config.mjs, the.rulvarstore directory, therulvar.*OTel attributes, and every URL are unchanged. Documentation and metadata only; no runtime behaviour changes. - Updated dependencies [da4dbad]
- Updated dependencies [487da86]
- Updated dependencies [df416fc]
- Updated dependencies [886d065]
- Updated dependencies [a737810]
- Updated dependencies [9eb66b4]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.5.2
Patch Changes
- Updated dependencies [54936a0]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.5.1
Patch Changes
- Updated dependencies [6c6d56f]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.5.0
Patch Changes
- Updated dependencies [4fba3c7]
- Updated dependencies [8655c0f]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.4.0
Patch Changes
- Updated dependencies [c4f563d]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.3.2
Patch Changes
- ddef383: Every published package now ships a README, so its npm page states what the package is, how it installs, and where the documentation lives (npm includes README.md in the tarball regardless of the files allowlist, so no manifest changes are involved; @rulvar/compat gains its README on its own next release). Alongside, the repository-level pages are refreshed to the current project state: the root README is rewritten around the never-pay-twice pitch with a runnable quickstart condensation and the full package table, CONTRIBUTING.md lists the complete PR gate set, the examples README drops retired-spec citations for live docs.rulvar.com links and documents the dogfood journal replay, and the pointer README gets the same treatment.
- Updated dependencies [ddef383]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.3.1
Patch Changes
- 7d1552e: Runtime message strings no longer cite the retired internal specification set: error and warning messages, validation issues, and the CLI help text drop the dangling
docs/NN, section ...references, pointing at https://docs.rulvar.com pages where a pointer earns its place (the CLI help header, tool naming, toolset registries, bare resume). The umbrella package description sheds the naming-contingency note: the unscoped alias is published and owned. Three strings embedded in frozen recordings stay byte-identical on purpose (the no-progress abort reason and two testing-internal recorder strings), as does the byte-locked golden-fold fixture. Test-file comments lose their citations too; test titles are unchanged. - Updated dependencies [7d1552e]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.3.0
Patch Changes
- Updated dependencies [7d1a287]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.2.0
Patch Changes
- 154507b: TSDoc and inline comments no longer cite the retired internal specification set (the pre-docs-site
docs/NN, section ...references). The citations either became links to the public documentation at docs.rulvar.com or were dropped where the comment already carried the rule; traceability markers (DEF-n, XF-nn, FR-nnn, OQ-nn, W-nnn) are untouched. Comment-only change: no runtime behavior, no API shapes, and no runtime message strings were modified; the frozen golden-fold fixture is byte-identical. - Updated dependencies [3bfaec0]
- Updated dependencies [890f42c]
- Updated dependencies [154507b]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.1.0
Patch Changes
- Updated dependencies [f2253cb]
- Updated dependencies [63b2c01]
- Updated dependencies [99dc3ed]
- Updated dependencies [d16b04a]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
1.0.0
Patch Changes
- Updated dependencies [0e0b569]
- Updated dependencies [b28b7a3]
- Updated dependencies [b53a89e]
- Updated dependencies [4454175]
- Updated dependencies [6599ca8]
- Updated dependencies [6649e5f]
- Updated dependencies [fd2f83b]
- Updated dependencies [01d6b2d]
- Updated dependencies [9a20dbb]
- Updated dependencies [0fbe7ea]
- Updated dependencies [ebe0abc]
- Updated dependencies [a3079d0]
- Updated dependencies [596a39b]
- Updated dependencies [464ab6e]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
0.9.0
Patch Changes
- Updated dependencies [84f94d4]
- Updated dependencies [65c7b2c]
- Updated dependencies [a2a3243]
- Updated dependencies [ebc8101]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
0.8.0
Patch Changes
- Updated dependencies [85d55cf]
- Updated dependencies [b88c9e3]
- Updated dependencies [f3c4613]
- Updated dependencies [a41c20f]
- Updated dependencies [f4e70be]
- Updated dependencies [75d1646]
- Updated dependencies [0627413]
- Updated dependencies [55c0f87]
- Updated dependencies [fd33871]
- Updated dependencies [e70e7f4]
- Updated dependencies [bc9c903]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
0.7.0
Patch Changes
- Updated dependencies [fd1d06c]
- Updated dependencies [6fcf296]
- Updated dependencies [dcc97a9]
- Updated dependencies [434dc83]
- Updated dependencies [03173c1]
- Updated dependencies [11c0afc]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
0.6.0
Minor Changes
fa05007: M5-T01 workflow registry and the @rulvar/cli base.
@rulvar/coregains the per-engineWorkflowRegistrytype anddefaults.workflowson createEngine (docs/06 section 10.4): an explicit first-class value, no module-level registry; shells resolve by-name runs against it (ctx.workflow's string form arrives M6, the queue worker M8).- Spec-conformance fix: the M4-T09 quality floors option moves from the createEngine top level to its canonical home
defaults.roleFloors(docs/06 section 10.1). UpdatecreateEngine({ floors })call sites tocreateEngine({ defaults: { roleFloors } }). @rulvar/cliships its first real surface: the canonical grammarrulvar run <file|name> [--args JSON] [--store PATH] [--budget-usd N],rulvar resume <runId> [--args JSON] [--store PATH],rulvar runs ls [--store PATH],rulvar inspect <runId> [--store PATH](no aliases), a line-oriented TUI progress renderer over the event stream, and interactive resolution of suspended approvals and externals (EOF leaves the run suspended, never errors). Engine assembly follows the host-config convention:rulvar.config.mjsdefault-exports{ engineOptions?, workflows? }, a workflow module may exportworkflow/engineOptions/workflows, and --store selects the JsonlFileStore directory (default.rulvar), so the CLI itself depends only on @rulvar/core. Therulvarbin is included; the resume/inspect grammar amendment (--args re-supply, --store symmetry) is recorded in docs/06 section 10.5.
Patch Changes
- Updated dependencies [fa05007]
- Updated dependencies [9234dc8]
- Updated dependencies [644512c]
- Updated dependencies [8a41656]
- Updated dependencies [02f7f7a]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
0.5.0
Minor Changes
b840aba: M4-T08 canonical effort completion and M4-T09 role quality floors.
- Effort semantics are complete: the role effort defaults and the per-adapter mapping tables (Anthropic passthrough including max, OpenAI max downmapped to xhigh and recorded in providerMetadata, provider none only via namespaced providerOptions) shipped earlier milestones; this change completes VISIBLE scrubbing everywhere it was still silent: the summarize invocation surfaces its scrubs at fire time and a failover takeover surfaces the fallback's scrubs the moment it starts serving. Scrubbed effort is never mapped into max_tokens.
- The effort-defaults-shift cassette is now RECORDED through the live runtime (docs/10 M4 gating row): the frozen v1 prefix, closed offline the way an operator would, resumes live under explicit high effort with the completed semantics; every v1 entry matches and the one new spawn carries canonical effort in v2 identity. The recorder output is pinned byte-for-byte by the frozen-drift suite and the fixture lock now covers 18 files.
- Quality floors (
model/floors.ts, M4-T09): per-role and per-declared-taskClass allow/deny lists supplied viacreateEngine({ floors }), enforced INSIDE the router at resolution, before any live call and before any journal entry, for every invocation the chain produces (primaries, failover fallbacks, and the summarize fallback alike).AgentProfile.taskClassdeclares the class; unclassified profiles see only byRole floors. A violation is a typed ConfigError. - The umbrella
rulvarpackage now ships floors opinions next to its strong routing defaults:recommendedDefaults.floorspins orchestrate and plan to strong named models. The core itself ships no named model strings, and the umbrella suite enforces that with a source scan.
Patch Changes
- Updated dependencies [ac274f4]
- Updated dependencies [5735d92]
- Updated dependencies [46ca98e]
- Updated dependencies [8ae129e]
- Updated dependencies [d1c4525]
- Updated dependencies [b840aba]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
0.4.0
Patch Changes
- Updated dependencies [dfe03b5]
- Updated dependencies [d2089a7]
- Updated dependencies [3f60234]
- Updated dependencies [f668890]
- Updated dependencies [16d7aa6]
- Updated dependencies [6513ce8]
- Updated dependencies [7dad493]
- Updated dependencies [2bbf180]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
0.3.0
Patch Changes
- Updated dependencies [43444f6]
- Updated dependencies [279881b]
- Updated dependencies [9fd0966]
- Updated dependencies [24ebadf]
- Updated dependencies [a1b35d3]
- Updated dependencies [18a5821]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
0.2.0
Minor Changes
- c24228d: M1-T10/T11: the WorkflowEvent envelope and M1 catalog (per-run telemetry seq distinct from JournalEntry.seq, span hierarchy run > phase > agent), the per-run EventBus feeding RunHandle.events and on(), RunOutcome with exhausted-overrides-error precedence and the normative CostReport (byModel/byPhase/byAgentType/byRole, the all-zero orchestrator block, unpriced evidence); createEngine with per-engine registries and engine.run over the ScriptRunner seam; InProcessRunner with the dev-mode bare-Date.now/Math.random warnings; run cancellation (host signal, handle.cancel, run deadline) and RunMeta run-to-definition binding fields. The umbrella ships the minimal terminal progress renderer (renderProgress) and re-exports the core surface.
- 5c4fc32: M1-T14/T15: @rulvar/testing tier 1 (FakeAdapter matching on agentType/label/prompt regex with a '*' fallback, honoring the selected structured-output tier, zero USD by construction; createTestEngine over the full real engine with recorded event streams; toHaveCalledAgent and toStayUnderBudget matchers at '@rulvar/testing/matchers') and the completed umbrella (re-exports of @rulvar/core and both first-class adapters, renderProgress, the umbrella-only recommendedDefaults strong model slots, the M1 exit-criteria example workflow, and the CI install smoke on packed tarballs). The core now populates the reserved providerOptions 'rulvar' telemetry namespace on every request (docs/04 section 1.8 as amended) and AgentResult carries errorMessage detail for journaled WireError fidelity.
Patch Changes
- Updated dependencies [527c9b4]
- Updated dependencies [c24228d]
- Updated dependencies [c50871e]
- Updated dependencies [1af8fb9]
- Updated dependencies [1fe0249]
- Updated dependencies [5c4fc32]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
0.1.0
Minor Changes
- f4e2be9: M0 repo bootstrap (v0.1.0, docs/10-implementation-plan.md section "M0"): monorepo scaffold on the committed toolchain (pnpm 11 workspaces with catalogs, TypeScript 6.0, tsdown, Vitest 4, ESLint 9 flat config, Turborepo 2, changesets fixed mode, npm trusted publishing), the docs/ canon as single source of truth, the L0 contracts skeleton in @rulvar/core, and the vendored dependencies (StandardSchemaV1/StandardJSONSchemaV1 types, the @cfworker/json-schema lineage validator subset, a first-party monotonic ULID). Placeholder scaffolds only: no public API ships in this release.
Patch Changes
- Updated dependencies [f4e2be9]
- @rulvar/[email protected]
- @rulvar/[email protected]
- @rulvar/[email protected]
@rulvar/store-conformance
1.252.0
Patch Changes
- Updated dependencies [3ccb6cf]
- Updated dependencies [52d807f]
- Updated dependencies [517ed00]
- Updated dependencies [a7e589d]
- Updated dependencies [76e95eb]
- @rulvar/[email protected]
1.251.0
Patch Changes
- Updated dependencies [e7e829c]
- Updated dependencies [5982be8]
- Updated dependencies [7c58fb2]
- Updated dependencies [b3e465a]
- Updated dependencies [c4e5d6a]
- Updated dependencies [c6fc3da]
- Updated dependencies [c6fc3da]
- Updated dependencies [0ae8b85]
- Updated dependencies [7932936]
- Updated dependencies [7932936]
- Updated dependencies [88da0ed]
- Updated dependencies [06c0e85]
- @rulvar/[email protected]
1.250.0
Minor Changes
- c5eb19c: The restoration generation (RV4503, plan 45, rfcs/effects.md section 4.5, item 3): SqliteStore and PostgresStore implement the
EffectLaneStorecapability, carrying a restoration generation OUTSIDE the journal bytes (a one-row table beside the leases). The restore runbook is one rule: after a point-in-time restore, callbumpRestorationGeneration()BEFORE the restored database becomes reachable to any worker, so the effect lane comes up with dispatch disabled by construction until an operator appends a fresheffect_epochciting the bumped generation. The neweffectLaneStoreConformancesuite in @rulvar/store-conformance is the executable definition: generation starts at 0 and bumps monotonically (ELS1, ELS2), a bumped generation refuses every lane append until the fresh epoch (ELS3, the kill point 25 window, driven through the real writer over the real store), and a lane append under a non-current lease dies on the store's fence with nothing consumed (ELS4, the kill point 16 shape). - c6d197b: The reconciler, the trust envelope, and the whole kill point kit (RV4505, plan 45, rfcs/effects.md sections 3.1, 7, 8, 9). The sweep makes "every intent deterministically reaches confirmed, compensated, or quarantined" true: crossing
reconcileByquarantines whatever state with the state recorded, receipt waits and attempt budgets quarantine on exhaustion, lookups are bounded SEPARATELY through journaledeffect_proberows (countable from the journal alone, crash-proof), pre-terminal conflicting receipts quarantine, and effect authorizations past their deadline refuse durably instead of waiting forever. Receipt verification runs a declared trust envelope: issuer identity, per-class content bindings, key validity windows, revocation from its time forward, and the host's signature check; every failure classifies unverified, which routes to unknown. The post-restore reconciliation (kill 25) quarantines provider effects the journal cannot reconstruct by name (or the whole range without authoritative enumeration), and a restoration epoch stays undispatchable until the neweffect_reconciliation_completedecision cites it. Section 9 telemetry folds effective dispositions (the compensated overlay included), pressure, duplicate classification, and open incidents. The kit exports all thirtyeffects.kill.*rows as named conformance checks parameterized by a store factory (ambiguous acks and restoration generations injected through delegating proxies, so any store qualifies), registered over the in-memory reference store in single-process posture and over the REAL sqlite and postgres stores in their own packages. - df9ed76: The admission conformance matrix, all twelve rows (RV4509, plan 45, rfcs/admission.md section 7):
admissionConformanceruns the RFC's named acceptance surface over any scheduler factory, registered over the in-memory reference (snapshot/hydrate plays the crash reopen), the sqlite document, and the postgres document. The fairness rows measure GRANTED RAW SERVICE, the property itself: sixty equal tenants each receive their exact share with every consecutive sixty-grant window containing every tenant, and weights 1/2/4 grant exactly 1:2:4 in the first virtual-time cycle with weight 1 never starving (the tenant plugs that assemble the queue first carry weight equal to their cost, a uniform one-unit tag shift that preserves the burst's relative order bit for bit). The remaining rows: the minute-boundary burst bound, queued-ticket crash survival with arrival identity intact, the conservative fenced-cover expiry settlement with late debt, the denied-versus-queued state distinction, region loss without double grants, hundred-percent repair amplification held inside caps through debt, fail-closed foreign scope, multi-level all-or-nothing, the atomic failover rebind (newrebindon the SPI: the target slot acquires before the source releases, and a failed transfer changes nothing), and tenant resolution parity. The reference pump's scan is now bucket-blocking: a refused ticket blocks ITS bucket for the pass, so no later ticket of the same bucket overtakes it (the no-starvation guarantee), while independent buckets proceed;releaseno longer grants implicitly, making every grant an observablepumpevent.
Patch Changes
- Updated dependencies [0e240b9]
- Updated dependencies [6fe585e]
- Updated dependencies [c5eb19c]
- Updated dependencies [565c13b]
- Updated dependencies [c6d197b]
- Updated dependencies [c9d9729]
- Updated dependencies [fed9db6]
- Updated dependencies [df9ed76]
- Updated dependencies [3020912]
- Updated dependencies [d8d598d]
- @rulvar/[email protected]
1.249.0
Patch Changes
- Updated dependencies [8862133]
- Updated dependencies [0d7a717]
- Updated dependencies [e4428bd]
- Updated dependencies [d6873c1]
- Updated dependencies [4092e8d]
- Updated dependencies [e086590]
- Updated dependencies [1411938]
- Updated dependencies [737d1ee]
- Updated dependencies [634f966]
- Updated dependencies [052cc26]
- Updated dependencies [bbae134]
- @rulvar/[email protected]
1.248.0
Minor Changes
- 95f6a5e: The scope identity gains a declarative value normalization table, and the journal is its authority (RV4302, plan 43).
scopePolicy.normalizeis a versioned table over a closed vocabulary (trim,lowercase,nfc, applied per dimension in declared order), deliberately data and not a callback: a host function is not replay stable, not journalable, and free to read locale or time. The table applies innormalizeExecutionScopestrictly AFTER the existing input validation, the result re-validates by the same rule (an all-whitespace value that trims to empty refuses typed instead of recording an identity that asserts nothing), and the canonical values exist BEFORE any digest does, so' EU-West 'and'eu-west'stop splitting one tenant's quota buckets and FinOps joins across two identities. The table is journaled in the genesisexecution_scopedecision beside the scope and digest it shaped, mirrored inRunMeta.scopeNormalize(stores must round-trip it; the conformance kit checks), and on resume the RECORDED table is what normalizes the supplied scope before any comparison, so a host that re-supplies the raw values it started with asserts true; a conflicting re-supplied table refuses typed (the args-binding rule), and a table supplied over a run that recorded none warns and is never applied.compileRegulatedProfilepreserves a declared table under its pinnedunknown: 'reject'and hashes it into the posture, so two compiles over the same canonical values with different declared tables carry different profileHashes; absence keeps every undeclared config byte for byte, hash included. Beside the code,rfcs/admission.mdrecords the accepted design for the durable fairness and admission SPI (P1.4): the split from the live-onlyQuotaLimiter, hierarchical buckets over the resolved effective tenant, start time fair queuing with reserved wires as the one scheduler unit, conditional-create tickets with lease-fenced consumption covers, and the conformance matrix, hardened by adversarial review to the final verdict closed.
Patch Changes
- Updated dependencies [8d0cd69]
- Updated dependencies [81065e4]
- Updated dependencies [8573f20]
- Updated dependencies [95f6a5e]
- @rulvar/[email protected]
1.247.0
Patch Changes
- Updated dependencies [1933ecc]
- Updated dependencies [db0a5f0]
- Updated dependencies [b698726]
- Updated dependencies [48348d2]
- Updated dependencies [4cfa1cc]
- Updated dependencies [4b7197a]
- Updated dependencies [5ebc842]
- Updated dependencies [16ff6b9]
- Updated dependencies [0c9941d]
- @rulvar/[email protected]
1.246.0
Patch Changes
- Updated dependencies [d165b0c]
- Updated dependencies [d59f4a0]
- Updated dependencies [46907ac]
- Updated dependencies [9929ad3]
- Updated dependencies [1790a6a]
- @rulvar/[email protected]
1.245.0
Minor Changes
- 60b461c: The bounded execution scope (RV4007, the fifth comparison experiment's P0.4). Who a run executes for, as the host names it, carried WITHOUT LOSS and never interpreted:
RunOptions.scope({ tenant?, account?, project? }, own properties, non-empty strings, at least one field, copied at intake so later mutation moves nothing) records at genesis into RunMeta and a journaledexecution_scopedecision, is immutable for the run's life (no resume door), rides the invoice header asexecutionScope(a pure fold from the entries, so a FinOps pipeline reads the owner off the money document), travels in the export bundle via its meta, andResumeOptions.scopeasserts it back (mismatch refuses typed before ownership; a supplied scope over a run that recorded none warns). On the provider side,ProviderAdapter.scopeKeynames the ACCOUNT within a family: the retention transport then keys provider-raw blocks by(family, scopeKey)instead of family alone, so cache handles and thinking blocks minted under one account never ride a request served by another; undeclared adapters keep the family-wide sharing byte for byte, and routing, pricing, and quota keys are untouched. The store conformance kit pins the RunMeta round-trip; probes pin the genesis decision and the retention separation. Attribution envelope, not IAM: tenancy semantics stay host decisions.
Patch Changes
- Updated dependencies [b4d47a8]
- Updated dependencies [dee6db4]
- Updated dependencies [b85c113]
- Updated dependencies [bc556e7]
- Updated dependencies [9f11d29]
- Updated dependencies [19bcea0]
- Updated dependencies [60b461c]
- Updated dependencies [61e3a1a]
- Updated dependencies [a156b81]
- Updated dependencies [0bd7045]
- @rulvar/[email protected]
1.244.0
Minor Changes
- 38d839a:
RunOptions.budgetPolicy: 'segment' | 'immutable-lifetime'(RV3902, the fourth comparison experiment): the regulated posture the docs used to promise by accident is now a real, opt-in invariant. Default'segment'is today's behavior byte for byte. Under'immutable-lifetime'the posture is recorded inRunMetaat genesis (only the non-default is written; the store conformance kit holds stores to the round-trip) and restored on every resume, and a resume carrying ANY applyingResumeOptions.runoverride refuses with a typedConfigErrorbefore ownership, meta writes, or any append, raising and lowering alike; the emptyrun: {}object stays the documented no-op, a bare resume stays a pure replay, and a store that drops the field degrades to'segment'(the door works again), never to an invented refusal. The fault kit gains thebudget-policy-immutablescenario (typed refusal, zero wires, zero durable mutations, bare replay intact); two mutation probes pin the refusal gate and the genesis recording. The source TSDoc sweep retires the lastimmutable after startcomments (engine, budget, termination, orchestrate, plan), and the docs doctrine pins now scandocs/apitoo.
Patch Changes
- Updated dependencies [38d839a]
- Updated dependencies [ce13b0f]
- Updated dependencies [4fa23e3]
- Updated dependencies [6841c69]
- Updated dependencies [f56721d]
- Updated dependencies [c894a43]
- Updated dependencies [f6944a3]
- Updated dependencies [23fd0e0]
- @rulvar/[email protected]
1.243.0
Patch Changes
- Updated dependencies [746d1f4]
- Updated dependencies [009b29c]
- Updated dependencies [1674cbe]
- Updated dependencies [bd096bc]
- @rulvar/[email protected]
1.242.0
Patch Changes
- Updated dependencies [6e3438e]
- Updated dependencies [ba5cf67]
- Updated dependencies [c2d1531]
- @rulvar/[email protected]
1.241.0
Patch Changes
- Updated dependencies [dbcdd24]
- Updated dependencies [7ae7243]
- Updated dependencies [4f832c4]
- Updated dependencies [7452d3d]
- Updated dependencies [a4e22bf]
- Updated dependencies [82df4af]
- @rulvar/[email protected]
1.240.0
Patch Changes
- @rulvar/[email protected]
1.239.0
Patch Changes
- Updated dependencies [74ce99a]
- Updated dependencies [ccd0665]
- Updated dependencies [0c5ce21]
- Updated dependencies [0616934]
- @rulvar/[email protected]
1.238.0
Patch Changes
- Updated dependencies [cf00947]
- Updated dependencies [c7b9382]
- Updated dependencies [88aea96]
- Updated dependencies [6da8d05]
- Updated dependencies [eae5c4c]
- @rulvar/[email protected]
1.237.0
Patch Changes
- Updated dependencies [9d6a279]
- Updated dependencies [49a98f6]
- Updated dependencies [a734ca0]
- Updated dependencies [deb406f]
- @rulvar/[email protected]
1.236.0
Patch Changes
- Updated dependencies [26306ea]
- Updated dependencies [709b942]
- @rulvar/[email protected]
1.235.0
Patch Changes
- Updated dependencies [ba4e10d]
- Updated dependencies [172402b]
- Updated dependencies [2ecd787]
- Updated dependencies [e20a5e9]
- Updated dependencies [98c8691]
- Updated dependencies [c70def0]
- @rulvar/[email protected]
1.234.0
Patch Changes
- Updated dependencies [8420c04]
- @rulvar/[email protected]
1.233.0
Patch Changes
- Updated dependencies [48b5200]
- Updated dependencies [73bc32b]
- Updated dependencies [e63b743]
- Updated dependencies [ef45da7]
- @rulvar/[email protected]
1.232.0
Patch Changes
- Updated dependencies [1440410]
- Updated dependencies [6e467f4]
- Updated dependencies [0b14293]
- Updated dependencies [e3bcab2]
- Updated dependencies [b55a0f7]
- @rulvar/[email protected]
1.231.0
Patch Changes
- Updated dependencies [4eb4b56]
- Updated dependencies [bc8f09e]
- Updated dependencies [ff9b8c2]
- @rulvar/[email protected]
1.230.0
Patch Changes
- Updated dependencies [e9bf910]
- Updated dependencies [57bfb38]
- @rulvar/[email protected]
1.229.0
Patch Changes
- Updated dependencies [3370342]
- Updated dependencies [2fb6656]
- Updated dependencies [edce170]
- @rulvar/[email protected]
1.228.0
Patch Changes
- Updated dependencies [4034fac]
- Updated dependencies [a54b085]
- Updated dependencies [9d0a9be]
- Updated dependencies [be9ef28]
- @rulvar/[email protected]
1.227.0
Patch Changes
- Updated dependencies [f262e9f]
- Updated dependencies [f191ff7]
- Updated dependencies [fbbfbe8]
- Updated dependencies [263b5e8]
- Updated dependencies [db4d56d]
- Updated dependencies [41f93a9]
- Updated dependencies [98c8ca9]
- @rulvar/[email protected]
1.226.0
Patch Changes
- @rulvar/[email protected]
1.225.0
Patch Changes
- @rulvar/[email protected]
1.224.0
Patch Changes
- Updated dependencies [4eca1a3]
- @rulvar/[email protected]
1.223.0
Patch Changes
- Updated dependencies [549aabd]
- Updated dependencies [549aabd]
- @rulvar/[email protected]
1.222.0
Patch Changes
- Updated dependencies [8326268]
- @rulvar/[email protected]
1.221.0
Patch Changes
- Updated dependencies [032ce93]
- @rulvar/[email protected]
1.220.0
Patch Changes
- Updated dependencies [0babe70]
- @rulvar/[email protected]
1.219.0
Patch Changes
- Updated dependencies [65a4ce7]
- @rulvar/[email protected]
1.218.0
Patch Changes
- Updated dependencies [088bda6]
- @rulvar/[email protected]
1.217.0
Patch Changes
- Updated dependencies [ab80b97]
- @rulvar/[email protected]
1.216.0
Patch Changes
- Updated dependencies [b357f4a]
- @rulvar/[email protected]
1.215.0
Patch Changes
- Updated dependencies [e1da4c7]
- @rulvar/[email protected]
1.214.0
Patch Changes
- Updated dependencies [c8af0ec]
- @rulvar/[email protected]
1.213.0
Patch Changes
- Updated dependencies [61680df]
- @rulvar/[email protected]
1.212.0
Patch Changes
- Updated dependencies [e6f8516]
- @rulvar/[email protected]
1.211.0
Patch Changes
- Updated dependencies [d5a8a36]
- @rulvar/[email protected]
1.210.0
Patch Changes
- Updated dependencies [c871ddc]
- @rulvar/[email protected]
1.209.0
Patch Changes
- Updated dependencies [514c7bb]
- @rulvar/[email protected]
1.208.0
Patch Changes
- Updated dependencies [e7d426f]
- @rulvar/[email protected]
1.207.0
Patch Changes
- Updated dependencies [99beee2]
- @rulvar/[email protected]
1.206.0
Patch Changes
- Updated dependencies [ec8e1f1]
- @rulvar/[email protected]
1.205.0
Patch Changes
- Updated dependencies [6d224da]
- @rulvar/[email protected]
1.204.0
Patch Changes
- Updated dependencies [efaec9b]
- @rulvar/[email protected]
1.203.0
Patch Changes
- Updated dependencies [fb08c10]
- @rulvar/[email protected]
1.202.0
Patch Changes
- @rulvar/[email protected]
1.201.0
Patch Changes
- Updated dependencies [7e01189]
- @rulvar/[email protected]
1.200.0
Patch Changes
- Updated dependencies [e2ddbdf]
- @rulvar/[email protected]
1.199.0
Patch Changes
- Updated dependencies [29891c6]
- @rulvar/[email protected]
1.198.0
Patch Changes
- Updated dependencies [c097c96]
- @rulvar/[email protected]
1.197.0
Patch Changes
- @rulvar/[email protected]
1.196.0
Patch Changes
- Updated dependencies [ec9c3e3]
- @rulvar/[email protected]
1.195.0
Patch Changes
- Updated dependencies [5702a70]
- @rulvar/[email protected]
1.194.0
Patch Changes
- Updated dependencies [360a659]
- @rulvar/[email protected]
1.193.0
Patch Changes
- Updated dependencies [2bca1d1]
- @rulvar/[email protected]
1.192.0
Patch Changes
- Updated dependencies [8757601]
- @rulvar/[email protected]
1.191.0
Patch Changes
- Updated dependencies [745387c]
- @rulvar/[email protected]
1.190.0
Patch Changes
- Updated dependencies [8e02021]
- @rulvar/[email protected]
1.189.0
Patch Changes
- Updated dependencies [6a5cc2d]
- @rulvar/[email protected]
1.188.0
Patch Changes
- @rulvar/[email protected]
1.187.0
Patch Changes
- Updated dependencies [c9798ef]
- @rulvar/[email protected]
1.186.0
Patch Changes
- Updated dependencies [242647e]
- @rulvar/[email protected]
1.185.0
Patch Changes
- Updated dependencies [1248623]
- @rulvar/[email protected]
1.184.0
Patch Changes
- Updated dependencies [8a9caca]
- @rulvar/[email protected]
1.183.0
Patch Changes
- Updated dependencies [dd3767c]
- @rulvar/[email protected]
1.182.0
Patch Changes
- Updated dependencies [144d026]
- @rulvar/[email protected]
1.181.0
Patch Changes
- @rulvar/[email protected]
1.180.0
Patch Changes
- Updated dependencies [b124d26]
- @rulvar/[email protected]
1.179.0
Patch Changes
- Updated dependencies [1a5a85a]
- @rulvar/[email protected]
1.178.0
Patch Changes
- @rulvar/[email protected]
1.177.0
Patch Changes
- Updated dependencies [94db8ff]
- @rulvar/[email protected]
1.176.0
Patch Changes
- Updated dependencies [a74304d]
- @rulvar/[email protected]
1.175.0
Patch Changes
- Updated dependencies [1999c5d]
- @rulvar/[email protected]
1.174.0
Patch Changes
- Updated dependencies [aa9a772]
- @rulvar/[email protected]
1.173.0
Patch Changes
- Updated dependencies [67d27ac]
- @rulvar/[email protected]
1.172.0
Patch Changes
- Updated dependencies [0d4770b]
- @rulvar/[email protected]
1.171.0
Patch Changes
- Updated dependencies [f6116b9]
- @rulvar/[email protected]
1.170.0
Patch Changes
- Updated dependencies [86e4c06]
- @rulvar/[email protected]
1.169.0
Patch Changes
- Updated dependencies [623b2ae]
- @rulvar/[email protected]
1.168.0
Patch Changes
- Updated dependencies [ebba79a]
- @rulvar/[email protected]
1.167.0
Patch Changes
- @rulvar/[email protected]
1.166.0
Patch Changes
- Updated dependencies [d8262c3]
- @rulvar/[email protected]
1.165.0
Patch Changes
- Updated dependencies [6391274]
- @rulvar/[email protected]
1.164.0
Patch Changes
- Updated dependencies [9f2dda9]
- @rulvar/[email protected]
1.163.0
Patch Changes
- Updated dependencies [e8d9ada]
- @rulvar/[email protected]
1.162.0
Patch Changes
- Updated dependencies [2031e82]
- @rulvar/[email protected]
1.161.0
Minor Changes
d4547b7: Refuse unpriced, malformed, and stale-priced dispatches before the wire under the opt-in strict pricing gate (RV1508). The fourth PR of the eighteenth plan.
Dollars come from the price table, and a model absent from it debits NOTHING, so every USD ceiling silently fails to bound it; the docs called that hole honest, and the seventeenth comparison benchmark asked for a mode that closes it.
RunOptions.strictPricingarms the gate: every paid dispatch must resolve a well-formed price row for its serving model BEFORE the wire call, at the same dispatch chokepoint the exposure admission holds, or the dispatch refuses with a typedConfigErrornaming the model and the defect (no row, a non-finite or negative rate, a malformed long-context tier).maxRatesAgeDaysadditionally demands a freshratesVerifiedAton the row, binding only when declared;allowUnpricedlists the exact model refs the host KNOWS are free, the one explicit exception. Each model vets once per run, since the price table is fixed for the run's life.The posture follows the exposure cap's durability rule (RV1504): canonicalized and recorded in
RunMetaat genesis, restored by every resume with noResumeOptionsoverride, absence stays absent, and the store conformance kit holds stores to the round-trip, because a FinOps gate a resumed segment silently drops is not a gate.
Patch Changes
- Updated dependencies [d4547b7]
- @rulvar/[email protected]
1.160.0
Patch Changes
- Updated dependencies [1c6f0d0]
- @rulvar/[email protected]
1.159.0
Minor Changes
e881c8b: Record the in-flight exposure cap in RunMeta and restore it on every resume, and fold each budget account's settled spend for audits (RV1504, RV1505 first half). The second PR of the eighteenth plan.
The durable exposure cap (RV1504).
RunOptions.maxInFlightExposureUsdwas operational and per-invocation, so a resumed segment silently ran WITHOUT the exposure bound the original invocation declared, the seventeenth comparison benchmark's top FinOps gap. The cap now follows the ceiling's exact rule: recorded inRunMetaat genesis, restored by every resume, noResumeOptionsfield to override it, absence stays absent (a run started uncapped stays uncapped, a pre-field journal resumes exactly as before), and the store conformance kit holds stores to the round-trip. One honest asymmetry is documented rather than papered over:limitsstay per-invocation, so a resumed segment that does not re-supply them prices turn estimates from the model's full output allowance, and a tight restored cap then refuses dispatches the original clamped estimates admitted; that direction is fail closed, never silent uncapping.The per-account audit fold (RV1505, the audit half).
accountSpendFromJournal, exported from@rulvar/core, folds the same settled entries the cost report folds into each budget account's INCLUSIVE spend, with the account tree read from the journaled spawn-admission decisions, so a host can hold any orchestrator cap or child allowance against what its subtree actually spent on a plain stored journal. Abandoned subtrees and unpriced slices contribute zero, exactly like the net total. Seeding the fold into re-opened accounts on resume is deliberately NOT wired yet: a rerun of a journaled invocation re-admits with exact-fill arithmetic today, so spend-at-reopen would refuse the continuation of the very work the money was spent on; the reopen seeding lands together with a seed-aware rerun re-admission, and the docs name the remaining amnesia instead of hiding it.
Patch Changes
- Updated dependencies [e881c8b]
- @rulvar/[email protected]
1.158.0
Patch Changes
- Updated dependencies [a266bc7]
- @rulvar/[email protected]
1.157.0
Patch Changes
- Updated dependencies [1883421]
- @rulvar/[email protected]
1.156.0
Patch Changes
- Updated dependencies [537144e]
- @rulvar/[email protected]
1.155.0
Patch Changes
- Updated dependencies [49b08a7]
- @rulvar/[email protected]
1.154.0
Patch Changes
- Updated dependencies [9259f24]
- @rulvar/[email protected]
1.153.0
Patch Changes
- Updated dependencies [d8bebcb]
- @rulvar/[email protected]
1.152.0
Patch Changes
- Updated dependencies [dd6a616]
- @rulvar/[email protected]
1.151.0
Patch Changes
- Updated dependencies [1de0610]
- @rulvar/[email protected]
1.150.0
Patch Changes
- Updated dependencies [a331211]
- @rulvar/[email protected]
1.149.0
Patch Changes
- Updated dependencies [08b4537]
- @rulvar/[email protected]
1.148.0
Patch Changes
- Updated dependencies [c85dac9]
- @rulvar/[email protected]
1.147.0
Patch Changes
- Updated dependencies [6367231]
- @rulvar/[email protected]
1.146.0
Patch Changes
- Updated dependencies [5d9bbc8]
- @rulvar/[email protected]
1.145.0
Patch Changes
- @rulvar/[email protected]
1.144.0
Patch Changes
- Updated dependencies [c11bcd6]
- @rulvar/[email protected]
1.143.0
Patch Changes
- Updated dependencies [f412169]
- @rulvar/[email protected]
1.142.0
Patch Changes
- @rulvar/[email protected]
1.141.0
Patch Changes
- Updated dependencies [4f12a62]
- @rulvar/[email protected]
1.140.0
Patch Changes
- @rulvar/[email protected]
1.139.0
Patch Changes
- Updated dependencies [03a2141]
- @rulvar/[email protected]
1.138.0
Patch Changes
- Updated dependencies [ed0c4fb]
- @rulvar/[email protected]
1.137.0
Patch Changes
- Updated dependencies [96f6788]
- @rulvar/[email protected]
1.136.0
Patch Changes
- Updated dependencies [aa6ca71]
- @rulvar/[email protected]
1.135.0
Patch Changes
- Updated dependencies [cf75e22]
- @rulvar/[email protected]
1.134.0
Patch Changes
- @rulvar/[email protected]
1.133.0
Patch Changes
- @rulvar/[email protected]
1.132.0
Patch Changes
- Updated dependencies [2bec904]
- @rulvar/[email protected]
1.131.0
Patch Changes
- Updated dependencies [256cae1]
- @rulvar/[email protected]
1.130.0
Patch Changes
- Updated dependencies [d6bec7a]
- @rulvar/[email protected]
1.129.0
Patch Changes
- Updated dependencies [1612439]
- @rulvar/[email protected]
1.128.0
Patch Changes
- Updated dependencies [27c4e38]
- @rulvar/[email protected]
1.127.0
Patch Changes
- Updated dependencies [b3b1805]
- @rulvar/[email protected]
1.126.0
Patch Changes
- @rulvar/[email protected]
1.125.0
Patch Changes
- @rulvar/[email protected]
1.124.0
Patch Changes
- Updated dependencies [37fd1f2]
- @rulvar/[email protected]
1.123.0
Patch Changes
- Updated dependencies [5c46468]
- @rulvar/[email protected]
1.122.0
Patch Changes
- Updated dependencies [8cf45c5]
- @rulvar/[email protected]
1.121.0
Patch Changes
- Updated dependencies [3d67d41]
- @rulvar/[email protected]
1.120.0
Patch Changes
- Updated dependencies [d630c9e]
- @rulvar/[email protected]
1.119.0
Patch Changes
- Updated dependencies [1e4ff3c]
- @rulvar/[email protected]
1.118.0
Patch Changes
- Updated dependencies [f8341a3]
- @rulvar/[email protected]
1.117.0
Patch Changes
- @rulvar/[email protected]
1.116.0
Patch Changes
- Updated dependencies [a213878]
- @rulvar/[email protected]
1.115.0
Patch Changes
- Updated dependencies [63642ae]
- @rulvar/[email protected]
1.114.0
Patch Changes
- Updated dependencies [5759731]
- @rulvar/[email protected]
1.113.0
Patch Changes
- Updated dependencies [a60807a]
- @rulvar/[email protected]
1.112.0
Minor Changes
- 00ae55b: Duplicate quota rules are refused at construction in every reference limiter (RV704).
snapshotQuotaRules, the shared construction chokepoint ofmemoryQuotaLimiter,SqliteQuotaLimiter, andPostgresQuotaLimiter, now throws a typedConfigErrornaming both indexes and the canonicalquotaRuleKeywhen a rule set contains two identical rules. Before the refusal, the same duplicated configuration admitted differently per storage: the memory reference buckets by rule index, so each copy counted independently and the full cap admitted, while the store references bucket by rule key, so one shared bucket was debited once per matching copy and half the cap admitted (a cap-4 set granted 4 in memory and 2 on sqlite), breaking storage parity with a configuration nothing had refused.@rulvar/store-conformancegainsquotaRulesConformance, the executable construction contract any limiter implementation can register.
Patch Changes
- Updated dependencies [00ae55b]
- @rulvar/[email protected]
1.111.0
Patch Changes
- Updated dependencies [fd25169]
- @rulvar/[email protected]
1.110.0
Patch Changes
- Updated dependencies [58afdb5]
- @rulvar/[email protected]
1.109.0
Patch Changes
- Updated dependencies [85b1d39]
- @rulvar/[email protected]
1.108.0
Patch Changes
- Updated dependencies [affa3d4]
- @rulvar/[email protected]
1.107.0
Patch Changes
- Updated dependencies [9f5f6f6]
- @rulvar/[email protected]
1.106.0
Patch Changes
- Updated dependencies [9a4ce49]
- @rulvar/[email protected]
1.105.0
Patch Changes
- Updated dependencies [531dc88]
- @rulvar/[email protected]
1.104.0
Patch Changes
- @rulvar/[email protected]
1.103.0
Patch Changes
- Updated dependencies [f2b809e]
- @rulvar/[email protected]
1.102.0
Patch Changes
- Updated dependencies [3eb6515]
- @rulvar/[email protected]
1.101.0
Patch Changes
- Updated dependencies [51b215c]
- @rulvar/[email protected]
1.100.0
Patch Changes
- Updated dependencies [9785bea]
- @rulvar/[email protected]
1.99.1
Patch Changes
- ef08d73: Guarantee matrix and exactly-once claim hygiene (RV508); no runtime behavior changes. The isolated-executor guide now carries the guarantee matrix stating flatly who provides what: the library's layers give at-least-once execution with attempt binding and intent-before-effect, exactly-once effect execution is promised by NO library layer, and what IS exactly-once is pay and replay (the never-pay-twice invariant). The two claims the ninth comparison experiment's judge caught are rewritten to the precise statements ("each ran once" became attempt counting under a stable idempotency key; the approvals guide now says continuation is a run-level guarantee, not an effect-level one, with the at-least-once window named);
ctx.stepdocs state the same window for effectful steps; aResolutionBynote says the field records a channel, never a verified principal (identity, signatures, and separation of duties are host IAM). The worker header now points at the shippedSqliteQuotaLimiterandPostgresQuotaLimiterinstead of denying that cross-process limiters exist. A new docs-lint sentinel forbids "exactly once" claims in the hand-written docs and in package source comments outside a vetted (file, heading anchor) allowlist (the durability pay doctrine and the guarantee matrix), and every remaining occurrence in doc prose and source comments was rewritten to the precise wording; string literals are deliberately out of scope (tool descriptions enter the toolset hash). - Updated dependencies [ef08d73]
- @rulvar/[email protected]
1.99.0
Patch Changes
- Updated dependencies [9e00888]
- @rulvar/[email protected]
1.98.0
Patch Changes
- @rulvar/[email protected]
1.97.0
Patch Changes
- Updated dependencies [5c3b453]
- @rulvar/[email protected]
1.96.0
Patch Changes
- @rulvar/[email protected]
1.95.0
Patch Changes
- @rulvar/[email protected]
1.94.0
Patch Changes
- @rulvar/[email protected]
1.93.0
Patch Changes
- Updated dependencies [c62150a]
- @rulvar/[email protected]
1.92.0
Patch Changes
- Updated dependencies [351d1f5]
- @rulvar/[email protected]
1.91.0
Patch Changes
- @rulvar/[email protected]
1.90.0
Minor Changes
- 9603940: Scope the isolated-executor idempotency key to the run incarnation (RV403, the eighth-experiment review). A fresh run stamps the additive optional
RunMeta.execKeyDerivationfield (version 2) at genesis and every resume segment carries it verbatim; version 2 keys bind the run's generation token, so adeleteRun-then-recreate of the same explicit runId never reuses the deleted incarnation's keys against a long-lived external dedup store, while a crash-and-resume redispatch inside one incarnation keeps its key exactly as before. Runs recorded without the stamp derive the original genesis-free version 1 keys for their whole life, across resume and upgrade, so external dedup state accumulated for them stays valid; a recorded derivation the engine does not know, or a version 2 stamp whose store dropped the genesis token, is a typed resume refusal when executors are configured, never a silent fallback. The store conformance kit now checks the field's round trip alongsidegenesis.
Patch Changes
- Updated dependencies [9603940]
- @rulvar/[email protected]
1.89.0
Patch Changes
- Updated dependencies [f18b671]
- Updated dependencies [f18b671]
- @rulvar/[email protected]
1.88.0
Patch Changes
- Updated dependencies [3b339d9]
- @rulvar/[email protected]
1.87.0
Patch Changes
- Updated dependencies [c4c02b1]
- @rulvar/[email protected]
1.86.0
Patch Changes
- Updated dependencies [2f71894]
- @rulvar/[email protected]
1.85.0
Patch Changes
- Updated dependencies [6932a9f]
- @rulvar/[email protected]
1.84.0
Patch Changes
- @rulvar/[email protected]
1.83.0
Patch Changes
- @rulvar/[email protected]
1.82.0
Minor Changes
- 9cc5d66: The free-cleanup harvest (cycle 80).
leasableStoreConformancegains theexpiryoption: the mandatory lease checks follow the suite's no-wall-clock convention, so the harness now hands them a store whose ttl no scheduler stall can cross, and only the wall-clock expiry check keeps a short-ttl store of its own; the legacy single-ttlMspairing let one CI stall past 150 ms expire a just-acquired lease inside a fencing check (the flake observed on Node 22). All three shipped harnesses move to the split pairing, and the store-authors guide stops recommending the flaky shape. In@rulvar/cli, worker retention is no longer slot-bound: a worker whose every concurrency slot is busy still applies retention over settled runs during its sweeps instead of starving until idle. In@rulvar/core, concurrent coldtools()calls on an MCP source share one in-flighttools/listfetch instead of each sweeping the list, andAdmissionController'smaxTotalSpawnsTSDoc now tells the truth: it is the controller-lifetime cap on admitted spawns for hosts driving the controller directly (pinned by a test), while engine runs cap totals throughbudgetDefaults.lifetimeSpawnCap; the old comment claimed it was the per-orchestratemaxSpawns.
Patch Changes
- Updated dependencies [9cc5d66]
- @rulvar/[email protected]
1.81.2
Patch Changes
- Updated dependencies [296885b]
- @rulvar/[email protected]
1.81.1
Patch Changes
- Updated dependencies [c030982]
- @rulvar/[email protected]
1.81.0
Patch Changes
- Updated dependencies [ce4c392]
- @rulvar/[email protected]
1.80.0
Patch Changes
- Updated dependencies [262e397]
- @rulvar/[email protected]
1.79.0
Patch Changes
- Updated dependencies [85956ab]
- @rulvar/[email protected]
1.78.0
Patch Changes
- Updated dependencies [941b6e1]
- @rulvar/[email protected]
1.77.0
Patch Changes
- Updated dependencies [6aba271]
- @rulvar/[email protected]
1.76.0
Patch Changes
- Updated dependencies [22cba47]
- @rulvar/[email protected]
1.75.1
Patch Changes
- Updated dependencies [82bc0f0]
- @rulvar/[email protected]
1.75.0
Patch Changes
- Updated dependencies [c486de8]
- @rulvar/[email protected]
1.74.0
Patch Changes
- Updated dependencies [d94beab]
- @rulvar/[email protected]
1.73.0
Patch Changes
- Updated dependencies [3e95bd1]
- @rulvar/[email protected]
1.72.0
Patch Changes
- Updated dependencies [662e9e0]
- @rulvar/[email protected]
1.71.0
Patch Changes
- Updated dependencies [20d02e0]
- @rulvar/[email protected]
1.70.1
Patch Changes
- ac57099: Kill-point suite hardening against loaded test runners: the worker's default lease ttl rises from 300 ms to 2000 ms, because a scheduler stall past the ttl between the worker's own renewals cancels the run by contract BEFORE the kill point is reached (the worker then exits zero as ran-to-completion and the scenario reads a self-inflicted takeover as a violation); the referee's post-kill wait is now the resume retry loop itself (each attempt against a live lease rejects typed with zero writes, so polling is free) instead of a fixed sleep; and the ran-to-completion violation names the worker's settled status for diagnosability. Only the killed owner is short-leased; referees and successor instances belong on their store's generous default ttl.
- @rulvar/[email protected]
1.70.0
Minor Changes
- 29141ed: The engine-level kill-point suite (the 1.65.0 experiment review, P1.10):
killPointConformancespawns a child process that drives a scripted engine run over the consumer's store and SIGKILLs itself around each durable write, both brackets of all five points (the running entry, the ok terminal, the limit terminal, the run settle decision, the meta projection), then resumes the run from the referee process after the dead owner's lease lapses and asserts the documented recovery semantics with exact provider re-pay counts: the lost ok terminal is the only bracket that pays a step twice (the at-least-once window), a lost limit terminal re-pays only the turns since the last transcript boundary (the checkpoint restore), a durable limit terminal in a never-settled run re-runs the agent live in full (the second chance), and the settle and meta brackets recover as pure replays with exactly one ok run settle, a healed meta, and a contiguous journal. A worker that runs to completion is a violation, never a pass.runKillPointWorkerpluskillPointWorkerConfigFromEnvkeep the consumer's writer script to a few lines,runKillPointScenarioruns one scenario standalone, andKILL_POINT_SCENARIOSis the pinned table.SqliteStoreandPostgresStorerun the whole table in their own test suites (postgres gated onRULVAR_POSTGRES_URL).
Patch Changes
- @rulvar/[email protected]
1.69.0
Patch Changes
- Updated dependencies [b21a681]
- @rulvar/[email protected]
1.68.0
Patch Changes
- Updated dependencies [b227874]
- @rulvar/[email protected]
1.67.0
Patch Changes
- Updated dependencies [8e6006d]
- @rulvar/[email protected]
1.66.0
Patch Changes
- Updated dependencies [1b8987e]
- @rulvar/[email protected]
1.65.0
Patch Changes
- Updated dependencies [0b6b859]
- @rulvar/[email protected]
1.64.0
Patch Changes
- Updated dependencies [991f9b5]
- @rulvar/[email protected]
1.63.0
Minor Changes
8a28aed: Durable settlement acknowledgement and the fencing-epoch tombstone (the 1.62.0 experiment review, P0.1 and P0.2).
Settlement acknowledgement: a NON-fencing failure of either settlement write now rejects
handle.resultwith the new typedSettlementError(codesettlement, retryable;stagenames the write,datacarries the runId and the computed run status) instead of resolving as if nothing happened. Only a superseded segment'sLeaseHeldErrorstays swallowed, on both writes, because the successor owns settlement. A failedrun_settleappend also skips the terminal meta write, so the projection can never run ahead of the journal (published 1.62.0 wrote metaokover a journal with no settle record when the append failed). Recovery is deterministic and free: the run's work entries are already durable,engine.resumereplays to the same outcome without one paid provider call and re-attempts the settlement writes (a non-empty journal with no recorded settle now re-settles on pure replay), andrulvar runs audit [--repair]reconciles offline.Fencing-epoch tombstone:
SqliteStoreandPostgresStoreno longer erase the per-run epoch high-water mark ondelete, so a recreate of the same explicit runId always acquires a strictly higher epoch and a zombie lease from the deleted incarnation (same runId, same stable owner identity) is rejected on every fenced surface instead of fencing green. TheLeasableStorecontract now states the rule, and the conformance kit enforces it with two new mandatory checks (fencing-epoch-tombstoneinleasableStoreConformance,fenced-tombstone-zombie-rejectedinfencedWritesConformance). The tombstone holds only the runId and a counter, never run content; the data-protection guide documents the erasure boundary.
Patch Changes
- Updated dependencies [8a28aed]
- @rulvar/[email protected]
1.62.0
Patch Changes
- Updated dependencies [fca5fd1]
- @rulvar/[email protected]
1.61.0
Patch Changes
- Updated dependencies [b4c1f1f]
- @rulvar/[email protected]
1.60.0
Patch Changes
- Updated dependencies [59bbeaa]
- @rulvar/[email protected]
1.59.4
Patch Changes
- Updated dependencies [c49d7a1]
- @rulvar/[email protected]
1.59.3
Patch Changes
- Updated dependencies [deaef36]
- @rulvar/[email protected]
1.59.2
Patch Changes
- Updated dependencies [dd0e10f]
- @rulvar/[email protected]
1.59.1
Patch Changes
- Updated dependencies [c127770]
- @rulvar/[email protected]
1.59.0
Patch Changes
- Updated dependencies [615dc90]
- @rulvar/[email protected]
1.58.0
Patch Changes
- Updated dependencies [4fa35ce]
- @rulvar/[email protected]
1.57.0
Patch Changes
- Updated dependencies [5897232]
- @rulvar/[email protected]
1.56.0
Patch Changes
- Updated dependencies [f26dba0]
- @rulvar/[email protected]
1.55.0
Patch Changes
- Updated dependencies [e9b005b]
- @rulvar/[email protected]
1.54.0
Patch Changes
- Updated dependencies [3f6bc03]
- @rulvar/[email protected]
1.53.0
Patch Changes
- Updated dependencies [b821bd1]
- @rulvar/[email protected]
1.52.0
Patch Changes
- Updated dependencies [e138df9]
- @rulvar/[email protected]
1.51.0
Patch Changes
- @rulvar/[email protected]
1.50.0
Patch Changes
- Updated dependencies [e39a885]
- @rulvar/[email protected]
1.49.0
Patch Changes
- Updated dependencies [bab7b2c]
- @rulvar/[email protected]
1.48.0
Minor Changes
96093ea: Ship the adversarial multi-process soak and fix the SqliteStore concurrent-boot race it found (the fenced run state RFC, phase 3's last open item).
The conformance kit gains the soak harness:
runMultiProcessSoakspawns real OS processes that storm one store location through EVERY fenced write surface (journal append, meta write, transcript blob put and delete, fenced run deletion, renew, release) with stalls injected past the lease ttl, then rebuilds the one serial history the fencing epochs promise (accepted mutations ordered by epoch and per-tenure counter) and diffs it against the actual journal, meta row, and blobs. Any stale acceptance, lost accepted write, epoch inversion, or divergent final byte is a violation. The stale probe sweep re-reads the journal tail before each stale append attempt, so the monotonic-seq guard cannot mask a fencing hole; a live lease is also probed against a foreign run, and side runs get full create-and-fenced-delete cycles. The storm runs until an activity quorum is met (takeovers, per-surface accepted writes, typed stale rejections), so a slow machine storms longer instead of asserting on thin coverage. The child side isrunSoakWriterplussoakWriterConfigFromEnv(the consumer's writer script constructs its store bare and passes aretryablehook for backend contention errors); the pure refereeverifySoakHistory, the report toolsparseSoakReportandcountSoakActivity, and the quorum types are exported alongside.The soak's first storm against the published 1.47.0 never reached the fencing: N processes constructing
SqliteStoreover one SAME fresh file (an ordinary fleet start) collided in the constructor's schema bootstrap and the losers died with a raw SQLITE_BUSY (a 60 percent crash rate at six concurrent boots). A driver busy_timeout is not enough because the journal-mode conversion skips the busy handler on some lock transitions, so the constructor now retries the idempotent bootstrap as a unit through the SQLITE_BUSY family (extended result codes included, e.g. SQLITE_BUSY_RECOVERY while a sibling recovers the fresh WAL) under a wall-clock bound, exported asBOOT_BUSY_TIMEOUT_MS. Every runtime contention path keeps the documented fail-fast semantics. With the fix, 480 of 480 concurrent boots succeed, and the full storm (five writers, hundreds of takeovers, thousands of stale probes) holds every fenced surface with zero violations;SqliteStorenow runs the soak and a concurrent-boot regression in its test suite.
Patch Changes
- @rulvar/[email protected]
1.47.0
Patch Changes
- Updated dependencies [a3687fe]
- @rulvar/[email protected]
1.46.0
Minor Changes
- 865e7bf: Close finding F2 of the fenced run state RFC with the sqlite transcript twin.
SqliteStore.transcripts()returns aTranscriptStorethat declaresfencedWritesbecause its blobs live in the store's own database, beside the lease rows: a lease-carryingputordeleteverifies the current holder of the run the ref's leading path segment names atomically with the blob mutation, in the same one-immediate-transaction shape as the journal side, and rejects stale or cross-run holders with the typedLeaseHeldErrorleaving the prior blob byte intact. Demonstrated against the published 1.45.0 first: the engine threaded the superseded segment's lease into its late checkpoint save, both shipped transcript stores ignored it, and the blob at the deterministic ref both segments share regressed to older turn state (the state a later boot decodes, replaying turns the successor already paid for) while the same holder's journal append bounced typed. Over the{ journal: store, transcripts: store.transcripts() }pair,assertFencedWritesnow passes and every durable run mutation is fenced. The conformance kit gainsfencedTranscriptsConformance, the executable definition of the transcript-side promise, taking a factory for the pair that shares the fencing domain; staleness is produced with release plus reacquire, so the suite needs no wall sleeps.
Patch Changes
- Updated dependencies [865e7bf]
- @rulvar/[email protected]
1.45.0
Minor Changes
- b96305d: The fenced writes capability (the fenced run state RFC, phase 2).
JournalStore.putMetaanddeleteandTranscriptStore.putanddeleteaccept the same optional trailing lease thatappendalways took, and a store declares enforcement with thefencedWrites: truemarker: a mutation carrying a lease that is not the current holder for the mutated run rejects with the typedLeaseHeldError, atomically and leaving nothing changed, including a live lease for a different run. The engine threads the segment's lease into every durable mutation of a leased resume (meta writes, checkpoints, compaction summaries, worktree patches, workflow sources), so over a declaring store a superseded worker can no longer overwrite the successor's meta at its late settle and strand the run from worker sweeps, and its very first refused meta write now fails the stale segment typed at boot with zero paid calls.SqliteStoredeclares the marker and enforces it onputMeta,delete, andappend(with the run-match rule as defense in depth); the conformance kit gainsfencedWritesConformanceas the capability's executable definition; the queue worker's retention sweep passes its brief lease through the new optional second argument ofengine.deleteRun(pruneRuntakes the same); andhasFencedWritesplusassertFencedWriteslet a host assert the full fence at deployment time. Stores written before the capability are untouched: without the marker the extra argument is ignored and the journal-append fence works exactly as before.
Patch Changes
- Updated dependencies [b96305d]
- @rulvar/[email protected]
1.44.1
Patch Changes
- @rulvar/[email protected]
1.44.0
Patch Changes
- Updated dependencies [299f7d2]
- @rulvar/[email protected]
1.43.0
Patch Changes
- Updated dependencies [71b7181]
- @rulvar/[email protected]
1.42.0
Patch Changes
- Updated dependencies [9b70f27]
- @rulvar/[email protected]
1.41.0
Patch Changes
- Updated dependencies [be589ec]
- @rulvar/[email protected]
1.40.0
Patch Changes
- Updated dependencies [cf33550]
- @rulvar/[email protected]
1.39.0
Patch Changes
- @rulvar/[email protected]
1.38.0
Patch Changes
- @rulvar/[email protected]
1.37.0
Patch Changes
- Updated dependencies [e6b1481]
- Updated dependencies [e6b1481]
- @rulvar/[email protected]
1.36.0
Patch Changes
- Updated dependencies [101795b]
- @rulvar/[email protected]
1.35.0
Patch Changes
- Updated dependencies [d4ac3bf]
- @rulvar/[email protected]
1.34.0
Patch Changes
- Updated dependencies [f1505ec]
- @rulvar/[email protected]
1.33.0
Patch Changes
- @rulvar/[email protected]
1.32.0
Patch Changes
- @rulvar/[email protected]
1.31.0
Patch Changes
- @rulvar/[email protected]
1.30.0
Patch Changes
- Updated dependencies [87ce985]
- @rulvar/[email protected]
1.29.0
Patch Changes
- Updated dependencies [621d566]
- @rulvar/[email protected]
1.28.0
Patch Changes
- Updated dependencies [d98eb0b]
- @rulvar/[email protected]
1.27.0
Patch Changes
- Updated dependencies [884a433]
- @rulvar/[email protected]
1.26.0
Minor Changes
- a4fc757:
SqliteStoreimplements the exact lookup capability (getMetaas a primary key query) and narrowsstatus,statuses, andnamein SQL over the JSON payload behind new expression indexes (created idempotently, so existing database files gain them on the next open), so a selectivelistRunsreads only the matching rows instead of decoding the whole catalog; the tags containment check stays in JS over the reduced set with unchanged semantics. The conformance kit checks thegenesisround trip, that astatusesfilter never drops a matching meta (supersets stay allowed), and that a store exposinggetMetaagrees withlistRunsand resolvesundefinedfor a missing run. The planner's deterministic plan lookup reads one meta through the capability instead of scanning the catalog.
Patch Changes
- Updated dependencies [a4fc757]
- @rulvar/[email protected]
1.25.0
Patch Changes
- @rulvar/[email protected]
1.24.1
Patch Changes
- Updated dependencies [0bb14db]
- @rulvar/[email protected]
1.24.0
Minor Changes
- 2b033e8: Record the genesis args binding in RunMeta and make the dry-run preview mutation-free (the v1.23.0 review).
RunMetagainsargsProvided(whether the run started with defined args) andargsHash(sha256 over the JCS canonical serialization of the genesis args, never the raw value), written by the engine at genesis and preserved verbatim by every resume segment, so hosts can refuse a resume whose re-supplied args silently diverge from the original invocation; the new publichashRunArgs()derives the same hash host-side. Legacy metas never gain the marker retroactively, and unserializable args record presence without a hash. AdryRunresume now performs ZERO store mutations by invariant:putMetais skipped entirely (no status flip, nosegmentsbump), the compiled-source blob is not re-put, and the Replayer's single append site refuses any journal append under replay-strict with a typedJournalMissError. The store conformance kit checks the round-trip of both new fields.
Patch Changes
- Updated dependencies [2b033e8]
- @rulvar/[email protected]
1.23.0
Minor Changes
1f9c272: PlanRunner spawn telemetry, the missing evals export, and the conformance kit's new meta field (v1.22.0 review P2-5, P2-6, P1-2).
@rulvar/plan: PlanRunner journals every admission INSIDE a carrying entry (decomposition rows in escalation decisions, ladder-verdict respawns, reuse and graft links, revision admissions) and emitted nospawn:admitted/spawn:rejectedat all; a live PlanRunner run with admitted roots showed an event count of zero. Every embedded admission row now announces through one formatter, identically on the live path and on replay absorb, withreplayed: trueon recovered rows,entryRefon the journaled carrying entry, andagentTyperesolved from the landed specs.@rulvar/evals:agentTypeRuleHoldsjoins the package root next torungRuleHolds, exactly as the v1.21.0 changelog had already announced; a public-API test now imports the checkpoint quartet from the root. The evals guide gains a full measured-value checkpoint section (ladder/pool/cell/arm vocabulary, both criteria, the vacuous-pass guard, cost discipline, a runnable example).@rulvar/store-conformance: the meta round-trip case now also pins the new optionalRunMeta.segmentsfield, which the engine bumps durably at every resume to keep eventseq/spanIdunique per run.
Patch Changes
- Updated dependencies [1f9c272]
- @rulvar/[email protected]
1.22.0
Patch Changes
- Updated dependencies [77b554f]
- @rulvar/[email protected]
1.21.0
Patch Changes
- Updated dependencies [7ee42a0]
- @rulvar/[email protected]
1.20.0
Patch Changes
- Updated dependencies [9367030]
- @rulvar/[email protected]
1.19.0
Patch Changes
- Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- @rulvar/[email protected]
1.18.0
Patch Changes
- Updated dependencies [943962d]
- @rulvar/[email protected]
1.17.0
Patch Changes
- @rulvar/[email protected]
1.16.2
Patch Changes
- @rulvar/[email protected]
1.16.1
Patch Changes
- @rulvar/[email protected]
1.16.0
Patch Changes
- @rulvar/[email protected]
1.15.0
Patch Changes
- @rulvar/[email protected]
1.14.0
Patch Changes
- @rulvar/[email protected]
1.13.0
Patch Changes
- @rulvar/[email protected]
1.12.0
Patch Changes
- Updated dependencies [46edcc0]
- @rulvar/[email protected]
1.11.0
Minor Changes
- 0c70c5e: New mandatory obligation A5, monotonic seq: three new checks reject stores that persist duplicate or stale seqs.
a5-monotonic-seq(a duplicate or stale append rejects with codejournal_order_violationand never becomes visible, while the true next seq still lands),a5-stale-tail-race(two writers appending the same next seq: exactly one persists, the loser observes the typed conflict, reload shows a strictly increasing order), anda5-stale-replayer-fencing(the same race driven through two kernel Replayers from one loaded tail). TheCommunityMemoryStorewalkthrough listing gains the guard in step withdocs/guide/store-authors.md. Third-party stores that pass the previous kit but accept duplicate seqs will fail the new checks until they add the guard; the obligation is documented inguide/storesandguide/store-authors.
Patch Changes
- Updated dependencies [0c70c5e]
- @rulvar/[email protected]
1.10.0
Patch Changes
- Updated dependencies [0e8d78e]
- @rulvar/[email protected]
1.9.0
Patch Changes
- Updated dependencies [3a53383]
- @rulvar/[email protected]
1.8.0
Patch Changes
- Updated dependencies [25724b5]
- Updated dependencies [57ea1de]
- Updated dependencies [7884ec5]
- Updated dependencies [52db30d]
- @rulvar/[email protected]
1.7.0
Patch Changes
- Updated dependencies [45285aa]
- Updated dependencies [2f20d1d]
- Updated dependencies [22f65a8]
- Updated dependencies [2ddfa29]
- Updated dependencies [2abd9c2]
- Updated dependencies [1c1175d]
- @rulvar/[email protected]
1.6.0
Patch Changes
- da4dbad: Write the product name as Rulvar in prose: package READMEs, npm descriptions, and the documentation site now capitalize the brand. Identifiers keep their exact casing, so package names, the
rulvarbinary,rulvar.config.mjs, the.rulvarstore directory, therulvar.*OTel attributes, and every URL are unchanged. Documentation and metadata only; no runtime behaviour changes. - Updated dependencies [da4dbad]
- Updated dependencies [487da86]
- Updated dependencies [df416fc]
- Updated dependencies [a737810]
- Updated dependencies [9eb66b4]
- @rulvar/[email protected]
1.5.2
Patch Changes
- Updated dependencies [54936a0]
- @rulvar/[email protected]
1.5.1
Patch Changes
- Updated dependencies [6c6d56f]
- @rulvar/[email protected]
1.5.0
Patch Changes
- Updated dependencies [4fba3c7]
- Updated dependencies [8655c0f]
- @rulvar/[email protected]
1.4.0
Minor Changes
c4f563d: Production readiness fixes from the July 2026 full audit.
The
budgetUsdceiling now survives resume: the engine records it inRunMeta.budgetUsdand restores it on every resume, so the replayed spend counts against the original invocation's bound andResumeOptionsstill exposes no way to raise it. Journals written before the field existed (or read through a store that drops optionalRunMetafields) resume uncapped, exactly as before; the conformance kit gains a round-trip check so custom stores cannot drop the field silently.spawn:rejectedandresolution:applied/resolution:supersededare now emitted: live admission rejections carry the rejectioncode,agentType, and the journaled decisionentryRef(absent only for pre-admission config gates), and live resolution attempts report winning or losing the first-closing-wins fold.spawn:admittednow carries the decisionentryRefand the admittingverdictarm. Theorchestrator:budgetunion member now types the two payload shapes actually emitted;journal:compatstays declared but unemitted (the scan runs before a run's event stream exists) and its TSDoc says so.toOtelimplements real parent-child span nesting whencontextApiandsetSpanare passed; without them spans stay flat but attributed.'readonly'isolation now compiles a deny rule for tools declaring riskwriteordestructiveinto the spawn's permission chain, exactly as the tools guide documents; read tools and other isolation modes are unaffected.VCR
replay()refuses a cassette recorded outside the engine's hashVersion support window ([CURRENT-1, CURRENT]) with a typedConfigErrorinstead of silently drifting; in-window cassettes replay as before.InMemoryStoreaccepts{ quiet: true }to opt out of the durability warning, and the warning text now states the precise truth: nothing survives a process exit and cross-process resume is impossible (same-process resume of a kept instance works).createTestEngineconstructs its store quietly, so the blessed offline tier no longer prints a misleading warning.The bare
Date.now()/Math.random()development warnings no longer blame workflow code for calls that originate in library internals (the engine's own retry jitter, provider SDKs): the retry jitter uses a natively capturedMath.random, and the in-process guard skips callers that live undernode_modules.rulvar run --profilenow applies the profile's per-role effort hints: entries indefaults.routingthat carry no effort are seeded fromRunProfile.effortByRole(an explicit host effort always wins; ladder entries and unrouted roles stay untouched).rulvar --helpdocuments the shippedkb inboxandkb gatesubcommands.The unscoped
rulvarpointer package ships TypeScript declarations (index.d.tswith atypesexport condition), so strict TypeScript projects can import the bare name; the install smoke gate now packs and checks the pointer alongside the umbrella.
Patch Changes
- Updated dependencies [c4f563d]
- @rulvar/[email protected]
1.3.2
Patch Changes
- ddef383: Every published package now ships a README, so its npm page states what the package is, how it installs, and where the documentation lives (npm includes README.md in the tarball regardless of the files allowlist, so no manifest changes are involved; @rulvar/compat gains its README on its own next release). Alongside, the repository-level pages are refreshed to the current project state: the root README is rewritten around the never-pay-twice pitch with a runnable quickstart condensation and the full package table, CONTRIBUTING.md lists the complete PR gate set, the examples README drops retired-spec citations for live docs.rulvar.com links and documents the dogfood journal replay, and the pointer README gets the same treatment.
- Updated dependencies [ddef383]
- @rulvar/[email protected]
1.3.1
Patch Changes
- 7d1552e: Runtime message strings no longer cite the retired internal specification set: error and warning messages, validation issues, and the CLI help text drop the dangling
docs/NN, section ...references, pointing at https://docs.rulvar.com pages where a pointer earns its place (the CLI help header, tool naming, toolset registries, bare resume). The umbrella package description sheds the naming-contingency note: the unscoped alias is published and owned. Three strings embedded in frozen recordings stay byte-identical on purpose (the no-progress abort reason and two testing-internal recorder strings), as does the byte-locked golden-fold fixture. Test-file comments lose their citations too; test titles are unchanged. - Updated dependencies [7d1552e]
- @rulvar/[email protected]
1.3.0
Patch Changes
- Updated dependencies [7d1a287]
- @rulvar/[email protected]
1.2.0
Patch Changes
- 154507b: TSDoc and inline comments no longer cite the retired internal specification set (the pre-docs-site
docs/NN, section ...references). The citations either became links to the public documentation at docs.rulvar.com or were dropped where the comment already carried the rule; traceability markers (DEF-n, XF-nn, FR-nnn, OQ-nn, W-nnn) are untouched. Comment-only change: no runtime behavior, no API shapes, and no runtime message strings were modified; the frozen golden-fold fixture is byte-identical. - Updated dependencies [3bfaec0]
- Updated dependencies [890f42c]
- Updated dependencies [154507b]
- @rulvar/[email protected]
1.1.0
Patch Changes
- Updated dependencies [d16b04a]
- @rulvar/[email protected]
1.0.0
Minor Changes
5f0fdcd: M9-T03: community adapter and store guides (docs/10 section 3.10; docs/11 M9 exit row "conformance kits published as community guides").
- New informative docs:
docs/guide-adapter-authors.md(wire mapping requirements, the Usage invariant checklist, caps posture, an adapter skeleton template, and the VCR-based contract-test pattern with record and hermetic replay legs) anddocs/guide-store-authors.md(the storage contracts A1-A4 plus leasing and fencing, a complete minimal LeasableStore walkthrough with an injectable clock and release-surviving epochs, conformance kit wiring, common failure modes, and publishing checklists). Both are indexed in the docs README inventory. - @rulvar/store-conformance gains the dogfood suite: the guide's CommunityMemoryStore walkthrough listing runs VERBATIM through journalStoreConformance and leasableStoreConformance in CI, so the acceptance ("a third-party mock store built only from the guide passes conformance") holds permanently and the guide's code cannot rot.
- New informative docs:
Patch Changes
- Updated dependencies [0e0b569]
- Updated dependencies [b28b7a3]
- Updated dependencies [b53a89e]
- Updated dependencies [4454175]
- Updated dependencies [6599ca8]
- Updated dependencies [6649e5f]
- Updated dependencies [fd2f83b]
- Updated dependencies [01d6b2d]
- Updated dependencies [9a20dbb]
- Updated dependencies [0fbe7ea]
- Updated dependencies [ebe0abc]
- Updated dependencies [a3079d0]
- Updated dependencies [596a39b]
- Updated dependencies [464ab6e]
- @rulvar/[email protected]
0.9.0
Patch Changes
- Updated dependencies [84f94d4]
- Updated dependencies [65c7b2c]
- Updated dependencies [a2a3243]
- Updated dependencies [ebc8101]
- @rulvar/[email protected]
0.8.0
Patch Changes
- Updated dependencies [85d55cf]
- Updated dependencies [b88c9e3]
- Updated dependencies [f3c4613]
- Updated dependencies [a41c20f]
- Updated dependencies [f4e70be]
- Updated dependencies [75d1646]
- Updated dependencies [0627413]
- Updated dependencies [55c0f87]
- Updated dependencies [fd33871]
- Updated dependencies [e70e7f4]
- Updated dependencies [bc9c903]
- @rulvar/[email protected]
0.7.0
Patch Changes
- Updated dependencies [fd1d06c]
- Updated dependencies [6fcf296]
- Updated dependencies [dcc97a9]
- Updated dependencies [434dc83]
- Updated dependencies [03173c1]
- Updated dependencies [11c0afc]
- @rulvar/[email protected]
0.6.0
Patch Changes
- Updated dependencies [fa05007]
- Updated dependencies [9234dc8]
- Updated dependencies [644512c]
- Updated dependencies [8a41656]
- Updated dependencies [02f7f7a]
- @rulvar/[email protected]
0.5.0
Patch Changes
- Updated dependencies [ac274f4]
- Updated dependencies [5735d92]
- Updated dependencies [46ca98e]
- Updated dependencies [8ae129e]
- Updated dependencies [d1c4525]
- Updated dependencies [b840aba]
- @rulvar/[email protected]
0.4.0
Patch Changes
- Updated dependencies [dfe03b5]
- Updated dependencies [d2089a7]
- Updated dependencies [3f60234]
- Updated dependencies [f668890]
- Updated dependencies [16d7aa6]
- Updated dependencies [6513ce8]
- Updated dependencies [7dad493]
- Updated dependencies [2bbf180]
- @rulvar/[email protected]
0.3.0
Minor Changes
43444f6: M2-T11/T12: the executable store conformance kit and the M2 gating cassettes with frozen fixtures.
@rulvar/store-conformance ships its first real API: journalStoreConformance (A1 append atomicity, A2 total per-run order, A3 read-your-writes, A4 opaque payload with read-side-only normalization, meta separation, the golden fold-state fixture with a frozen reference hash, the decide-once oracle, and the abandon-derived-skip fixture) and leasableStoreConformance (typed LeaseHeldError on held acquire, monotonic fencing epochs, stale-epoch appends rejected and invisible, released leases fenced from renew and append, optional ttl/renew-cadence timing checks), plus registerConformance for Vitest/Jest and the stableStringify fold-state hasher. InMemoryStore and JsonlFileStore pass; deliberately broken stores (reordering, normalizing, tearing, fencing-less) fail loudly.
@rulvar/core kernel closes three DEF-1/DEF-4 gaps the cassettes gate: an abandon-covered hanging dispatch derives skipped instead of redispatching, abandon-covered operations contribute a zero ledger increment, the resume report lists covered entries as skipped (never orphaned), and an abandon over an already-resolved suspension folds to a noop with already_resolved (first-closing-wins per target, both closer kinds).
@rulvar/testing ships the M2 cassette suite over committed frozen fixtures: the DEF-1 synthetic subset (abandon-subtree, memoize-classifier, v1-journal-on-v2), the DEF-4 set (timeout-vs-live-race, class-decision-fanout, abandon-then-crash-then-resume, abandon-vs-resolution-race, offline-invalid-then-valid, double-abandon-idempotent), the DEF-6 six IDs (resume-v1-on-engine-v2, resume-v1-with-inserted-call, suspended-v1-resolves-on-v2, reject-version-too-old via deriverV0Synthetic, reject-version-from-future, effort-defaults-shift), the mandatory mixed-version scenarios (ordinal-space split, forward-cursor preference, cross-version resolution, the compatibility and never-pay-twice-through-upgrade lemmas), and KeyDeriver contract tests against the frozen v2 golden identities including the docs/03 worked example. Fixture regeneration is deliberate: scripts/record-m2-cassettes.mjs rebuilds, and CI write protection (scripts/check-frozen-fixtures.mjs plus fixtures.sha256) fails any fixture diff shipped without the explicit bump token (the hyphenated compound of hashVersion and bump) in a changeset.
Patch Changes
- Updated dependencies [43444f6]
- Updated dependencies [279881b]
- Updated dependencies [9fd0966]
- Updated dependencies [24ebadf]
- Updated dependencies [a1b35d3]
- Updated dependencies [18a5821]
- @rulvar/[email protected]
0.2.0
Patch Changes
- Updated dependencies [c24228d]
- Updated dependencies [c50871e]
- Updated dependencies [1af8fb9]
- Updated dependencies [1fe0249]
- Updated dependencies [5c4fc32]
- @rulvar/[email protected]
0.1.0
Minor Changes
- f4e2be9: M0 repo bootstrap (v0.1.0, docs/10-implementation-plan.md section "M0"): monorepo scaffold on the committed toolchain (pnpm 11 workspaces with catalogs, TypeScript 6.0, tsdown, Vitest 4, ESLint 9 flat config, Turborepo 2, changesets fixed mode, npm trusted publishing), the docs/ canon as single source of truth, the L0 contracts skeleton in @rulvar/core, and the vendored dependencies (StandardSchemaV1/StandardJSONSchemaV1 types, the @cfworker/json-schema lineage validator subset, a first-party monotonic ULID). Placeholder scaffolds only: no public API ships in this release.
Patch Changes
- Updated dependencies [f4e2be9]
- @rulvar/[email protected]
@rulvar/store-postgres
1.252.0
Minor Changes
- a7e589d: The durable admission bracket hardens on every seam the ninth experiment named (RV4804). The queued wait honors a verdict's
retryAfterMsverbatim for its next sleep (pollMsstays the fallback cadence) and ends with the RUN: the run's cancel signal rides into the wait, so host abort and the deadline stop the polling, cancel the ticket best effort, and hand the run to its own cancellation machinery, where before a cancelled run camped in the queue forever. Renew failures are announced, never fatal: the first failure warns, a verify recover that no longer answersgrantedemits the newadmission:lease-lostevent once (the scheduler expired the grant and may re-admit the capacity while the holder is alive), and the run continues, because the wire quota still gates every dispatch and the settle release is idempotent. The postgres scheduler takes its schema-scoped advisory lock under alock_timeoutbound (lockTimeoutMs, default 10 seconds, validated typed): a holder that hangs mid-transaction used to block every lifecycle call of the whole fleet forever; past the bound the call refuses with the typed retryableLeaseHeldErrorinstead of camping.
Patch Changes
- Updated dependencies [3ccb6cf]
- Updated dependencies [52d807f]
- Updated dependencies [517ed00]
- Updated dependencies [a7e589d]
- Updated dependencies [76e95eb]
- @rulvar/[email protected]
1.251.0
Patch Changes
- Updated dependencies [e7e829c]
- Updated dependencies [5982be8]
- Updated dependencies [7c58fb2]
- Updated dependencies [b3e465a]
- Updated dependencies [c4e5d6a]
- Updated dependencies [c6fc3da]
- Updated dependencies [c6fc3da]
- Updated dependencies [0ae8b85]
- Updated dependencies [7932936]
- Updated dependencies [7932936]
- Updated dependencies [88da0ed]
- Updated dependencies [06c0e85]
- @rulvar/[email protected]
1.250.0
Minor Changes
- c5eb19c: The restoration generation (RV4503, plan 45, rfcs/effects.md section 4.5, item 3): SqliteStore and PostgresStore implement the
EffectLaneStorecapability, carrying a restoration generation OUTSIDE the journal bytes (a one-row table beside the leases). The restore runbook is one rule: after a point-in-time restore, callbumpRestorationGeneration()BEFORE the restored database becomes reachable to any worker, so the effect lane comes up with dispatch disabled by construction until an operator appends a fresheffect_epochciting the bumped generation. The neweffectLaneStoreConformancesuite in @rulvar/store-conformance is the executable definition: generation starts at 0 and bumps monotonically (ELS1, ELS2), a bumped generation refuses every lane append until the fresh epoch (ELS3, the kill point 25 window, driven through the real writer over the real store), and a lane append under a non-current lease dies on the store's fence with nothing consumed (ELS4, the kill point 16 shape). - c6d197b: The reconciler, the trust envelope, and the whole kill point kit (RV4505, plan 45, rfcs/effects.md sections 3.1, 7, 8, 9). The sweep makes "every intent deterministically reaches confirmed, compensated, or quarantined" true: crossing
reconcileByquarantines whatever state with the state recorded, receipt waits and attempt budgets quarantine on exhaustion, lookups are bounded SEPARATELY through journaledeffect_proberows (countable from the journal alone, crash-proof), pre-terminal conflicting receipts quarantine, and effect authorizations past their deadline refuse durably instead of waiting forever. Receipt verification runs a declared trust envelope: issuer identity, per-class content bindings, key validity windows, revocation from its time forward, and the host's signature check; every failure classifies unverified, which routes to unknown. The post-restore reconciliation (kill 25) quarantines provider effects the journal cannot reconstruct by name (or the whole range without authoritative enumeration), and a restoration epoch stays undispatchable until the neweffect_reconciliation_completedecision cites it. Section 9 telemetry folds effective dispositions (the compensated overlay included), pressure, duplicate classification, and open incidents. The kit exports all thirtyeffects.kill.*rows as named conformance checks parameterized by a store factory (ambiguous acks and restoration generations injected through delegating proxies, so any store qualifies), registered over the in-memory reference store in single-process posture and over the REAL sqlite and postgres stores in their own packages. - fed9db6: Durable admission over sqlite and postgres (RV4508, plan 45, rfcs/admission.md section 9):
SqliteAdmissionSchedulerandPostgresAdmissionSchedulerpersist the scheduler's WHOLE state as one plain-JSON document (AdmissionState, now exported withsnapshot()and hydration on the reference core), committed atomically per lifecycle call inside a BEGIN IMMEDIATE transaction (sqlite) or an advisory-lock-serialized transaction (postgres). This is the RFC's first shipped durable shape, recorded as a deliberate decision: a single scheduler over durable state with deterministic ordering, where "state moved AND buckets moved" holds trivially because the whole document commits or none of it does; per-row schemas are an optimization the SPI does not require. A queued ticket survives its holder with position and arrival identity intact, re-enqueueing the same (unitId, generation) returns the SAME ticket, and settlement operation ids replay as durable no-ops across holders (a late-settlement debt entry lands exactly once).
Patch Changes
- Updated dependencies [0e240b9]
- Updated dependencies [6fe585e]
- Updated dependencies [c5eb19c]
- Updated dependencies [565c13b]
- Updated dependencies [c6d197b]
- Updated dependencies [c9d9729]
- Updated dependencies [fed9db6]
- Updated dependencies [df9ed76]
- Updated dependencies [3020912]
- Updated dependencies [d8d598d]
- @rulvar/[email protected]
1.249.0
Patch Changes
- Updated dependencies [8862133]
- Updated dependencies [0d7a717]
- Updated dependencies [e4428bd]
- Updated dependencies [d6873c1]
- Updated dependencies [4092e8d]
- Updated dependencies [e086590]
- Updated dependencies [1411938]
- Updated dependencies [737d1ee]
- Updated dependencies [634f966]
- Updated dependencies [052cc26]
- Updated dependencies [bbae134]
- @rulvar/[email protected]
1.248.0
Patch Changes
- Updated dependencies [8d0cd69]
- Updated dependencies [81065e4]
- Updated dependencies [8573f20]
- Updated dependencies [95f6a5e]
- @rulvar/[email protected]
1.247.0
Patch Changes
- Updated dependencies [1933ecc]
- Updated dependencies [db0a5f0]
- Updated dependencies [b698726]
- Updated dependencies [48348d2]
- Updated dependencies [4cfa1cc]
- Updated dependencies [4b7197a]
- Updated dependencies [5ebc842]
- Updated dependencies [16ff6b9]
- Updated dependencies [0c9941d]
- @rulvar/[email protected]
1.246.0
Patch Changes
- Updated dependencies [d165b0c]
- Updated dependencies [d59f4a0]
- Updated dependencies [46907ac]
- Updated dependencies [9929ad3]
- Updated dependencies [1790a6a]
- @rulvar/[email protected]
1.245.0
Patch Changes
- Updated dependencies [b4d47a8]
- Updated dependencies [dee6db4]
- Updated dependencies [b85c113]
- Updated dependencies [bc556e7]
- Updated dependencies [9f11d29]
- Updated dependencies [19bcea0]
- Updated dependencies [60b461c]
- Updated dependencies [61e3a1a]
- Updated dependencies [a156b81]
- Updated dependencies [0bd7045]
- @rulvar/[email protected]
1.244.0
Patch Changes
- Updated dependencies [38d839a]
- Updated dependencies [ce13b0f]
- Updated dependencies [4fa23e3]
- Updated dependencies [6841c69]
- Updated dependencies [f56721d]
- Updated dependencies [c894a43]
- Updated dependencies [f6944a3]
- Updated dependencies [23fd0e0]
- @rulvar/[email protected]
1.243.0
Patch Changes
- Updated dependencies [746d1f4]
- Updated dependencies [009b29c]
- Updated dependencies [1674cbe]
- Updated dependencies [bd096bc]
- @rulvar/[email protected]
1.242.0
Patch Changes
- Updated dependencies [6e3438e]
- Updated dependencies [ba5cf67]
- Updated dependencies [c2d1531]
- @rulvar/[email protected]
1.241.0
Patch Changes
- Updated dependencies [dbcdd24]
- Updated dependencies [7ae7243]
- Updated dependencies [4f832c4]
- Updated dependencies [7452d3d]
- Updated dependencies [a4e22bf]
- Updated dependencies [82df4af]
- @rulvar/[email protected]
1.240.0
Patch Changes
- @rulvar/[email protected]
1.239.0
Patch Changes
- Updated dependencies [74ce99a]
- Updated dependencies [ccd0665]
- Updated dependencies [0c5ce21]
- Updated dependencies [0616934]
- @rulvar/[email protected]
1.238.0
Patch Changes
- Updated dependencies [cf00947]
- Updated dependencies [c7b9382]
- Updated dependencies [88aea96]
- Updated dependencies [6da8d05]
- Updated dependencies [eae5c4c]
- @rulvar/[email protected]
1.237.0
Patch Changes
- Updated dependencies [9d6a279]
- Updated dependencies [49a98f6]
- Updated dependencies [a734ca0]
- Updated dependencies [deb406f]
- @rulvar/[email protected]
1.236.0
Patch Changes
- Updated dependencies [26306ea]
- Updated dependencies [709b942]
- @rulvar/[email protected]
1.235.0
Patch Changes
- Updated dependencies [ba4e10d]
- Updated dependencies [172402b]
- Updated dependencies [2ecd787]
- Updated dependencies [e20a5e9]
- Updated dependencies [98c8691]
- Updated dependencies [c70def0]
- @rulvar/[email protected]
1.234.0
Patch Changes
- Updated dependencies [8420c04]
- @rulvar/[email protected]
1.233.0
Patch Changes
- Updated dependencies [48b5200]
- Updated dependencies [73bc32b]
- Updated dependencies [e63b743]
- Updated dependencies [ef45da7]
- @rulvar/[email protected]
1.232.0
Patch Changes
- Updated dependencies [1440410]
- Updated dependencies [6e467f4]
- Updated dependencies [0b14293]
- Updated dependencies [e3bcab2]
- Updated dependencies [b55a0f7]
- @rulvar/[email protected]
1.231.0
Patch Changes
- Updated dependencies [4eb4b56]
- Updated dependencies [bc8f09e]
- Updated dependencies [ff9b8c2]
- @rulvar/[email protected]
1.230.0
Patch Changes
- Updated dependencies [e9bf910]
- Updated dependencies [57bfb38]
- @rulvar/[email protected]
1.229.0
Patch Changes
- Updated dependencies [3370342]
- Updated dependencies [2fb6656]
- Updated dependencies [edce170]
- @rulvar/[email protected]
1.228.0
Patch Changes
- Updated dependencies [4034fac]
- Updated dependencies [a54b085]
- Updated dependencies [9d0a9be]
- Updated dependencies [be9ef28]
- @rulvar/[email protected]
1.227.0
Patch Changes
- Updated dependencies [f262e9f]
- Updated dependencies [f191ff7]
- Updated dependencies [fbbfbe8]
- Updated dependencies [263b5e8]
- Updated dependencies [db4d56d]
- Updated dependencies [41f93a9]
- Updated dependencies [98c8ca9]
- @rulvar/[email protected]
1.226.0
Patch Changes
- @rulvar/[email protected]
1.225.0
Patch Changes
- @rulvar/[email protected]
1.224.0
Patch Changes
- Updated dependencies [4eca1a3]
- @rulvar/[email protected]
1.223.0
Patch Changes
- Updated dependencies [549aabd]
- Updated dependencies [549aabd]
- @rulvar/[email protected]
1.222.0
Patch Changes
- Updated dependencies [8326268]
- @rulvar/[email protected]
1.221.0
Patch Changes
- Updated dependencies [032ce93]
- @rulvar/[email protected]
1.220.0
Patch Changes
- Updated dependencies [0babe70]
- @rulvar/[email protected]
1.219.0
Patch Changes
- Updated dependencies [65a4ce7]
- @rulvar/[email protected]
1.218.0
Patch Changes
- Updated dependencies [088bda6]
- @rulvar/[email protected]
1.217.0
Patch Changes
- Updated dependencies [ab80b97]
- @rulvar/[email protected]
1.216.0
Patch Changes
- Updated dependencies [b357f4a]
- @rulvar/[email protected]
1.215.0
Patch Changes
- Updated dependencies [e1da4c7]
- @rulvar/[email protected]
1.214.0
Patch Changes
- Updated dependencies [c8af0ec]
- @rulvar/[email protected]
1.213.0
Patch Changes
- Updated dependencies [61680df]
- @rulvar/[email protected]
1.212.0
Patch Changes
- Updated dependencies [e6f8516]
- @rulvar/[email protected]
1.211.0
Patch Changes
- Updated dependencies [d5a8a36]
- @rulvar/[email protected]
1.210.0
Patch Changes
- Updated dependencies [c871ddc]
- @rulvar/[email protected]
1.209.0
Patch Changes
- Updated dependencies [514c7bb]
- @rulvar/[email protected]
1.208.0
Patch Changes
- Updated dependencies [e7d426f]
- @rulvar/[email protected]
1.207.0
Patch Changes
- Updated dependencies [99beee2]
- @rulvar/[email protected]
1.206.0
Patch Changes
- Updated dependencies [ec8e1f1]
- @rulvar/[email protected]
1.205.0
Patch Changes
- Updated dependencies [6d224da]
- @rulvar/[email protected]
1.204.0
Patch Changes
- Updated dependencies [efaec9b]
- @rulvar/[email protected]
1.203.0
Patch Changes
- Updated dependencies [fb08c10]
- @rulvar/[email protected]
1.202.0
Patch Changes
- @rulvar/[email protected]
1.201.0
Patch Changes
- Updated dependencies [7e01189]
- @rulvar/[email protected]
1.200.0
Patch Changes
- Updated dependencies [e2ddbdf]
- @rulvar/[email protected]
1.199.0
Patch Changes
- Updated dependencies [29891c6]
- @rulvar/[email protected]
1.198.0
Patch Changes
- Updated dependencies [c097c96]
- @rulvar/[email protected]
1.197.0
Patch Changes
- @rulvar/[email protected]
1.196.0
Patch Changes
- Updated dependencies [ec9c3e3]
- @rulvar/[email protected]
1.195.0
Patch Changes
- Updated dependencies [5702a70]
- @rulvar/[email protected]
1.194.0
Patch Changes
- Updated dependencies [360a659]
- @rulvar/[email protected]
1.193.0
Patch Changes
- Updated dependencies [2bca1d1]
- @rulvar/[email protected]
1.192.0
Patch Changes
- Updated dependencies [8757601]
- @rulvar/[email protected]
1.191.0
Patch Changes
- Updated dependencies [745387c]
- @rulvar/[email protected]
1.190.0
Patch Changes
- Updated dependencies [8e02021]
- @rulvar/[email protected]
1.189.0
Patch Changes
- Updated dependencies [6a5cc2d]
- @rulvar/[email protected]
1.188.0
Patch Changes
- @rulvar/[email protected]
1.187.0
Patch Changes
- Updated dependencies [c9798ef]
- @rulvar/[email protected]
1.186.0
Patch Changes
- Updated dependencies [242647e]
- @rulvar/[email protected]
1.185.0
Patch Changes
- Updated dependencies [1248623]
- @rulvar/[email protected]
1.184.0
Patch Changes
- Updated dependencies [8a9caca]
- @rulvar/[email protected]
1.183.0
Patch Changes
- Updated dependencies [dd3767c]
- @rulvar/[email protected]
1.182.0
Patch Changes
- Updated dependencies [144d026]
- @rulvar/[email protected]
1.181.0
Patch Changes
- @rulvar/[email protected]
1.180.0
Patch Changes
- Updated dependencies [b124d26]
- @rulvar/[email protected]
1.179.0
Patch Changes
- Updated dependencies [1a5a85a]
- @rulvar/[email protected]
1.178.0
Patch Changes
- @rulvar/[email protected]
1.177.0
Patch Changes
- Updated dependencies [94db8ff]
- @rulvar/[email protected]
1.176.0
Patch Changes
- Updated dependencies [a74304d]
- @rulvar/[email protected]
1.175.0
Patch Changes
- Updated dependencies [1999c5d]
- @rulvar/[email protected]
1.174.0
Patch Changes
- Updated dependencies [aa9a772]
- @rulvar/[email protected]
1.173.0
Patch Changes
- Updated dependencies [67d27ac]
- @rulvar/[email protected]
1.172.0
Patch Changes
- Updated dependencies [0d4770b]
- @rulvar/[email protected]
1.171.0
Patch Changes
- Updated dependencies [f6116b9]
- @rulvar/[email protected]
1.170.0
Patch Changes
- Updated dependencies [86e4c06]
- @rulvar/[email protected]
1.169.0
Patch Changes
- Updated dependencies [623b2ae]
- @rulvar/[email protected]
1.168.0
Patch Changes
- Updated dependencies [ebba79a]
- @rulvar/[email protected]
1.167.0
Patch Changes
- @rulvar/[email protected]
1.166.0
Patch Changes
- Updated dependencies [d8262c3]
- @rulvar/[email protected]
1.165.0
Patch Changes
- Updated dependencies [6391274]
- @rulvar/[email protected]
1.164.0
Patch Changes
- Updated dependencies [9f2dda9]
- @rulvar/[email protected]
1.163.0
Patch Changes
- Updated dependencies [e8d9ada]
- @rulvar/[email protected]
1.162.0
Patch Changes
- Updated dependencies [2031e82]
- @rulvar/[email protected]
1.161.0
Patch Changes
- Updated dependencies [d4547b7]
- @rulvar/[email protected]
1.160.0
Patch Changes
- Updated dependencies [1c6f0d0]
- @rulvar/[email protected]
1.159.0
Patch Changes
- Updated dependencies [e881c8b]
- @rulvar/[email protected]
1.158.0
Patch Changes
- Updated dependencies [a266bc7]
- @rulvar/[email protected]
1.157.0
Patch Changes
- Updated dependencies [1883421]
- @rulvar/[email protected]
1.156.0
Patch Changes
- Updated dependencies [537144e]
- @rulvar/[email protected]
1.155.0
Patch Changes
- Updated dependencies [49b08a7]
- @rulvar/[email protected]
1.154.0
Patch Changes
- Updated dependencies [9259f24]
- @rulvar/[email protected]
1.153.0
Patch Changes
- Updated dependencies [d8bebcb]
- @rulvar/[email protected]
1.152.0
Patch Changes
- Updated dependencies [dd6a616]
- @rulvar/[email protected]
1.151.0
Patch Changes
- Updated dependencies [1de0610]
- @rulvar/[email protected]
1.150.0
Patch Changes
- Updated dependencies [a331211]
- @rulvar/[email protected]
1.149.0
Patch Changes
- Updated dependencies [08b4537]
- @rulvar/[email protected]
1.148.0
Patch Changes
- Updated dependencies [c85dac9]
- @rulvar/[email protected]
1.147.0
Patch Changes
- Updated dependencies [6367231]
- @rulvar/[email protected]
1.146.0
Patch Changes
- Updated dependencies [5d9bbc8]
- @rulvar/[email protected]
1.145.0
Patch Changes
- @rulvar/[email protected]
1.144.0
Patch Changes
- Updated dependencies [c11bcd6]
- @rulvar/[email protected]
1.143.0
Patch Changes
- Updated dependencies [f412169]
- @rulvar/[email protected]
1.142.0
Patch Changes
- @rulvar/[email protected]
1.141.0
Patch Changes
- Updated dependencies [4f12a62]
- @rulvar/[email protected]
1.140.0
Minor Changes
- 3044838: Both store limiters implement the optional
QuotaLimiter.release(RV1103 + RV1104, the SPI method from RV1013): a cancelled admission returns exactly what it consumed, the admitted requests and the token estimate, to the window, from any process sharing the file (SqliteQuotaLimiter) or any host sharing the schema (PostgresQuotaLimiter, under the same advisory lock and generation fence as every admission). Unknown, expired, and repeated ids are no-ops; a rolled-over window already aged the estimate out; a released id settles nothing afterwards; verdicts mirrormemoryQuotaLimiterexactly. Both reservation tables grew arequestscolumn, migrated in place on boot (sqlite: a serializedALTERunderBEGIN IMMEDIATE; postgres:ADD COLUMN IF NOT EXISTSunder the boot lock) defaulting to 1, the single request every engine admission reserves, so pre-release reservations release exactly what their admission consumed.
Patch Changes
- @rulvar/[email protected]
1.139.0
Patch Changes
- Updated dependencies [03a2141]
- @rulvar/[email protected]
1.138.0
Patch Changes
- Updated dependencies [ed0c4fb]
- @rulvar/[email protected]
1.137.0
Patch Changes
- Updated dependencies [96f6788]
- @rulvar/[email protected]
1.136.0
Patch Changes
- Updated dependencies [aa6ca71]
- @rulvar/[email protected]
1.135.0
Patch Changes
- Updated dependencies [cf75e22]
- @rulvar/[email protected]
1.134.0
Patch Changes
- @rulvar/[email protected]
1.133.0
Patch Changes
- @rulvar/[email protected]
1.132.0
Patch Changes
- Updated dependencies [2bec904]
- @rulvar/[email protected]
1.131.0
Patch Changes
- Updated dependencies [256cae1]
- @rulvar/[email protected]
1.130.0
Patch Changes
- Updated dependencies [d6bec7a]
- @rulvar/[email protected]
1.129.0
Patch Changes
- Updated dependencies [1612439]
- @rulvar/[email protected]
1.128.0
Minor Changes
27c4e38: pause_turn continuations become accounted wire units (RV905, the thirteenth experiment's fifth release risk). The Anthropic adapter absorbs server-side turn pauses by re-sending, making up to six wire requests inside ONE core dispatch; until now the request quota window, the provider call record, and the invoice row all saw one, and a per-request provider statement matched one segment while the rest read statement-only.
The adapter's finish metadata now names the whole segment set (
providerMetadata.anthropic.wireRequests = { count, responseIds }); the provider call record and the invoice row carrywireResponseIds; and the quota reconciliation settles the reservation against the TRUE wire request count. TheQuotaLimiter.reconcileSPI gains an optionalactual.requestsargument, honored by all three reference limiters through one shared arithmetic (quotaActualRequestsDelta), so a window that admitted one request per reservation now reflects what the provider's own RPM meter saw; a settlement only ever adds, never denies retroactively, and implementations written against the two-argument form remain valid.reconcileStatementjoins a multi-wire invoice row by ANY id of its segment set, all-or-nothing: a partially delivered segment set readspartial-coveragewith its delivered segments never counted as statement-only (and neverno-overlapwhen segments touched our data), and provider-reported token counts compare as the SUM over the segments against the dispatch's recorded usage. Single-wire dispatches carry none of the new fields and stay byte-identical, journals and events included.
Patch Changes
- Updated dependencies [27c4e38]
- @rulvar/[email protected]
1.127.0
Patch Changes
- Updated dependencies [b3b1805]
- @rulvar/[email protected]
1.126.0
Patch Changes
- @rulvar/[email protected]
1.125.0
Patch Changes
- @rulvar/[email protected]
1.124.0
Patch Changes
- Updated dependencies [37fd1f2]
- @rulvar/[email protected]
1.123.0
Patch Changes
- Updated dependencies [5c46468]
- @rulvar/[email protected]
1.122.0
Patch Changes
- Updated dependencies [8cf45c5]
- @rulvar/[email protected]
1.121.0
Patch Changes
- Updated dependencies [3d67d41]
- @rulvar/[email protected]
1.120.0
Patch Changes
- Updated dependencies [d630c9e]
- @rulvar/[email protected]
1.119.0
Patch Changes
- Updated dependencies [1e4ff3c]
- @rulvar/[email protected]
1.118.0
Patch Changes
- Updated dependencies [f8341a3]
- @rulvar/[email protected]
1.117.0
Patch Changes
- @rulvar/[email protected]
1.116.0
Patch Changes
- Updated dependencies [a213878]
- @rulvar/[email protected]
1.115.0
Patch Changes
- Updated dependencies [63642ae]
- @rulvar/[email protected]
1.114.0
Patch Changes
- Updated dependencies [5759731]
- @rulvar/[email protected]
1.113.0
Patch Changes
- Updated dependencies [a60807a]
- @rulvar/[email protected]
1.112.0
Patch Changes
- Updated dependencies [00ae55b]
- @rulvar/[email protected]
1.111.0
Patch Changes
- Updated dependencies [fd25169]
- @rulvar/[email protected]
1.110.0
Patch Changes
- Updated dependencies [58afdb5]
- @rulvar/[email protected]
1.109.0
Patch Changes
- Updated dependencies [85b1d39]
- @rulvar/[email protected]
1.108.0
Patch Changes
- Updated dependencies [affa3d4]
- @rulvar/[email protected]
1.107.0
Patch Changes
- Updated dependencies [9f5f6f6]
- @rulvar/[email protected]
1.106.0
Patch Changes
- Updated dependencies [9a4ce49]
- @rulvar/[email protected]
1.105.0
Minor Changes
531dc88: Make quota rules an immutable snapshot with a canonical denial order in all three limiters, and give the postgres limiter rotation generations, a fenced stale host, a bounded bootstrap, and strict intake (RV608).
Immutable snapshot (all three limiters):
memoryQuotaLimiter,SqliteQuotaLimiter, andPostgresQuotaLimiternow admit under the new exportedsnapshotQuotaRules(rules): a validated, frozen copy carrying only the known rule fields, taken at construction. Mutating the caller's array or rule objects afterwards (a pushed rule, a reassigned cap) can no longer change a decision, a bucket key, telemetry, or the fingerprint the postgres schema records; previously the caller's live graph was read on every admission and the fingerprint was computed lazily from it at first boot. The canonical per-rule content key is also exported asquotaRuleKey, and every limiter folds a denial over matching rules in that canonical order, so permuted but identical rule sets now produce the byte-identical refusal object (reason and retryAfterMs), not just the same fingerprint.Rotation generations (postgres):
rulvar_quota_metanow records a rules generation beside the fingerprint. Every admission re-reads both inside its own locked transaction and, on a mismatch, is refused with the new typedQuotaGenerationErrorinstead of admitting under retired bucket keys, so a host that booted before a rotation is fenced rather than silently splitting the budget; its next call re-boots into the honest boot-timeConfigError, and its outstanding reservations age out with their window. Rotation (acceptRulesUpdate: true) now serializes with in-flight admissions on the same advisory lock, bumps the generation, and carries current-window consumption conservatively: a new bucket inherits the retired bucket's counters for the same(provider, model, tenant)dimension triple (the maximum when several retired rules share it), so a raised cap grants only the difference, a lowered cap counts what was already consumed, and a genuinely new dimension starts empty. The carry decision is conservative by design: estimates held by fenced hosts settle nowhere and age out, which errs toward under-admission inside the rotation window, never over.Bounded bootstrap and honest deadline phases (postgres): the bootstrap transaction now runs under the same
SET LOCAL lock_timeoutas admissions (a held boot lock used to wait unboundedly), and its connection is registered with the full-path deadline, which destroys it on expiry so an abandoned bootstrap can never commit DDL or a rotation after the caller was already refused.QuotaDeadlineError.phasegains'bootstrap', and each phase's message now narrates only what actually happened: an'acquire'refusal held no connection and no longer claims one was destroyed.Strict intake (postgres):
acceptRulesUpdateis runtime-checked as a real boolean (the string"false"used to enable rotation by truthiness), andadmissionDeadlineMsis refused above the Node timer maximum (2147483647 ms, now exported from@rulvar/coreasMAX_TIMER_DELAY_MS) before the pool is constructed; above it, the deadline timer used to clamp and refuse every admission after about a millisecond.Migration note: hosts running mixed rule sets over one schema now fail loud during a rotation instead of silently splitting the budget: old booted hosts receive
QuotaGenerationErroron their next admission the moment a new deployment boots withacceptRulesUpdate: true. That refusal is the designed rollout signal, not a regression; roll the refused hosts to the new rule set and remove the flag. Existing recorded fingerprints keep matching (the key encoding is unchanged), and pre-generation schemas are backfilled to generation 1 on the first matching boot.
Patch Changes
- Updated dependencies [531dc88]
- @rulvar/[email protected]
1.104.0
Patch Changes
- @rulvar/[email protected]
1.103.0
Patch Changes
- Updated dependencies [f2b809e]
- @rulvar/[email protected]
1.102.0
Patch Changes
- Updated dependencies [3eb6515]
- @rulvar/[email protected]
1.101.0
Patch Changes
- Updated dependencies [51b215c]
- @rulvar/[email protected]
1.100.0
Patch Changes
- Updated dependencies [9785bea]
- @rulvar/[email protected]
1.99.1
Patch Changes
- Updated dependencies [ef08d73]
- @rulvar/[email protected]
1.99.0
Patch Changes
- Updated dependencies [9e00888]
- @rulvar/[email protected]
1.98.0
Minor Changes
- 6c7fbd8:
PostgresQuotaLimiterbounds each WHOLE admission path and fingerprints the shared rules (RV506). NewadmissionDeadlineMs(default the exportedQUOTA_ADMISSION_DEADLINE_MS, 5000 ms; refused at construction unless it exceeds the internalQUOTA_LOCK_TIMEOUT_MSstage bound) races lazy bootstrap, pool checkout, and the admission transaction together: before, the 2000 ms lock bound covered only the lock-wait stage, so a call could spend it once at checkout and again at the lock without ever being refused. Expiry throws a typedQuotaDeadlineErrorinto the engine'sonLimiterErrorpolicy and destroys the held connection viarelease(err)instead of returning it dirty to the pool. Boot now recordsquotaRulesFingerprint(rules)(exported; sha256 over the canonical rule keys, insensitive to array order) in a newrulvar_quota_metatable under the boot lock, and refuses an instance whose rule set drifted with a typedConfigErrornaming both hashes and the schema, so mismatched hosts can no longer silently split one budget across different bucket keys; rotation is the explicitacceptRulesUpdate: trueopt-in (enable on the new deployment, roll every host, remove the flag).
Patch Changes
- @rulvar/[email protected]
1.97.0
Patch Changes
- Updated dependencies [5c3b453]
- @rulvar/[email protected]
1.96.0
Patch Changes
- @rulvar/[email protected]
1.95.0
Minor Changes
- 2bda821:
PostgresQuotaLimiter(RV410): the multi-host reference implementation of the coreQuotaLimiterSPI. Engine processes on any number of hosts pointing instances at one database and schema enforce one global provider quota: admission consumes the window counters inside a single transaction serialized on a schema-wide advisory lock, so two hosts can never both take the last slot; reservations are rows, so reconciliation settles a grant from any host; both tables are lazily pruned to two accounting windows. The rule model, the fixed epoch-aligned one-minute windows, and the admission decision are the core's own exported functions, so this limiter,memoryQuotaLimiter, andSqliteQuotaLimiteragree byte for byte on every verdict. A call still waiting for the admission lock past the exportedQUOTA_LOCK_TIMEOUT_MS(2000 ms) throws into the engine'sonLimiterErrorpolicy instead of hanging. The durable admission queue stays the host's documented boundary: a denial carries the honest window remainder, and what to do while waiting is host policy.
Patch Changes
- @rulvar/[email protected]
1.94.0
Patch Changes
- @rulvar/[email protected]
1.93.0
Patch Changes
- Updated dependencies [c62150a]
- @rulvar/[email protected]
1.92.0
Patch Changes
- Updated dependencies [351d1f5]
- @rulvar/[email protected]
1.91.0
Patch Changes
- @rulvar/[email protected]
1.90.0
Patch Changes
- Updated dependencies [9603940]
- @rulvar/[email protected]
1.89.0
Patch Changes
- Updated dependencies [f18b671]
- Updated dependencies [f18b671]
- @rulvar/[email protected]
1.88.0
Patch Changes
- Updated dependencies [3b339d9]
- @rulvar/[email protected]
1.87.0
Patch Changes
- Updated dependencies [c4c02b1]
- @rulvar/[email protected]
1.86.0
Patch Changes
- Updated dependencies [2f71894]
- @rulvar/[email protected]
1.85.0
Patch Changes
- Updated dependencies [6932a9f]
- @rulvar/[email protected]
1.84.0
Patch Changes
- @rulvar/[email protected]
1.83.0
Patch Changes
- @rulvar/[email protected]
1.82.0
Patch Changes
- Updated dependencies [9cc5d66]
- @rulvar/[email protected]
1.81.2
Patch Changes
- Updated dependencies [296885b]
- @rulvar/[email protected]
1.81.1
Patch Changes
- Updated dependencies [c030982]
- @rulvar/[email protected]
1.81.0
Patch Changes
- Updated dependencies [ce4c392]
- @rulvar/[email protected]
1.80.0
Patch Changes
- Updated dependencies [262e397]
- @rulvar/[email protected]
1.79.0
Patch Changes
- Updated dependencies [85956ab]
- @rulvar/[email protected]
1.78.0
Patch Changes
- Updated dependencies [941b6e1]
- @rulvar/[email protected]
1.77.0
Patch Changes
- Updated dependencies [6aba271]
- @rulvar/[email protected]
1.76.0
Patch Changes
- Updated dependencies [22cba47]
- @rulvar/[email protected]
1.75.1
Patch Changes
- Updated dependencies [82bc0f0]
- @rulvar/[email protected]
1.75.0
Patch Changes
- Updated dependencies [c486de8]
- @rulvar/[email protected]
1.74.0
Patch Changes
- Updated dependencies [d94beab]
- @rulvar/[email protected]
1.73.0
Patch Changes
- Updated dependencies [3e95bd1]
- @rulvar/[email protected]
1.72.0
Patch Changes
- Updated dependencies [662e9e0]
- @rulvar/[email protected]
1.71.0
Patch Changes
- Updated dependencies [20d02e0]
- @rulvar/[email protected]
1.70.1
Patch Changes
- @rulvar/[email protected]
1.70.0
Patch Changes
- @rulvar/[email protected]
1.69.0
Patch Changes
- Updated dependencies [b21a681]
- @rulvar/[email protected]
1.68.0
Patch Changes
- Updated dependencies [b227874]
- @rulvar/[email protected]
1.67.0
Patch Changes
- Updated dependencies [8e6006d]
- @rulvar/[email protected]
1.66.0
Patch Changes
- Updated dependencies [1b8987e]
- @rulvar/[email protected]
1.65.0
Patch Changes
- Updated dependencies [0b6b859]
- @rulvar/[email protected]
1.64.0
Patch Changes
- Updated dependencies [991f9b5]
- @rulvar/[email protected]
1.63.0
Minor Changes
8a28aed: Durable settlement acknowledgement and the fencing-epoch tombstone (the 1.62.0 experiment review, P0.1 and P0.2).
Settlement acknowledgement: a NON-fencing failure of either settlement write now rejects
handle.resultwith the new typedSettlementError(codesettlement, retryable;stagenames the write,datacarries the runId and the computed run status) instead of resolving as if nothing happened. Only a superseded segment'sLeaseHeldErrorstays swallowed, on both writes, because the successor owns settlement. A failedrun_settleappend also skips the terminal meta write, so the projection can never run ahead of the journal (published 1.62.0 wrote metaokover a journal with no settle record when the append failed). Recovery is deterministic and free: the run's work entries are already durable,engine.resumereplays to the same outcome without one paid provider call and re-attempts the settlement writes (a non-empty journal with no recorded settle now re-settles on pure replay), andrulvar runs audit [--repair]reconciles offline.Fencing-epoch tombstone:
SqliteStoreandPostgresStoreno longer erase the per-run epoch high-water mark ondelete, so a recreate of the same explicit runId always acquires a strictly higher epoch and a zombie lease from the deleted incarnation (same runId, same stable owner identity) is rejected on every fenced surface instead of fencing green. TheLeasableStorecontract now states the rule, and the conformance kit enforces it with two new mandatory checks (fencing-epoch-tombstoneinleasableStoreConformance,fenced-tombstone-zombie-rejectedinfencedWritesConformance). The tombstone holds only the runId and a counter, never run content; the data-protection guide documents the erasure boundary.
Patch Changes
- Updated dependencies [8a28aed]
- @rulvar/[email protected]
1.62.0
Patch Changes
- Updated dependencies [fca5fd1]
- @rulvar/[email protected]
1.61.0
Patch Changes
- Updated dependencies [b4c1f1f]
- @rulvar/[email protected]
1.60.0
Patch Changes
- Updated dependencies [59bbeaa]
- @rulvar/[email protected]
1.59.4
Patch Changes
- Updated dependencies [c49d7a1]
- @rulvar/[email protected]
1.59.3
Patch Changes
- Updated dependencies [deaef36]
- @rulvar/[email protected]
1.59.2
Patch Changes
- Updated dependencies [dd0e10f]
- @rulvar/[email protected]
1.59.1
Patch Changes
- Updated dependencies [c127770]
- @rulvar/[email protected]
1.59.0
Patch Changes
- Updated dependencies [615dc90]
- @rulvar/[email protected]
1.58.0
Patch Changes
- Updated dependencies [4fa35ce]
- @rulvar/[email protected]
1.57.0
Minor Changes
- dc6ef2c: RV-214: the official PostgreSQL store. The new
@rulvar/store-postgrespackage shipsPostgresStore, implementing the full storage contract over node-postgres for multi-process AND multi-host deployments:JournalStoreplusLeasableStorewith fencing epochs,fencedWriteson both the journal side and thetranscripts()twin, and thegetMeta/leaseTtlMscapabilities. Payloads stay opaque TEXT (obligation A4 forbids jsonb normalization; jsonb appears only in query-side casts and expression indexes). Every run-scoped mutation runs inside one transaction that first takes a per-run advisory transaction lock, this store's translation of the sqlite BEGIN IMMEDIATE lesson: the fence check and the guarded mutation commit as ONE serialized unit across processes and hosts, at per-run granularity so unrelated runs never queue behind each other. The A5 monotonic-seq guard is one conditional INSERT under that lock, with per-instance appends chained in submission order (a genuinely async pool would otherwise let a later-submitted seq reach the server first). The lazy idempotent schema bootstrap serializes on a schema-scoped advisory lock so a fleet start over one fresh database boots clean; theschemaoption namespaces the five tables and doubles as cheap isolation. Lease expiry uses the client clock with an injectablenow(NTP-synced hosts; the 60 s default ttl dwarfs sane drift), and one write region per run is the documented boundary. The package's own suite runs the full conformance kit, cross-instance fencing over one schema, an engine-level e2e (run on one store instance, resume from another with zero adapter calls), the adversarial multi-process soak, and the fleet boot race, all against a real postgres (gated onRULVAR_POSTGRES_URL; CI provides a service container). The stores guide documents options, pooling and backpressure sizing, the clock and single-write-region boundaries, and a backup/PITR runbook.
Patch Changes
- Updated dependencies [5897232]
- @rulvar/[email protected]
@rulvar/store-sqlite
1.252.0
Patch Changes
- Updated dependencies [3ccb6cf]
- Updated dependencies [52d807f]
- Updated dependencies [517ed00]
- Updated dependencies [a7e589d]
- Updated dependencies [76e95eb]
- @rulvar/[email protected]
1.251.0
Patch Changes
- Updated dependencies [e7e829c]
- Updated dependencies [5982be8]
- Updated dependencies [7c58fb2]
- Updated dependencies [b3e465a]
- Updated dependencies [c4e5d6a]
- Updated dependencies [c6fc3da]
- Updated dependencies [c6fc3da]
- Updated dependencies [0ae8b85]
- Updated dependencies [7932936]
- Updated dependencies [7932936]
- Updated dependencies [88da0ed]
- Updated dependencies [06c0e85]
- @rulvar/[email protected]
1.250.0
Minor Changes
- c5eb19c: The restoration generation (RV4503, plan 45, rfcs/effects.md section 4.5, item 3): SqliteStore and PostgresStore implement the
EffectLaneStorecapability, carrying a restoration generation OUTSIDE the journal bytes (a one-row table beside the leases). The restore runbook is one rule: after a point-in-time restore, callbumpRestorationGeneration()BEFORE the restored database becomes reachable to any worker, so the effect lane comes up with dispatch disabled by construction until an operator appends a fresheffect_epochciting the bumped generation. The neweffectLaneStoreConformancesuite in @rulvar/store-conformance is the executable definition: generation starts at 0 and bumps monotonically (ELS1, ELS2), a bumped generation refuses every lane append until the fresh epoch (ELS3, the kill point 25 window, driven through the real writer over the real store), and a lane append under a non-current lease dies on the store's fence with nothing consumed (ELS4, the kill point 16 shape). - c6d197b: The reconciler, the trust envelope, and the whole kill point kit (RV4505, plan 45, rfcs/effects.md sections 3.1, 7, 8, 9). The sweep makes "every intent deterministically reaches confirmed, compensated, or quarantined" true: crossing
reconcileByquarantines whatever state with the state recorded, receipt waits and attempt budgets quarantine on exhaustion, lookups are bounded SEPARATELY through journaledeffect_proberows (countable from the journal alone, crash-proof), pre-terminal conflicting receipts quarantine, and effect authorizations past their deadline refuse durably instead of waiting forever. Receipt verification runs a declared trust envelope: issuer identity, per-class content bindings, key validity windows, revocation from its time forward, and the host's signature check; every failure classifies unverified, which routes to unknown. The post-restore reconciliation (kill 25) quarantines provider effects the journal cannot reconstruct by name (or the whole range without authoritative enumeration), and a restoration epoch stays undispatchable until the neweffect_reconciliation_completedecision cites it. Section 9 telemetry folds effective dispositions (the compensated overlay included), pressure, duplicate classification, and open incidents. The kit exports all thirtyeffects.kill.*rows as named conformance checks parameterized by a store factory (ambiguous acks and restoration generations injected through delegating proxies, so any store qualifies), registered over the in-memory reference store in single-process posture and over the REAL sqlite and postgres stores in their own packages. - fed9db6: Durable admission over sqlite and postgres (RV4508, plan 45, rfcs/admission.md section 9):
SqliteAdmissionSchedulerandPostgresAdmissionSchedulerpersist the scheduler's WHOLE state as one plain-JSON document (AdmissionState, now exported withsnapshot()and hydration on the reference core), committed atomically per lifecycle call inside a BEGIN IMMEDIATE transaction (sqlite) or an advisory-lock-serialized transaction (postgres). This is the RFC's first shipped durable shape, recorded as a deliberate decision: a single scheduler over durable state with deterministic ordering, where "state moved AND buckets moved" holds trivially because the whole document commits or none of it does; per-row schemas are an optimization the SPI does not require. A queued ticket survives its holder with position and arrival identity intact, re-enqueueing the same (unitId, generation) returns the SAME ticket, and settlement operation ids replay as durable no-ops across holders (a late-settlement debt entry lands exactly once).
Patch Changes
- Updated dependencies [0e240b9]
- Updated dependencies [6fe585e]
- Updated dependencies [c5eb19c]
- Updated dependencies [565c13b]
- Updated dependencies [c6d197b]
- Updated dependencies [c9d9729]
- Updated dependencies [fed9db6]
- Updated dependencies [df9ed76]
- Updated dependencies [3020912]
- Updated dependencies [d8d598d]
- @rulvar/[email protected]
1.249.0
Patch Changes
- Updated dependencies [8862133]
- Updated dependencies [0d7a717]
- Updated dependencies [e4428bd]
- Updated dependencies [d6873c1]
- Updated dependencies [4092e8d]
- Updated dependencies [e086590]
- Updated dependencies [1411938]
- Updated dependencies [737d1ee]
- Updated dependencies [634f966]
- Updated dependencies [052cc26]
- Updated dependencies [bbae134]
- @rulvar/[email protected]
1.248.0
Patch Changes
- Updated dependencies [8d0cd69]
- Updated dependencies [81065e4]
- Updated dependencies [8573f20]
- Updated dependencies [95f6a5e]
- @rulvar/[email protected]
1.247.0
Patch Changes
- Updated dependencies [1933ecc]
- Updated dependencies [db0a5f0]
- Updated dependencies [b698726]
- Updated dependencies [48348d2]
- Updated dependencies [4cfa1cc]
- Updated dependencies [4b7197a]
- Updated dependencies [5ebc842]
- Updated dependencies [16ff6b9]
- Updated dependencies [0c9941d]
- @rulvar/[email protected]
1.246.0
Patch Changes
- Updated dependencies [d165b0c]
- Updated dependencies [d59f4a0]
- Updated dependencies [46907ac]
- Updated dependencies [9929ad3]
- Updated dependencies [1790a6a]
- @rulvar/[email protected]
1.245.0
Patch Changes
- Updated dependencies [b4d47a8]
- Updated dependencies [dee6db4]
- Updated dependencies [b85c113]
- Updated dependencies [bc556e7]
- Updated dependencies [9f11d29]
- Updated dependencies [19bcea0]
- Updated dependencies [60b461c]
- Updated dependencies [61e3a1a]
- Updated dependencies [a156b81]
- Updated dependencies [0bd7045]
- @rulvar/[email protected]
1.244.0
Patch Changes
- Updated dependencies [38d839a]
- Updated dependencies [ce13b0f]
- Updated dependencies [4fa23e3]
- Updated dependencies [6841c69]
- Updated dependencies [f56721d]
- Updated dependencies [c894a43]
- Updated dependencies [f6944a3]
- Updated dependencies [23fd0e0]
- @rulvar/[email protected]
1.243.0
Patch Changes
- Updated dependencies [746d1f4]
- Updated dependencies [009b29c]
- Updated dependencies [1674cbe]
- Updated dependencies [bd096bc]
- @rulvar/[email protected]
1.242.0
Patch Changes
- Updated dependencies [6e3438e]
- Updated dependencies [ba5cf67]
- Updated dependencies [c2d1531]
- @rulvar/[email protected]
1.241.0
Patch Changes
- Updated dependencies [dbcdd24]
- Updated dependencies [7ae7243]
- Updated dependencies [4f832c4]
- Updated dependencies [7452d3d]
- Updated dependencies [a4e22bf]
- Updated dependencies [82df4af]
- @rulvar/[email protected]
1.240.0
Patch Changes
- @rulvar/[email protected]
1.239.0
Patch Changes
- Updated dependencies [74ce99a]
- Updated dependencies [ccd0665]
- Updated dependencies [0c5ce21]
- Updated dependencies [0616934]
- @rulvar/[email protected]
1.238.0
Patch Changes
- Updated dependencies [cf00947]
- Updated dependencies [c7b9382]
- Updated dependencies [88aea96]
- Updated dependencies [6da8d05]
- Updated dependencies [eae5c4c]
- @rulvar/[email protected]
1.237.0
Patch Changes
- Updated dependencies [9d6a279]
- Updated dependencies [49a98f6]
- Updated dependencies [a734ca0]
- Updated dependencies [deb406f]
- @rulvar/[email protected]
1.236.0
Patch Changes
- Updated dependencies [26306ea]
- Updated dependencies [709b942]
- @rulvar/[email protected]
1.235.0
Patch Changes
- Updated dependencies [ba4e10d]
- Updated dependencies [172402b]
- Updated dependencies [2ecd787]
- Updated dependencies [e20a5e9]
- Updated dependencies [98c8691]
- Updated dependencies [c70def0]
- @rulvar/[email protected]
1.234.0
Patch Changes
- Updated dependencies [8420c04]
- @rulvar/[email protected]
1.233.0
Patch Changes
- Updated dependencies [48b5200]
- Updated dependencies [73bc32b]
- Updated dependencies [e63b743]
- Updated dependencies [ef45da7]
- @rulvar/[email protected]
1.232.0
Patch Changes
- Updated dependencies [1440410]
- Updated dependencies [6e467f4]
- Updated dependencies [0b14293]
- Updated dependencies [e3bcab2]
- Updated dependencies [b55a0f7]
- @rulvar/[email protected]
1.231.0
Patch Changes
- Updated dependencies [4eb4b56]
- Updated dependencies [bc8f09e]
- Updated dependencies [ff9b8c2]
- @rulvar/[email protected]
1.230.0
Patch Changes
- Updated dependencies [e9bf910]
- Updated dependencies [57bfb38]
- @rulvar/[email protected]
1.229.0
Patch Changes
- Updated dependencies [3370342]
- Updated dependencies [2fb6656]
- Updated dependencies [edce170]
- @rulvar/[email protected]
1.228.0
Patch Changes
- Updated dependencies [4034fac]
- Updated dependencies [a54b085]
- Updated dependencies [9d0a9be]
- Updated dependencies [be9ef28]
- @rulvar/[email protected]
1.227.0
Patch Changes
- Updated dependencies [f262e9f]
- Updated dependencies [f191ff7]
- Updated dependencies [fbbfbe8]
- Updated dependencies [263b5e8]
- Updated dependencies [db4d56d]
- Updated dependencies [41f93a9]
- Updated dependencies [98c8ca9]
- @rulvar/[email protected]
1.226.0
Patch Changes
- @rulvar/[email protected]
1.225.0
Patch Changes
- @rulvar/[email protected]
1.224.0
Patch Changes
- Updated dependencies [4eca1a3]
- @rulvar/[email protected]
1.223.0
Patch Changes
- Updated dependencies [549aabd]
- Updated dependencies [549aabd]
- @rulvar/[email protected]
1.222.0
Patch Changes
- Updated dependencies [8326268]
- @rulvar/[email protected]
1.221.0
Patch Changes
- Updated dependencies [032ce93]
- @rulvar/[email protected]
1.220.0
Patch Changes
- Updated dependencies [0babe70]
- @rulvar/[email protected]
1.219.0
Patch Changes
- Updated dependencies [65a4ce7]
- @rulvar/[email protected]
1.218.0
Patch Changes
- Updated dependencies [088bda6]
- @rulvar/[email protected]
1.217.0
Patch Changes
- Updated dependencies [ab80b97]
- @rulvar/[email protected]
1.216.0
Patch Changes
- Updated dependencies [b357f4a]
- @rulvar/[email protected]
1.215.0
Patch Changes
- Updated dependencies [e1da4c7]
- @rulvar/[email protected]
1.214.0
Patch Changes
- Updated dependencies [c8af0ec]
- @rulvar/[email protected]
1.213.0
Patch Changes
- Updated dependencies [61680df]
- @rulvar/[email protected]
1.212.0
Patch Changes
- Updated dependencies [e6f8516]
- @rulvar/[email protected]
1.211.0
Patch Changes
- Updated dependencies [d5a8a36]
- @rulvar/[email protected]
1.210.0
Patch Changes
- Updated dependencies [c871ddc]
- @rulvar/[email protected]
1.209.0
Patch Changes
- Updated dependencies [514c7bb]
- @rulvar/[email protected]
1.208.0
Patch Changes
- Updated dependencies [e7d426f]
- @rulvar/[email protected]
1.207.0
Patch Changes
- Updated dependencies [99beee2]
- @rulvar/[email protected]
1.206.0
Patch Changes
- Updated dependencies [ec8e1f1]
- @rulvar/[email protected]
1.205.0
Patch Changes
- Updated dependencies [6d224da]
- @rulvar/[email protected]
1.204.0
Patch Changes
- Updated dependencies [efaec9b]
- @rulvar/[email protected]
1.203.0
Patch Changes
- Updated dependencies [fb08c10]
- @rulvar/[email protected]
1.202.0
Patch Changes
- @rulvar/[email protected]
1.201.0
Patch Changes
- Updated dependencies [7e01189]
- @rulvar/[email protected]
1.200.0
Patch Changes
- Updated dependencies [e2ddbdf]
- @rulvar/[email protected]
1.199.0
Patch Changes
- Updated dependencies [29891c6]
- @rulvar/[email protected]
1.198.0
Patch Changes
- Updated dependencies [c097c96]
- @rulvar/[email protected]
1.197.0
Patch Changes
- @rulvar/[email protected]
1.196.0
Patch Changes
- Updated dependencies [ec9c3e3]
- @rulvar/[email protected]
1.195.0
Patch Changes
- Updated dependencies [5702a70]
- @rulvar/[email protected]
1.194.0
Patch Changes
- Updated dependencies [360a659]
- @rulvar/[email protected]
1.193.0
Patch Changes
- Updated dependencies [2bca1d1]
- @rulvar/[email protected]
1.192.0
Patch Changes
- Updated dependencies [8757601]
- @rulvar/[email protected]
1.191.0
Patch Changes
- Updated dependencies [745387c]
- @rulvar/[email protected]
1.190.0
Patch Changes
- Updated dependencies [8e02021]
- @rulvar/[email protected]
1.189.0
Patch Changes
- Updated dependencies [6a5cc2d]
- @rulvar/[email protected]
1.188.0
Patch Changes
- @rulvar/[email protected]
1.187.0
Patch Changes
- Updated dependencies [c9798ef]
- @rulvar/[email protected]
1.186.0
Patch Changes
- Updated dependencies [242647e]
- @rulvar/[email protected]
1.185.0
Patch Changes
- Updated dependencies [1248623]
- @rulvar/[email protected]
1.184.0
Patch Changes
- Updated dependencies [8a9caca]
- @rulvar/[email protected]
1.183.0
Patch Changes
- Updated dependencies [dd3767c]
- @rulvar/[email protected]
1.182.0
Patch Changes
- Updated dependencies [144d026]
- @rulvar/[email protected]
1.181.0
Patch Changes
- @rulvar/[email protected]
1.180.0
Patch Changes
- Updated dependencies [b124d26]
- @rulvar/[email protected]
1.179.0
Patch Changes
- Updated dependencies [1a5a85a]
- @rulvar/[email protected]
1.178.0
Patch Changes
- @rulvar/[email protected]
1.177.0
Patch Changes
- Updated dependencies [94db8ff]
- @rulvar/[email protected]
1.176.0
Patch Changes
- Updated dependencies [a74304d]
- @rulvar/[email protected]
1.175.0
Patch Changes
- Updated dependencies [1999c5d]
- @rulvar/[email protected]
1.174.0
Patch Changes
- Updated dependencies [aa9a772]
- @rulvar/[email protected]
1.173.0
Patch Changes
- Updated dependencies [67d27ac]
- @rulvar/[email protected]
1.172.0
Patch Changes
- Updated dependencies [0d4770b]
- @rulvar/[email protected]
1.171.0
Patch Changes
- Updated dependencies [f6116b9]
- @rulvar/[email protected]
1.170.0
Patch Changes
- Updated dependencies [86e4c06]
- @rulvar/[email protected]
1.169.0
Patch Changes
- Updated dependencies [623b2ae]
- @rulvar/[email protected]
1.168.0
Patch Changes
- Updated dependencies [ebba79a]
- @rulvar/[email protected]
1.167.0
Patch Changes
- @rulvar/[email protected]
1.166.0
Patch Changes
- Updated dependencies [d8262c3]
- @rulvar/[email protected]
1.165.0
Patch Changes
- Updated dependencies [6391274]
- @rulvar/[email protected]
1.164.0
Patch Changes
- Updated dependencies [9f2dda9]
- @rulvar/[email protected]
1.163.0
Patch Changes
- Updated dependencies [e8d9ada]
- @rulvar/[email protected]
1.162.0
Patch Changes
- Updated dependencies [2031e82]
- @rulvar/[email protected]
1.161.0
Patch Changes
- Updated dependencies [d4547b7]
- @rulvar/[email protected]
1.160.0
Patch Changes
- Updated dependencies [1c6f0d0]
- @rulvar/[email protected]
1.159.0
Patch Changes
- Updated dependencies [e881c8b]
- @rulvar/[email protected]
1.158.0
Patch Changes
- Updated dependencies [a266bc7]
- @rulvar/[email protected]
1.157.0
Patch Changes
- Updated dependencies [1883421]
- @rulvar/[email protected]
1.156.0
Patch Changes
- Updated dependencies [537144e]
- @rulvar/[email protected]
1.155.0
Patch Changes
- Updated dependencies [49b08a7]
- @rulvar/[email protected]
1.154.0
Patch Changes
- Updated dependencies [9259f24]
- @rulvar/[email protected]
1.153.0
Patch Changes
- Updated dependencies [d8bebcb]
- @rulvar/[email protected]
1.152.0
Patch Changes
- Updated dependencies [dd6a616]
- @rulvar/[email protected]
1.151.0
Patch Changes
- Updated dependencies [1de0610]
- @rulvar/[email protected]
1.150.0
Patch Changes
- Updated dependencies [a331211]
- @rulvar/[email protected]
1.149.0
Patch Changes
- Updated dependencies [08b4537]
- @rulvar/[email protected]
1.148.0
Patch Changes
- Updated dependencies [c85dac9]
- @rulvar/[email protected]
1.147.0
Patch Changes
- Updated dependencies [6367231]
- @rulvar/[email protected]
1.146.0
Patch Changes
- Updated dependencies [5d9bbc8]
- @rulvar/[email protected]
1.145.0
Patch Changes
- @rulvar/[email protected]
1.144.0
Patch Changes
- Updated dependencies [c11bcd6]
- @rulvar/[email protected]
1.143.0
Patch Changes
- Updated dependencies [f412169]
- @rulvar/[email protected]
1.142.0
Patch Changes
- @rulvar/[email protected]
1.141.0
Patch Changes
- Updated dependencies [4f12a62]
- @rulvar/[email protected]
1.140.0
Minor Changes
- 3044838: Both store limiters implement the optional
QuotaLimiter.release(RV1103 + RV1104, the SPI method from RV1013): a cancelled admission returns exactly what it consumed, the admitted requests and the token estimate, to the window, from any process sharing the file (SqliteQuotaLimiter) or any host sharing the schema (PostgresQuotaLimiter, under the same advisory lock and generation fence as every admission). Unknown, expired, and repeated ids are no-ops; a rolled-over window already aged the estimate out; a released id settles nothing afterwards; verdicts mirrormemoryQuotaLimiterexactly. Both reservation tables grew arequestscolumn, migrated in place on boot (sqlite: a serializedALTERunderBEGIN IMMEDIATE; postgres:ADD COLUMN IF NOT EXISTSunder the boot lock) defaulting to 1, the single request every engine admission reserves, so pre-release reservations release exactly what their admission consumed.
Patch Changes
- @rulvar/[email protected]
1.139.0
Patch Changes
- Updated dependencies [03a2141]
- @rulvar/[email protected]
1.138.0
Patch Changes
- Updated dependencies [ed0c4fb]
- @rulvar/[email protected]
1.137.0
Patch Changes
- Updated dependencies [96f6788]
- @rulvar/[email protected]
1.136.0
Patch Changes
- Updated dependencies [aa6ca71]
- @rulvar/[email protected]
1.135.0
Patch Changes
- Updated dependencies [cf75e22]
- @rulvar/[email protected]
1.134.0
Patch Changes
- @rulvar/[email protected]
1.133.0
Patch Changes
- @rulvar/[email protected]
1.132.0
Patch Changes
- Updated dependencies [2bec904]
- @rulvar/[email protected]
1.131.0
Patch Changes
- Updated dependencies [256cae1]
- @rulvar/[email protected]
1.130.0
Patch Changes
- Updated dependencies [d6bec7a]
- @rulvar/[email protected]
1.129.0
Patch Changes
- Updated dependencies [1612439]
- @rulvar/[email protected]
1.128.0
Minor Changes
27c4e38: pause_turn continuations become accounted wire units (RV905, the thirteenth experiment's fifth release risk). The Anthropic adapter absorbs server-side turn pauses by re-sending, making up to six wire requests inside ONE core dispatch; until now the request quota window, the provider call record, and the invoice row all saw one, and a per-request provider statement matched one segment while the rest read statement-only.
The adapter's finish metadata now names the whole segment set (
providerMetadata.anthropic.wireRequests = { count, responseIds }); the provider call record and the invoice row carrywireResponseIds; and the quota reconciliation settles the reservation against the TRUE wire request count. TheQuotaLimiter.reconcileSPI gains an optionalactual.requestsargument, honored by all three reference limiters through one shared arithmetic (quotaActualRequestsDelta), so a window that admitted one request per reservation now reflects what the provider's own RPM meter saw; a settlement only ever adds, never denies retroactively, and implementations written against the two-argument form remain valid.reconcileStatementjoins a multi-wire invoice row by ANY id of its segment set, all-or-nothing: a partially delivered segment set readspartial-coveragewith its delivered segments never counted as statement-only (and neverno-overlapwhen segments touched our data), and provider-reported token counts compare as the SUM over the segments against the dispatch's recorded usage. Single-wire dispatches carry none of the new fields and stay byte-identical, journals and events included.
Patch Changes
- Updated dependencies [27c4e38]
- @rulvar/[email protected]
1.127.0
Patch Changes
- Updated dependencies [b3b1805]
- @rulvar/[email protected]
1.126.0
Patch Changes
- @rulvar/[email protected]
1.125.0
Patch Changes
- @rulvar/[email protected]
1.124.0
Patch Changes
- Updated dependencies [37fd1f2]
- @rulvar/[email protected]
1.123.0
Patch Changes
- Updated dependencies [5c46468]
- @rulvar/[email protected]
1.122.0
Patch Changes
- Updated dependencies [8cf45c5]
- @rulvar/[email protected]
1.121.0
Patch Changes
- Updated dependencies [3d67d41]
- @rulvar/[email protected]
1.120.0
Patch Changes
- Updated dependencies [d630c9e]
- @rulvar/[email protected]
1.119.0
Patch Changes
- Updated dependencies [1e4ff3c]
- @rulvar/[email protected]
1.118.0
Patch Changes
- Updated dependencies [f8341a3]
- @rulvar/[email protected]
1.117.0
Patch Changes
- @rulvar/[email protected]
1.116.0
Patch Changes
- Updated dependencies [a213878]
- @rulvar/[email protected]
1.115.0
Patch Changes
- Updated dependencies [63642ae]
- @rulvar/[email protected]
1.114.0
Patch Changes
- Updated dependencies [5759731]
- @rulvar/[email protected]
1.113.0
Patch Changes
- Updated dependencies [a60807a]
- @rulvar/[email protected]
1.112.0
Patch Changes
- Updated dependencies [00ae55b]
- @rulvar/[email protected]
1.111.0
Patch Changes
- Updated dependencies [fd25169]
- @rulvar/[email protected]
1.110.0
Patch Changes
- Updated dependencies [58afdb5]
- @rulvar/[email protected]
1.109.0
Patch Changes
- Updated dependencies [85b1d39]
- @rulvar/[email protected]
1.108.0
Patch Changes
- Updated dependencies [affa3d4]
- @rulvar/[email protected]
1.107.0
Patch Changes
- Updated dependencies [9f5f6f6]
- @rulvar/[email protected]
1.106.0
Patch Changes
- Updated dependencies [9a4ce49]
- @rulvar/[email protected]
1.105.0
Minor Changes
531dc88: Make quota rules an immutable snapshot with a canonical denial order in all three limiters, and give the postgres limiter rotation generations, a fenced stale host, a bounded bootstrap, and strict intake (RV608).
Immutable snapshot (all three limiters):
memoryQuotaLimiter,SqliteQuotaLimiter, andPostgresQuotaLimiternow admit under the new exportedsnapshotQuotaRules(rules): a validated, frozen copy carrying only the known rule fields, taken at construction. Mutating the caller's array or rule objects afterwards (a pushed rule, a reassigned cap) can no longer change a decision, a bucket key, telemetry, or the fingerprint the postgres schema records; previously the caller's live graph was read on every admission and the fingerprint was computed lazily from it at first boot. The canonical per-rule content key is also exported asquotaRuleKey, and every limiter folds a denial over matching rules in that canonical order, so permuted but identical rule sets now produce the byte-identical refusal object (reason and retryAfterMs), not just the same fingerprint.Rotation generations (postgres):
rulvar_quota_metanow records a rules generation beside the fingerprint. Every admission re-reads both inside its own locked transaction and, on a mismatch, is refused with the new typedQuotaGenerationErrorinstead of admitting under retired bucket keys, so a host that booted before a rotation is fenced rather than silently splitting the budget; its next call re-boots into the honest boot-timeConfigError, and its outstanding reservations age out with their window. Rotation (acceptRulesUpdate: true) now serializes with in-flight admissions on the same advisory lock, bumps the generation, and carries current-window consumption conservatively: a new bucket inherits the retired bucket's counters for the same(provider, model, tenant)dimension triple (the maximum when several retired rules share it), so a raised cap grants only the difference, a lowered cap counts what was already consumed, and a genuinely new dimension starts empty. The carry decision is conservative by design: estimates held by fenced hosts settle nowhere and age out, which errs toward under-admission inside the rotation window, never over.Bounded bootstrap and honest deadline phases (postgres): the bootstrap transaction now runs under the same
SET LOCAL lock_timeoutas admissions (a held boot lock used to wait unboundedly), and its connection is registered with the full-path deadline, which destroys it on expiry so an abandoned bootstrap can never commit DDL or a rotation after the caller was already refused.QuotaDeadlineError.phasegains'bootstrap', and each phase's message now narrates only what actually happened: an'acquire'refusal held no connection and no longer claims one was destroyed.Strict intake (postgres):
acceptRulesUpdateis runtime-checked as a real boolean (the string"false"used to enable rotation by truthiness), andadmissionDeadlineMsis refused above the Node timer maximum (2147483647 ms, now exported from@rulvar/coreasMAX_TIMER_DELAY_MS) before the pool is constructed; above it, the deadline timer used to clamp and refuse every admission after about a millisecond.Migration note: hosts running mixed rule sets over one schema now fail loud during a rotation instead of silently splitting the budget: old booted hosts receive
QuotaGenerationErroron their next admission the moment a new deployment boots withacceptRulesUpdate: true. That refusal is the designed rollout signal, not a regression; roll the refused hosts to the new rule set and remove the flag. Existing recorded fingerprints keep matching (the key encoding is unchanged), and pre-generation schemas are backfilled to generation 1 on the first matching boot.
Patch Changes
- Updated dependencies [531dc88]
- @rulvar/[email protected]
1.104.0
Patch Changes
- @rulvar/[email protected]
1.103.0
Patch Changes
- Updated dependencies [f2b809e]
- @rulvar/[email protected]
1.102.0
Patch Changes
- Updated dependencies [3eb6515]
- @rulvar/[email protected]
1.101.0
Patch Changes
- Updated dependencies [51b215c]
- @rulvar/[email protected]
1.100.0
Patch Changes
- Updated dependencies [9785bea]
- @rulvar/[email protected]
1.99.1
Patch Changes
- Updated dependencies [ef08d73]
- @rulvar/[email protected]
1.99.0
Patch Changes
- Updated dependencies [9e00888]
- @rulvar/[email protected]
1.98.0
Patch Changes
- @rulvar/[email protected]
1.97.0
Patch Changes
- Updated dependencies [5c3b453]
- @rulvar/[email protected]
1.96.0
Patch Changes
- @rulvar/[email protected]
1.95.0
Patch Changes
- @rulvar/[email protected]
1.94.0
Patch Changes
- @rulvar/[email protected]
1.93.0
Patch Changes
- Updated dependencies [c62150a]
- @rulvar/[email protected]
1.92.0
Patch Changes
- Updated dependencies [351d1f5]
- @rulvar/[email protected]
1.91.0
Patch Changes
- @rulvar/[email protected]
1.90.0
Patch Changes
- Updated dependencies [9603940]
- @rulvar/[email protected]
1.89.0
Patch Changes
- Updated dependencies [f18b671]
- Updated dependencies [f18b671]
- @rulvar/[email protected]
1.88.0
Patch Changes
- Updated dependencies [3b339d9]
- @rulvar/[email protected]
1.87.0
Patch Changes
- Updated dependencies [c4c02b1]
- @rulvar/[email protected]
1.86.0
Patch Changes
- Updated dependencies [2f71894]
- @rulvar/[email protected]
1.85.0
Patch Changes
- Updated dependencies [6932a9f]
- @rulvar/[email protected]
1.84.0
Patch Changes
- @rulvar/[email protected]
1.83.0
Patch Changes
- @rulvar/[email protected]
1.82.0
Patch Changes
- Updated dependencies [9cc5d66]
- @rulvar/[email protected]
1.81.2
Patch Changes
- Updated dependencies [296885b]
- @rulvar/[email protected]
1.81.1
Patch Changes
- Updated dependencies [c030982]
- @rulvar/[email protected]
1.81.0
Patch Changes
- Updated dependencies [ce4c392]
- @rulvar/[email protected]
1.80.0
Patch Changes
- Updated dependencies [262e397]
- @rulvar/[email protected]
1.79.0
Patch Changes
- Updated dependencies [85956ab]
- @rulvar/[email protected]
1.78.0
Patch Changes
- Updated dependencies [941b6e1]
- @rulvar/[email protected]
1.77.0
Patch Changes
- Updated dependencies [6aba271]
- @rulvar/[email protected]
1.76.0
Patch Changes
- Updated dependencies [22cba47]
- @rulvar/[email protected]
1.75.1
Patch Changes
- Updated dependencies [82bc0f0]
- @rulvar/[email protected]
1.75.0
Patch Changes
- Updated dependencies [c486de8]
- @rulvar/[email protected]
1.74.0
Patch Changes
- Updated dependencies [d94beab]
- @rulvar/[email protected]
1.73.0
Patch Changes
- Updated dependencies [3e95bd1]
- @rulvar/[email protected]
1.72.0
Patch Changes
- Updated dependencies [662e9e0]
- @rulvar/[email protected]
1.71.0
Patch Changes
- Updated dependencies [20d02e0]
- @rulvar/[email protected]
1.70.1
Patch Changes
- @rulvar/[email protected]
1.70.0
Patch Changes
- @rulvar/[email protected]
1.69.0
Patch Changes
- Updated dependencies [b21a681]
- @rulvar/[email protected]
1.68.0
Patch Changes
- Updated dependencies [b227874]
- @rulvar/[email protected]
1.67.0
Patch Changes
- Updated dependencies [8e6006d]
- @rulvar/[email protected]
1.66.0
Patch Changes
- Updated dependencies [1b8987e]
- @rulvar/[email protected]
1.65.0
Patch Changes
- Updated dependencies [0b6b859]
- @rulvar/[email protected]
1.64.0
Patch Changes
- Updated dependencies [991f9b5]
- @rulvar/[email protected]
1.63.0
Minor Changes
8a28aed: Durable settlement acknowledgement and the fencing-epoch tombstone (the 1.62.0 experiment review, P0.1 and P0.2).
Settlement acknowledgement: a NON-fencing failure of either settlement write now rejects
handle.resultwith the new typedSettlementError(codesettlement, retryable;stagenames the write,datacarries the runId and the computed run status) instead of resolving as if nothing happened. Only a superseded segment'sLeaseHeldErrorstays swallowed, on both writes, because the successor owns settlement. A failedrun_settleappend also skips the terminal meta write, so the projection can never run ahead of the journal (published 1.62.0 wrote metaokover a journal with no settle record when the append failed). Recovery is deterministic and free: the run's work entries are already durable,engine.resumereplays to the same outcome without one paid provider call and re-attempts the settlement writes (a non-empty journal with no recorded settle now re-settles on pure replay), andrulvar runs audit [--repair]reconciles offline.Fencing-epoch tombstone:
SqliteStoreandPostgresStoreno longer erase the per-run epoch high-water mark ondelete, so a recreate of the same explicit runId always acquires a strictly higher epoch and a zombie lease from the deleted incarnation (same runId, same stable owner identity) is rejected on every fenced surface instead of fencing green. TheLeasableStorecontract now states the rule, and the conformance kit enforces it with two new mandatory checks (fencing-epoch-tombstoneinleasableStoreConformance,fenced-tombstone-zombie-rejectedinfencedWritesConformance). The tombstone holds only the runId and a counter, never run content; the data-protection guide documents the erasure boundary.
Patch Changes
- Updated dependencies [8a28aed]
- @rulvar/[email protected]
1.62.0
Patch Changes
- Updated dependencies [fca5fd1]
- @rulvar/[email protected]
1.61.0
Patch Changes
- Updated dependencies [b4c1f1f]
- @rulvar/[email protected]
1.60.0
Patch Changes
- Updated dependencies [59bbeaa]
- @rulvar/[email protected]
1.59.4
Patch Changes
- Updated dependencies [c49d7a1]
- @rulvar/[email protected]
1.59.3
Patch Changes
- Updated dependencies [deaef36]
- @rulvar/[email protected]
1.59.2
Patch Changes
- Updated dependencies [dd0e10f]
- @rulvar/[email protected]
1.59.1
Patch Changes
- Updated dependencies [c127770]
- @rulvar/[email protected]
1.59.0
Patch Changes
- Updated dependencies [615dc90]
- @rulvar/[email protected]
1.58.0
Patch Changes
- Updated dependencies [4fa35ce]
- @rulvar/[email protected]
1.57.0
Patch Changes
- 5897232: Two follow-ups from the RV-210 and RV-215 cycles. (1) Resume of a run that already SETTLED ok no longer re-dispatches plain cap-expiry
limitchildren live: the canonical replay predicate now takes arunSettledOkinput (computed by the engine from the loaded journal's run settle entry), and the memoize-limit rule replays unstamped limit entries when the run is finished history, so resuming a completed run makes ZERO adapter calls andreplay --assert-no-livestyle verification holds. Non-ok settles and never-settled journals keep the rerun retry semantics (a crashed segment still resumes into a second chance), and an explicit invalidate still forces a rerun. (2)SqliteQuotaLimitercarries its own class TSDoc (the api page previously inherited the bare SPI interface line), documenting the single-transaction admission, cross-process reconciliation, identical-rules requirement, pruning, and the busy_timeout contract. - Updated dependencies [5897232]
- @rulvar/[email protected]
1.56.0
Minor Changes
- f26dba0: RV-215: distributed provider limiting. The new
QuotaLimiterSPI is the extension seam for SHARED rate/quota limiting across engine instances and OS processes:createEngine({quota: {limiter, tenant?, onLimiterError?}})makes the engine reserve capacity before EVERY live wire dispatch (initial attempts, transport retries, and failover takeovers alike, in every phase), dimensioned by provider/model/tenant with a heuristic token estimate, and reconcile each granted reservation with the attempt's actual usage after the outcome settles. A denial becomes a synthetic rate-limit-class WireError that rides the existing provider-429 retry and failover machinery verbatim, except no wire call is paid: the limiter's retryAfterMs (the honest window remainder) drives the interruptible backoff, attempts stay bounded by RetryPolicy, exhaustion fails over (the takeover reserves under its own model), and the terminal is the typederrorof kindrate-limit.onLimiterErrordecides what a limiter INFRASTRUCTURE failure means:'deny'(default) fails closed as a retryable transport-class denial,'allow'logs a warning and dispatches without a reservation. Quota admission is live-only by construction (nothing journaled; replay and resume of memoized work never touch the limiter), and an unconfigured engine takes the exact pre-quota dispatch path down to promise-tick identity. Two reference implementations share one rule model (QuotaRule: optional provider/model/tenant dimensions;requestsPerMinuteexact and hard,tokensPerMinuteestimated at admission and settled to actual; every matching rule must admit; fixed epoch-aligned one-minute windows;validateQuotaRulesat intake):memoryQuotaLimiterin @rulvar/core coordinates engines inside one process, andSqliteQuotaLimiterin @rulvar/store-sqlite coordinates PROCESSES over one database file, with admission inside a single BEGIN IMMEDIATE transaction, cross-process reconciliation via reservation rows, lazy two-window pruning, and the store's boot-scoped busy retry; a multi-process test fleet of real engines proves the global cap holds (dispatched wire calls exactly equal recorded window consumption, no window over cap).createTestEnginein @rulvar/testing passes aquotaoption through to the engine.
Patch Changes
- Updated dependencies [f26dba0]
- @rulvar/[email protected]
1.55.0
Patch Changes
- Updated dependencies [e9b005b]
- @rulvar/[email protected]
1.54.0
Patch Changes
- Updated dependencies [3f6bc03]
- @rulvar/[email protected]
1.53.0
Patch Changes
- Updated dependencies [b821bd1]
- @rulvar/[email protected]
1.52.0
Patch Changes
- Updated dependencies [e138df9]
- @rulvar/[email protected]
1.51.0
Patch Changes
- @rulvar/[email protected]
1.50.0
Patch Changes
- Updated dependencies [e39a885]
- @rulvar/[email protected]
1.49.0
Patch Changes
- Updated dependencies [bab7b2c]
- @rulvar/[email protected]
1.48.0
Patch Changes
96093ea: Ship the adversarial multi-process soak and fix the SqliteStore concurrent-boot race it found (the fenced run state RFC, phase 3's last open item).
The conformance kit gains the soak harness:
runMultiProcessSoakspawns real OS processes that storm one store location through EVERY fenced write surface (journal append, meta write, transcript blob put and delete, fenced run deletion, renew, release) with stalls injected past the lease ttl, then rebuilds the one serial history the fencing epochs promise (accepted mutations ordered by epoch and per-tenure counter) and diffs it against the actual journal, meta row, and blobs. Any stale acceptance, lost accepted write, epoch inversion, or divergent final byte is a violation. The stale probe sweep re-reads the journal tail before each stale append attempt, so the monotonic-seq guard cannot mask a fencing hole; a live lease is also probed against a foreign run, and side runs get full create-and-fenced-delete cycles. The storm runs until an activity quorum is met (takeovers, per-surface accepted writes, typed stale rejections), so a slow machine storms longer instead of asserting on thin coverage. The child side isrunSoakWriterplussoakWriterConfigFromEnv(the consumer's writer script constructs its store bare and passes aretryablehook for backend contention errors); the pure refereeverifySoakHistory, the report toolsparseSoakReportandcountSoakActivity, and the quorum types are exported alongside.The soak's first storm against the published 1.47.0 never reached the fencing: N processes constructing
SqliteStoreover one SAME fresh file (an ordinary fleet start) collided in the constructor's schema bootstrap and the losers died with a raw SQLITE_BUSY (a 60 percent crash rate at six concurrent boots). A driver busy_timeout is not enough because the journal-mode conversion skips the busy handler on some lock transitions, so the constructor now retries the idempotent bootstrap as a unit through the SQLITE_BUSY family (extended result codes included, e.g. SQLITE_BUSY_RECOVERY while a sibling recovers the fresh WAL) under a wall-clock bound, exported asBOOT_BUSY_TIMEOUT_MS. Every runtime contention path keeps the documented fail-fast semantics. With the fix, 480 of 480 concurrent boots succeed, and the full storm (five writers, hundreds of takeovers, thousands of stale probes) holds every fenced surface with zero violations;SqliteStorenow runs the soak and a concurrent-boot regression in its test suite.- @rulvar/[email protected]
1.47.0
Patch Changes
- Updated dependencies [a3687fe]
- @rulvar/[email protected]
1.46.0
Minor Changes
- 865e7bf: Close finding F2 of the fenced run state RFC with the sqlite transcript twin.
SqliteStore.transcripts()returns aTranscriptStorethat declaresfencedWritesbecause its blobs live in the store's own database, beside the lease rows: a lease-carryingputordeleteverifies the current holder of the run the ref's leading path segment names atomically with the blob mutation, in the same one-immediate-transaction shape as the journal side, and rejects stale or cross-run holders with the typedLeaseHeldErrorleaving the prior blob byte intact. Demonstrated against the published 1.45.0 first: the engine threaded the superseded segment's lease into its late checkpoint save, both shipped transcript stores ignored it, and the blob at the deterministic ref both segments share regressed to older turn state (the state a later boot decodes, replaying turns the successor already paid for) while the same holder's journal append bounced typed. Over the{ journal: store, transcripts: store.transcripts() }pair,assertFencedWritesnow passes and every durable run mutation is fenced. The conformance kit gainsfencedTranscriptsConformance, the executable definition of the transcript-side promise, taking a factory for the pair that shares the fencing domain; staleness is produced with release plus reacquire, so the suite needs no wall sleeps.
Patch Changes
- Updated dependencies [865e7bf]
- @rulvar/[email protected]
1.45.0
Minor Changes
- b96305d: The fenced writes capability (the fenced run state RFC, phase 2).
JournalStore.putMetaanddeleteandTranscriptStore.putanddeleteaccept the same optional trailing lease thatappendalways took, and a store declares enforcement with thefencedWrites: truemarker: a mutation carrying a lease that is not the current holder for the mutated run rejects with the typedLeaseHeldError, atomically and leaving nothing changed, including a live lease for a different run. The engine threads the segment's lease into every durable mutation of a leased resume (meta writes, checkpoints, compaction summaries, worktree patches, workflow sources), so over a declaring store a superseded worker can no longer overwrite the successor's meta at its late settle and strand the run from worker sweeps, and its very first refused meta write now fails the stale segment typed at boot with zero paid calls.SqliteStoredeclares the marker and enforces it onputMeta,delete, andappend(with the run-match rule as defense in depth); the conformance kit gainsfencedWritesConformanceas the capability's executable definition; the queue worker's retention sweep passes its brief lease through the new optional second argument ofengine.deleteRun(pruneRuntakes the same); andhasFencedWritesplusassertFencedWriteslet a host assert the full fence at deployment time. Stores written before the capability are untouched: without the marker the extra argument is ignored and the journal-append fence works exactly as before.
Patch Changes
- Updated dependencies [b96305d]
- @rulvar/[email protected]
1.44.1
Patch Changes
- 248a19f: Commit the fence check and the mutation it guards as one immediate transaction. The store checked the lease row in one autocommit statement and mutated in the next, so a takeover landing between them (reachable across two processes) let a superseded holder append a visible journal entry despite the moved epoch, extend the successor's lease with its own ttl, or delete the successor's live lease outright. All three were demonstrated against the published 1.44.0. The check and the insert, extension, or deletion now share one
BEGIN IMMEDIATEtransaction (the shapeacquirealways had), and the renew and release mutations additionally pinownerandepochin theirWHEREclauses as defense in depth. The cross-instance tests shim the interleave and prove a takeover can no longer land mid-call. The fenced run state RFC on the docs site records the full audit this fix came out of.- @rulvar/[email protected]
1.44.0
Patch Changes
- Updated dependencies [299f7d2]
- @rulvar/[email protected]
1.43.0
Patch Changes
- Updated dependencies [71b7181]
- @rulvar/[email protected]
1.42.0
Patch Changes
- Updated dependencies [9b70f27]
- @rulvar/[email protected]
1.41.0
Patch Changes
- Updated dependencies [be589ec]
- @rulvar/[email protected]
1.40.0
Patch Changes
- Updated dependencies [cf33550]
- @rulvar/[email protected]
1.39.0
Patch Changes
- @rulvar/[email protected]
1.38.0
Patch Changes
- @rulvar/[email protected]
1.37.0
Patch Changes
- Updated dependencies [e6b1481]
- Updated dependencies [e6b1481]
- @rulvar/[email protected]
1.36.0
Minor Changes
- 101795b: Validate
SqliteStoreOptions.ttlMsas an integer between 1 and 2147483647 ms BEFORE the database opens, and expose the configured value as the readonlyleaseTtlMscapability (v1.35.0 review P2). Unvalidated, zero or a negative made every lease born expired so a second owner could take over immediately, NaN failed the first acquire with a raw sqlite error, and Infinity never expired.
Patch Changes
- Updated dependencies [101795b]
- @rulvar/[email protected]
1.35.0
Patch Changes
- Updated dependencies [d4ac3bf]
- @rulvar/[email protected]
1.34.0
Patch Changes
- Updated dependencies [f1505ec]
- @rulvar/[email protected]
1.33.0
Patch Changes
- @rulvar/[email protected]
1.32.0
Patch Changes
- @rulvar/[email protected]
1.31.0
Patch Changes
- @rulvar/[email protected]
1.30.0
Patch Changes
- Updated dependencies [87ce985]
- @rulvar/[email protected]
1.29.0
Patch Changes
- Updated dependencies [621d566]
- @rulvar/[email protected]
1.28.0
Patch Changes
- Updated dependencies [d98eb0b]
- @rulvar/[email protected]
1.27.0
Patch Changes
- Updated dependencies [884a433]
- @rulvar/[email protected]
1.26.0
Minor Changes
- a4fc757:
SqliteStoreimplements the exact lookup capability (getMetaas a primary key query) and narrowsstatus,statuses, andnamein SQL over the JSON payload behind new expression indexes (created idempotently, so existing database files gain them on the next open), so a selectivelistRunsreads only the matching rows instead of decoding the whole catalog; the tags containment check stays in JS over the reduced set with unchanged semantics. The conformance kit checks thegenesisround trip, that astatusesfilter never drops a matching meta (supersets stay allowed), and that a store exposinggetMetaagrees withlistRunsand resolvesundefinedfor a missing run. The planner's deterministic plan lookup reads one meta through the capability instead of scanning the catalog.
Patch Changes
- Updated dependencies [a4fc757]
- @rulvar/[email protected]
1.25.0
Patch Changes
- @rulvar/[email protected]
1.24.1
Patch Changes
- Updated dependencies [0bb14db]
- @rulvar/[email protected]
1.24.0
Patch Changes
- Updated dependencies [2b033e8]
- @rulvar/[email protected]
1.23.0
Patch Changes
- Updated dependencies [1f9c272]
- @rulvar/[email protected]
1.22.0
Patch Changes
- Updated dependencies [77b554f]
- @rulvar/[email protected]
1.21.0
Patch Changes
- Updated dependencies [7ee42a0]
- @rulvar/[email protected]
1.20.0
Patch Changes
- Updated dependencies [9367030]
- @rulvar/[email protected]
1.19.0
Patch Changes
- 8cc9a9c: Internal real-time reads bind the wall clock at module load, never the live global, eliminating false
RULVAR_BARE_DATE_NOWwarnings for consumers whose rulvar frames live outsidenode_modules(workspace dists, monorepo checkouts). Two composing defects:createEnginecapturedDate.nowper call, so an engine created after a previous run had installed the dev-mode patch bound the PATCHED wrapper as its real clock (itsEventBusthen warned from the engine's own frames), and the ULID factory read the live global at every mint, so ids minted mid-run (the orchestrator extension IO, PlanRunner revisions, adapter id maps) routed through the patch too. The engine now uses a module-loadrealNowbinding (module load always precedes the first patch install), the vendored ULID factory defaults to its own module-load clock, and@rulvar/store-sqlitefollows the same convention. The dev-mode guard itself is untouched and stays exactly as sharp for workflow code, which keeps reading the live global. - Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- @rulvar/[email protected]
1.18.0
Patch Changes
- Updated dependencies [943962d]
- @rulvar/[email protected]
1.17.0
Patch Changes
- @rulvar/[email protected]
1.16.2
Patch Changes
- @rulvar/[email protected]
1.16.1
Patch Changes
- @rulvar/[email protected]
1.16.0
Patch Changes
- @rulvar/[email protected]
1.15.0
Patch Changes
- @rulvar/[email protected]
1.14.0
Patch Changes
- @rulvar/[email protected]
1.13.0
Patch Changes
- @rulvar/[email protected]
1.12.0
Patch Changes
- Updated dependencies [46edcc0]
- @rulvar/[email protected]
1.11.0
Minor Changes
- 0c70c5e: Enforce the monotonic-seq store obligation:
appendcommits through one atomic conditional INSERT that rejects an entry whoseseqis not strictly greater than the run's stored tail with the typedJournalOrderViolation, so two writers racing the same journal from a stale tail can never both persist (the second writer of a split-brain resume gets a typed conflict instead of silently corrupting replay). Entries without a finiteseq(legacy or exotic shapes) pass through unguarded, preserving payload opacity. A non-unique expression index over(run_id, seq)keeps the tail check cheap on long journals; existing database files need no migration.
Patch Changes
- Updated dependencies [0c70c5e]
- @rulvar/[email protected]
1.10.0
Patch Changes
- Updated dependencies [0e8d78e]
- @rulvar/[email protected]
1.9.0
Patch Changes
- Updated dependencies [3a53383]
- @rulvar/[email protected]
1.8.0
Patch Changes
- Updated dependencies [25724b5]
- Updated dependencies [57ea1de]
- Updated dependencies [7884ec5]
- Updated dependencies [52db30d]
- @rulvar/[email protected]
1.7.0
Patch Changes
- Updated dependencies [45285aa]
- Updated dependencies [2f20d1d]
- Updated dependencies [22f65a8]
- Updated dependencies [2ddfa29]
- Updated dependencies [2abd9c2]
- Updated dependencies [1c1175d]
- @rulvar/[email protected]
1.6.0
Patch Changes
- da4dbad: Write the product name as Rulvar in prose: package READMEs, npm descriptions, and the documentation site now capitalize the brand. Identifiers keep their exact casing, so package names, the
rulvarbinary,rulvar.config.mjs, the.rulvarstore directory, therulvar.*OTel attributes, and every URL are unchanged. Documentation and metadata only; no runtime behaviour changes. - Updated dependencies [da4dbad]
- Updated dependencies [487da86]
- Updated dependencies [df416fc]
- Updated dependencies [a737810]
- Updated dependencies [9eb66b4]
- @rulvar/[email protected]
1.5.2
Patch Changes
- Updated dependencies [54936a0]
- @rulvar/[email protected]
1.5.1
Patch Changes
- Updated dependencies [6c6d56f]
- @rulvar/[email protected]
1.5.0
Patch Changes
- Updated dependencies [4fba3c7]
- Updated dependencies [8655c0f]
- @rulvar/[email protected]
1.4.0
Patch Changes
- Updated dependencies [c4f563d]
- @rulvar/[email protected]
1.3.2
Patch Changes
- ddef383: Every published package now ships a README, so its npm page states what the package is, how it installs, and where the documentation lives (npm includes README.md in the tarball regardless of the files allowlist, so no manifest changes are involved; @rulvar/compat gains its README on its own next release). Alongside, the repository-level pages are refreshed to the current project state: the root README is rewritten around the never-pay-twice pitch with a runnable quickstart condensation and the full package table, CONTRIBUTING.md lists the complete PR gate set, the examples README drops retired-spec citations for live docs.rulvar.com links and documents the dogfood journal replay, and the pointer README gets the same treatment.
- Updated dependencies [ddef383]
- @rulvar/[email protected]
1.3.1
Patch Changes
- 7d1552e: Runtime message strings no longer cite the retired internal specification set: error and warning messages, validation issues, and the CLI help text drop the dangling
docs/NN, section ...references, pointing at https://docs.rulvar.com pages where a pointer earns its place (the CLI help header, tool naming, toolset registries, bare resume). The umbrella package description sheds the naming-contingency note: the unscoped alias is published and owned. Three strings embedded in frozen recordings stay byte-identical on purpose (the no-progress abort reason and two testing-internal recorder strings), as does the byte-locked golden-fold fixture. Test-file comments lose their citations too; test titles are unchanged. - Updated dependencies [7d1552e]
- @rulvar/[email protected]
1.3.0
Patch Changes
- Updated dependencies [7d1a287]
- @rulvar/[email protected]
1.2.0
Patch Changes
- 154507b: TSDoc and inline comments no longer cite the retired internal specification set (the pre-docs-site
docs/NN, section ...references). The citations either became links to the public documentation at docs.rulvar.com or were dropped where the comment already carried the rule; traceability markers (DEF-n, XF-nn, FR-nnn, OQ-nn, W-nnn) are untouched. Comment-only change: no runtime behavior, no API shapes, and no runtime message strings were modified; the frozen golden-fold fixture is byte-identical. - Updated dependencies [3bfaec0]
- Updated dependencies [890f42c]
- Updated dependencies [154507b]
- @rulvar/[email protected]
1.1.0
Patch Changes
- Updated dependencies [d16b04a]
- @rulvar/[email protected]
1.0.0
Patch Changes
- Updated dependencies [0e0b569]
- Updated dependencies [b28b7a3]
- Updated dependencies [b53a89e]
- Updated dependencies [4454175]
- Updated dependencies [6599ca8]
- Updated dependencies [6649e5f]
- Updated dependencies [fd2f83b]
- Updated dependencies [01d6b2d]
- Updated dependencies [9a20dbb]
- Updated dependencies [0fbe7ea]
- Updated dependencies [ebe0abc]
- Updated dependencies [a3079d0]
- Updated dependencies [596a39b]
- Updated dependencies [464ab6e]
- @rulvar/[email protected]
0.9.0
Patch Changes
- Updated dependencies [84f94d4]
- Updated dependencies [65c7b2c]
- Updated dependencies [a2a3243]
- Updated dependencies [ebc8101]
- @rulvar/[email protected]
0.8.0
Patch Changes
- Updated dependencies [85d55cf]
- Updated dependencies [b88c9e3]
- Updated dependencies [f3c4613]
- Updated dependencies [a41c20f]
- Updated dependencies [f4e70be]
- Updated dependencies [75d1646]
- Updated dependencies [0627413]
- Updated dependencies [55c0f87]
- Updated dependencies [fd33871]
- Updated dependencies [e70e7f4]
- Updated dependencies [bc9c903]
- @rulvar/[email protected]
0.7.0
Patch Changes
- Updated dependencies [fd1d06c]
- Updated dependencies [6fcf296]
- Updated dependencies [dcc97a9]
- Updated dependencies [434dc83]
- Updated dependencies [03173c1]
- Updated dependencies [11c0afc]
- @rulvar/[email protected]
0.6.0
Minor Changes
- 8f7e61f: M5-T02 SqliteStore: the first real surface of @rulvar/store-sqlite.
SqliteStoreimplements JournalStore AND LeasableStore with fencing epochs over the builtin node:sqlite driver (zero native dependencies; requires a Node.js line with node:sqlite unflagged, 22.13+/23.4+). It passes the full @rulvar/store-conformance suites: A1-A4 store obligations, meta separation, the golden fold fixture, the decide-once oracle, the abandon-derived skip, lease exclusivity (typed LeaseHeldError), monotonic fencing epochs with stale-append rejection and invisibility, release fencing, and wall-clock ttl expiry with the renew-at-ttl/3 cadence. The lease ttl defaults to the Appendix A interim reference for this store (60000 ms; the committed value is an M8 decision), and an injectable clock supports expiry tests. This is the reference implementation for community stores (docs/03, section 12.6).
Patch Changes
- Updated dependencies [fa05007]
- Updated dependencies [9234dc8]
- Updated dependencies [644512c]
- Updated dependencies [8a41656]
- Updated dependencies [02f7f7a]
- @rulvar/[email protected]
0.5.0
Patch Changes
- Updated dependencies [ac274f4]
- Updated dependencies [5735d92]
- Updated dependencies [46ca98e]
- Updated dependencies [8ae129e]
- Updated dependencies [d1c4525]
- Updated dependencies [b840aba]
- @rulvar/[email protected]
0.4.0
Patch Changes
- Updated dependencies [dfe03b5]
- Updated dependencies [d2089a7]
- Updated dependencies [3f60234]
- Updated dependencies [f668890]
- Updated dependencies [16d7aa6]
- Updated dependencies [6513ce8]
- Updated dependencies [7dad493]
- Updated dependencies [2bbf180]
- @rulvar/[email protected]
0.3.0
Patch Changes
- Updated dependencies [43444f6]
- Updated dependencies [279881b]
- Updated dependencies [9fd0966]
- Updated dependencies [24ebadf]
- Updated dependencies [a1b35d3]
- Updated dependencies [18a5821]
- @rulvar/[email protected]
0.2.0
Patch Changes
- Updated dependencies [c24228d]
- Updated dependencies [c50871e]
- Updated dependencies [1af8fb9]
- Updated dependencies [1fe0249]
- Updated dependencies [5c4fc32]
- @rulvar/[email protected]
0.1.0
Minor Changes
- f4e2be9: M0 repo bootstrap (v0.1.0, docs/10-implementation-plan.md section "M0"): monorepo scaffold on the committed toolchain (pnpm 11 workspaces with catalogs, TypeScript 6.0, tsdown, Vitest 4, ESLint 9 flat config, Turborepo 2, changesets fixed mode, npm trusted publishing), the docs/ canon as single source of truth, the L0 contracts skeleton in @rulvar/core, and the vendored dependencies (StandardSchemaV1/StandardJSONSchemaV1 types, the @cfworker/json-schema lineage validator subset, a first-party monotonic ULID). Placeholder scaffolds only: no public API ships in this release.
Patch Changes
- Updated dependencies [f4e2be9]
- @rulvar/[email protected]
@rulvar/testing
1.252.0
Patch Changes
- Updated dependencies [3ccb6cf]
- Updated dependencies [52d807f]
- Updated dependencies [517ed00]
- Updated dependencies [a7e589d]
- Updated dependencies [76e95eb]
- @rulvar/[email protected]
1.251.0
Patch Changes
- Updated dependencies [e7e829c]
- Updated dependencies [5982be8]
- Updated dependencies [7c58fb2]
- Updated dependencies [b3e465a]
- Updated dependencies [c4e5d6a]
- Updated dependencies [c6fc3da]
- Updated dependencies [c6fc3da]
- Updated dependencies [0ae8b85]
- Updated dependencies [7932936]
- Updated dependencies [7932936]
- Updated dependencies [88da0ed]
- Updated dependencies [06c0e85]
- @rulvar/[email protected]
1.250.0
Patch Changes
- Updated dependencies [0e240b9]
- Updated dependencies [6fe585e]
- Updated dependencies [c5eb19c]
- Updated dependencies [565c13b]
- Updated dependencies [c6d197b]
- Updated dependencies [c9d9729]
- Updated dependencies [fed9db6]
- Updated dependencies [df9ed76]
- Updated dependencies [3020912]
- Updated dependencies [d8d598d]
- @rulvar/[email protected]
1.249.0
Patch Changes
- Updated dependencies [8862133]
- Updated dependencies [0d7a717]
- Updated dependencies [e4428bd]
- Updated dependencies [d6873c1]
- Updated dependencies [4092e8d]
- Updated dependencies [e086590]
- Updated dependencies [1411938]
- Updated dependencies [737d1ee]
- Updated dependencies [634f966]
- Updated dependencies [052cc26]
- Updated dependencies [bbae134]
- @rulvar/[email protected]
1.248.0
Patch Changes
- Updated dependencies [8d0cd69]
- Updated dependencies [81065e4]
- Updated dependencies [8573f20]
- Updated dependencies [95f6a5e]
- @rulvar/[email protected]
1.247.0
Patch Changes
- Updated dependencies [1933ecc]
- Updated dependencies [db0a5f0]
- Updated dependencies [b698726]
- Updated dependencies [48348d2]
- Updated dependencies [4cfa1cc]
- Updated dependencies [4b7197a]
- Updated dependencies [5ebc842]
- Updated dependencies [16ff6b9]
- Updated dependencies [0c9941d]
- @rulvar/[email protected]
1.246.0
Patch Changes
- Updated dependencies [d165b0c]
- Updated dependencies [d59f4a0]
- Updated dependencies [46907ac]
- Updated dependencies [9929ad3]
- Updated dependencies [1790a6a]
- @rulvar/[email protected]
1.245.0
Patch Changes
- Updated dependencies [b4d47a8]
- Updated dependencies [dee6db4]
- Updated dependencies [b85c113]
- Updated dependencies [bc556e7]
- Updated dependencies [9f11d29]
- Updated dependencies [19bcea0]
- Updated dependencies [60b461c]
- Updated dependencies [61e3a1a]
- Updated dependencies [a156b81]
- Updated dependencies [0bd7045]
- @rulvar/[email protected]
1.244.0
Patch Changes
- Updated dependencies [38d839a]
- Updated dependencies [ce13b0f]
- Updated dependencies [4fa23e3]
- Updated dependencies [6841c69]
- Updated dependencies [f56721d]
- Updated dependencies [c894a43]
- Updated dependencies [f6944a3]
- Updated dependencies [23fd0e0]
- @rulvar/[email protected]
1.243.0
Patch Changes
- Updated dependencies [746d1f4]
- Updated dependencies [009b29c]
- Updated dependencies [1674cbe]
- Updated dependencies [bd096bc]
- @rulvar/[email protected]
1.242.0
Patch Changes
- Updated dependencies [6e3438e]
- Updated dependencies [ba5cf67]
- Updated dependencies [c2d1531]
- @rulvar/[email protected]
1.241.0
Patch Changes
- Updated dependencies [dbcdd24]
- Updated dependencies [7ae7243]
- Updated dependencies [4f832c4]
- Updated dependencies [7452d3d]
- Updated dependencies [a4e22bf]
- Updated dependencies [82df4af]
- @rulvar/[email protected]
1.240.0
Patch Changes
- @rulvar/[email protected]
1.239.0
Patch Changes
- Updated dependencies [74ce99a]
- Updated dependencies [ccd0665]
- Updated dependencies [0c5ce21]
- Updated dependencies [0616934]
- @rulvar/[email protected]
1.238.0
Patch Changes
- Updated dependencies [cf00947]
- Updated dependencies [c7b9382]
- Updated dependencies [88aea96]
- Updated dependencies [6da8d05]
- Updated dependencies [eae5c4c]
- @rulvar/[email protected]
1.237.0
Patch Changes
- Updated dependencies [9d6a279]
- Updated dependencies [49a98f6]
- Updated dependencies [a734ca0]
- Updated dependencies [deb406f]
- @rulvar/[email protected]
1.236.0
Patch Changes
- Updated dependencies [26306ea]
- Updated dependencies [709b942]
- @rulvar/[email protected]
1.235.0
Patch Changes
- Updated dependencies [ba4e10d]
- Updated dependencies [172402b]
- Updated dependencies [2ecd787]
- Updated dependencies [e20a5e9]
- Updated dependencies [98c8691]
- Updated dependencies [c70def0]
- @rulvar/[email protected]
1.234.0
Patch Changes
- Updated dependencies [8420c04]
- @rulvar/[email protected]
1.233.0
Patch Changes
- Updated dependencies [48b5200]
- Updated dependencies [73bc32b]
- Updated dependencies [e63b743]
- Updated dependencies [ef45da7]
- @rulvar/[email protected]
1.232.0
Patch Changes
- Updated dependencies [1440410]
- Updated dependencies [6e467f4]
- Updated dependencies [0b14293]
- Updated dependencies [e3bcab2]
- Updated dependencies [b55a0f7]
- @rulvar/[email protected]
1.231.0
Patch Changes
- Updated dependencies [4eb4b56]
- Updated dependencies [bc8f09e]
- Updated dependencies [ff9b8c2]
- @rulvar/[email protected]
1.230.0
Patch Changes
- Updated dependencies [e9bf910]
- Updated dependencies [57bfb38]
- @rulvar/[email protected]
1.229.0
Patch Changes
- Updated dependencies [3370342]
- Updated dependencies [2fb6656]
- Updated dependencies [edce170]
- @rulvar/[email protected]
1.228.0
Patch Changes
- Updated dependencies [4034fac]
- Updated dependencies [a54b085]
- Updated dependencies [9d0a9be]
- Updated dependencies [be9ef28]
- @rulvar/[email protected]
1.227.0
Patch Changes
- Updated dependencies [f262e9f]
- Updated dependencies [f191ff7]
- Updated dependencies [fbbfbe8]
- Updated dependencies [263b5e8]
- Updated dependencies [db4d56d]
- Updated dependencies [41f93a9]
- Updated dependencies [98c8ca9]
- @rulvar/[email protected]
1.226.0
Patch Changes
- @rulvar/[email protected]
1.225.0
Patch Changes
- @rulvar/[email protected]
1.224.0
Patch Changes
- Updated dependencies [4eca1a3]
- @rulvar/[email protected]
1.223.0
Patch Changes
- Updated dependencies [549aabd]
- Updated dependencies [549aabd]
- @rulvar/[email protected]
1.222.0
Patch Changes
- Updated dependencies [8326268]
- @rulvar/[email protected]
1.221.0
Patch Changes
- Updated dependencies [032ce93]
- @rulvar/[email protected]
1.220.0
Patch Changes
- Updated dependencies [0babe70]
- @rulvar/[email protected]
1.219.0
Patch Changes
- Updated dependencies [65a4ce7]
- @rulvar/[email protected]
1.218.0
Patch Changes
- Updated dependencies [088bda6]
- @rulvar/[email protected]
1.217.0
Patch Changes
- Updated dependencies [ab80b97]
- @rulvar/[email protected]
1.216.0
Patch Changes
- Updated dependencies [b357f4a]
- @rulvar/[email protected]
1.215.0
Patch Changes
- Updated dependencies [e1da4c7]
- @rulvar/[email protected]
1.214.0
Patch Changes
- Updated dependencies [c8af0ec]
- @rulvar/[email protected]
1.213.0
Patch Changes
- Updated dependencies [61680df]
- @rulvar/[email protected]
1.212.0
Patch Changes
- Updated dependencies [e6f8516]
- @rulvar/[email protected]
1.211.0
Patch Changes
- Updated dependencies [d5a8a36]
- @rulvar/[email protected]
1.210.0
Patch Changes
- Updated dependencies [c871ddc]
- @rulvar/[email protected]
1.209.0
Patch Changes
- Updated dependencies [514c7bb]
- @rulvar/[email protected]
1.208.0
Minor Changes
- e7d426f: First-class prompt-cache policy (RV2006).
ChatRequest.cacheHintexisted and the Anthropic adapter compiled it intocache_control, but nothing in the core ever populated it: the third parity rerun's workers re-paid the full input rate on every turn of their ~550k-token contexts (cacheReadTokens 0across the run), and the $6 envelope sized on OpenAI's implicit server cache was incomparable on Anthropic. The agent loop now compiles the hint on every tool-cycle turn: breakpoints after tools, after system, and after the deepest message, sliding with the history. Default ON exactly where the adapter declares the newModelCaps.promptCaching: 'explicit'(the Anthropic adapter does); OpenAI declares'implicit'and undeclared adapters get byte-identical requests. Configure withdefaults.cache,AgentProfile.cache, or per-callopts.cache(CachePolicy { mode?: 'auto' | 'off'; ttl?: '5m' | '1h' }), call over profile over engine. Billing note: on cache-capable Anthropic models this changes the wire requests of every loop turn to carry cache breakpoints, typically cutting long-cycle input cost several-fold (cached reads bill at a tenth of the input rate);CostReportcache accounting is unchanged, the hint never enters identity or journals, and@rulvar/testing'srequestHashstrips it so existing cassettes replay byte for byte.
Patch Changes
- Updated dependencies [e7d426f]
- @rulvar/[email protected]
1.207.0
Patch Changes
- Updated dependencies [99beee2]
- @rulvar/[email protected]
1.206.0
Patch Changes
- Updated dependencies [ec8e1f1]
- @rulvar/[email protected]
1.205.0
Patch Changes
- Updated dependencies [6d224da]
- @rulvar/[email protected]
1.204.0
Patch Changes
- Updated dependencies [efaec9b]
- @rulvar/[email protected]
1.203.0
Patch Changes
- Updated dependencies [fb08c10]
- @rulvar/[email protected]
1.202.0
Patch Changes
- @rulvar/[email protected]
1.201.0
Patch Changes
- Updated dependencies [7e01189]
- @rulvar/[email protected]
1.200.0
Patch Changes
- Updated dependencies [e2ddbdf]
- @rulvar/[email protected]
1.199.0
Patch Changes
- Updated dependencies [29891c6]
- @rulvar/[email protected]
1.198.0
Patch Changes
- Updated dependencies [c097c96]
- @rulvar/[email protected]
1.197.0
Patch Changes
- @rulvar/[email protected]
1.196.0
Patch Changes
- Updated dependencies [ec9c3e3]
- @rulvar/[email protected]
1.195.0
Patch Changes
- Updated dependencies [5702a70]
- @rulvar/[email protected]
1.194.0
Patch Changes
- Updated dependencies [360a659]
- @rulvar/[email protected]
1.193.0
Patch Changes
- Updated dependencies [2bca1d1]
- @rulvar/[email protected]
1.192.0
Patch Changes
- Updated dependencies [8757601]
- @rulvar/[email protected]
1.191.0
Patch Changes
- Updated dependencies [745387c]
- @rulvar/[email protected]
1.190.0
Patch Changes
- Updated dependencies [8e02021]
- @rulvar/[email protected]
1.189.0
Patch Changes
- Updated dependencies [6a5cc2d]
- @rulvar/[email protected]
1.188.0
Patch Changes
- @rulvar/[email protected]
1.187.0
Patch Changes
- Updated dependencies [c9798ef]
- @rulvar/[email protected]
1.186.0
Patch Changes
- Updated dependencies [242647e]
- @rulvar/[email protected]
1.185.0
Patch Changes
- Updated dependencies [1248623]
- @rulvar/[email protected]
1.184.0
Patch Changes
- Updated dependencies [8a9caca]
- @rulvar/[email protected]
1.183.0
Patch Changes
- Updated dependencies [dd3767c]
- @rulvar/[email protected]
1.182.0
Patch Changes
- Updated dependencies [144d026]
- @rulvar/[email protected]
1.181.0
Patch Changes
- @rulvar/[email protected]
1.180.0
Patch Changes
- Updated dependencies [b124d26]
- @rulvar/[email protected]
1.179.0
Patch Changes
- Updated dependencies [1a5a85a]
- @rulvar/[email protected]
1.178.0
Patch Changes
- @rulvar/[email protected]
1.177.0
Patch Changes
- Updated dependencies [94db8ff]
- @rulvar/[email protected]
1.176.0
Patch Changes
- Updated dependencies [a74304d]
- @rulvar/[email protected]
1.175.0
Patch Changes
- Updated dependencies [1999c5d]
- @rulvar/[email protected]
1.174.0
Patch Changes
- Updated dependencies [aa9a772]
- @rulvar/[email protected]
1.173.0
Patch Changes
- Updated dependencies [67d27ac]
- @rulvar/[email protected]
1.172.0
Patch Changes
- Updated dependencies [0d4770b]
- @rulvar/[email protected]
1.171.0
Patch Changes
- Updated dependencies [f6116b9]
- @rulvar/[email protected]
1.170.0
Patch Changes
- Updated dependencies [86e4c06]
- @rulvar/[email protected]
1.169.0
Patch Changes
- Updated dependencies [623b2ae]
- @rulvar/[email protected]
1.168.0
Patch Changes
- Updated dependencies [ebba79a]
- @rulvar/[email protected]
1.167.0
Patch Changes
- @rulvar/[email protected]
1.166.0
Patch Changes
- Updated dependencies [d8262c3]
- @rulvar/[email protected]
1.165.0
Patch Changes
- Updated dependencies [6391274]
- @rulvar/[email protected]
1.164.0
Patch Changes
- Updated dependencies [9f2dda9]
- @rulvar/[email protected]
1.163.0
Patch Changes
- Updated dependencies [e8d9ada]
- @rulvar/[email protected]
1.162.0
Patch Changes
- Updated dependencies [2031e82]
- @rulvar/[email protected]
1.161.0
Patch Changes
- Updated dependencies [d4547b7]
- @rulvar/[email protected]
1.160.0
Patch Changes
- Updated dependencies [1c6f0d0]
- @rulvar/[email protected]
1.159.0
Patch Changes
- Updated dependencies [e881c8b]
- @rulvar/[email protected]
1.158.0
Patch Changes
- Updated dependencies [a266bc7]
- @rulvar/[email protected]
1.157.0
Patch Changes
- Updated dependencies [1883421]
- @rulvar/[email protected]
1.156.0
Patch Changes
- Updated dependencies [537144e]
- @rulvar/[email protected]
1.155.0
Patch Changes
- Updated dependencies [49b08a7]
- @rulvar/[email protected]
1.154.0
Patch Changes
- Updated dependencies [9259f24]
- @rulvar/[email protected]
1.153.0
Patch Changes
- Updated dependencies [d8bebcb]
- @rulvar/[email protected]
1.152.0
Patch Changes
- Updated dependencies [dd6a616]
- @rulvar/[email protected]
1.151.0
Patch Changes
- Updated dependencies [1de0610]
- @rulvar/[email protected]
1.150.0
Patch Changes
- Updated dependencies [a331211]
- @rulvar/[email protected]
1.149.0
Patch Changes
- Updated dependencies [08b4537]
- @rulvar/[email protected]
1.148.0
Patch Changes
- Updated dependencies [c85dac9]
- @rulvar/[email protected]
1.147.0
Patch Changes
- Updated dependencies [6367231]
- @rulvar/[email protected]
1.146.0
Patch Changes
- Updated dependencies [5d9bbc8]
- @rulvar/[email protected]
1.145.0
Patch Changes
- @rulvar/[email protected]
1.144.0
Patch Changes
- Updated dependencies [c11bcd6]
- @rulvar/[email protected]
1.143.0
Patch Changes
- Updated dependencies [f412169]
- @rulvar/[email protected]
1.142.0
Patch Changes
- @rulvar/[email protected]
1.141.0
Patch Changes
- Updated dependencies [4f12a62]
- @rulvar/[email protected]
1.140.0
Patch Changes
- @rulvar/[email protected]
1.139.0
Patch Changes
- Updated dependencies [03a2141]
- @rulvar/[email protected]
1.138.0
Patch Changes
- Updated dependencies [ed0c4fb]
- @rulvar/[email protected]
1.137.0
Patch Changes
- Updated dependencies [96f6788]
- @rulvar/[email protected]
1.136.0
Patch Changes
- Updated dependencies [aa6ca71]
- @rulvar/[email protected]
1.135.0
Patch Changes
- Updated dependencies [cf75e22]
- @rulvar/[email protected]
1.134.0
Patch Changes
- @rulvar/[email protected]
1.133.0
Patch Changes
- @rulvar/[email protected]
1.132.0
Patch Changes
- Updated dependencies [2bec904]
- @rulvar/[email protected]
1.131.0
Patch Changes
- Updated dependencies [256cae1]
- @rulvar/[email protected]
1.130.0
Patch Changes
- Updated dependencies [d6bec7a]
- @rulvar/[email protected]
1.129.0
Patch Changes
- Updated dependencies [1612439]
- @rulvar/[email protected]
1.128.0
Patch Changes
- Updated dependencies [27c4e38]
- @rulvar/[email protected]
1.127.0
Patch Changes
- Updated dependencies [b3b1805]
- @rulvar/[email protected]
1.126.0
Patch Changes
- @rulvar/[email protected]
1.125.0
Patch Changes
- @rulvar/[email protected]
1.124.0
Patch Changes
- Updated dependencies [37fd1f2]
- @rulvar/[email protected]
1.123.0
Patch Changes
- Updated dependencies [5c46468]
- @rulvar/[email protected]
1.122.0
Patch Changes
- Updated dependencies [8cf45c5]
- @rulvar/[email protected]
1.121.0
Patch Changes
- Updated dependencies [3d67d41]
- @rulvar/[email protected]
1.120.0
Patch Changes
- Updated dependencies [d630c9e]
- @rulvar/[email protected]
1.119.0
Patch Changes
- Updated dependencies [1e4ff3c]
- @rulvar/[email protected]
1.118.0
Patch Changes
- Updated dependencies [f8341a3]
- @rulvar/[email protected]
1.117.0
Patch Changes
- @rulvar/[email protected]
1.116.0
Patch Changes
- Updated dependencies [a213878]
- @rulvar/[email protected]
1.115.0
Patch Changes
- Updated dependencies [63642ae]
- @rulvar/[email protected]
1.114.0
Patch Changes
- Updated dependencies [5759731]
- @rulvar/[email protected]
1.113.0
Patch Changes
- Updated dependencies [a60807a]
- @rulvar/[email protected]
1.112.0
Patch Changes
- Updated dependencies [00ae55b]
- @rulvar/[email protected]
1.111.0
Patch Changes
- Updated dependencies [fd25169]
- @rulvar/[email protected]
1.110.0
Patch Changes
- Updated dependencies [58afdb5]
- @rulvar/[email protected]
1.109.0
Patch Changes
- Updated dependencies [85b1d39]
- @rulvar/[email protected]
1.108.0
Patch Changes
- Updated dependencies [affa3d4]
- @rulvar/[email protected]
1.107.0
Patch Changes
- Updated dependencies [9f5f6f6]
- @rulvar/[email protected]
1.106.0
Patch Changes
- Updated dependencies [9a4ce49]
- @rulvar/[email protected]
1.105.0
Patch Changes
- Updated dependencies [531dc88]
- @rulvar/[email protected]
1.104.0
Patch Changes
- @rulvar/[email protected]
1.103.0
Patch Changes
- Updated dependencies [f2b809e]
- @rulvar/[email protected]
1.102.0
Patch Changes
- Updated dependencies [3eb6515]
- @rulvar/[email protected]
1.101.0
Patch Changes
- Updated dependencies [51b215c]
- @rulvar/[email protected]
1.100.0
Patch Changes
- Updated dependencies [9785bea]
- @rulvar/[email protected]
1.99.1
Patch Changes
- ef08d73: Guarantee matrix and exactly-once claim hygiene (RV508); no runtime behavior changes. The isolated-executor guide now carries the guarantee matrix stating flatly who provides what: the library's layers give at-least-once execution with attempt binding and intent-before-effect, exactly-once effect execution is promised by NO library layer, and what IS exactly-once is pay and replay (the never-pay-twice invariant). The two claims the ninth comparison experiment's judge caught are rewritten to the precise statements ("each ran once" became attempt counting under a stable idempotency key; the approvals guide now says continuation is a run-level guarantee, not an effect-level one, with the at-least-once window named);
ctx.stepdocs state the same window for effectful steps; aResolutionBynote says the field records a channel, never a verified principal (identity, signatures, and separation of duties are host IAM). The worker header now points at the shippedSqliteQuotaLimiterandPostgresQuotaLimiterinstead of denying that cross-process limiters exist. A new docs-lint sentinel forbids "exactly once" claims in the hand-written docs and in package source comments outside a vetted (file, heading anchor) allowlist (the durability pay doctrine and the guarantee matrix), and every remaining occurrence in doc prose and source comments was rewritten to the precise wording; string literals are deliberately out of scope (tool descriptions enter the toolset hash). - Updated dependencies [ef08d73]
- @rulvar/[email protected]
1.99.0
Patch Changes
- Updated dependencies [9e00888]
- @rulvar/[email protected]
1.98.0
Patch Changes
- @rulvar/[email protected]
1.97.0
Patch Changes
- Updated dependencies [5c3b453]
- @rulvar/[email protected]
1.96.0
Patch Changes
- @rulvar/[email protected]
1.95.0
Patch Changes
- @rulvar/[email protected]
1.94.0
Patch Changes
- @rulvar/[email protected]
1.93.0
Patch Changes
- Updated dependencies [c62150a]
- @rulvar/[email protected]
1.92.0
Patch Changes
- Updated dependencies [351d1f5]
- @rulvar/[email protected]
1.91.0
Patch Changes
- @rulvar/[email protected]
1.90.0
Patch Changes
- Updated dependencies [9603940]
- @rulvar/[email protected]
1.89.0
Patch Changes
- Updated dependencies [f18b671]
- Updated dependencies [f18b671]
- @rulvar/[email protected]
1.88.0
Patch Changes
- Updated dependencies [3b339d9]
- @rulvar/[email protected]
1.87.0
Patch Changes
- Updated dependencies [c4c02b1]
- @rulvar/[email protected]
1.86.0
Patch Changes
- Updated dependencies [2f71894]
- @rulvar/[email protected]
1.85.0
Patch Changes
- Updated dependencies [6932a9f]
- @rulvar/[email protected]
1.84.0
Patch Changes
- @rulvar/[email protected]
1.83.0
Patch Changes
- @rulvar/[email protected]
1.82.0
Patch Changes
- Updated dependencies [9cc5d66]
- @rulvar/[email protected]
1.81.2
Patch Changes
- Updated dependencies [296885b]
- @rulvar/[email protected]
1.81.1
Patch Changes
- Updated dependencies [c030982]
- @rulvar/[email protected]
1.81.0
Patch Changes
- Updated dependencies [ce4c392]
- @rulvar/[email protected]
1.80.0
Patch Changes
- Updated dependencies [262e397]
- @rulvar/[email protected]
1.79.0
Patch Changes
- Updated dependencies [85956ab]
- @rulvar/[email protected]
1.78.0
Patch Changes
- Updated dependencies [941b6e1]
- @rulvar/[email protected]
1.77.0
Patch Changes
- Updated dependencies [6aba271]
- @rulvar/[email protected]
1.76.0
Patch Changes
- Updated dependencies [22cba47]
- @rulvar/[email protected]
1.75.1
Patch Changes
- Updated dependencies [82bc0f0]
- @rulvar/[email protected]
1.75.0
Minor Changes
- c486de8: The provider output floor and the finish arguments second chance (the v1.74 comparison review, P0.1 + P1.5).
ModelCaps.minOutputTokensPerTurndeclares the smallest request output cap the provider accepts (OpenAI Responses: 16; absent means one), and the layer-2b budget clamp never dispatches below it: the last-gasp turn goes out AT the floor instead of one token, a remainder that cannot buy the floor is refused as a typedBudgetExhaustedErrorwith zero wire calls, and a configured per-turn cap below the floor is aConfigError;preflightEstimatereports that configuration as the error findingoutput-cap-below-provider-minimum. Tool arguments an adapter delivered as the parse-failure wrapper{__unparsed: raw}now get one deterministic second chance before the schema rejection: a strict re-parse, then one bounded normalization (markdown fence, first balanced object, raw control characters escaped inside string literals); a recovered object that passes the tool schema executes as if it had parsed on the wire, with a warn log naming the pass, and replay or resume recovers identically with nothing journaled. The OpenAI wire re-projects an unparseable call as the ORIGINAL raw arguments string instead of the wrapper JSON, so a model no longer learns to imitate{"__unparsed": ...}from its own rewritten history. Both wires drop unsafe-integerx-ratelimitvalues instead of normalizing 400 digits intoInfinity.FakeAdaptergainscapsOverridesso offline tests can drive caps-declared behavior like the floor.
Patch Changes
- Updated dependencies [c486de8]
- @rulvar/[email protected]
1.74.0
Patch Changes
- Updated dependencies [d94beab]
- @rulvar/[email protected]
1.73.0
Patch Changes
- Updated dependencies [3e95bd1]
- @rulvar/[email protected]
1.72.0
Patch Changes
- Updated dependencies [662e9e0]
- @rulvar/[email protected]
1.71.0
Patch Changes
- Updated dependencies [20d02e0]
- @rulvar/[email protected]
1.70.1
Patch Changes
- @rulvar/[email protected]
1.70.0
Patch Changes
- @rulvar/[email protected]
1.69.0
Patch Changes
- Updated dependencies [b21a681]
- @rulvar/[email protected]
1.68.0
Patch Changes
- Updated dependencies [b227874]
- @rulvar/[email protected]
1.67.0
Patch Changes
- Updated dependencies [8e6006d]
- @rulvar/[email protected]
1.66.0
Patch Changes
- Updated dependencies [1b8987e]
- @rulvar/[email protected]
1.65.0
Patch Changes
- Updated dependencies [0b6b859]
- @rulvar/[email protected]
1.64.0
Patch Changes
- Updated dependencies [991f9b5]
- @rulvar/[email protected]
1.63.0
Patch Changes
- Updated dependencies [8a28aed]
- @rulvar/[email protected]
1.62.0
Patch Changes
- Updated dependencies [fca5fd1]
- @rulvar/[email protected]
1.61.0
Patch Changes
- Updated dependencies [b4c1f1f]
- @rulvar/[email protected]
1.60.0
Patch Changes
- Updated dependencies [59bbeaa]
- @rulvar/[email protected]
1.59.4
Patch Changes
- Updated dependencies [c49d7a1]
- @rulvar/[email protected]
1.59.3
Patch Changes
- Updated dependencies [deaef36]
- @rulvar/[email protected]
1.59.2
Patch Changes
- Updated dependencies [dd0e10f]
- @rulvar/[email protected]
1.59.1
Patch Changes
- Updated dependencies [c127770]
- @rulvar/[email protected]
1.59.0
Minor Changes
- 615dc90: RV-216: the isolated tool executor, the last open item in the improvement plan. In-process tools are ordinary function calls with full host capabilities (an execution convenience, never a sandbox for hostile or model-generated code); this release adds an official out-of-process executor contract so a tool whose input is untrusted cannot reach host capabilities. (1) THE SEAM in
@rulvar/core: aToolExecutorProviderSPI, registered on the engine ascreateEngine({ executors: { subprocess, container } }). A tool declaringexecutor: 'subprocess'or'container'(previously a hard "only inprocess in v1" rejection) dispatches through the matching provider instead of running itsexecuteclosure; an unregistered tag is a typed ConfigError at spawn time, before any provider or model call. The dispatch mints the tool span exactly like an inprocess call and derives a stable idempotency key (a pure function of runId, tool name, and canonical args) so a side-effecting tool can fold an at-least-once retry into effectively-once; the tag never enterstoolsetHash, so opting a tool into isolation does not change run identity, and inprocess dispatch stays byte-identical. (2) THE REFERENCE ADAPTERS in the new@rulvar/executorpackage:subprocessExecutorruns the tool in a child process with a REPLACED environment (host credentials scrubbed; the usual exfiltration path removed), a fresh ephemeral working directory per call, per-call short-lived credentials, a hard timeout that escalates SIGTERM to SIGKILL, and a bounded output capture, plus asandboxlauncher hook where bwrap/firejail/sandbox-exec plug in for filesystem and network isolation;containerExecutorruns it in a one-shot container with the network dropped (--network none), the root filesystem read-only, memory/CPU/pid caps, and all Linux capabilities dropped, which is where the strong isolation the subprocess adapter cannot promise on its own actually holds (a microVM adapter implements the same seam).subprocessTooldefines a tool that dispatches through them; aToolEffectLedgerrecords every dispatch (idempotency key, tool, argsHash, workdir, outcome) so a host can bind an approval to the effect it authorized. (3) THE CONFORMANCE KIT:executorConformanceis the executable shared-contract battery any command-based executor must pass, foremost the gate the epic exists for, a hostile tool cannot read the host's ambient credentials; the subprocess reference passes all of it, and the container reference additionally proves the network and filesystem isolation against a real runtime. New guide page: https://docs.rulvar.com/guide/isolated-executor.
Patch Changes
- Updated dependencies [615dc90]
- @rulvar/[email protected]
1.58.0
Minor Changes
- 4fa35ce: RV-217: data protection hooks, the full close. The plan's gate ("PII never persists or emits in plaintext under policy") now holds end to end. (1) ENVELOPE ENCRYPTION on the serialization seam:
createEnvelopeEncryption({provider, historicalWrappedKeys?, plaintextReads?})returns aSerializationHookthat AES-256-GCM encrypts every persisted byte (journal payloads, transcript blobs, checkpoints) with entry identity as associated data (a ciphertext moved between entries or refs fails authentication), keeping only the kernel-pinned ordering/identity fields plus spanId and timestamps plaintext;DataKeyProvideris the KMS seam (the exact shape of GenerateDataKey/Decrypt, called only in the async factory so the sync hooks run on in-memory data keys, and every envelope carries its wrapped key so reads need no live KMS); the shippedlocalKeyProviderderives KEKs via HKDF-SHA256 with aninfopartition for tenant-scoped keys (a different tenant's provider cannot unwrap, pinned by tests); reads of non-enveloped data fail closed by default withplaintextReads: 'passthrough'as the explicit migration mode;fromStored(toStored(e))reproduces entries exactly, so replay, resume, and recovery are untouched and a run over real files greps to ZERO plaintext PII whileEngine.storesreads plaintext through the one policy point. (2) REDACTION POLICY:redaction.patternsadds host-defined patterns (RegExp or strings, compiled once, typed ConfigError on an invalid one) on top of the default credential set for every emitted event, via the new exportedcompileSecretMasker; the OTel exporter accepts the samepatternsfor trace parity. (3) EXPORT/IMPORT:engine.exportRun(runId)produces the portable bundle (meta, entries, blobs) read through the policy point, so encrypted deployments export plaintext for subject-access requests;engine.importRun(bundle)writes through the target's stores (re-encrypting under its policy), keeps the original runId, and refuses an existing run typed; together with the existingdeleteRun/pruneRunthis completes the retention/deletion/export surface. (4) SALTED METADATA DIGESTS:security.argsHashSaltswitchesRunMeta.argsHashto HMAC-SHA256 under a deployment salt (equal args stop correlating across deployments; low-entropy args stop being recoverable from the digest),hashRunArgsgains the optional salt, and the CLI resume args gate picks the salt up fromengineOptions.securityautomatically. (5) AUDIT TRAIL:reduceAuditTrail(entries)folds a journal into the typed, ordered sequence of authority events (suspensions with deadlines, resolutions with who and what, abandons with reasons, engine decisions, termination denials, run settles), tolerant across journal vintages. New guide page: https://docs.rulvar.com/guide/data-protection.
Patch Changes
- Updated dependencies [4fa35ce]
- @rulvar/[email protected]
1.57.0
Patch Changes
- Updated dependencies [5897232]
- @rulvar/[email protected]
1.56.0
Minor Changes
- f26dba0: RV-215: distributed provider limiting. The new
QuotaLimiterSPI is the extension seam for SHARED rate/quota limiting across engine instances and OS processes:createEngine({quota: {limiter, tenant?, onLimiterError?}})makes the engine reserve capacity before EVERY live wire dispatch (initial attempts, transport retries, and failover takeovers alike, in every phase), dimensioned by provider/model/tenant with a heuristic token estimate, and reconcile each granted reservation with the attempt's actual usage after the outcome settles. A denial becomes a synthetic rate-limit-class WireError that rides the existing provider-429 retry and failover machinery verbatim, except no wire call is paid: the limiter's retryAfterMs (the honest window remainder) drives the interruptible backoff, attempts stay bounded by RetryPolicy, exhaustion fails over (the takeover reserves under its own model), and the terminal is the typederrorof kindrate-limit.onLimiterErrordecides what a limiter INFRASTRUCTURE failure means:'deny'(default) fails closed as a retryable transport-class denial,'allow'logs a warning and dispatches without a reservation. Quota admission is live-only by construction (nothing journaled; replay and resume of memoized work never touch the limiter), and an unconfigured engine takes the exact pre-quota dispatch path down to promise-tick identity. Two reference implementations share one rule model (QuotaRule: optional provider/model/tenant dimensions;requestsPerMinuteexact and hard,tokensPerMinuteestimated at admission and settled to actual; every matching rule must admit; fixed epoch-aligned one-minute windows;validateQuotaRulesat intake):memoryQuotaLimiterin @rulvar/core coordinates engines inside one process, andSqliteQuotaLimiterin @rulvar/store-sqlite coordinates PROCESSES over one database file, with admission inside a single BEGIN IMMEDIATE transaction, cross-process reconciliation via reservation rows, lazy two-window pruning, and the store's boot-scoped busy retry; a multi-process test fleet of real engines proves the global cap holds (dispatched wire calls exactly equal recorded window consumption, no window over cap).createTestEnginein @rulvar/testing passes aquotaoption through to the engine.
Patch Changes
- Updated dependencies [f26dba0]
- @rulvar/[email protected]
1.55.0
Patch Changes
- Updated dependencies [e9b005b]
- @rulvar/[email protected]
1.54.0
Patch Changes
- Updated dependencies [3f6bc03]
- @rulvar/[email protected]
1.53.0
Minor Changes
- b821bd1: Ship the RV-211 synthesis role and critical-path metrics.
InvocationRolegains'synthesize': the dynamic orchestrator's opt-in post-fan-in synthesis invocation (OrchestrateOptions.synthesis { model?, effort?, limits?, instructions?, estCost? }). With it configured, the coordination loop'sfinish({ result })becomes a draft and one fresh finish-only invocation with rolesynthesizecomposes the final run result from the goal, the draft, and the settled child digest, routable independently of coordination through the ordinary chain (the routing key picks its model and never summons it; no role effort default, likeloopandfinalize). Ordering and failure posture are strict: synthesis runs only after an accepted acceptance verdict;finishValidationvalidators bind the synthesis finish instead of the draft (same repair loop, same journaled verdicts); a dead synthesis falls back to the draft under a journaledorchestrator_synthesis_fallbackdecision and a warn log without validators, or fails the run typed (data.source'orchestrator_synthesis') with them. The invocation is an ordinary journaled agent entry, so a resume replays it with zero paid calls (the prompt derives from journaled state, and the replayed root now awaits recovery before the digest fold). Telemetry: fullsynthesizespan and phase pairs (CostReport.byRole.synthesize), a debuglogevent with the actual draft/digest/prompt sizes, and the new pure reducerreduceCriticalPath(events)(CriticalPath), which computes run wall, the post-fan-in interval, the synthesis wall, and their shares, so the improvement plan's post-fan-in gate (at most 40% of wall time) is a field read; the benchmark kit can expose any of them as metric extractors.createTestEngineroutessynthesizeto the fake model like every other model-picking key. Demonstrated against published 1.52.0 first: the whole orchestration emitted only orchestrate/loop roles, the final synthesis request ran on the coordination model,byRolehad no synthesize bucket, the post-fan-in share was hand-rolled or nothing, and the synthesis vocabulary was silently ignored words.
Patch Changes
- Updated dependencies [b821bd1]
- @rulvar/[email protected]
1.52.0
Patch Changes
- Updated dependencies [e138df9]
- @rulvar/[email protected]
1.51.0
Patch Changes
- @rulvar/[email protected]
1.50.0
Patch Changes
- Updated dependencies [e39a885]
- @rulvar/[email protected]
1.49.0
Patch Changes
- Updated dependencies [bab7b2c]
- @rulvar/[email protected]
1.48.0
Patch Changes
- @rulvar/[email protected]
1.47.0
Patch Changes
- Updated dependencies [a3687fe]
- @rulvar/[email protected]
1.46.0
Patch Changes
- Updated dependencies [865e7bf]
- @rulvar/[email protected]
1.45.0
Patch Changes
- Updated dependencies [b96305d]
- @rulvar/[email protected]
1.44.1
Patch Changes
- @rulvar/[email protected]
1.44.0
Patch Changes
- Updated dependencies [299f7d2]
- @rulvar/[email protected]
1.43.0
Patch Changes
- Updated dependencies [71b7181]
- @rulvar/[email protected]
1.42.0
Patch Changes
- Updated dependencies [9b70f27]
- @rulvar/[email protected]
1.41.0
Patch Changes
- Updated dependencies [be589ec]
- @rulvar/[email protected]
1.40.0
Patch Changes
- Updated dependencies [cf33550]
- @rulvar/[email protected]
1.39.0
Patch Changes
- @rulvar/[email protected]
1.38.0
Patch Changes
- @rulvar/[email protected]
1.37.0
Patch Changes
- Updated dependencies [e6b1481]
- Updated dependencies [e6b1481]
- @rulvar/[email protected]
1.36.0
Patch Changes
- Updated dependencies [101795b]
- @rulvar/[email protected]
1.35.0
Patch Changes
- Updated dependencies [d4ac3bf]
- @rulvar/[email protected]
1.34.0
Minor Changes
- f1505ec: The VCR occurrence numbering is now bounded and the appending seed scales (v1.33.0 review P3). An appending
record()session seeds each hash counter in one pass instead of spreading the whole group intoMath.max, which overflowed the call stack with an untyped RangeError once a group held enough rows (150000 in the review's reproducer). A group that already numbersNumber.MAX_SAFE_INTEGERrefuses the appending session at construction, and a session whose counter would pass the ceiling refuses that call, both with a typedConfigErrornaming the cassette, adapter, and hash, before dispatching the provider and before touching the file. Previously the recorder paid the provider, appended an unsafe number that a laterreadCassetterefuses, and the stalled float counter then duplicated that same unsafe number on every following append, so the library itself turned a valid cassette invalid. The cassette format stays v1 with no new fields,hashVersionis untouched, and existing valid cassettes replay unchanged.
Patch Changes
- Updated dependencies [f1505ec]
- @rulvar/[email protected]
1.33.0
Minor Changes
- 3f0f5e8: Appending record sessions continue the occurrence numbering, and ambiguous numbering refuses (v1.32.0 review P2). Each
record()call created a fresh occurrence counter, so a second session appending to an existing cassette restarted the numbering at zero for hashes the file already held: the file order stayed honest, butreplay, which sorts a fully numbered group by its occurrence numbers, served the appended exchange before earlier ones (rows numbered 0, 1, 0 replayed as first, third, second). The error was silent, the cassette validated, andonMiss: 'passthrough'exists precisely to complete a cassette across sessions.record()now reads and validates an existing target before wrapping anything and seeds every(adapterId, requestHash)counter one past the highest number already on disk, so sequential sessions continue the numbering; a gap left by an aborted call stays a gap rather than being filled. Groups recorded before v1.32.0 keep their documented file order mode, including rows a later session appends to them. A duplicate occurrence inside a fully numbered group now refuses with a typedConfigErrornaming the cassette, adapter, and hash, inreplayand in an appendingrecord()alike, because a duplicate means two recorder sessions wrote the file concurrently and either order would hand a caller the wrong exchange; the documented contract is one active recorder per cassette at a time, and a violation is now caught instead of silently misordering. Reading the target up front also closes two adjacent holes:record()no longer appends rows to a file that was never a cassette (or is empty), and it refuses a header recorded under a differenthashVersion, which would have mixed two identity profiles under one header. The cassette format stays v1 and existing valid cassettes replay unchanged.
Patch Changes
- @rulvar/[email protected]
1.32.0
Minor Changes
- e366d64: Concurrent identical calls replay to the callers that made them (v1.31.0 review P2).
recordappends rows when each stream completes, so two identical live requests that finished out of order were stored in completion order, andreplay, which hands occurrences out in caller order, served each caller the other one's response; a parallel workflow could branch differently on replay even though every hash and every row was valid. Every recordedstream()call now claims a zero based per(adapterId, requestHash)occurrence number synchronously in the call itself and persists it on the completed row, andreplayserves same hash rows sorted by that number when every row of the group carries one. An aborted or failed call claims a number but appends no row, and such gaps are valid. The cassette format stays v1: readers before this release tolerate the new optional field and keep file order, and groups recorded before this release (no numbers) keep file order too.readCassettechecks the field is a nonnegative safe integer when present. - e366d64: Cassette event validation now covers every constrained nested field of the canonical vocabulary (v1.31.0 review P3). Three shapes the documentation already promised to refuse were accepted by
readCassetteandreplay: atool-call-endwithout itsargs(required payload; any JSON value includingnullis valid, absence is not, because the replayed event would differ from what the live adapter emitted), a refusalstopDetailsthat is not a plain object or whose presenttype,category, orexplanationis not a string, and a finishproviderMetadatathat is not a plain object. All three now refuse with a typedConfigErrornaming the JSONL line and the exact field path. - e366d64: VCR passthrough now preserves truthful adapter provenance (v1.31.0 review P2). The engine journals every response served through a replay wrapper under the wrapper's own
providerandusageSemanticsdeclarations, and underonMiss: 'passthrough'that includes live served misses: before this release a miss served by the live adapter was journaled under the declarations of the recorded rows (a stale stamp asserting a semantics the serving adapter did not use), and a live adapter with no recorded rows lost both declarations entirely, so its journals went unstamped.replaynow refuses at construction with a typedConfigErrorwhen the cassette rows and the live passthrough adapter disagree on either declaration, absent versus present included, and an adapter with no recorded rows keeps the live adapter's own declarations, so wrapping stays metadata preserving. UnderonMiss: 'throw'the live adapter only backs caps lookups and never serves, so no agreement is demanded there.
Patch Changes
- @rulvar/[email protected]
1.31.0
Minor Changes
- df6b8f8:
readCassettenow validates the nested structures of every row, not only field presence: the request must be a plain object (an array was accepted), every event must be a member of the canonicalChatEventvocabulary with its required payload and the numeric Usage invariants (a null element used to crash replay with a rawTypeError, and a bare{ type: 'finish' }reached the engine and died there on the missing usage), and caps must carry everyModelCapsfield, with the optional pricing table checked when present (an empty object passed as a snapshot). Failures throw a typedConfigErrornaming the cassette path, the JSONL line, and the field path. Unknown extra fields stay tolerated for forward compatibility; an unknown event type is refused. Event stream semantics (exactly one trailing terminal per row) and adapter consistency across rows stayreplaybuild concerns, so reading never blocks inspecting a well formed file. - df6b8f8: VCR cassettes now carry the recording adapter's declared
usageSemantics, and replay restores it.recordsnapshots the field into every row,readCassetterequires a nonempty string when the field is present, and the adapter thatreplayrebuilds declares the recorded value, so the fresh journal of a replayed run gets the same provenance stamp the recorded run got. Before this, a replayed run's usage bearing entries were unstamped, which reads exactly like an entry recorded before the stamp existed; for an OpenAI journal with cache writes that unstamped shape is what the v1.19 cache audit treats as affected, so an honest replayed total could be "corrected" into a wrong number. All rows of one adapter must agree onproviderand onusageSemantics; a conflict refuses with a typedConfigErrorbefore anything is served. Cassettes recorded before this release store nousageSemanticsand keep replaying, with nothing stamped (the documented legacy reading).
Patch Changes
- @rulvar/[email protected]
1.30.0
Minor Changes
- 87ce985: Replay repeated request hashes as ordered occurrences and validate the full cassette shape (v1.29.0 review P2 and P3). Published 1.29.0 built replay on a
Map<requestHash, row>, so a cassette holding two exchanges under one hash (a recorded retry: error then success) served only the later row, on the first call and forever: the recorded error branch never replayed, usage and cost silently shrank, and no occurrence was ever exhausted. Rows sharing one(adapterId, requestHash)key now form an ordered occurrence list; everystream()call consumes exactly one occurrence in file order, claimed synchronously inside the call itself so concurrent identical requests each get their own exchange. A call past the last occurrence is a typed miss:VcrMissErrorgains arecordedOccurrencesfield saying the hash was recorded but is exhausted, andonMiss: 'passthrough'forwards exhausted hashes to the live adapter.replayalso refuses a cassette whose row does not end with exactly one terminal event or whose caps snapshots conflict for one(adapterId, model), andreadCassettenow validates the full documented header and row shape (integerhashVersion, date stringrecordedAt, nonemptymodel, arequestobject, acapsobject, a stringproviderwhen present) with errors naming the cassette path and line; unknown extra fields stay tolerated for forward compatibility. Hand written cassettes missing documented fields, previously accepted and failed late with misleading errors, are now refused at read time; cassettes written byrecordalways carried the full shape.
Patch Changes
- Updated dependencies [87ce985]
- @rulvar/[email protected]
1.29.0
Minor Changes
621d566: A VCR cassette row is now always the record of one completed exchange, and
readCassettevalidates the cassette format version (v1.28.0 review P2 and P3).recordappends a row only when the wrapped stream delivered exactly one terminal event: a requested abort and a naturally truncated stream (no terminal), a thrown wire failure, and a contract violating stream (a second terminal or data after the terminal) append nothing. The v1.28.0 behavior that made the append unconditional on a clean generator exit could commit a partial, finish less exchange, which the fail closed core would then replay as a transport error; the intent of that fix is preserved, because a consumer that stops consuming right after the terminal (the engine shape) still commits its row.readCassettenow refuses a cassette whose header does not declare formatv: 1with a typedConfigError, instead of silently interpreting an unknown future format as v1 (hashVersion, checked by replay, gates request identity and never substitutes for the format version). Corrupt JSON lines and rows missing their required fields also throw a typedConfigErrornaming the cassette path and line, so a torn cassette fails loudly before any partial replay.
Patch Changes
- Updated dependencies [621d566]
- @rulvar/[email protected]
1.28.0
Minor Changes
- d98eb0b: Enforce the terminal stream contract end to end (v1.27.0 deep E2E review P1 and P2). The runtime now fails closed when an adapter stream drains without a terminal
finishorerrorevent: the partial turn becomes a retryable transport fault that feeds the ordinary retry and failover machinery instead of settling asokwith truncated text, and a requested abort (cancel, budget ceiling, idle severance) remains a clean end with no fabricated provider error. Consumption stops at the first terminal event, so events afterfinishcan no longer mutate the value, revise the authoritative bill, or trigger tool execution. The first party adapters enforce the same contract at the wire: the Chat Completions mapper no longer synthesizesfinish: stopwhen the stream is cut before afinish_reason(usage the provider did report is still forwarded, half assembled tool calls are dropped), the Responses mapper fails closed on EOF without a response terminal event, and the Anthropic adapter surfaces a read cut beforemessage_stopas a retryable transport error and no longer converts a caller requested abort duringmessages.create()into a terminal error.mapResponsesStreamandmapChatCompletionsStreamaccept an optionalsignalso a requested abort keeps ending the stream without a terminal event. The VCRrecordwrapper now commits its cassette row even when the consumer stops reading at the terminal event (the engine always does now); adapter middleware must not rely on being drained past the terminal. The committedcombined-loop-descentcatalog cassette is refrozen because stopping consumption at the terminal shifts the deterministic interleaving of two parallel plan children by one scheduler turn; entry content, keys, and the actualhashVersionare unchanged, journals recorded under earlier versions replay unchanged, and this changeset carries the frozen fixture gate's hashVersion-bump ceremony token only to unlock that refreeze.
Patch Changes
- Updated dependencies [d98eb0b]
- @rulvar/[email protected]
1.27.0
Minor Changes
- 884a433: Types referenced by public signatures are now exported from their package barrels, so the API docs resolve them instead of carrying known incomplete references (v1.26.0 deep E2E review):
BaseAppendfrom@rulvar/core(the fields common to everyReplayerappend),BlockandMappedStopfrom@rulvar/anthropic(the wire level content block alias and the stop reason mapping), andVcrHeaderfrom@rulvar/testing(the first line of every cassette file). The frozen TypeDoc baseline shrinks from eleven entries to the four vendored Standard Schema notices.
Patch Changes
- Updated dependencies [884a433]
- @rulvar/[email protected]
1.26.0
Patch Changes
- Updated dependencies [a4fc757]
- @rulvar/[email protected]
1.25.0
Patch Changes
- @rulvar/[email protected]
1.24.1
Patch Changes
- Updated dependencies [0bb14db]
- @rulvar/[email protected]
1.24.0
Minor Changes
- 2b033e8: Remove the repository-only cassette recording plumbing from the public root barrel (the v1.23.0 review):
buildFrozenV1JournalRaw,buildM2CassetteFixtures,buildV2GoldenIdentity,recordLiveCassettes, and the M6 recording constants/helpers no longer appear indist/index.jsordist/index.d.ts. They were@internaland absent from the API reference, yet importable and visible to every consumer's autocomplete, which read as public semver surface. They now live on an internal dist entry that the exports map never exposes; the monorepo's recorder scripts import it by file path. Per the documented versioning policy,@internalexports are outside the contract, so this rides a minor release. The supported tiers (FakeAdapter, createTestEngine, VCR, replay-strict, live smoke, matchers) are unchanged.
Patch Changes
- Updated dependencies [2b033e8]
- @rulvar/[email protected]
1.23.0
Patch Changes
- Updated dependencies [1f9c272]
- @rulvar/[email protected]
1.22.0
Patch Changes
- Updated dependencies [77b554f]
- @rulvar/[email protected]
1.21.0
Patch Changes
- Updated dependencies [7ee42a0]
- @rulvar/[email protected]
1.20.0
Patch Changes
- Updated dependencies [9367030]
- @rulvar/[email protected]
1.19.0
Patch Changes
- Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- Updated dependencies [8cc9a9c]
- @rulvar/[email protected]
1.18.0
Patch Changes
- Updated dependencies [943962d]
- @rulvar/[email protected]
1.17.0
Patch Changes
- @rulvar/[email protected]
1.16.2
Patch Changes
- @rulvar/[email protected]
1.16.1
Patch Changes
- @rulvar/[email protected]
1.16.0
Minor Changes
- 5f76cf2: Cap
runLiveSmokebackoffs at Node's timer maximum (v1.15 review P2-1). BothbaseDelayMsand the largest scheduled backoff,baseDelayMs * (attempts - 1), are now validated against the new exportedMAX_LIVE_SMOKE_DELAY_MS(2^31 - 1 ms) before any stream opens; past that bound Node would not sleep longer, it would clamp the timer to 1 ms with aTimeoutOverflowWarningand retry almost immediately. Every option rejection now carriesfield,value, andmaxin theConfigErrordata. PreviouslybaseDelayMs: 2_147_483_648was accepted and silently turned the backoff into an immediate retry.
Patch Changes
- @rulvar/[email protected]
1.15.0
Minor Changes
- 4aee1f3: Harden
runLiveSmoke(v1.14 review P2-1 and P3-1). Options are validated before any stream opens:attemptsmust be an integer from 1 to the new exportedMAX_LIVE_SMOKE_ATTEMPTS(10) andbaseDelayMsa non-negative integer; anything else,NaN,Infinity, and fractions included, rejects with a typedConfigErrorinstead of being clamped, defaulted, or (forInfinity) allowed to spend without bound. The provider SPI's terminal contract is now enforced per attempt: a stream with multiple terminal events, or whose single terminal is not the final event, classifies as the new'contract-violation'outcome (reason: 'multiple-terminals' | 'terminal-not-final') and is never retried;'no-terminal'keeps meaning exactly zero terminals. Previously anerrorfollowed by afinishclassified as'ok', and explicitattempts: 0or fractional values were silently coerced.DEFAULT_LIVE_SMOKE_ATTEMPTSis also exported.
Patch Changes
- @rulvar/[email protected]
1.14.0
Minor Changes
- 6073226: Add the live-test opt-in gate and the bounded live smoke.
liveTestEnabled(...keys)is true only whenRULVAR_LIVE_TESTS=1AND every named environment key is present, so a provider key alone never triggers a paid call from an ordinary test run.runLiveSmoke(adapter, req, options?)drains one adapter stream per attempt and classifies the terminal event:finishpasses, a typed retryable error (429 rate limit, 529 overload, transport) retries with linear backoff up to the attempt bound, a non-retryable error fails immediately with the typedWireErrorintact, a stream without any terminal event is reported as the adapter-contract violation it is, and a thrown stream propagates unchanged. Rulvar's own key-gated live suites (Anthropic, OpenAI, ai-sdk bridge, the umbrella example) now require the explicit opt-in and run via the documentedpnpm test:livecommand, which reports which suites will fire and never prints key values.
Patch Changes
- @rulvar/[email protected]
1.13.0
Minor Changes
- c28c4c0:
FakeAdapterhonors the caller'sAbortSignalunder the same contract as live adapters (v1.12 follow-up review, P2).streamnow accepts the optionalsignaleveryProviderAdapterreceives and obeys the adapter-authors abort rule: an abort ends the stream promptly with no terminal event and is never converted into a fake provider error. A request whose signal is already aborted on arrival is never served: no responder runs, nothing is recorded infake.calls, no events are emitted. An abort while an async responder is pending detaches the responder (its late value is discarded and a late rejection cannot become an unhandled rejection) and ends the iterator without waiting it out; an abort during event emission stops at the next synchronous boundary. Cancellation, deadline, and budget tests overcreateTestEnginetherefore observe the same journal shapes as production adapters: a cancelled run journals the agent ascancelled, never as a falseagent: okterminal. Non-aborted behavior (output events, usage, tool calls, structured-output tiers, call recording, deterministic ids) is unchanged.
Patch Changes
- @rulvar/[email protected]
1.12.0
Patch Changes
- Updated dependencies [46edcc0]
- @rulvar/[email protected]
1.11.0
Patch Changes
- 0c70c5e: Repair the committed
class-decision-fanoutcassette: the M9 live re-record was itself corrupted by the suspension split-brain fixed in this release (its recorder resolvedreport-1on the settled handle, waking the closed body while a resume appended concurrently), so the committed journal held two byte-identicalreport-2suspended entries with the same seq. Re-recording through the fixed engine drops exactly the duplicate twin; every other live cassette is byte-identical. This is NOT a hashVersion-bump and no identity profile changed; the literal ceremony token appears here only because the frozen-fixture lock refresh requires a changeset carrying it, and a corrupt-fixture repair is precisely the deliberate, reviewable diff the ceremony exists to force. - Updated dependencies [0c70c5e]
- @rulvar/[email protected]
1.10.0
Patch Changes
- Updated dependencies [0e8d78e]
- @rulvar/[email protected]
1.9.0
Minor Changes
7577f8e: Correct the Anthropic fallback pricing to the official table and export versioned price tables from both first-party adapters.
The
ANTHROPIC_MODELSseed rows had never been audited against the published price list and overcharged every current Claude model: Fable 5 was seeded at exactly 2x the official rate (20/100 vs 10/50 per MTok, cache rates likewise), Opus 4.8 at 12/60 vs 5/25, Opus 4.7 at 10/50 vs 5/25, and Opus 4.6 at 15/75 vs 5/25. Claude Sonnet 5 now carries its introductory price (2/10, in effect through 2026-08-31); Haiku 4.5 and Sonnet 4.6 were already correct. Cost reports for affected models drop accordingly, and budget ceilings admit roughly twice the work they previously rejected.New exports
ANTHROPIC_PRICING(anthropic-2026-07-16) andOPENAI_PRICING(openai-2026-07-16) publish the seed rows as versionedPriceTables forcreateEngine({ pricing }), so runs journal a concrete pricing version instead ofunpricedand price revisions become explicit table updates.createTestEnginegained apricingpassthrough for testing against a versioned table.
Patch Changes
- Updated dependencies [3a53383]
- @rulvar/[email protected]
1.8.0
Patch Changes
- Updated dependencies [25724b5]
- Updated dependencies [57ea1de]
- Updated dependencies [7884ec5]
- Updated dependencies [52db30d]
- @rulvar/[email protected]
1.7.0
Patch Changes
- Updated dependencies [45285aa]
- Updated dependencies [2f20d1d]
- Updated dependencies [22f65a8]
- Updated dependencies [2ddfa29]
- Updated dependencies [2abd9c2]
- Updated dependencies [1c1175d]
- @rulvar/[email protected]
1.6.0
Patch Changes
- da4dbad: Write the product name as Rulvar in prose: package READMEs, npm descriptions, and the documentation site now capitalize the brand. Identifiers keep their exact casing, so package names, the
rulvarbinary,rulvar.config.mjs, the.rulvarstore directory, therulvar.*OTel attributes, and every URL are unchanged. Documentation and metadata only; no runtime behaviour changes. - Updated dependencies [da4dbad]
- Updated dependencies [487da86]
- Updated dependencies [df416fc]
- Updated dependencies [a737810]
- Updated dependencies [9eb66b4]
- @rulvar/[email protected]
1.5.2
Patch Changes
- Updated dependencies [54936a0]
- @rulvar/[email protected]
1.5.1
Patch Changes
- Updated dependencies [6c6d56f]
- @rulvar/[email protected]
1.5.0
Patch Changes
- Updated dependencies [4fba3c7]
- Updated dependencies [8655c0f]
- @rulvar/[email protected]
1.4.0
Minor Changes
c4f563d: Production readiness fixes from the July 2026 full audit.
The
budgetUsdceiling now survives resume: the engine records it inRunMeta.budgetUsdand restores it on every resume, so the replayed spend counts against the original invocation's bound andResumeOptionsstill exposes no way to raise it. Journals written before the field existed (or read through a store that drops optionalRunMetafields) resume uncapped, exactly as before; the conformance kit gains a round-trip check so custom stores cannot drop the field silently.spawn:rejectedandresolution:applied/resolution:supersededare now emitted: live admission rejections carry the rejectioncode,agentType, and the journaled decisionentryRef(absent only for pre-admission config gates), and live resolution attempts report winning or losing the first-closing-wins fold.spawn:admittednow carries the decisionentryRefand the admittingverdictarm. Theorchestrator:budgetunion member now types the two payload shapes actually emitted;journal:compatstays declared but unemitted (the scan runs before a run's event stream exists) and its TSDoc says so.toOtelimplements real parent-child span nesting whencontextApiandsetSpanare passed; without them spans stay flat but attributed.'readonly'isolation now compiles a deny rule for tools declaring riskwriteordestructiveinto the spawn's permission chain, exactly as the tools guide documents; read tools and other isolation modes are unaffected.VCR
replay()refuses a cassette recorded outside the engine's hashVersion support window ([CURRENT-1, CURRENT]) with a typedConfigErrorinstead of silently drifting; in-window cassettes replay as before.InMemoryStoreaccepts{ quiet: true }to opt out of the durability warning, and the warning text now states the precise truth: nothing survives a process exit and cross-process resume is impossible (same-process resume of a kept instance works).createTestEngineconstructs its store quietly, so the blessed offline tier no longer prints a misleading warning.The bare
Date.now()/Math.random()development warnings no longer blame workflow code for calls that originate in library internals (the engine's own retry jitter, provider SDKs): the retry jitter uses a natively capturedMath.random, and the in-process guard skips callers that live undernode_modules.rulvar run --profilenow applies the profile's per-role effort hints: entries indefaults.routingthat carry no effort are seeded fromRunProfile.effortByRole(an explicit host effort always wins; ladder entries and unrouted roles stay untouched).rulvar --helpdocuments the shippedkb inboxandkb gatesubcommands.The unscoped
rulvarpointer package ships TypeScript declarations (index.d.tswith atypesexport condition), so strict TypeScript projects can import the bare name; the install smoke gate now packs and checks the pointer alongside the umbrella.
Patch Changes
- Updated dependencies [c4f563d]
- @rulvar/[email protected]
1.3.2
Patch Changes
- ddef383: Every published package now ships a README, so its npm page states what the package is, how it installs, and where the documentation lives (npm includes README.md in the tarball regardless of the files allowlist, so no manifest changes are involved; @rulvar/compat gains its README on its own next release). Alongside, the repository-level pages are refreshed to the current project state: the root README is rewritten around the never-pay-twice pitch with a runnable quickstart condensation and the full package table, CONTRIBUTING.md lists the complete PR gate set, the examples README drops retired-spec citations for live docs.rulvar.com links and documents the dogfood journal replay, and the pointer README gets the same treatment.
- Updated dependencies [ddef383]
- @rulvar/[email protected]
1.3.1
Patch Changes
- 7d1552e: Runtime message strings no longer cite the retired internal specification set: error and warning messages, validation issues, and the CLI help text drop the dangling
docs/NN, section ...references, pointing at https://docs.rulvar.com pages where a pointer earns its place (the CLI help header, tool naming, toolset registries, bare resume). The umbrella package description sheds the naming-contingency note: the unscoped alias is published and owned. Three strings embedded in frozen recordings stay byte-identical on purpose (the no-progress abort reason and two testing-internal recorder strings), as does the byte-locked golden-fold fixture. Test-file comments lose their citations too; test titles are unchanged. - Updated dependencies [7d1552e]
- @rulvar/[email protected]
1.3.0
Patch Changes
- Updated dependencies [7d1a287]
- @rulvar/[email protected]
1.2.0
Patch Changes
- 154507b: TSDoc and inline comments no longer cite the retired internal specification set (the pre-docs-site
docs/NN, section ...references). The citations either became links to the public documentation at docs.rulvar.com or were dropped where the comment already carried the rule; traceability markers (DEF-n, XF-nn, FR-nnn, OQ-nn, W-nnn) are untouched. Comment-only change: no runtime behavior, no API shapes, and no runtime message strings were modified; the frozen golden-fold fixture is byte-identical. - Updated dependencies [3bfaec0]
- Updated dependencies [890f42c]
- Updated dependencies [154507b]
- @rulvar/[email protected]
1.1.0
Patch Changes
- Updated dependencies [d16b04a]
- @rulvar/[email protected]
1.0.0
Minor Changes
807d1f9: M9-T04 (final part): the DEF-4 live re-record, production-journal replay, and the one-CI-job catalog gate (docs/09 section 6; docs/10 M9 row "Complete catalog green in one CI run"; the 1.0 gate of docs/12 section 5).
- The six DEF-4 cassettes are re-recorded through the LIVE producers per the synthetic-fixture rule: engine runs, RunHandle.resolveExternal, and the offline kernel writer (the M8 machinery) produce the committed journals; recordLiveCassettes gains the six recorders and scripts/record-m3-cassettes.mjs regenerates them. The synthetic builders stay in the suite as the kernel regression (def1-def4.test.ts now replays the builder output for DEF-4), and the new def4-live.test.ts replays the committed live forms end-to-end, seq-agnostic.
- Production-journal replay is wired: dogfood journals live under the frozen
journals/directory and every one replays STRICT with zero live calls against its shipped workflow (examples/src/journals.test.ts; RECORD_DOGFOOD=1 re-records). Seeded with judge-panel-fake, a full run of the shipped judge-panel example. - The catalog gates as ONE CI job:
cassette-catalogruns scripts/catalog-audit.mjs (every docs/09 section 6 ID must resolve to a cassettes/ fixture or a named suite; 58 IDs today, parser-drift guarded) and then a single vitest invocation over every cassette suite (the M2/M3/M9 fixture suites, the M7/M8/M9 plan cassettes, the M8 multi-process soak, and the dogfood journals), replay-strict with zero live calls.
Patch Changes
- Updated dependencies [0e0b569]
- Updated dependencies [b28b7a3]
- Updated dependencies [b53a89e]
- Updated dependencies [4454175]
- Updated dependencies [6599ca8]
- Updated dependencies [6649e5f]
- Updated dependencies [fd2f83b]
- Updated dependencies [01d6b2d]
- Updated dependencies [9a20dbb]
- Updated dependencies [0fbe7ea]
- Updated dependencies [ebe0abc]
- Updated dependencies [a3079d0]
- Updated dependencies [596a39b]
- Updated dependencies [464ab6e]
- @rulvar/[email protected]
0.9.0
Minor Changes
65c7b2c: M8-T01: createServer, the HTTP shell (docs/02 section 8.2; FR-702), plus the Engine.stores seam it stands on (docs/06 10.2, M8 entry amendment).
@rulvar/cli:createServer({ engine, workflows })returns{ fetch(req: Request): Promise<Response> }with the five canonical routes: POST /runs (start a registered workflow), GET /runs/:id (status and outcome), GET /runs/:id/events (SSE; Last-Event-ID maps to the event seq, replay is at-least-once and consumers deduplicate onreplayed), POST /runs/:id/external/:key (programmatic resolution,by: 'external'; a run that settled suspended in-process auto-resumes; a run not live in this process gets the documented offline append under a lease where the store is leasable, and resumes on a worker), GET /runs/:id/cost (the settled in-process CostReport, or the pure journal fold priced by the optionalpriceUsd). Authentication stays host middleware (docs/14, OQ-16).@rulvar/core: the Engine interface gains the readonlystoresaccessor exposing the configured journal and transcript stores; exactly the instances createEngine received (or defaulted), no store contract widens.@rulvar/testing:createTestEngineforwards the newstoresaccessor.
ebc8101: M8-T04: the redaction and retention interim rules executed (docs/14 OQ-20 and OQ-22; docs/09 section 8 rewritten to the executed state; docs/03 12.4 and 12.8; docs/06 10.1 and 10.2 amendments).
@rulvar/core: the L0 SerializationHook (createEngine({ serialization })): redact/encrypt at the append/put boundaries, symmetric on load/get, applied by wrapping the stores soEngine.storesexposes the one policy point; kernel ordering fields are drift-checked with a loud ConfigError. Default key masking at the telemetry boundary: every emitted WorkflowEvent passesmaskSecrets(provider keys, PATs, bearer tokens, JWTs, private-key blocks become[masked-secret]); opt out viaredaction: { maskEvents: false }; never touches the journal. Retention:TranscriptStore.delete(ref)joins the SPI (missing ref is a no-op; InMemory and File stores implement it),Engine.deleteRun(runId)cascades blob deletion before the journal (no orphan transcripts), andEngine.pruneRun(runId)deletes checkpoint blobs of ok-terminal attempts that nothing else references (parked, cancelled, escalated, and hanging attempts keep theirs).@rulvar/cli:createServerandcreateWorkertake the opt-inretentionpredicate over RunMeta (the server applies it at terminal settles, the worker during sweeps under a brief lease); the OTel exporter masks string span attributes with the same policy, defense in depth over the already conservative attribute content policy.@rulvar/testing:createTestEngineforwardsdeleteRun/pruneRun.
Patch Changes
- Updated dependencies [84f94d4]
- Updated dependencies [65c7b2c]
- Updated dependencies [a2a3243]
- Updated dependencies [ebc8101]
- @rulvar/[email protected]
0.8.0
Patch Changes
- Updated dependencies [85d55cf]
- Updated dependencies [b88c9e3]
- Updated dependencies [f3c4613]
- Updated dependencies [a41c20f]
- Updated dependencies [f4e70be]
- Updated dependencies [75d1646]
- Updated dependencies [0627413]
- Updated dependencies [55c0f87]
- Updated dependencies [fd33871]
- Updated dependencies [e70e7f4]
- Updated dependencies [bc9c903]
- @rulvar/[email protected]
0.7.0
Minor Changes
- 10b45f1: M6-T11: the rulvar plan command and the M6 gating cassettes.
rulvar plan "<goal>" [--dry-run](the canonical grammar) loads @rulvar/planner DYNAMICALLY (the CLI's static dependency stays @rulvar/core; a missing install is a clear error), plans against the host-config engine, prints the accepted script plus its advisory diagnostics, and runs it in the worker sandbox unless --dry-run. The three docs/09 6.10 gating cassettes are recorded on the FakeAdapter and committed under the frozen-fixture lock with exported scenario builders shared by the recorder script and the replay tests: sandbox-determinism (two fresh runs of one CompiledWorkflow produce byte-identical normalized journals matching the cassette), planner-self-repair (the failing draft round-trips through the JSON-diagnostics repair, re-planning from the committed journal is free, and the accepted script executes deterministically in the sandbox), and orchestrator-crash-resume (the committed pre-crash journal plus boundary checkpoints resume with zero re-paid spawns, no duplicate spawn decisions, and byte-stable handles).
Patch Changes
- Updated dependencies [fd1d06c]
- Updated dependencies [6fcf296]
- Updated dependencies [dcc97a9]
- Updated dependencies [434dc83]
- Updated dependencies [03173c1]
- Updated dependencies [11c0afc]
- @rulvar/[email protected]
0.6.0
Minor Changes
- 638d9a1: M5-T04 VCR cassettes and cron contract tests.
@rulvar/testinggains the tier-2 VCR at the adapter boundary:record({ adapters, cassette, redact? })wraps live adapters and appends redacted JSONL rows keyed by a hash of the canonical wire-contract request (the engine-populated providerOptions.rulvar telemetry namespace is excluded from the key);replay({ cassette, onMiss })serves recorded streams back with the typed VcrMissError under 'throw' (hermetic CI) or live forwarding under 'passthrough'. Redaction happens at record time: the built-in policy masks authorization material (key-shaped strings, bearer tokens, api-key assignments) in every stored string and a custom hook composes on top, so secrets never reach cassette bytes. Cassette headers record the hashVersion they were produced under (DEF-6), and replay adapters expose the recorded caps snapshots. The live contract-test cron workflow is now real: weekly, non-blocking, gated on the CONTRACT_TESTS_ENABLED variable and provider keys, validating the wire contract (one terminal event, Usage invariant, finish vocabulary) against committed provider cassettes and opening a contract-drift issue on failure instead of rerecording.
Patch Changes
- Updated dependencies [fa05007]
- Updated dependencies [9234dc8]
- Updated dependencies [644512c]
- Updated dependencies [8a41656]
- Updated dependencies [02f7f7a]
- @rulvar/[email protected]
0.5.0
Minor Changes
ac274f4: M4-T01 role protocol completion. The full trigger protocol for the six invocation roles lands in
@rulvar/core(model/roles.ts):- Extract necessity is completed per docs/04 section 8.3: a separate final structured-output invocation fires when a schema is set AND (routing directs extract to a different model OR the loop model's required tier cannot ride a tools-available turn OR finalize is routed). The required-tier rule is new: a
forced-tooltier pins toolChoice toemit_resultand cannot ride while the agent's tools must remain available, so such agents now pay one separate extract call instead of silently losing tool access. Agents without tools keep the M1 single-shot behavior byte for byte. - The finalize role fires for the first time: only when configured in routing and only for tool-bearing agents, as one synthesis invocation with toolChoice
'none'over the full transcript after tools stop. Its text is the output for schema-less calls; with a schema the separate extract runs over the transcript including the synthesis. - A separate extract invocation over a tool-bearing transcript now carries the agent's tool contracts (both providers reject tool-use history without tool definitions) with toolChoice pinned to
'none'or toemit_resultper tier. - Both adapters map
toolChoice: 'none'to the provider's explicit none choice with the tools param present instead of dropping tools from the request. createTestEngineno longer routesfinalizeby default: the routing key is the firing opt-in, and the old default would have summoned a synthesis call for every tool-bearing test agent. Tests that want finalize route it explicitly.
Identity is untouched: extract and finalize resolutions never enter the spawn content key, and existing journals replay unchanged.
- Extract necessity is completed per docs/04 section 8.3: a separate final structured-output invocation fires when a schema is set AND (routing directs extract to a different model OR the loop model's required tier cannot ride a tools-available turn OR finalize is routed). The required-tier rule is new: a
b840aba: M4-T08 canonical effort completion and M4-T09 role quality floors.
- Effort semantics are complete: the role effort defaults and the per-adapter mapping tables (Anthropic passthrough including max, OpenAI max downmapped to xhigh and recorded in providerMetadata, provider none only via namespaced providerOptions) shipped earlier milestones; this change completes VISIBLE scrubbing everywhere it was still silent: the summarize invocation surfaces its scrubs at fire time and a failover takeover surfaces the fallback's scrubs the moment it starts serving. Scrubbed effort is never mapped into max_tokens.
- The effort-defaults-shift cassette is now RECORDED through the live runtime (docs/10 M4 gating row): the frozen v1 prefix, closed offline the way an operator would, resumes live under explicit high effort with the completed semantics; every v1 entry matches and the one new spawn carries canonical effort in v2 identity. The recorder output is pinned byte-for-byte by the frozen-drift suite and the fixture lock now covers 18 files.
- Quality floors (
model/floors.ts, M4-T09): per-role and per-declared-taskClass allow/deny lists supplied viacreateEngine({ floors }), enforced INSIDE the router at resolution, before any live call and before any journal entry, for every invocation the chain produces (primaries, failover fallbacks, and the summarize fallback alike).AgentProfile.taskClassdeclares the class; unclassified profiles see only byRole floors. A violation is a typed ConfigError. - The umbrella
rulvarpackage now ships floors opinions next to its strong routing defaults:recommendedDefaults.floorspins orchestrate and plan to strong named models. The core itself ships no named model strings, and the umbrella suite enforces that with a source scan.
Patch Changes
- Updated dependencies [ac274f4]
- Updated dependencies [5735d92]
- Updated dependencies [46ca98e]
- Updated dependencies [8ae129e]
- Updated dependencies [d1c4525]
- Updated dependencies [b840aba]
- @rulvar/[email protected]
0.4.0
Minor Changes
dfe03b5: M3-T11 gating cassettes and the v0.4.0 BREAKING release notes.
BREAKING (pre-1.0 convention, docs/12):
AgentStatusnow produces'escalated'at runtime andAgentResultcarries the optionalescalation: EscalationReportfield (present if and only if the status is escalated). This is the third kernel amendment of the replay predicate (escalated-replays-as-ok, DEF-1) whose table row shipped frozen in M2; the producers ship here. Migration: add anescalatedbranch to every switch overAgentStatus; consumers not adopting the protocol are advised to mapescalatedtolimit(paid partial work, output null, the report stays available for logs).isEscalatedandEscalatedResultare exported for narrowing. Status production stays gated by opt-in: workflows that never passescalationoptions cannot observe the new status at runtime.Cassettes: the DEF-1 live set (escalate-replay, crash-between-report-and-decision, flavor-b-timeout) is recorded through the live runtime and replayed strict; the M2 synthetic DEF-1 subset is re-recorded (memoize-classifier fully live; abandon-subtree through the kernel write APIs with a realistic escalated child report and an authorizing owner cancel decision; both re-record again with the orchestrator producers in M7). FakeAdapter gains fakeToolCalls and fakeWireError responder markers; replayRun gains the onEscalation pass-through so replay tests can prove the hook stays cold. The deliberate fixture regeneration updates fixtures.sha256 in the same change (the identity profile is UNCHANGED; this is the docs/10 M3-T11 ordered re-record, not an identity-pipeline revision).
Patch Changes
- Updated dependencies [dfe03b5]
- Updated dependencies [d2089a7]
- Updated dependencies [3f60234]
- Updated dependencies [f668890]
- Updated dependencies [16d7aa6]
- Updated dependencies [6513ce8]
- Updated dependencies [7dad493]
- Updated dependencies [2bbf180]
- @rulvar/[email protected]
0.3.0
Minor Changes
43444f6: M2-T11/T12: the executable store conformance kit and the M2 gating cassettes with frozen fixtures.
@rulvar/store-conformance ships its first real API: journalStoreConformance (A1 append atomicity, A2 total per-run order, A3 read-your-writes, A4 opaque payload with read-side-only normalization, meta separation, the golden fold-state fixture with a frozen reference hash, the decide-once oracle, and the abandon-derived-skip fixture) and leasableStoreConformance (typed LeaseHeldError on held acquire, monotonic fencing epochs, stale-epoch appends rejected and invisible, released leases fenced from renew and append, optional ttl/renew-cadence timing checks), plus registerConformance for Vitest/Jest and the stableStringify fold-state hasher. InMemoryStore and JsonlFileStore pass; deliberately broken stores (reordering, normalizing, tearing, fencing-less) fail loudly.
@rulvar/core kernel closes three DEF-1/DEF-4 gaps the cassettes gate: an abandon-covered hanging dispatch derives skipped instead of redispatching, abandon-covered operations contribute a zero ledger increment, the resume report lists covered entries as skipped (never orphaned), and an abandon over an already-resolved suspension folds to a noop with already_resolved (first-closing-wins per target, both closer kinds).
@rulvar/testing ships the M2 cassette suite over committed frozen fixtures: the DEF-1 synthetic subset (abandon-subtree, memoize-classifier, v1-journal-on-v2), the DEF-4 set (timeout-vs-live-race, class-decision-fanout, abandon-then-crash-then-resume, abandon-vs-resolution-race, offline-invalid-then-valid, double-abandon-idempotent), the DEF-6 six IDs (resume-v1-on-engine-v2, resume-v1-with-inserted-call, suspended-v1-resolves-on-v2, reject-version-too-old via deriverV0Synthetic, reject-version-from-future, effort-defaults-shift), the mandatory mixed-version scenarios (ordinal-space split, forward-cursor preference, cross-version resolution, the compatibility and never-pay-twice-through-upgrade lemmas), and KeyDeriver contract tests against the frozen v2 golden identities including the docs/03 worked example. Fixture regeneration is deliberate: scripts/record-m2-cassettes.mjs rebuilds, and CI write protection (scripts/check-frozen-fixtures.mjs plus fixtures.sha256) fails any fixture diff shipped without the explicit bump token (the hyphenated compound of hashVersion and bump) in a changeset.
a1b35d3: M2-T09/T10: engine.resume under the run-to-definition binding contract (wf required for in-process runs, name mismatch is a typed ConfigError, body-hash mismatch warns loudly and proceeds; the compatibility scan runs strictly before any side effect; the resumed run seeds the budget from the ledger fold, re-emits open suspensions, and reports ResumePreview hits/misses/reruns/orphans plus invalid offline resolutions), the dryRun option (replay-strict matching: the first would-be-live call settles the run with the typed journal_miss error and zero live calls), and @rulvar/testing replayRun (tier 3: strict replay of any journal with JournalMissError on ANY live call; suspended journals finish suspended with zero live calls).
Patch Changes
- Updated dependencies [43444f6]
- Updated dependencies [279881b]
- Updated dependencies [9fd0966]
- Updated dependencies [24ebadf]
- Updated dependencies [a1b35d3]
- Updated dependencies [18a5821]
- @rulvar/[email protected]
0.2.0
Minor Changes
- 5c4fc32: M1-T14/T15: @rulvar/testing tier 1 (FakeAdapter matching on agentType/label/prompt regex with a '*' fallback, honoring the selected structured-output tier, zero USD by construction; createTestEngine over the full real engine with recorded event streams; toHaveCalledAgent and toStayUnderBudget matchers at '@rulvar/testing/matchers') and the completed umbrella (re-exports of @rulvar/core and both first-class adapters, renderProgress, the umbrella-only recommendedDefaults strong model slots, the M1 exit-criteria example workflow, and the CI install smoke on packed tarballs). The core now populates the reserved providerOptions 'rulvar' telemetry namespace on every request (docs/04 section 1.8 as amended) and AgentResult carries errorMessage detail for journaled WireError fidelity.
Patch Changes
- Updated dependencies [c24228d]
- Updated dependencies [c50871e]
- Updated dependencies [1af8fb9]
- Updated dependencies [1fe0249]
- Updated dependencies [5c4fc32]
- @rulvar/[email protected]
0.1.0
Minor Changes
- f4e2be9: M0 repo bootstrap (v0.1.0, docs/10-implementation-plan.md section "M0"): monorepo scaffold on the committed toolchain (pnpm 11 workspaces with catalogs, TypeScript 6.0, tsdown, Vitest 4, ESLint 9 flat config, Turborepo 2, changesets fixed mode, npm trusted publishing), the docs/ canon as single source of truth, the L0 contracts skeleton in @rulvar/core, and the vendored dependencies (StandardSchemaV1/StandardJSONSchemaV1 types, the @cfworker/json-schema lineage validator subset, a first-party monotonic ULID). Placeholder scaffolds only: no public API ships in this release.
Patch Changes
- Updated dependencies [f4e2be9]
- @rulvar/[email protected]