@cavelang/scenario 0.29.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.
@@ -0,0 +1,65 @@
1
+ import { Exact } from '@cavelang/solver';
2
+ import { ScenarioInputError } from "./error.js";
3
+ const multiplier = {
4
+ K: 1000n,
5
+ M: 1000000n,
6
+ B: 1000000000n,
7
+ T: 1000000000000n
8
+ };
9
+ const hasMultiplier = (value) => Object.hasOwn(multiplier, value);
10
+ const reduce = (numerator, denominator) => {
11
+ const divisor = (() => {
12
+ let left = numerator < 0n ? -numerator : numerator;
13
+ let right = denominator < 0n ? -denominator : denominator;
14
+ while (right !== 0n)
15
+ [left, right] = [right, left % right];
16
+ return left;
17
+ })();
18
+ const sign = denominator < 0n ? -1n : 1n;
19
+ return {
20
+ numerator: String((numerator / divisor) * sign),
21
+ denominator: String((denominator / divisor) * sign)
22
+ };
23
+ };
24
+ const multiply = (left, right) => reduce(BigInt(left.numerator) * BigInt(right.numerator), BigInt(left.denominator) * BigInt(right.denominator));
25
+ export const add = (left, right) => reduce(BigInt(left.numerator) * BigInt(right.denominator) + BigInt(right.numerator) * BigInt(left.denominator), BigInt(left.denominator) * BigInt(right.denominator));
26
+ export const compare = (left, right) => BigInt(left.numerator) * BigInt(right.denominator) < BigInt(right.numerator) * BigInt(left.denominator) ? -1 :
27
+ BigInt(left.numerator) * BigInt(right.denominator) > BigInt(right.numerator) * BigInt(left.denominator) ? 1 : 0;
28
+ const rational = (value) => Exact.rational(value);
29
+ /** Parses CAVE's exact scalar spelling without passing the digits through `number`. */
30
+ export const parse = (authored, bindingId) => {
31
+ const approximate = authored.startsWith('~');
32
+ const body = approximate ? authored.slice(1) : authored;
33
+ const [head = '', ...tailParts] = body.trim().split(/\s+/);
34
+ const tail = tailParts.length === 0 ? undefined : tailParts.join(' ');
35
+ const match = /^([+-]?\d+(?:\.\d+)?)([A-Za-z%]*)$/.exec(head);
36
+ if (match === null || tailParts.length > 1) {
37
+ throw new ScenarioInputError('invalid-value', `expected a scalar number, received ${JSON.stringify(authored)}`, bindingId);
38
+ }
39
+ const digits = match[1];
40
+ const suffix = match[2] ?? '';
41
+ const factor = hasMultiplier(suffix) ? multiplier[suffix] : 1n;
42
+ const unit = hasMultiplier(suffix) ? tail : suffix === '' ? tail : suffix;
43
+ if (suffix !== '' && !hasMultiplier(suffix) && tail !== undefined) {
44
+ throw new ScenarioInputError('invalid-value', `cannot combine glued unit ${JSON.stringify(suffix)} with ${JSON.stringify(tail)}`, bindingId);
45
+ }
46
+ const base = rational(digits);
47
+ return {
48
+ exact: reduce(BigInt(base.numerator) * factor, BigInt(base.denominator)),
49
+ ...(unit === undefined ? {} : { unit }),
50
+ approximate
51
+ };
52
+ };
53
+ export const convert = (parsed, expectedUnit, conversions, bindingId) => {
54
+ if (expectedUnit === undefined || parsed.unit === expectedUnit)
55
+ return parsed;
56
+ if (parsed.unit === undefined) {
57
+ throw new ScenarioInputError('incompatible-unit', `expected unit ${JSON.stringify(expectedUnit)}, received a unitless value`, bindingId);
58
+ }
59
+ const conversion = conversions?.find(item => item.from === parsed.unit && item.to === expectedUnit);
60
+ if (conversion === undefined) {
61
+ throw new ScenarioInputError('incompatible-unit', `cannot convert ${JSON.stringify(parsed.unit)} to ${JSON.stringify(expectedUnit)} without an explicit conversion`, bindingId);
62
+ }
63
+ return { ...parsed, exact: multiply(parsed.exact, rational(conversion.factor)), unit: expectedUnit };
64
+ };
65
+ //# sourceMappingURL=exact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exact.js","sourceRoot":"","sources":["../../src/exact.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { Explain } from '@cavelang/solver';
2
+ import type { Definition, InputRecord } from './model.ts';
3
+ /** Convert a frozen scenario binding into solver-neutral run provenance. */
4
+ export declare const explanationContext: (definition: Definition, record: InputRecord) => Explain.Context;
5
+ //# sourceMappingURL=explain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain.d.ts","sourceRoot":"","sources":["../../src/explain.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,KAAK,EAAW,UAAU,EAAE,WAAW,EAAS,MAAM,YAAY,CAAA;AAoCzE,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,GAAI,YAAY,UAAU,EAAE,QAAQ,WAAW,KAAG,OAAO,CAAC,OA6BxF,CAAA"}
@@ -0,0 +1,59 @@
1
+ import { Explain } from '@cavelang/solver';
2
+ const compareText = (left, right) => left < right ? -1 : left > right ? 1 : 0;
3
+ const unique = (values) => [...new Set(values)].sort(compareText);
4
+ const authored = (value) => {
5
+ switch (value.kind) {
6
+ case 'boolean': return value.value;
7
+ case 'integer': return value.authored ?? value.value;
8
+ case 'number': return value.authored ?? `${value.value.numerator}/${value.value.denominator}`;
9
+ case 'enum': return value.value;
10
+ case 'text': return value.value;
11
+ }
12
+ };
13
+ const authoredValue = (value) => value === undefined ? undefined : Array.isArray(value) ? value.map(authored) : authored(value);
14
+ const bindingInput = (binding, result) => {
15
+ const evidence = result.candidates.flatMap(candidate => candidate.evidence);
16
+ const value = result.value;
17
+ const authoredInput = authoredValue(value);
18
+ return {
19
+ id: result.id,
20
+ query: binding.query,
21
+ ...(value === undefined ? {} : { value: value }),
22
+ ...(authoredInput === undefined ? {} : { authoredValue: authoredInput }),
23
+ evidenceRowIds: unique(evidence.flatMap(item => item.origin === 'belief' ? item.rowIds : [])),
24
+ scenarioClaimIds: unique(evidence.flatMap(item => item.origin === 'scenario' ? item.claimIds : []))
25
+ };
26
+ };
27
+ /** Convert a frozen scenario binding into solver-neutral run provenance. */
28
+ export const explanationContext = (definition, record) => {
29
+ if (record.scenarioId !== definition.id) {
30
+ throw new TypeError(`scenario record ${JSON.stringify(record.scenarioId)} does not match ${JSON.stringify(definition.id)}`);
31
+ }
32
+ if (record.modelDigest !== definition.modelDigest) {
33
+ throw new TypeError(`scenario record model digest does not match its definition`);
34
+ }
35
+ const definitions = new Map(definition.bindings.map(binding => [binding.id, binding]));
36
+ const inputs = record.bindings.map(result => {
37
+ const binding = definitions.get(result.id);
38
+ if (binding === undefined)
39
+ throw new TypeError(`scenario record contains unknown binding ${JSON.stringify(result.id)}`);
40
+ return bindingInput(binding, result);
41
+ });
42
+ return {
43
+ modelDigest: record.modelDigest,
44
+ scenario: {
45
+ id: record.scenarioId,
46
+ inputDigest: record.digest,
47
+ overlayDigest: record.overlay.digest
48
+ },
49
+ snapshot: {
50
+ transactionTime: record.snapshot.transactionTime,
51
+ ...(record.snapshot.at === undefined ? {} : { validTime: record.snapshot.at }),
52
+ aliases: record.snapshot.aliases,
53
+ resolution: record.snapshot.resolution,
54
+ minimumConfidence: record.snapshot.minimumConfidence
55
+ },
56
+ inputs
57
+ };
58
+ };
59
+ //# sourceMappingURL=explain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain.js","sourceRoot":"","sources":["../../src/explain.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /** Typed, replayable CAVE snapshot bindings for decision and solver inputs. */
2
+ export { bind, run } from './bind.ts';
3
+ export { explanationContext } from './explain.ts';
4
+ export { ScenarioInputError } from './error.ts';
5
+ export * as Model from './model.ts';
6
+ export * as Record from './record.ts';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAE/E,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA"}
@@ -0,0 +1,7 @@
1
+ /** Typed, replayable CAVE snapshot bindings for decision and solver inputs. */
2
+ export { bind, run } from "./bind.js";
3
+ export { explanationContext } from "./explain.js";
4
+ export { ScenarioInputError } from "./error.js";
5
+ export * as Model from "./model.js";
6
+ export * as Record from "./record.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAE/E,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA"}
@@ -0,0 +1,141 @@
1
+ import type { Model } from '@cavelang/solver';
2
+ export declare const schema: "cave.scenario/inputs@1";
3
+ export type Snapshot = {
4
+ /** Transaction-time boundary. Omit to freeze the current store head. */
5
+ readonly asOf?: string;
6
+ /** Valid-time instant passed to CAVE-Q. */
7
+ readonly at?: string;
8
+ readonly aliases: 'exact' | 'closure';
9
+ readonly resolution: 'coexisting' | 'winner';
10
+ readonly minimumConfidence: number;
11
+ };
12
+ export type Conversion = {
13
+ readonly from: string;
14
+ readonly to: string;
15
+ /** Exact `to` units per one `from` unit. */
16
+ readonly factor: Model.Rational;
17
+ };
18
+ export type Expected = {
19
+ readonly kind: 'boolean';
20
+ readonly trueValue?: string;
21
+ readonly falseValue?: string;
22
+ } | {
23
+ readonly kind: 'integer';
24
+ readonly unit?: string;
25
+ readonly conversions?: readonly Conversion[];
26
+ } | {
27
+ readonly kind: 'number';
28
+ readonly unit?: string;
29
+ readonly conversions?: readonly Conversion[];
30
+ } | {
31
+ readonly kind: 'enum';
32
+ readonly values: readonly string[];
33
+ } | {
34
+ readonly kind: 'text';
35
+ };
36
+ export type MissingPolicy = 'reject' | 'omit' | 'empty';
37
+ export type Policies = {
38
+ readonly missing: MissingPolicy;
39
+ readonly contested: 'reject' | 'allow';
40
+ readonly retracted: 'reject' | 'exclude' | 'include';
41
+ readonly unresolved: 'reject' | 'allow';
42
+ };
43
+ type CommonBinding = {
44
+ readonly id: string;
45
+ readonly query: string;
46
+ /** CAVE-Q variable to bind. Omit only for Boolean existence inputs. */
47
+ readonly select?: string;
48
+ readonly expected: Expected;
49
+ readonly scenarioOverride: boolean;
50
+ readonly policies: Policies;
51
+ };
52
+ export type Binding = CommonBinding & ({
53
+ readonly cardinality: 'one';
54
+ } | {
55
+ readonly cardinality: 'optional';
56
+ } | {
57
+ readonly cardinality: 'many';
58
+ readonly reduce: 'all' | 'min' | 'max' | 'sum';
59
+ });
60
+ export type Definition = {
61
+ readonly id: string;
62
+ /** Digest of the portable model or evaluator receiving these inputs. */
63
+ readonly modelDigest: string;
64
+ readonly snapshot: Snapshot;
65
+ readonly overlay?: string;
66
+ readonly bindings: readonly Binding[];
67
+ };
68
+ export type ExactNumber = {
69
+ readonly numerator: string;
70
+ readonly denominator: string;
71
+ };
72
+ export type Uncertainty = {
73
+ readonly authored: string;
74
+ readonly exact: ExactNumber;
75
+ readonly unit?: string;
76
+ readonly sigmaLevel: number;
77
+ };
78
+ export type Value = {
79
+ readonly kind: 'boolean';
80
+ readonly value: boolean;
81
+ } | {
82
+ readonly kind: 'integer';
83
+ readonly value: string;
84
+ readonly unit?: string;
85
+ readonly authored?: string;
86
+ readonly approximate: boolean;
87
+ readonly uncertainty?: Uncertainty;
88
+ } | {
89
+ readonly kind: 'number';
90
+ readonly value: ExactNumber;
91
+ readonly unit?: string;
92
+ readonly authored?: string;
93
+ readonly approximate: boolean;
94
+ readonly uncertainty?: Uncertainty;
95
+ } | {
96
+ readonly kind: 'enum';
97
+ readonly value: string;
98
+ } | {
99
+ readonly kind: 'text';
100
+ readonly value: string;
101
+ };
102
+ export type Evidence = {
103
+ readonly origin: 'belief';
104
+ readonly rowIds: readonly string[];
105
+ } | {
106
+ readonly origin: 'scenario';
107
+ readonly claimIds: readonly string[];
108
+ };
109
+ export type Candidate = {
110
+ readonly value: Value;
111
+ readonly confidence: number;
112
+ readonly evidence: readonly Evidence[];
113
+ };
114
+ export type BindingResult = {
115
+ readonly id: string;
116
+ readonly candidates: readonly Candidate[];
117
+ readonly value?: Value | readonly Value[];
118
+ };
119
+ export type FrozenSnapshot = Snapshot & {
120
+ /** Exact newest base row visible at `asOf`, or null for an empty snapshot. */
121
+ readonly transactionTime: string | null;
122
+ };
123
+ export type InputRecord = {
124
+ readonly schema: typeof schema;
125
+ readonly scenarioId: string;
126
+ readonly modelDigest: string;
127
+ readonly digest: string;
128
+ readonly snapshot: FrozenSnapshot;
129
+ readonly overlay: {
130
+ readonly digest: string;
131
+ readonly source: string;
132
+ readonly claimIds: readonly string[];
133
+ };
134
+ readonly values: Readonly<Record<string, Value | readonly Value[]>>;
135
+ readonly bindings: readonly BindingResult[];
136
+ readonly supportingRowIds: readonly string[];
137
+ readonly scenarioClaimIds: readonly string[];
138
+ };
139
+ export type t = InputRecord;
140
+ export {};
141
+ //# sourceMappingURL=model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export const schema = 'cave.scenario/inputs@1';
2
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/model.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,MAAM,GAAG,wBAAiC,CAAA"}
@@ -0,0 +1,100 @@
1
+ import type { Explain } from '@cavelang/solver';
2
+ import type { Store } from '@cavelang/store';
3
+ import type { InputRecord } from './model.ts';
4
+ export declare const resultSchema: "cave.scenario/result@1";
5
+ export declare const evaluationSchema: "cave.scenario/evaluation@1";
6
+ export declare const recommendationSchema: "cave.scenario/recommendation@1";
7
+ export declare const decisionSchema: "cave.scenario/decision@1";
8
+ export declare const actionSchema: "cave.scenario/action@1";
9
+ export declare const externalEffectSchema: "cave.scenario/external-effect@1";
10
+ export type Result = {
11
+ readonly schema: typeof resultSchema;
12
+ /** Stable caller-supplied identity. Reusing it with different content is an error. */
13
+ readonly id: string;
14
+ readonly report: Explain.Report;
15
+ };
16
+ /** Ordinary external-evaluator result over one frozen scenario input record. */
17
+ export type Evaluation = {
18
+ readonly schema: typeof evaluationSchema;
19
+ readonly id: string;
20
+ readonly inputs: InputRecord;
21
+ readonly evaluator: {
22
+ readonly name: string;
23
+ readonly version: string;
24
+ };
25
+ readonly output: Explain.Json;
26
+ };
27
+ export type ResultArtifact = Result | Evaluation;
28
+ export type Recommendation = {
29
+ readonly schema: typeof recommendationSchema;
30
+ readonly id: string;
31
+ readonly resultId: string;
32
+ readonly value: Explain.Json;
33
+ readonly rationale?: string;
34
+ readonly authoredBy?: string;
35
+ };
36
+ export type Decision = {
37
+ readonly schema: typeof decisionSchema;
38
+ readonly id: string;
39
+ readonly resultId: string;
40
+ readonly recommendationId?: string;
41
+ readonly selected: Explain.Json;
42
+ readonly decidedBy: string;
43
+ readonly rationale?: string;
44
+ };
45
+ /** Audit record only. Creating it never invokes an action or external hook. */
46
+ export type Action = {
47
+ readonly schema: typeof actionSchema;
48
+ readonly id: string;
49
+ readonly decisionId: string;
50
+ readonly name: string;
51
+ readonly parameters: Explain.Json;
52
+ readonly status: 'validated' | 'executed' | 'failed';
53
+ readonly message?: string;
54
+ };
55
+ /** Audit record only. External effects remain owned by governed action execution. */
56
+ export type ExternalEffect = {
57
+ readonly schema: typeof externalEffectSchema;
58
+ readonly id: string;
59
+ readonly actionId: string;
60
+ readonly kind: string;
61
+ readonly status: 'succeeded' | 'failed' | 'unknown';
62
+ readonly details?: Explain.Json;
63
+ };
64
+ export type Artifact = ResultArtifact | Recommendation | Decision | Action | ExternalEffect;
65
+ export type Kind = 'result' | 'recommendation' | 'decision' | 'action' | 'external-effect';
66
+ export type RecordOutcome = {
67
+ readonly status: 'recorded' | 'existing';
68
+ readonly rowId: string;
69
+ readonly artifact: Artifact;
70
+ };
71
+ export type ReplayExpectation = {
72
+ readonly modelDigest: string;
73
+ readonly backend?: {
74
+ readonly name: string;
75
+ readonly version: string;
76
+ };
77
+ };
78
+ export type Replay = {
79
+ readonly artifact: Result;
80
+ readonly compatible: boolean;
81
+ readonly reasons: readonly string[];
82
+ };
83
+ export declare class RecordConflictError extends Error {
84
+ constructor(kind: Kind, id: string);
85
+ }
86
+ export declare class MissingRecordError extends Error {
87
+ constructor(kind: Kind, id: string);
88
+ }
89
+ export declare const result: (store: Store, artifact: ResultArtifact) => RecordOutcome;
90
+ export declare const recommendation: (store: Store, artifact: Recommendation) => RecordOutcome;
91
+ export declare const decision: (store: Store, artifact: Decision) => RecordOutcome;
92
+ export declare const action: (store: Store, artifact: Action) => RecordOutcome;
93
+ export declare const externalEffect: (store: Store, artifact: ExternalEffect) => RecordOutcome;
94
+ export declare const read: <T extends Artifact>(store: Store, kind: Kind, id: string) => T;
95
+ /**
96
+ * Reads an immutable result without re-running it. Compatibility is explicit:
97
+ * a different model or backend version is reported, never silently upgraded.
98
+ */
99
+ export declare const replay: (store: Store, id: string, expected: ReplayExpectation) => Replay;
100
+ //# sourceMappingURL=record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../src/record.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,189 @@
1
+ import { Buffer } from 'node:buffer';
2
+ import { Key } from '@cavelang/core';
3
+ import { canonicalizeText } from '@cavelang/canonical';
4
+ export const resultSchema = 'cave.scenario/result@1';
5
+ export const evaluationSchema = 'cave.scenario/evaluation@1';
6
+ export const recommendationSchema = 'cave.scenario/recommendation@1';
7
+ export const decisionSchema = 'cave.scenario/decision@1';
8
+ export const actionSchema = 'cave.scenario/action@1';
9
+ export const externalEffectSchema = 'cave.scenario/external-effect@1';
10
+ export class RecordConflictError extends Error {
11
+ constructor(kind, id) {
12
+ super(`${kind} ${JSON.stringify(id)} is already recorded with different content`);
13
+ this.name = 'RecordConflictError';
14
+ }
15
+ }
16
+ export class MissingRecordError extends Error {
17
+ constructor(kind, id) {
18
+ super(`${kind} ${JSON.stringify(id)} is not recorded`);
19
+ this.name = 'MissingRecordError';
20
+ }
21
+ }
22
+ const kindOf = (artifact) => {
23
+ switch (artifact.schema) {
24
+ case resultSchema: return 'result';
25
+ case evaluationSchema: return 'result';
26
+ case recommendationSchema: return 'recommendation';
27
+ case decisionSchema: return 'decision';
28
+ case actionSchema: return 'action';
29
+ case externalEffectSchema: return 'external-effect';
30
+ }
31
+ };
32
+ const prefix = {
33
+ result: 'scenario-result',
34
+ recommendation: 'scenario-recommendation',
35
+ decision: 'scenario-decision',
36
+ action: 'scenario-action',
37
+ 'external-effect': 'scenario-effect'
38
+ };
39
+ const source = {
40
+ result: 'scenario/result',
41
+ recommendation: 'scenario/recommendation',
42
+ decision: 'scenario/decision',
43
+ action: 'scenario/action',
44
+ 'external-effect': 'scenario/external-effect'
45
+ };
46
+ const entity = (kind, id) => {
47
+ if (id === '')
48
+ throw new TypeError(`${kind} id must not be empty`);
49
+ return `${prefix[kind]}/${id}`;
50
+ };
51
+ const compareText = (left, right) => left < right ? -1 : left > right ? 1 : 0;
52
+ const canonicalJson = (value) => {
53
+ const normalize = (item, path) => {
54
+ if (item === null || typeof item === 'string' || typeof item === 'boolean')
55
+ return item;
56
+ if (typeof item === 'number') {
57
+ if (!Number.isFinite(item))
58
+ throw new TypeError(`${path} must be finite`);
59
+ return item;
60
+ }
61
+ if (Array.isArray(item))
62
+ return item.map((entry, index) => normalize(entry, `${path}[${index}]`));
63
+ if (typeof item === 'object') {
64
+ return Object.fromEntries(Object.entries(item)
65
+ .filter(([, entry]) => entry !== undefined)
66
+ .sort(([left], [right]) => compareText(left, right))
67
+ .map(([key, entry]) => [key, normalize(entry, `${path}.${key}`)]));
68
+ }
69
+ throw new TypeError(`${path} is not JSON`);
70
+ };
71
+ return JSON.stringify(normalize(value, 'artifact'));
72
+ };
73
+ const encode = (artifact) => Buffer.from(canonicalJson(artifact), 'utf8').toString('base64url');
74
+ const decode = (payload) => {
75
+ let parsed;
76
+ try {
77
+ parsed = JSON.parse(Buffer.from(payload, 'base64url').toString('utf8'));
78
+ }
79
+ catch {
80
+ throw new TypeError('recorded scenario artifact is not valid base64url JSON');
81
+ }
82
+ if (typeof parsed !== 'object' || parsed === null || typeof parsed.schema !== 'string') {
83
+ throw new TypeError('recorded scenario artifact has no schema');
84
+ }
85
+ const schema = parsed.schema;
86
+ if (![resultSchema, evaluationSchema, recommendationSchema, decisionSchema, actionSchema, externalEffectSchema].includes(schema)) {
87
+ throw new TypeError(`unsupported recorded scenario artifact schema ${JSON.stringify(schema)}`);
88
+ }
89
+ return parsed;
90
+ };
91
+ const line = (kind, id, payload) => `${entity(kind, id)} HAS artifact: \`${payload}\` @src:${source[kind]}`;
92
+ const claimOf = (store, kind, id, payload) => {
93
+ const parsed = canonicalizeText(line(kind, id, payload), store.registry());
94
+ const claim = parsed.claims[0]?.claim;
95
+ if (parsed.problems.length > 0 || claim === undefined) {
96
+ const detail = parsed.problems.map(problem => `line ${problem.line}: ${problem.message}`).join('; ');
97
+ throw new TypeError(`invalid ${kind} identity ${JSON.stringify(id)}${detail === '' ? '' : `: ${detail}`}`);
98
+ }
99
+ return { parsed, claim };
100
+ };
101
+ const currentPayload = (store, kind, id) => {
102
+ // The payload is excluded from an attribute claim key, so an empty
103
+ // placeholder locates the one append-only series for this artifact ID.
104
+ const { claim } = claimOf(store, kind, id, '');
105
+ const row = store.currentBelief(Key.of(claim));
106
+ if (row === undefined || row.conf === 0)
107
+ return undefined;
108
+ const stored = store.toClaim(row);
109
+ if (stored.payload.kind !== 'attribute' || stored.payload.attribute !== 'artifact' || stored.payload.value.kind !== 'code') {
110
+ throw new TypeError(`${kind} ${JSON.stringify(id)} has an invalid stored representation`);
111
+ }
112
+ return { payload: stored.payload.value.raw, rowId: row.id };
113
+ };
114
+ const requireRecord = (store, kind, id) => {
115
+ const found = currentPayload(store, kind, id);
116
+ if (found === undefined)
117
+ throw new MissingRecordError(kind, id);
118
+ const artifact = decode(found.payload);
119
+ if (kindOf(artifact) !== kind || artifact.id !== id) {
120
+ throw new TypeError(`${kind} ${JSON.stringify(id)} has mismatched stored identity`);
121
+ }
122
+ return artifact;
123
+ };
124
+ const append = (store, artifact, validate) => store.transaction(() => {
125
+ validate();
126
+ const kind = kindOf(artifact);
127
+ const payload = encode(artifact);
128
+ const existing = currentPayload(store, kind, artifact.id);
129
+ if (existing !== undefined) {
130
+ if (existing.payload !== payload)
131
+ throw new RecordConflictError(kind, artifact.id);
132
+ return { status: 'existing', rowId: existing.rowId, artifact };
133
+ }
134
+ const { parsed } = claimOf(store, kind, artifact.id, payload);
135
+ const inserted = store.insertResult(parsed);
136
+ return { status: 'recorded', rowId: inserted.ids[0], artifact };
137
+ });
138
+ export const result = (store, artifact) => append(store, artifact, () => {
139
+ if (artifact.schema === resultSchema && artifact.report.schema !== 'cave.solver/explanation@1') {
140
+ throw new TypeError(`unsupported solver explanation schema ${JSON.stringify(artifact.report.schema)}`);
141
+ }
142
+ if (artifact.schema === evaluationSchema) {
143
+ if (artifact.inputs.schema !== 'cave.scenario/inputs@1') {
144
+ throw new TypeError(`unsupported scenario input schema ${JSON.stringify(artifact.inputs.schema)}`);
145
+ }
146
+ if (artifact.evaluator.name === '' || artifact.evaluator.version === '') {
147
+ throw new TypeError('scenario evaluator name and version must not be empty');
148
+ }
149
+ }
150
+ });
151
+ export const recommendation = (store, artifact) => append(store, artifact, () => { requireRecord(store, 'result', artifact.resultId); });
152
+ export const decision = (store, artifact) => append(store, artifact, () => {
153
+ requireRecord(store, 'result', artifact.resultId);
154
+ if (artifact.recommendationId !== undefined) {
155
+ const proposal = requireRecord(store, 'recommendation', artifact.recommendationId);
156
+ if (proposal.resultId !== artifact.resultId) {
157
+ throw new TypeError(`recommendation ${JSON.stringify(artifact.recommendationId)} belongs to another result`);
158
+ }
159
+ }
160
+ });
161
+ export const action = (store, artifact) => append(store, artifact, () => { requireRecord(store, 'decision', artifact.decisionId); });
162
+ export const externalEffect = (store, artifact) => append(store, artifact, () => { requireRecord(store, 'action', artifact.actionId); });
163
+ export const read = (store, kind, id) => requireRecord(store, kind, id);
164
+ /**
165
+ * Reads an immutable result without re-running it. Compatibility is explicit:
166
+ * a different model or backend version is reported, never silently upgraded.
167
+ */
168
+ export const replay = (store, id, expected) => {
169
+ const found = requireRecord(store, 'result', id);
170
+ if (found.schema !== resultSchema) {
171
+ throw new TypeError(`result ${JSON.stringify(id)} is an external evaluation, not a solver result`);
172
+ }
173
+ const artifact = found;
174
+ const reasons = [];
175
+ if (artifact.report.run.modelDigest !== expected.modelDigest) {
176
+ reasons.push(`model digest ${artifact.report.run.modelDigest} does not match ${expected.modelDigest}`);
177
+ }
178
+ if (expected.backend !== undefined) {
179
+ const actual = artifact.report.run.backend;
180
+ if (actual.name !== expected.backend.name) {
181
+ reasons.push(`solver backend ${actual.name} does not match ${expected.backend.name}`);
182
+ }
183
+ if (actual.version !== expected.backend.version) {
184
+ reasons.push(`solver version ${actual.version} does not match ${expected.backend.version}`);
185
+ }
186
+ }
187
+ return { artifact, compatible: reasons.length === 0, reasons };
188
+ };
189
+ //# sourceMappingURL=record.js.map