@rulvar/core 1.235.0 → 1.236.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 +64 -0
- package/dist/index.js +32 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1217,6 +1217,15 @@ type RunMeta = {
|
|
|
1217
1217
|
allowUnpriced?: string[];
|
|
1218
1218
|
};
|
|
1219
1219
|
/**
|
|
1220
|
+
* The host-declared config identity (RunOptions.configFingerprint,
|
|
1221
|
+
* RV3210): an opaque pin over what the workflow body closes over,
|
|
1222
|
+
* recorded at genesis and compared on every resume that asserts one.
|
|
1223
|
+
* Absent when the run declared none. A store that drops the field
|
|
1224
|
+
* degrades the check to the UNRECORDED warning, never a false pass
|
|
1225
|
+
* or a false refusal (absence means NOT RECORDED).
|
|
1226
|
+
*/
|
|
1227
|
+
configFingerprint?: string;
|
|
1228
|
+
/**
|
|
1220
1229
|
* Count of execution segments this run has STARTED (a fresh start
|
|
1221
1230
|
* writes 1; every resume writes prior + 1, durably, BEFORE the
|
|
1222
1231
|
* segment emits its first event). The engine derives each segment's
|
|
@@ -7784,6 +7793,24 @@ interface RunOptions {
|
|
|
7784
7793
|
/** Explicit id; otherwise the engine mints a ULID. */
|
|
7785
7794
|
runId?: string;
|
|
7786
7795
|
/**
|
|
7796
|
+
* An opaque host-declared identity over the config the workflow body
|
|
7797
|
+
* CLOSES OVER (RV3210, the honest answer to `hashWorkflowBody`'s
|
|
7798
|
+
* closure blindness: the body-text hash cannot see captured values,
|
|
7799
|
+
* so two byte-identical bodies over different closures pin
|
|
7800
|
+
* identically). Recorded in RunMeta at genesis and compared on every
|
|
7801
|
+
* resume that supplies one: a mismatch refuses the resume typed
|
|
7802
|
+
* BEFORE ownership, meta writes, and appends, because the host
|
|
7803
|
+
* itself asserted the identity; a recorded fingerprint the resume
|
|
7804
|
+
* does not supply warns (`RULVAR_RESUME_FINGERPRINT_UNCHECKED`), and
|
|
7805
|
+
* a supplied fingerprint the run never recorded warns
|
|
7806
|
+
* (`RULVAR_RESUME_FINGERPRINT_UNRECORDED`) instead of failing,
|
|
7807
|
+
* because absence means NOT RECORDED. The preferred pattern is still
|
|
7808
|
+
* to close over nothing and pass config through args; the
|
|
7809
|
+
* fingerprint is the pin for what must stay closed over. A non-empty
|
|
7810
|
+
* string of at most 512 characters.
|
|
7811
|
+
*/
|
|
7812
|
+
configFingerprint?: string;
|
|
7813
|
+
/**
|
|
7787
7814
|
* Run ceiling B0; immutable after start. Enforced by projected
|
|
7788
7815
|
* admission (a spawn whose reserve does not fit is denied before any
|
|
7789
7816
|
* dispatch), the per-turn guard with a budget-derived maxOutputTokens
|
|
@@ -7931,6 +7958,18 @@ interface ResumeOptions {
|
|
|
7931
7958
|
*/
|
|
7932
7959
|
bodyHash?: "warn" | "refuse";
|
|
7933
7960
|
/**
|
|
7961
|
+
* The host's asserted config identity for this resume (RV3210),
|
|
7962
|
+
* compared against the RunMeta-recorded
|
|
7963
|
+
* {@link RunOptions.configFingerprint} BEFORE ownership, meta
|
|
7964
|
+
* writes, or any append. Both present and unequal is a typed
|
|
7965
|
+
* ConfigError always, no posture knob: supplying the fingerprint IS
|
|
7966
|
+
* the assertion. A recorded fingerprint the resume does not supply
|
|
7967
|
+
* warns (`RULVAR_RESUME_FINGERPRINT_UNCHECKED`); a supplied one the
|
|
7968
|
+
* run never recorded warns (`RULVAR_RESUME_FINGERPRINT_UNRECORDED`),
|
|
7969
|
+
* because absence means NOT RECORDED, never a verdict.
|
|
7970
|
+
*/
|
|
7971
|
+
configFingerprint?: string;
|
|
7972
|
+
/**
|
|
7934
7973
|
* Dry-run: replay-strict matching; the first would-be-live call throws
|
|
7935
7974
|
* JournalMissError and the run settles with that typed error, zero live
|
|
7936
7975
|
* calls performed.
|
|
@@ -14304,6 +14343,17 @@ interface PreflightOrchestratorSpec {
|
|
|
14304
14343
|
* the finding entirely. Default 2.
|
|
14305
14344
|
*/
|
|
14306
14345
|
headroomTurns?: number;
|
|
14346
|
+
/**
|
|
14347
|
+
* The `ceiling-headroom-thin` threshold as a fraction of the ceiling
|
|
14348
|
+
* (RV3208, the 2026-08-11 experiment's admission cliff: a $7.00
|
|
14349
|
+
* ceiling over a $6.80 required minimum left 2.86 percent headroom,
|
|
14350
|
+
* and a small pricing or context drift would have refused the whole
|
|
14351
|
+
* workflow at admission). The finding warns when
|
|
14352
|
+
* `ceilingHeadroomShare` sits below this fraction. A number in
|
|
14353
|
+
* [0, 1]; 0 (the default) keeps the finding silent, so declared
|
|
14354
|
+
* configs are byte identical until a host opts in.
|
|
14355
|
+
*/
|
|
14356
|
+
minCeilingHeadroomShare?: number;
|
|
14307
14357
|
}
|
|
14308
14358
|
/** The full input: engine surface, run surface, and the declared wave. */
|
|
14309
14359
|
interface PreflightInput {
|
|
@@ -14531,6 +14581,20 @@ interface PreflightReport {
|
|
|
14531
14581
|
*/
|
|
14532
14582
|
requiredMinimumCeilingUsd?: number;
|
|
14533
14583
|
/**
|
|
14584
|
+
* The ceiling minus the required minimum (RV3208): the absolute
|
|
14585
|
+
* dollars of drift the admission survives before the wave stops
|
|
14586
|
+
* seating. Present beside requiredMinimumCeilingUsd whenever a
|
|
14587
|
+
* ceiling is declared.
|
|
14588
|
+
*/
|
|
14589
|
+
ceilingHeadroomUsd?: number;
|
|
14590
|
+
/**
|
|
14591
|
+
* The same headroom as a fraction of the ceiling (RV3208): the
|
|
14592
|
+
* one-field read of the admission cliff (the 2026-08-11 experiment
|
|
14593
|
+
* ran at 0.0286). Present beside ceilingHeadroomUsd on positive
|
|
14594
|
+
* ceilings.
|
|
14595
|
+
*/
|
|
14596
|
+
ceilingHeadroomShare?: number;
|
|
14597
|
+
/**
|
|
14534
14598
|
* The live-root-exposure term of the wave projection (RV2004): the
|
|
14535
14599
|
* orchestrator's own worst-case turn floor, the money coordination
|
|
14536
14600
|
* has ALWAYS already spent (and holds in flight) by the time any
|
package/dist/index.js
CHANGED
|
@@ -26769,6 +26769,14 @@ function preflightEstimate(input) {
|
|
|
26769
26769
|
code: "reserve-line-headroom",
|
|
26770
26770
|
message: `the admitted wave's steady state sits ${reserveLineHeadroomUsd.toFixed(4)} USD under the reserve line ${reserveLineUsd.toFixed(4)} USD (the ceiling minus the synthesis reserve), less than ${String(headroomTurns)} coordination turn floors of headroom (${liveRootExposureTermUsd.toFixed(4)} USD each): child spend past the declared estimates eats that headroom, the coordination loop is then refused at the line, and the run settles partial with the synthesis redeemed from its reserve (RV2101); size the wave below the line or raise the ceiling to keep coordinating past it`
|
|
26771
26771
|
});
|
|
26772
|
+
const ceilingHeadroomUsd = ceilingUsd === void 0 || requiredMinimumCeilingUsd === void 0 ? void 0 : ceilingUsd - requiredMinimumCeilingUsd;
|
|
26773
|
+
const ceilingHeadroomShare = ceilingHeadroomUsd === void 0 || ceilingUsd === void 0 || ceilingUsd <= 0 ? void 0 : ceilingHeadroomUsd / ceilingUsd;
|
|
26774
|
+
const minCeilingHeadroomShare = input.orchestrator?.minCeilingHeadroomShare ?? 0;
|
|
26775
|
+
if (ceilingHeadroomShare !== void 0 && minCeilingHeadroomShare > 0 && ceilingHeadroomShare < minCeilingHeadroomShare) say({
|
|
26776
|
+
severity: "warning",
|
|
26777
|
+
code: "ceiling-headroom-thin",
|
|
26778
|
+
message: `the ceiling headroom is ${(ceilingHeadroomShare * 100).toFixed(2)} percent of the ceiling (${(ceilingHeadroomUsd ?? 0).toFixed(4)} USD over the required minimum ${(requiredMinimumCeilingUsd ?? 0).toFixed(4)} USD), below the declared ${(minCeilingHeadroomShare * 100).toFixed(2)} percent floor: a small pricing or context drift refuses the whole wave at admission; raise the ceiling or slim the wave`
|
|
26779
|
+
});
|
|
26772
26780
|
{
|
|
26773
26781
|
const judgeEstUsd = input.orchestrator?.claimConsistency?.judge?.estCost;
|
|
26774
26782
|
if (judgeEstUsd !== void 0 && effectiveCapUsd !== void 0 && synthesisHoldUsd > 0) {
|
|
@@ -27052,6 +27060,8 @@ function preflightEstimate(input) {
|
|
|
27052
27060
|
reservedForFinalizationUsd,
|
|
27053
27061
|
synthesisReserveUsd: synthesisHoldUsd,
|
|
27054
27062
|
...requiredMinimumCeilingUsd === void 0 ? {} : { requiredMinimumCeilingUsd },
|
|
27063
|
+
...ceilingHeadroomUsd === void 0 ? {} : { ceilingHeadroomUsd },
|
|
27064
|
+
...ceilingHeadroomShare === void 0 ? {} : { ceilingHeadroomShare },
|
|
27055
27065
|
...liveRootExposureTermUsd > 0 ? { liveRootExposureTermUsd } : {},
|
|
27056
27066
|
...reserveLineUsd === void 0 ? {} : { reserveLineUsd },
|
|
27057
27067
|
...reserveLineHeadroomUsd === void 0 ? {} : { reserveLineHeadroomUsd },
|
|
@@ -27588,6 +27598,10 @@ function parseDeadlineAt(value) {
|
|
|
27588
27598
|
if (month < 1 || month > 12 || day < 1 || day > daysInMonth) refuse();
|
|
27589
27599
|
return parsed;
|
|
27590
27600
|
}
|
|
27601
|
+
/** Validates a declared config fingerprint (RV3210): a non-empty string of at most 512 chars. */
|
|
27602
|
+
function requireConfigFingerprint(value, site) {
|
|
27603
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 512) throw new ConfigError(`${site} must be a non-empty string of at most 512 characters; got ` + (typeof value === "string" ? `${String(value.length)} characters` : JSON.stringify(value)));
|
|
27604
|
+
}
|
|
27591
27605
|
/** Content hash of an in-process workflow body (run-to-definition binding). */
|
|
27592
27606
|
function hashWorkflowBody(wf) {
|
|
27593
27607
|
return createHash("sha256").update(wf.body.toString(), "utf8").digest("hex");
|
|
@@ -27894,6 +27908,7 @@ function createEngine(options) {
|
|
|
27894
27908
|
if (wf.kind !== "workflow" && wf.kind !== "compiled-workflow") throw new ConfigError("engine.run accepts in-process Workflow values or compileScript CompiledWorkflow values");
|
|
27895
27909
|
if (opts?.budgetUsd !== void 0) requireNonNegativeNumber(opts.budgetUsd, "RunOptions.budgetUsd");
|
|
27896
27910
|
if (opts?.maxInFlightExposureUsd !== void 0) requireNonNegativeNumber(opts.maxInFlightExposureUsd, "RunOptions.maxInFlightExposureUsd");
|
|
27911
|
+
if (opts?.configFingerprint !== void 0) requireConfigFingerprint(opts.configFingerprint, "RunOptions.configFingerprint");
|
|
27897
27912
|
if (opts?.clampTurnToExposure !== void 0 && typeof opts.clampTurnToExposure !== "boolean") throw new ConfigError("RunOptions.clampTurnToExposure must be a boolean; got " + JSON.stringify(opts.clampTurnToExposure));
|
|
27898
27913
|
if (opts?.strictPricing !== void 0 && typeof opts.strictPricing !== "boolean" && (typeof opts.strictPricing !== "object" || opts.strictPricing === null || Array.isArray(opts.strictPricing))) throw new ConfigError("RunOptions.strictPricing must be a boolean or an options object; got " + JSON.stringify(opts.strictPricing));
|
|
27899
27914
|
if (opts?.limits !== void 0) validateUsageLimits(opts.limits, "RunOptions.limits");
|
|
@@ -27929,6 +27944,7 @@ function createEngine(options) {
|
|
|
27929
27944
|
...opts.strictPricing.maxRatesAgeDays === void 0 ? {} : { maxRatesAgeDays: opts.strictPricing.maxRatesAgeDays },
|
|
27930
27945
|
...opts.strictPricing.allowUnpriced === void 0 ? {} : { allowUnpriced: [...opts.strictPricing.allowUnpriced] }
|
|
27931
27946
|
};
|
|
27947
|
+
const configFingerprint = opts?.configFingerprint ?? resumeCtx?.configFingerprint;
|
|
27932
27948
|
const makeBudget = () => new RunBudget({
|
|
27933
27949
|
...ceilingUsd === void 0 ? {} : { ceilingUsd },
|
|
27934
27950
|
...exposureCapUsd === void 0 ? {} : { maxInFlightExposureUsd: exposureCapUsd },
|
|
@@ -28109,6 +28125,7 @@ function createEngine(options) {
|
|
|
28109
28125
|
...ceilingUsd === void 0 ? {} : { budgetUsd: ceilingUsd },
|
|
28110
28126
|
...exposureCapUsd === void 0 ? {} : { maxInFlightExposureUsd: exposureCapUsd },
|
|
28111
28127
|
...strictPricing === void 0 ? {} : { strictPricing },
|
|
28128
|
+
...configFingerprint === void 0 ? {} : { configFingerprint },
|
|
28112
28129
|
...argsBinding.argsProvided === void 0 ? {} : { argsProvided: argsBinding.argsProvided },
|
|
28113
28130
|
...argsBinding.argsHash === void 0 ? {} : { argsHash: argsBinding.argsHash },
|
|
28114
28131
|
...genesis === void 0 ? {} : { genesis },
|
|
@@ -28508,6 +28525,20 @@ function createEngine(options) {
|
|
|
28508
28525
|
}
|
|
28509
28526
|
bound = supplied;
|
|
28510
28527
|
}
|
|
28528
|
+
{
|
|
28529
|
+
const supplied = resumeOptions?.configFingerprint;
|
|
28530
|
+
if (supplied !== void 0) requireConfigFingerprint(supplied, "ResumeOptions.configFingerprint");
|
|
28531
|
+
const recorded = typeof meta?.configFingerprint === "string" ? meta.configFingerprint : void 0;
|
|
28532
|
+
if (supplied !== void 0 && recorded !== void 0 && supplied !== recorded) throw new ConfigError(`resume: the supplied configFingerprint does not match the one run '${runId}' recorded at genesis; the config the workflow closes over changed, and the host declared exactly this check. Resume under the original config, or drop the option to proceed under the loud warning`);
|
|
28533
|
+
if (supplied !== void 0 && recorded === void 0) process.emitWarning(`resume: a configFingerprint was supplied but run '${runId}' never recorded one; the assertion cannot be verified (absence means NOT RECORDED)`, {
|
|
28534
|
+
code: "RULVAR_RESUME_FINGERPRINT_UNRECORDED",
|
|
28535
|
+
type: "RulvarWarning"
|
|
28536
|
+
});
|
|
28537
|
+
if (supplied === void 0 && recorded !== void 0) process.emitWarning(`resume: run '${runId}' recorded a configFingerprint at genesis and this resume did not supply one; the declared config identity goes unchecked`, {
|
|
28538
|
+
code: "RULVAR_RESUME_FINGERPRINT_UNCHECKED",
|
|
28539
|
+
type: "RulvarWarning"
|
|
28540
|
+
});
|
|
28541
|
+
}
|
|
28511
28542
|
const priorEntries = (await journal.load(runId)).map((entry) => normalizeEntry(entry));
|
|
28512
28543
|
scanJournalCompatibility(runId, priorEntries, buildDeriverRegistry(options.extraDerivers));
|
|
28513
28544
|
if (priorEntries.some((entry) => entry.usageSemantics === void 0 && (entry.servedBy?.startsWith("openai:") === true && (entry.usage?.cacheWriteTokens ?? 0) > 0 || (entry.usageByModel?.some((slice) => slice.servedBy.startsWith("openai:") && slice.usage.cacheWriteTokens > 0) ?? false)))) process.emitWarning(`resume: run '${runId}' contains OpenAI cache-write usage recorded without a usage-semantics stamp. Entries written by rulvar v1.19.0 double-counted cache writes into inputTokens, so their recorded cost and budget debits are OVERSTATED; unstamped entries from v1.20.0 are correct. Resuming keeps the recorded debits. Audit procedure: https://docs.rulvar.com/guide/providers#openai-legacy-cache-journals`, {
|
|
@@ -28534,6 +28565,7 @@ function createEngine(options) {
|
|
|
28534
28565
|
...typeof meta?.argsHash === "string" ? { argsHash: meta.argsHash } : {},
|
|
28535
28566
|
...typeof meta?.genesis === "string" ? { genesis: meta.genesis } : {},
|
|
28536
28567
|
...typeof meta?.execKeyDerivation === "number" ? { execKeyDerivation: meta.execKeyDerivation } : {},
|
|
28568
|
+
...typeof meta?.configFingerprint === "string" ? { configFingerprint: meta.configFingerprint } : {},
|
|
28537
28569
|
previewResolve
|
|
28538
28570
|
});
|
|
28539
28571
|
})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rulvar/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.236.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",
|