@rulvar/core 1.241.0 → 1.242.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +110 -1
- package/dist/index.js +178 -16
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1122,6 +1122,16 @@ type JournalEntry = {
|
|
|
1122
1122
|
cap?: number;
|
|
1123
1123
|
};
|
|
1124
1124
|
/**
|
|
1125
|
+
* Terminal agent entries whose invocation was aborted by the host's
|
|
1126
|
+
* finish rejection (RV3702): the declared finish contract rejected
|
|
1127
|
+
* the candidate past its repair bound, so the span died by host
|
|
1128
|
+
* hand with its wires fine. Stamped at settle from the typed abort
|
|
1129
|
+
* reason; never on a defective (throwing) validator, whose abort
|
|
1130
|
+
* carries its own reason, because a host defect is not a verdict on
|
|
1131
|
+
* the candidate. Policy, never identity, exactly like usageByModel.
|
|
1132
|
+
*/
|
|
1133
|
+
hostRejected?: boolean;
|
|
1134
|
+
/**
|
|
1125
1135
|
* Terminal escalated entries ONLY: the schema-validated
|
|
1126
1136
|
* EscalationReport with runtime-filled costToDate and salvage; replay
|
|
1127
1137
|
* synthesizes the byte-identical report from here (DEF-1).
|
|
@@ -2599,6 +2609,15 @@ type AgentEvents = {
|
|
|
2599
2609
|
*/
|
|
2600
2610
|
retryCount?: number;
|
|
2601
2611
|
/**
|
|
2612
|
+
* Present and true when the invocation was aborted by the host's
|
|
2613
|
+
* finish rejection (RV3702): the declared finish contract
|
|
2614
|
+
* rejected the candidate past its repair bound. Journaled on the
|
|
2615
|
+
* terminal agent entry (unlike retryCount), so a replayed
|
|
2616
|
+
* agent:end carries it too and both surfaces of the RV3404 cut
|
|
2617
|
+
* read the same count.
|
|
2618
|
+
*/
|
|
2619
|
+
hostRejected?: boolean;
|
|
2620
|
+
/**
|
|
2602
2621
|
* The exploration guard counters (RV-210). Present live whenever
|
|
2603
2622
|
* any exploration guard limit was configured for the invocation;
|
|
2604
2623
|
* on replay present only when the guard abort journaled it in the
|
|
@@ -3826,6 +3845,8 @@ interface TerminalPatch {
|
|
|
3826
3845
|
used: number;
|
|
3827
3846
|
cap?: number;
|
|
3828
3847
|
};
|
|
3848
|
+
/** Terminal agent entries: the host finish rejection stamp (RV3702); see JournalEntry. */
|
|
3849
|
+
hostRejected?: boolean;
|
|
3829
3850
|
/** Terminal escalated entries: the validated EscalationReport. */
|
|
3830
3851
|
escalation?: unknown;
|
|
3831
3852
|
/**
|
|
@@ -6428,6 +6449,8 @@ interface BudgetAccountView {
|
|
|
6428
6449
|
finalizeReserveUsd: number;
|
|
6429
6450
|
/** The synthesis payload hold (cycle 76); zero when none is committed. */
|
|
6430
6451
|
synthesisReserveUsd: number;
|
|
6452
|
+
/** The repair round's verdict hold (RV3701); zero when none is committed. */
|
|
6453
|
+
convergenceReserveUsd: number;
|
|
6431
6454
|
parentScope?: string;
|
|
6432
6455
|
}
|
|
6433
6456
|
/**
|
|
@@ -6727,6 +6750,28 @@ declare class RunBudget {
|
|
|
6727
6750
|
commitSynthesisReserve(scope: string, reserveUsd: number): void;
|
|
6728
6751
|
/** The synthesis dispatch consumes its reserve; see commitSynthesisReserve. */
|
|
6729
6752
|
releaseSynthesisReserve(scope: string): void;
|
|
6753
|
+
/**
|
|
6754
|
+
* Registers the repair round's verdict reserve (RV3701, the third
|
|
6755
|
+
* comparison experiment's arc): absolute dollars held on the
|
|
6756
|
+
* orchestrator account AND the run root for the verdict pass (the
|
|
6757
|
+
* round's second judge invocation) that must follow a DISPATCHED
|
|
6758
|
+
* claim repair round. The third comparison run
|
|
6759
|
+
* proved the round's two invocation tail is only as convergent as
|
|
6760
|
+
* the money left when the candidate materializes; with the verdict
|
|
6761
|
+
* money held from the moment the round is admitted, the round's own
|
|
6762
|
+
* repair turns (the layer-2b clamp prices output from a remainder
|
|
6763
|
+
* this hold shrinks) and any concurrent admission (the hold joins
|
|
6764
|
+
* the projected admission sum) cannot eat it, so a round the budget
|
|
6765
|
+
* can only START is refused before any wire call instead of being
|
|
6766
|
+
* paid for and left unjudgeable. Exactly the synthesis reserve
|
|
6767
|
+
* mechanics: released to the invocation it was held FOR (the
|
|
6768
|
+
* verdict pass dispatch), never joined to the severing check.
|
|
6769
|
+
* Idempotent per account: registering again adjusts the root by the
|
|
6770
|
+
* delta.
|
|
6771
|
+
*/
|
|
6772
|
+
commitConvergenceReserve(scope: string, reserveUsd: number): void;
|
|
6773
|
+
/** The verdict pass dispatch consumes its reserve; see commitConvergenceReserve. */
|
|
6774
|
+
releaseConvergenceReserve(scope: string): void;
|
|
6730
6775
|
/** The reserve is replaced by real spend when the spawn settles. */
|
|
6731
6776
|
releaseReserve(reserveUsd: number, accountScope?: string): void;
|
|
6732
6777
|
/**
|
|
@@ -13641,6 +13686,15 @@ interface JournaledCriticalPath {
|
|
|
13641
13686
|
*/
|
|
13642
13687
|
lastCandidateMs?: number;
|
|
13643
13688
|
/**
|
|
13689
|
+
* Settled agent spans whose invocation was aborted by the host's
|
|
13690
|
+
* finish rejection (RV3702): the journaled `hostRejected` stamps
|
|
13691
|
+
* counted. Unconditional (the stamp is self contained: no label, no
|
|
13692
|
+
* segment condition) and zero when none, exactly the live reading
|
|
13693
|
+
* of the same run: the layer split (wires fine, document refused by
|
|
13694
|
+
* host) stays readable years after the process exited.
|
|
13695
|
+
*/
|
|
13696
|
+
hostRejectedSpans: number;
|
|
13697
|
+
/**
|
|
13644
13698
|
* The window itemization a journal CAN answer (RV3404); present
|
|
13645
13699
|
* exactly when `postFanInMs` is.
|
|
13646
13700
|
*/
|
|
@@ -13925,6 +13979,28 @@ interface PinnedPricingSegment {
|
|
|
13925
13979
|
pricingVersion?: string;
|
|
13926
13980
|
/** The applied rows THIS settle pinned. */
|
|
13927
13981
|
rows: AppliedPricingRow[];
|
|
13982
|
+
/**
|
|
13983
|
+
* sha256 over the canonical JSON of THIS pin's rows (RV3703): the
|
|
13984
|
+
* version string is a label the table author chose, and the third
|
|
13985
|
+
* experiment's arc found a price defect that a label cannot expose;
|
|
13986
|
+
* the hash is the content. Two tables sharing a version string but
|
|
13987
|
+
* disagreeing on rates are distinguishable, and two folds of one
|
|
13988
|
+
* journal always derive the same hex. Computed at read time from
|
|
13989
|
+
* the pinned bytes: the journal is unchanged and every existing pin
|
|
13990
|
+
* gains it.
|
|
13991
|
+
*/
|
|
13992
|
+
rowsHash: string;
|
|
13993
|
+
/**
|
|
13994
|
+
* The freshness range of THIS pin's dated rows (RV3703): the oldest
|
|
13995
|
+
* and newest `ratesVerifiedAt` among rows carrying a parsable one,
|
|
13996
|
+
* the machine-readable age of the table that priced the segment.
|
|
13997
|
+
* Absent when no row is dated: freshness is then unattested, never
|
|
13998
|
+
* guessed.
|
|
13999
|
+
*/
|
|
14000
|
+
ratesVerifiedAt?: {
|
|
14001
|
+
oldest: string;
|
|
14002
|
+
newest: string;
|
|
14003
|
+
};
|
|
13928
14004
|
}
|
|
13929
14005
|
/** What `journalPricingSnapshot` rebuilds from a pinned run settle. */
|
|
13930
14006
|
interface JournalPricingSnapshot {
|
|
@@ -13932,6 +14008,16 @@ interface JournalPricingSnapshot {
|
|
|
13932
14008
|
pricingVersion?: string;
|
|
13933
14009
|
/** The last pin's rows: the union covering the whole settled journal. */
|
|
13934
14010
|
rows: AppliedPricingRow[];
|
|
14011
|
+
/** The last pin's content hash (RV3703); see PinnedPricingSegment.rowsHash. */
|
|
14012
|
+
rowsHash: string;
|
|
14013
|
+
/**
|
|
14014
|
+
* The last pin's freshness range (RV3703); see the per-segment
|
|
14015
|
+
* field. Absent when no row of the last pin is dated.
|
|
14016
|
+
*/
|
|
14017
|
+
ratesVerifiedAt?: {
|
|
14018
|
+
oldest: string;
|
|
14019
|
+
newest: string;
|
|
14020
|
+
};
|
|
13935
14021
|
/**
|
|
13936
14022
|
* The seq of the last pinning settle: rows at or past it belong to a
|
|
13937
14023
|
* segment no pin covers yet, so a caller composing with a live table
|
|
@@ -14738,7 +14824,13 @@ interface PreflightOrchestratorSpec {
|
|
|
14738
14824
|
* before the first wire, not the journal after the last. Pairings
|
|
14739
14825
|
* orchestrate() refuses at intake (repair at the draft stage,
|
|
14740
14826
|
* repair without a synthesis, carry at the final stage, RV3301)
|
|
14741
|
-
* surface as error findings: the run would refuse to start.
|
|
14827
|
+
* surface as error findings: the run would refuse to start. This
|
|
14828
|
+
* static arithmetic has a runtime twin (RV3701): at the moment a
|
|
14829
|
+
* round actually dispatches, the engine holds the money of the round's second judge pass
|
|
14830
|
+
* (this same `judge.estCost` first, else the run's own observed
|
|
14831
|
+
* post draft judge price) until that pass admits, so the
|
|
14832
|
+
* declared estimate is not only judged before the run but enforced
|
|
14833
|
+
* inside it.
|
|
14742
14834
|
*/
|
|
14743
14835
|
onFound?: "report" | "carry" | "fail" | "repair";
|
|
14744
14836
|
/**
|
|
@@ -15559,6 +15651,14 @@ interface AgentInvocationRow {
|
|
|
15559
15651
|
replayed: boolean;
|
|
15560
15652
|
/** True when the span's agent:end never arrived. */
|
|
15561
15653
|
open: boolean;
|
|
15654
|
+
/**
|
|
15655
|
+
* Present and true when the invocation was aborted by the host's
|
|
15656
|
+
* finish rejection (RV3702): the declared finish contract rejected
|
|
15657
|
+
* the candidate past its repair bound, so the span died by host
|
|
15658
|
+
* hand with its wires fine. From the agent:end stamp; absent
|
|
15659
|
+
* everywhere else.
|
|
15660
|
+
*/
|
|
15661
|
+
hostRejected?: boolean;
|
|
15562
15662
|
phases: PhaseRow[];
|
|
15563
15663
|
}
|
|
15564
15664
|
/** The reduced table plus the per-role aggregate across every span. */
|
|
@@ -15669,6 +15769,15 @@ interface CriticalPath {
|
|
|
15669
15769
|
synthesisShare?: number;
|
|
15670
15770
|
/** Settled non-coordination agent spans that anchored the fan-in. */
|
|
15671
15771
|
workerSpans: number;
|
|
15772
|
+
/**
|
|
15773
|
+
* Settled spans whose invocation was aborted by the host's finish
|
|
15774
|
+
* rejection (RV3702): the `hostRejected` stamps counted. The count
|
|
15775
|
+
* is unconditional (the stamp is self contained, no labelling
|
|
15776
|
+
* condition applies) and zero when none: on the third comparison
|
|
15777
|
+
* run's shape it reads 1, the round's composition, telling the host
|
|
15778
|
+
* rejection apart from a provider death at the cut level.
|
|
15779
|
+
*/
|
|
15780
|
+
hostRejectedSpans: number;
|
|
15672
15781
|
/** The RV710 decomposition of the window; present with postFanInMs. */
|
|
15673
15782
|
postFanIn?: PostFanInBreakdown;
|
|
15674
15783
|
}
|
package/dist/index.js
CHANGED
|
@@ -7972,6 +7972,7 @@ var Replayer = class {
|
|
|
7972
7972
|
if (patch.evidence !== void 0) entry.evidence = patch.evidence;
|
|
7973
7973
|
if (patch.evidenceEntries !== void 0) entry.evidenceEntries = patch.evidenceEntries;
|
|
7974
7974
|
if (patch.toolBudget !== void 0) entry.toolBudget = patch.toolBudget;
|
|
7975
|
+
if (patch.hostRejected !== void 0) entry.hostRejected = patch.hostRejected;
|
|
7975
7976
|
if (patch.artifacts !== void 0) entry.artifacts = toJournalValue(patch.artifacts, "terminal artifacts");
|
|
7976
7977
|
if (patch.escalation !== void 0) entry.escalation = toJournalValue(patch.escalation, "escalation report");
|
|
7977
7978
|
if (patch.memoizeOutcome !== void 0) entry.memoizeOutcome = patch.memoizeOutcome;
|
|
@@ -9311,6 +9312,7 @@ function reduceInvocationTable(events) {
|
|
|
9311
9312
|
row.usageApprox = event.usageApprox === true;
|
|
9312
9313
|
row.retryCount = event.retryCount ?? 0;
|
|
9313
9314
|
if (event.toolBudget !== void 0) row.toolBudget = event.toolBudget;
|
|
9315
|
+
if (event.hostRejected === true) row.hostRejected = true;
|
|
9314
9316
|
totalCostUsd += event.costUsd;
|
|
9315
9317
|
break;
|
|
9316
9318
|
}
|
|
@@ -9331,6 +9333,20 @@ function reduceInvocationTable(events) {
|
|
|
9331
9333
|
*/
|
|
9332
9334
|
const CLAIM_JUDGE_LABEL = "claim-consistency-judge";
|
|
9333
9335
|
/**
|
|
9336
|
+
* The live abort reason of a finish rejection (RV3702): the value
|
|
9337
|
+
* `orchestrate()` aborts a composition invocation's signal with when
|
|
9338
|
+
* the declared finish contract rejects its candidate past the repair
|
|
9339
|
+
* bound, and ONLY then; a defective (throwing) validator aborts with
|
|
9340
|
+
* its own distinct reason, because a host defect is not a verdict on
|
|
9341
|
+
* the candidate. The settle layer reads the reason back and stamps
|
|
9342
|
+
* `hostRejected` onto the terminal agent entry and the live
|
|
9343
|
+
* `agent:end` event, so both span surfaces can tell a host rejection
|
|
9344
|
+
* (wires fine, document refused) from a provider failure without a
|
|
9345
|
+
* journal dig; the third comparison run's reader had exactly that
|
|
9346
|
+
* span (two successful wires, span cancelled) and nothing to name it.
|
|
9347
|
+
*/
|
|
9348
|
+
const FINISH_REJECTION_ABORT_REASON = "rulvar:finish-validation";
|
|
9349
|
+
/**
|
|
9334
9350
|
* Whether a synthesize span's label names a claim-consistency judge
|
|
9335
9351
|
* invocation: the exact {@link CLAIM_JUDGE_LABEL}, or a suffixed
|
|
9336
9352
|
* variant of it (the final pass dispatches under
|
|
@@ -9413,6 +9429,7 @@ function reduceCriticalPath(events) {
|
|
|
9413
9429
|
let finalJudgeMs = 0;
|
|
9414
9430
|
let compositionSpans = 0;
|
|
9415
9431
|
let judgeSpans = 0;
|
|
9432
|
+
let hostRejectedSpans = 0;
|
|
9416
9433
|
let firstCompositionEnd;
|
|
9417
9434
|
let lastCompositionEnd;
|
|
9418
9435
|
const coordinationModel = [];
|
|
@@ -9453,6 +9470,7 @@ function reduceCriticalPath(events) {
|
|
|
9453
9470
|
case "agent:end": {
|
|
9454
9471
|
const started = startBySpan.get(event.spanId);
|
|
9455
9472
|
if (started === void 0) break;
|
|
9473
|
+
if (event.hostRejected === true) hostRejectedSpans += 1;
|
|
9456
9474
|
if (started.role === "synthesize") {
|
|
9457
9475
|
const wall = Math.max(0, at - started.at);
|
|
9458
9476
|
const stage = claimJudgeStageOf(started.label);
|
|
@@ -9491,7 +9509,8 @@ function reduceCriticalPath(events) {
|
|
|
9491
9509
|
finalJudgeMs,
|
|
9492
9510
|
compositionSpans,
|
|
9493
9511
|
judgeSpans,
|
|
9494
|
-
workerSpans
|
|
9512
|
+
workerSpans,
|
|
9513
|
+
hostRejectedSpans
|
|
9495
9514
|
};
|
|
9496
9515
|
if (runStart !== void 0 && runEnd !== void 0) path.runWallMs = Math.max(0, runEnd - runStart);
|
|
9497
9516
|
if (runStart !== void 0 && firstCompositionEnd !== void 0) path.firstCandidateMs = Math.max(0, firstCompositionEnd - runStart);
|
|
@@ -9583,6 +9602,7 @@ function criticalPathFromJournal(entries) {
|
|
|
9583
9602
|
let lastWorkerEnd;
|
|
9584
9603
|
let workerSpans = 0;
|
|
9585
9604
|
let unclassifiedSpans = 0;
|
|
9605
|
+
let hostRejectedSpans = 0;
|
|
9586
9606
|
let synthesisMs = 0;
|
|
9587
9607
|
let finalCompositionMs = 0;
|
|
9588
9608
|
let semanticJudgeMs = 0;
|
|
@@ -9602,6 +9622,7 @@ function criticalPathFromJournal(entries) {
|
|
|
9602
9622
|
const last = endedAt ?? startedAt;
|
|
9603
9623
|
if (last !== void 0) runEnd = runEnd === void 0 ? last : Math.max(runEnd, last);
|
|
9604
9624
|
if (entry.kind !== "agent" || entry.status === "running" || entry.status === "suspended") continue;
|
|
9625
|
+
if (entry.hostRejected === true) hostRejectedSpans += 1;
|
|
9605
9626
|
const role = entry.costAttribution?.role;
|
|
9606
9627
|
if (role === void 0) {
|
|
9607
9628
|
unclassifiedSpans += 1;
|
|
@@ -9649,7 +9670,8 @@ function criticalPathFromJournal(entries) {
|
|
|
9649
9670
|
workerSpans,
|
|
9650
9671
|
synthesisMs,
|
|
9651
9672
|
unclassifiedSpans,
|
|
9652
|
-
segments
|
|
9673
|
+
segments,
|
|
9674
|
+
hostRejectedSpans
|
|
9653
9675
|
};
|
|
9654
9676
|
const splitLegible = labelledSynthesis && !unlabelledSynthesis;
|
|
9655
9677
|
if (splitLegible) {
|
|
@@ -14875,6 +14897,7 @@ var RunBudget = class {
|
|
|
14875
14897
|
committedReserveUsd: 0,
|
|
14876
14898
|
finalizeReserveUsd: 0,
|
|
14877
14899
|
synthesisReserveUsd: 0,
|
|
14900
|
+
convergenceReserveUsd: 0,
|
|
14878
14901
|
controller: new AbortController()
|
|
14879
14902
|
};
|
|
14880
14903
|
if (options.ceilingUsd !== void 0) root.ceilingUsd = options.ceilingUsd;
|
|
@@ -14925,6 +14948,7 @@ var RunBudget = class {
|
|
|
14925
14948
|
committedReserveUsd: 0,
|
|
14926
14949
|
finalizeReserveUsd: options.finalizeReserveUsd ?? 0,
|
|
14927
14950
|
synthesisReserveUsd: 0,
|
|
14951
|
+
convergenceReserveUsd: 0,
|
|
14928
14952
|
parentScope,
|
|
14929
14953
|
controller: new AbortController()
|
|
14930
14954
|
};
|
|
@@ -15025,7 +15049,8 @@ var RunBudget = class {
|
|
|
15025
15049
|
spentUsd: account.spentUsd,
|
|
15026
15050
|
committedReserveUsd: account.committedReserveUsd,
|
|
15027
15051
|
finalizeReserveUsd: account.finalizeReserveUsd,
|
|
15028
|
-
synthesisReserveUsd: account.synthesisReserveUsd
|
|
15052
|
+
synthesisReserveUsd: account.synthesisReserveUsd,
|
|
15053
|
+
convergenceReserveUsd: account.convergenceReserveUsd
|
|
15029
15054
|
};
|
|
15030
15055
|
if (account.ceilingUsd !== void 0) view.ceilingUsd = account.ceilingUsd;
|
|
15031
15056
|
if (account.parentScope !== void 0) view.parentScope = account.parentScope;
|
|
@@ -15039,7 +15064,7 @@ var RunBudget = class {
|
|
|
15039
15064
|
remainderOf(scope) {
|
|
15040
15065
|
const account = this.accounts.get(scope);
|
|
15041
15066
|
if (account?.ceilingUsd === void 0) return;
|
|
15042
|
-
return Math.max(0, account.ceilingUsd - account.spentUsd - account.committedReserveUsd - account.finalizeReserveUsd - account.synthesisReserveUsd);
|
|
15067
|
+
return Math.max(0, account.ceilingUsd - account.spentUsd - account.committedReserveUsd - account.finalizeReserveUsd - account.synthesisReserveUsd - account.convergenceReserveUsd);
|
|
15043
15068
|
}
|
|
15044
15069
|
/**
|
|
15045
15070
|
* The tightest allowance headroom on the chain of `scope`: the minimum
|
|
@@ -15119,15 +15144,16 @@ var RunBudget = class {
|
|
|
15119
15144
|
}
|
|
15120
15145
|
for (const account of this.chainOf(accountScope)) {
|
|
15121
15146
|
if (account.ceilingUsd === void 0) continue;
|
|
15122
|
-
const committed = account.spentUsd + account.committedReserveUsd + account.finalizeReserveUsd + account.synthesisReserveUsd;
|
|
15147
|
+
const committed = account.spentUsd + account.committedReserveUsd + account.finalizeReserveUsd + account.synthesisReserveUsd + account.convergenceReserveUsd;
|
|
15123
15148
|
if (committed >= account.ceilingUsd || committed + reserveUsd > account.ceilingUsd) {
|
|
15124
15149
|
if (account.scope === "run") this.exhaustedInternal = true;
|
|
15125
|
-
throw new BudgetExhaustedError(`budget ceiling reached on account '${account.scope}': spent ${account.spentUsd.toFixed(4)} USD plus committed reserves ${(account.committedReserveUsd + account.finalizeReserveUsd).toFixed(4)} USD ` + (account.synthesisReserveUsd > 0 ? `plus the held synthesis reserve ${account.synthesisReserveUsd.toFixed(4)} USD ` : "") + `plus the proposed reserve ${reserveUsd.toFixed(4)} USD does not fit the ceiling ${account.ceilingUsd.toFixed(4)} USD`, { data: {
|
|
15150
|
+
throw new BudgetExhaustedError(`budget ceiling reached on account '${account.scope}': spent ${account.spentUsd.toFixed(4)} USD plus committed reserves ${(account.committedReserveUsd + account.finalizeReserveUsd).toFixed(4)} USD ` + (account.synthesisReserveUsd > 0 ? `plus the held synthesis reserve ${account.synthesisReserveUsd.toFixed(4)} USD ` : "") + (account.convergenceReserveUsd > 0 ? `plus the held convergence reserve ${account.convergenceReserveUsd.toFixed(4)} USD ` : "") + `plus the proposed reserve ${reserveUsd.toFixed(4)} USD does not fit the ceiling ${account.ceilingUsd.toFixed(4)} USD`, { data: {
|
|
15126
15151
|
account: account.scope,
|
|
15127
15152
|
spentUsd: account.spentUsd,
|
|
15128
15153
|
committedReserveUsd: account.committedReserveUsd,
|
|
15129
15154
|
finalizeReserveUsd: account.finalizeReserveUsd,
|
|
15130
15155
|
synthesisReserveUsd: account.synthesisReserveUsd,
|
|
15156
|
+
convergenceReserveUsd: account.convergenceReserveUsd,
|
|
15131
15157
|
proposedReserveUsd: reserveUsd,
|
|
15132
15158
|
ceilingUsd: account.ceilingUsd
|
|
15133
15159
|
} });
|
|
@@ -15219,6 +15245,41 @@ var RunBudget = class {
|
|
|
15219
15245
|
account.synthesisReserveUsd = 0;
|
|
15220
15246
|
this.emitUpdate();
|
|
15221
15247
|
}
|
|
15248
|
+
/**
|
|
15249
|
+
* Registers the repair round's verdict reserve (RV3701, the third
|
|
15250
|
+
* comparison experiment's arc): absolute dollars held on the
|
|
15251
|
+
* orchestrator account AND the run root for the verdict pass (the
|
|
15252
|
+
* round's second judge invocation) that must follow a DISPATCHED
|
|
15253
|
+
* claim repair round. The third comparison run
|
|
15254
|
+
* proved the round's two invocation tail is only as convergent as
|
|
15255
|
+
* the money left when the candidate materializes; with the verdict
|
|
15256
|
+
* money held from the moment the round is admitted, the round's own
|
|
15257
|
+
* repair turns (the layer-2b clamp prices output from a remainder
|
|
15258
|
+
* this hold shrinks) and any concurrent admission (the hold joins
|
|
15259
|
+
* the projected admission sum) cannot eat it, so a round the budget
|
|
15260
|
+
* can only START is refused before any wire call instead of being
|
|
15261
|
+
* paid for and left unjudgeable. Exactly the synthesis reserve
|
|
15262
|
+
* mechanics: released to the invocation it was held FOR (the
|
|
15263
|
+
* verdict pass dispatch), never joined to the severing check.
|
|
15264
|
+
* Idempotent per account: registering again adjusts the root by the
|
|
15265
|
+
* delta.
|
|
15266
|
+
*/
|
|
15267
|
+
commitConvergenceReserve(scope, reserveUsd) {
|
|
15268
|
+
const account = this.accounts.get(scope);
|
|
15269
|
+
if (account === void 0) throw new ConfigError(`unknown budget account '${scope}' for the convergence reserve`);
|
|
15270
|
+
const previous = account.convergenceReserveUsd;
|
|
15271
|
+
account.convergenceReserveUsd = reserveUsd;
|
|
15272
|
+
if (account.scope !== "run") this.root.convergenceReserveUsd = Math.max(0, this.root.convergenceReserveUsd + reserveUsd - previous);
|
|
15273
|
+
this.emitUpdate();
|
|
15274
|
+
}
|
|
15275
|
+
/** The verdict pass dispatch consumes its reserve; see commitConvergenceReserve. */
|
|
15276
|
+
releaseConvergenceReserve(scope) {
|
|
15277
|
+
const account = this.accounts.get(scope);
|
|
15278
|
+
if (account === void 0 || account.convergenceReserveUsd === 0) return;
|
|
15279
|
+
if (account.scope !== "run") this.root.convergenceReserveUsd = Math.max(0, this.root.convergenceReserveUsd - account.convergenceReserveUsd);
|
|
15280
|
+
account.convergenceReserveUsd = 0;
|
|
15281
|
+
this.emitUpdate();
|
|
15282
|
+
}
|
|
15222
15283
|
/** The reserve is replaced by real spend when the spawn settles. */
|
|
15223
15284
|
releaseReserve(reserveUsd, accountScope = "run") {
|
|
15224
15285
|
for (const account of this.chainOf(accountScope)) account.committedReserveUsd = Math.max(0, account.committedReserveUsd - reserveUsd);
|
|
@@ -15426,7 +15487,7 @@ var RunBudget = class {
|
|
|
15426
15487
|
let remaining;
|
|
15427
15488
|
for (const account of this.chainOf(accountScope)) {
|
|
15428
15489
|
if (account.ceilingUsd === void 0) continue;
|
|
15429
|
-
const headroom = account.ceilingUsd - account.spentUsd - account.synthesisReserveUsd;
|
|
15490
|
+
const headroom = account.ceilingUsd - account.spentUsd - account.synthesisReserveUsd - account.convergenceReserveUsd;
|
|
15430
15491
|
remaining = remaining === void 0 ? headroom : Math.min(remaining, headroom);
|
|
15431
15492
|
}
|
|
15432
15493
|
return remaining === void 0 ? void 0 : Math.max(0, remaining);
|
|
@@ -16865,6 +16926,33 @@ function persistedTerminalEnvelope(input) {
|
|
|
16865
16926
|
//#endregion
|
|
16866
16927
|
//#region src/engine/pricing-snapshot.ts
|
|
16867
16928
|
/**
|
|
16929
|
+
* The applied-pricing snapshot (RV407, the eighth-experiment review).
|
|
16930
|
+
* `invoiceFromJournal` and `costReportFromJournal` price at fold time
|
|
16931
|
+
* from the table the caller passes, so a live price-table update used
|
|
16932
|
+
* to silently re-price HISTORY: the same journal folded to different
|
|
16933
|
+
* invoices before and after the change. When `createEngine({ pricing })`
|
|
16934
|
+
* is configured, the settling segment now pins what it actually
|
|
16935
|
+
* applied: the resolved pricing row of every model the journal used
|
|
16936
|
+
* (table rows plus the caps-fallback rows of models the table misses),
|
|
16937
|
+
* and the table's version, additively inside the existing run-settle
|
|
16938
|
+
* decision value (the `outputHash` precedent; no journal shape change).
|
|
16939
|
+
* The gate is deliberate: caps-fallback pricing arrives ambiently from
|
|
16940
|
+
* adapters, and a setting the user never enabled must not change the
|
|
16941
|
+
* journal, so table-less runs settle byte for byte as before.
|
|
16942
|
+
* `journalPricingSnapshot` reads the pin back and
|
|
16943
|
+
* rebuilds a `priceUsd` from the pinned rows, so a repeated fold after
|
|
16944
|
+
* the live table changed reproduces the original numbers exactly.
|
|
16945
|
+
*
|
|
16946
|
+
* The snapshot governs REPORTING folds (the CLI invoice and inspect
|
|
16947
|
+
* cost views, and any host that opts in by passing the rebuilt
|
|
16948
|
+
* priceUsd; since RV611 those consumers pass `composedPriceUsd`, the
|
|
16949
|
+
* same pin-plus-current-table composition the engine's outcome mirror
|
|
16950
|
+
* applies, so a stored fold and the settled outcome can never
|
|
16951
|
+
* disagree). The engine's own live pricing, budget admission, and the
|
|
16952
|
+
* journaled spend debits are untouched: they were always priced at
|
|
16953
|
+
* write time and never re-priced by a fold.
|
|
16954
|
+
*/
|
|
16955
|
+
/**
|
|
16868
16956
|
* A pinnable row: every present rate is a finite non-negative number.
|
|
16869
16957
|
* The fold already treats a broken rate as unpriced (a NaN or negative
|
|
16870
16958
|
* price never poisons the CostReport), so the pin mirrors exactly that
|
|
@@ -16902,6 +16990,42 @@ function snapshotJournalPricing(entries, pricingOf) {
|
|
|
16902
16990
|
}
|
|
16903
16991
|
return rows.length === 0 ? void 0 : rows;
|
|
16904
16992
|
}
|
|
16993
|
+
/**
|
|
16994
|
+
* The pin's content hash (RV3703): sha256 over the canonical JSON of
|
|
16995
|
+
* the rows, so the derivation is byte-stable across folds, engines and
|
|
16996
|
+
* platforms; JCS fixes the key order, and the row order is the pin's
|
|
16997
|
+
* own (sorted at write, preserved at read).
|
|
16998
|
+
*/
|
|
16999
|
+
function rowsHashOf(rows) {
|
|
17000
|
+
return createHash("sha256").update(jcsSerialize(rows), "utf8").digest("hex");
|
|
17001
|
+
}
|
|
17002
|
+
/**
|
|
17003
|
+
* The freshness range of a pin's dated rows (RV3703): oldest and
|
|
17004
|
+
* newest parsable `ratesVerifiedAt`, original strings preserved.
|
|
17005
|
+
* Undefined when no row carries a parsable date.
|
|
17006
|
+
*/
|
|
17007
|
+
function ratesVerifiedRangeOf(rows) {
|
|
17008
|
+
let oldest;
|
|
17009
|
+
let newest;
|
|
17010
|
+
for (const row of rows) {
|
|
17011
|
+
const raw = row.rates.ratesVerifiedAt;
|
|
17012
|
+
if (raw === void 0) continue;
|
|
17013
|
+
const at = Date.parse(raw);
|
|
17014
|
+
if (!Number.isFinite(at)) continue;
|
|
17015
|
+
if (oldest === void 0 || at < oldest.at) oldest = {
|
|
17016
|
+
at,
|
|
17017
|
+
raw
|
|
17018
|
+
};
|
|
17019
|
+
if (newest === void 0 || at > newest.at) newest = {
|
|
17020
|
+
at,
|
|
17021
|
+
raw
|
|
17022
|
+
};
|
|
17023
|
+
}
|
|
17024
|
+
return oldest === void 0 || newest === void 0 ? void 0 : {
|
|
17025
|
+
oldest: oldest.raw,
|
|
17026
|
+
newest: newest.raw
|
|
17027
|
+
};
|
|
17028
|
+
}
|
|
16905
17029
|
function pinnedRows(value) {
|
|
16906
17030
|
const candidate = value?.pricing;
|
|
16907
17031
|
if (!Array.isArray(candidate) || candidate.length === 0) return;
|
|
@@ -16953,16 +17077,24 @@ function journalPricingSnapshot(entries) {
|
|
|
16953
17077
|
const rates = ratesFor(servedBy, seq);
|
|
16954
17078
|
return rates === void 0 ? void 0 : priceUsdOf(rates, usage);
|
|
16955
17079
|
};
|
|
17080
|
+
const lastRange = ratesVerifiedRangeOf(last.rows);
|
|
16956
17081
|
return {
|
|
16957
17082
|
...last.pricingVersion === void 0 ? {} : { pricingVersion: last.pricingVersion },
|
|
16958
17083
|
rows: last.rows,
|
|
17084
|
+
rowsHash: rowsHashOf(last.rows),
|
|
17085
|
+
...lastRange === void 0 ? {} : { ratesVerifiedAt: lastRange },
|
|
16959
17086
|
pinnedThroughSeq,
|
|
16960
|
-
segments: pins.map((pin, index) =>
|
|
16961
|
-
|
|
16962
|
-
|
|
16963
|
-
|
|
16964
|
-
|
|
16965
|
-
|
|
17087
|
+
segments: pins.map((pin, index) => {
|
|
17088
|
+
const range = ratesVerifiedRangeOf(pin.rows);
|
|
17089
|
+
return {
|
|
17090
|
+
fromSeq: index === 0 ? 0 : pins[index - 1]?.seq ?? 0,
|
|
17091
|
+
settleSeq: pin.seq,
|
|
17092
|
+
...pin.pricingVersion === void 0 ? {} : { pricingVersion: pin.pricingVersion },
|
|
17093
|
+
rows: pin.rows,
|
|
17094
|
+
rowsHash: rowsHashOf(pin.rows),
|
|
17095
|
+
...range === void 0 ? {} : { ratesVerifiedAt: range }
|
|
17096
|
+
};
|
|
17097
|
+
}),
|
|
16966
17098
|
priceUsd,
|
|
16967
17099
|
composedPriceUsd: (current) => (servedBy, usage, seq) => seq !== void 0 && seq < pinnedThroughSeq ? priceUsd(servedBy, usage, seq) ?? current(servedBy, usage) : current(servedBy, usage)
|
|
16968
17100
|
};
|
|
@@ -18810,6 +18942,7 @@ function createCtx(internals, rootWorkflow) {
|
|
|
18810
18942
|
costBasis: replayBasis,
|
|
18811
18943
|
entryRef: terminal?.seq ?? matched.running.seq,
|
|
18812
18944
|
...terminal?.usageApprox === true ? { usageApprox: true } : {},
|
|
18945
|
+
...terminal?.hostRejected === true ? { hostRejected: true } : {},
|
|
18813
18946
|
...result.exploration === void 0 ? {} : { exploration: result.exploration },
|
|
18814
18947
|
...result.toolBudget === void 0 ? {} : { toolBudget: result.toolBudget }
|
|
18815
18948
|
}, spanId, true);
|
|
@@ -19538,6 +19671,8 @@ function createCtx(internals, rootWorkflow) {
|
|
|
19538
19671
|
}
|
|
19539
19672
|
};
|
|
19540
19673
|
}
|
|
19674
|
+
const settleSignal = state.signal ?? internals.runSignal;
|
|
19675
|
+
if (result.status !== "ok" && settleSignal?.aborted === true && settleSignal.reason === "rulvar:finish-validation") terminalPatch.hostRejected = true;
|
|
19541
19676
|
if (checkpointWritten) terminalPatch.checkpointRef = ckptRef;
|
|
19542
19677
|
const terminal = await internals.replayer.appendTerminal(running.seq, terminalPatch);
|
|
19543
19678
|
internals.events.emit({
|
|
@@ -19551,6 +19686,7 @@ function createCtx(internals, rootWorkflow) {
|
|
|
19551
19686
|
entryRef: terminal.seq,
|
|
19552
19687
|
...resultUsageApprox ? { usageApprox: true } : {},
|
|
19553
19688
|
...result.transportRetries !== void 0 && result.transportRetries > 0 ? { retryCount: result.transportRetries } : {},
|
|
19689
|
+
...terminalPatch.hostRejected === true ? { hostRejected: true } : {},
|
|
19554
19690
|
...result.quotaDenials === void 0 ? {} : { quotaDenials: result.quotaDenials },
|
|
19555
19691
|
...result.exploration === void 0 ? {} : { exploration: result.exploration },
|
|
19556
19692
|
...result.toolBudget === void 0 ? {} : { toolBudget: result.toolBudget }
|
|
@@ -24326,7 +24462,7 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
24326
24462
|
verdict = validator.validate(input);
|
|
24327
24463
|
} catch (thrown) {
|
|
24328
24464
|
validationTermination = new ConfigError(`finish validator '${validator.name}' threw instead of returning a verdict: ` + (thrown instanceof Error ? thrown.message : String(thrown)));
|
|
24329
|
-
validationAbort.abort("rulvar:finish-validation");
|
|
24465
|
+
validationAbort.abort("rulvar:finish-validation-defect");
|
|
24330
24466
|
return {
|
|
24331
24467
|
ok: false,
|
|
24332
24468
|
feedback: { error: `finish validator '${validator.name}' is defective; the run fails` }
|
|
@@ -24389,7 +24525,7 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
24389
24525
|
if (decision.verdict === "rejected") {
|
|
24390
24526
|
if (contractGenerationCurrent(decision)) {
|
|
24391
24527
|
validationTermination = finishValidationError(decision);
|
|
24392
|
-
validationAbort.abort(
|
|
24528
|
+
validationAbort.abort(FINISH_REJECTION_ABORT_REASON);
|
|
24393
24529
|
}
|
|
24394
24530
|
return {
|
|
24395
24531
|
ok: false,
|
|
@@ -24924,6 +25060,15 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
24924
25060
|
* not settle ok, because an empty list would claim the pool agreed.
|
|
24925
25061
|
*/
|
|
24926
25062
|
let claimFindingsFound;
|
|
25063
|
+
/**
|
|
25064
|
+
* The observed price of this run's own latest post draft claim
|
|
25065
|
+
* judge pass (RV3701): the fallback sizing of the repair round's
|
|
25066
|
+
* convergence hold when the host declared no `judge.estCost`. By
|
|
25067
|
+
* the time the bounded round can dispatch, a post draft pass has
|
|
25068
|
+
* always settled (the round's findings came from it), so the
|
|
25069
|
+
* fallback is this run's own money, never an invented constant.
|
|
25070
|
+
*/
|
|
25071
|
+
let observedFinalJudgeCostUsd;
|
|
24927
25072
|
/** Set whenever the pass ran, findings or not (the RV1404 pairing). */
|
|
24928
25073
|
let claimConsistencyMeta;
|
|
24929
25074
|
/**
|
|
@@ -25208,6 +25353,7 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
25208
25353
|
try {
|
|
25209
25354
|
judged = await runtime.runInScope(judgeState, () => ctx.agent(judgePrompt, judgeOpts));
|
|
25210
25355
|
noteInternalSettle(judged);
|
|
25356
|
+
if (stage !== "draft" && typeof judged.costUsd === "number") observedFinalJudgeCostUsd = judged.costUsd;
|
|
25211
25357
|
} catch (declined) {
|
|
25212
25358
|
if (!(declined instanceof BudgetExhaustedError)) throw declined;
|
|
25213
25359
|
claimConsistencyMeta = finishMeta({
|
|
@@ -26391,6 +26537,9 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
26391
26537
|
const hashOfDocument = (value) => createHash("sha256").update(jcsSerialize(value ?? null), "utf8").digest("hex");
|
|
26392
26538
|
const preRepairHash = hashOfDocument(synthesizedFinal);
|
|
26393
26539
|
const carried = claimFindingsFound;
|
|
26540
|
+
const convergenceHoldUsd = opts?.claimConsistency?.judge?.estCost ?? observedFinalJudgeCostUsd ?? 0;
|
|
26541
|
+
const convergenceScope = orchestratorAccount ?? "run";
|
|
26542
|
+
if (convergenceHoldUsd > 0) internals.budget.commitConvergenceReserve(convergenceScope, convergenceHoldUsd);
|
|
26394
26543
|
try {
|
|
26395
26544
|
synthesizedFinal = await runSynthesis(result.output);
|
|
26396
26545
|
} catch (thrown) {
|
|
@@ -26422,8 +26571,21 @@ function makeOrchestratorWorkflow(goal, opts) {
|
|
|
26422
26571
|
preRepairHash,
|
|
26423
26572
|
...acceptanceSnapshot
|
|
26424
26573
|
} });
|
|
26574
|
+
} finally {
|
|
26575
|
+
if (convergenceHoldUsd > 0) internals.budget.releaseConvergenceReserve(convergenceScope);
|
|
26576
|
+
}
|
|
26577
|
+
try {
|
|
26578
|
+
await runClaimConsistencyPass(synthesizedFinal, acceptanceSnapshot, "final");
|
|
26579
|
+
} catch (thrown) {
|
|
26580
|
+
if (thrown instanceof FailRunError && typeof thrown.data === "object" && thrown.data !== null && !Array.isArray(thrown.data) && thrown.data.source === "orchestrator_claim_consistency") throw new FailRunError(thrown.message, { data: {
|
|
26581
|
+
...thrown.data,
|
|
26582
|
+
...thrown.data.claimContradictions === void 0 ? { claimContradictions: carried } : {},
|
|
26583
|
+
roundDispatched: true,
|
|
26584
|
+
repairsUsed: 1,
|
|
26585
|
+
preRepairHash
|
|
26586
|
+
} });
|
|
26587
|
+
throw thrown;
|
|
26425
26588
|
}
|
|
26426
|
-
await runClaimConsistencyPass(synthesizedFinal, acceptanceSnapshot, "final");
|
|
26427
26589
|
if (claimFindingsFound !== void 0 && claimFindingsFound.length > 0) throw new FailRunError(`the claim-consistency judge still found ${String(claimFindingsFound.length)} contradiction${claimFindingsFound.length === 1 ? "" : "s"} after the bounded repair round: the repaired composition keeps contradicting the settled pool`, { data: {
|
|
26428
26590
|
source: "orchestrator_claim_consistency",
|
|
26429
26591
|
claimContradictions: claimFindingsFound,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rulvar/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.242.0",
|
|
4
4
|
"description": "Rulvar core: L0 contracts, journal kernel, ctx primitives, agent runtime, model router, tool system, dynamic orchestrator, InMemory and JSONL stores, event stream.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|