@victframework/runtime 0.1.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/agent-governance.d.ts +285 -0
- package/dist/agent-governance.js +438 -0
- package/dist/agent-governance.js.map +1 -0
- package/dist/agent-registry.d.ts +103 -0
- package/dist/agent-registry.js +758 -0
- package/dist/agent-registry.js.map +1 -0
- package/dist/agent-types.d.ts +433 -0
- package/dist/agent-types.js +480 -0
- package/dist/agent-types.js.map +1 -0
- package/dist/authority.d.ts +83 -0
- package/dist/authority.js +170 -0
- package/dist/authority.js.map +1 -0
- package/dist/boundary-conformance.d.ts +51 -0
- package/dist/boundary-conformance.js +364 -0
- package/dist/boundary-conformance.js.map +1 -0
- package/dist/control-conformance.d.ts +68 -0
- package/dist/control-conformance.js +1131 -0
- package/dist/control-conformance.js.map +1 -0
- package/dist/control-in-memory.d.ts +257 -0
- package/dist/control-in-memory.js +886 -0
- package/dist/control-in-memory.js.map +1 -0
- package/dist/control-types.d.ts +1017 -0
- package/dist/control-types.js +779 -0
- package/dist/control-types.js.map +1 -0
- package/dist/durable-run.d.ts +73 -0
- package/dist/durable-run.js +262 -0
- package/dist/durable-run.js.map +1 -0
- package/dist/effect-policy.d.ts +22 -0
- package/dist/effect-policy.js +45 -0
- package/dist/effect-policy.js.map +1 -0
- package/dist/errors.d.ts +36 -0
- package/dist/errors.js +71 -0
- package/dist/errors.js.map +1 -0
- package/dist/in-memory-stores.d.ts +16 -0
- package/dist/in-memory-stores.js +522 -0
- package/dist/in-memory-stores.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/operator-config.d.ts +141 -0
- package/dist/operator-config.js +289 -0
- package/dist/operator-config.js.map +1 -0
- package/dist/orchestration-activation.d.ts +116 -0
- package/dist/orchestration-activation.js +223 -0
- package/dist/orchestration-activation.js.map +1 -0
- package/dist/orchestration-canary-conformance.d.ts +10 -0
- package/dist/orchestration-canary-conformance.js +726 -0
- package/dist/orchestration-canary-conformance.js.map +1 -0
- package/dist/orchestration-commands.d.ts +47 -0
- package/dist/orchestration-commands.js +538 -0
- package/dist/orchestration-commands.js.map +1 -0
- package/dist/orchestration-conformance.d.ts +59 -0
- package/dist/orchestration-conformance.js +594 -0
- package/dist/orchestration-conformance.js.map +1 -0
- package/dist/orchestration-driver-types.d.ts +163 -0
- package/dist/orchestration-driver-types.js +21 -0
- package/dist/orchestration-driver-types.js.map +1 -0
- package/dist/orchestration-driver.d.ts +48 -0
- package/dist/orchestration-driver.js +1030 -0
- package/dist/orchestration-driver.js.map +1 -0
- package/dist/orchestration-in-memory.d.ts +18 -0
- package/dist/orchestration-in-memory.js +1313 -0
- package/dist/orchestration-in-memory.js.map +1 -0
- package/dist/orchestration-join-conformance.d.ts +20 -0
- package/dist/orchestration-join-conformance.js +542 -0
- package/dist/orchestration-join-conformance.js.map +1 -0
- package/dist/orchestration-plan.d.ts +52 -0
- package/dist/orchestration-plan.js +265 -0
- package/dist/orchestration-plan.js.map +1 -0
- package/dist/orchestration-race-conformance.d.ts +35 -0
- package/dist/orchestration-race-conformance.js +1265 -0
- package/dist/orchestration-race-conformance.js.map +1 -0
- package/dist/orchestration-remediation-conformance.d.ts +54 -0
- package/dist/orchestration-remediation-conformance.js +632 -0
- package/dist/orchestration-remediation-conformance.js.map +1 -0
- package/dist/orchestration-store-types.d.ts +568 -0
- package/dist/orchestration-store-types.js +2 -0
- package/dist/orchestration-store-types.js.map +1 -0
- package/dist/pack-conformance.d.ts +59 -0
- package/dist/pack-conformance.js +222 -0
- package/dist/pack-conformance.js.map +1 -0
- package/dist/pack-install.d.ts +44 -0
- package/dist/pack-install.js +126 -0
- package/dist/pack-install.js.map +1 -0
- package/dist/registry.d.ts +107 -0
- package/dist/registry.js +481 -0
- package/dist/registry.js.map +1 -0
- package/dist/runtime.d.ts +158 -0
- package/dist/runtime.js +1341 -0
- package/dist/runtime.js.map +1 -0
- package/dist/serialization.d.ts +26 -0
- package/dist/serialization.js +162 -0
- package/dist/serialization.js.map +1 -0
- package/dist/store-conformance.d.ts +45 -0
- package/dist/store-conformance.js +876 -0
- package/dist/store-conformance.js.map +1 -0
- package/dist/store-errors.d.ts +49 -0
- package/dist/store-errors.js +48 -0
- package/dist/store-errors.js.map +1 -0
- package/dist/store-types.d.ts +331 -0
- package/dist/store-types.js +14 -0
- package/dist/store-types.js.map +1 -0
- package/dist/store-validation.d.ts +63 -0
- package/dist/store-validation.js +164 -0
- package/dist/store-validation.js.map +1 -0
- package/dist/stream-hub.d.ts +151 -0
- package/dist/stream-hub.js +402 -0
- package/dist/stream-hub.js.map +1 -0
- package/dist/testing.d.ts +25 -0
- package/dist/testing.js +19 -0
- package/dist/testing.js.map +1 -0
- package/dist/types.d.ts +221 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { VictRuntimeError } from './errors.js';
|
|
2
|
+
/** The authority-name fields of a capability definition, in declaration order. */
|
|
3
|
+
const AUTHORITY_FIELDS = [
|
|
4
|
+
'permissions',
|
|
5
|
+
'configuration',
|
|
6
|
+
'requiredConfiguration',
|
|
7
|
+
'secrets',
|
|
8
|
+
'requiredSecrets',
|
|
9
|
+
];
|
|
10
|
+
/**
|
|
11
|
+
* Validate and PIN the authority declarations of a capability definition:
|
|
12
|
+
* every entry must be a non-empty, non-whitespace string; duplicates are
|
|
13
|
+
* rejected. Returns fresh frozen copies — the caller's arrays are never
|
|
14
|
+
* retained by reference.
|
|
15
|
+
*/
|
|
16
|
+
export function pinAuthorityDeclarations(definition) {
|
|
17
|
+
const pinned = {};
|
|
18
|
+
for (const field of AUTHORITY_FIELDS) {
|
|
19
|
+
const raw = definition[field];
|
|
20
|
+
const names = new Set();
|
|
21
|
+
if (raw !== undefined) {
|
|
22
|
+
if (!Array.isArray(raw)) {
|
|
23
|
+
throw new VictRuntimeError('VICT_RUNTIME_INVALID_AUTHORITY', `Capability '${definition.id}' declares '${field}' that is not an array of names.`, { capabilityId: definition.id, field });
|
|
24
|
+
}
|
|
25
|
+
for (const entry of raw) {
|
|
26
|
+
if (typeof entry !== 'string' || entry.trim().length === 0) {
|
|
27
|
+
throw new VictRuntimeError('VICT_RUNTIME_INVALID_AUTHORITY', `Capability '${definition.id}' declares an invalid '${field}' entry: every authority name must be a non-empty, non-whitespace string.`, { capabilityId: definition.id, field });
|
|
28
|
+
}
|
|
29
|
+
if (names.has(entry)) {
|
|
30
|
+
throw new VictRuntimeError('VICT_RUNTIME_INVALID_AUTHORITY', `Capability '${definition.id}' declares '${entry}' more than once in '${field}'; duplicate authority names are rejected.`, { capabilityId: definition.id, field });
|
|
31
|
+
}
|
|
32
|
+
names.add(entry);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
pinned[field] = Object.freeze([...(raw ?? [])]);
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
permissions: Object.freeze(pinned.permissions ?? []),
|
|
39
|
+
configuration: Object.freeze(pinned.configuration ?? []),
|
|
40
|
+
requiredConfiguration: Object.freeze(pinned.requiredConfiguration ?? []),
|
|
41
|
+
secrets: Object.freeze(pinned.secrets ?? []),
|
|
42
|
+
requiredSecrets: Object.freeze(pinned.requiredSecrets ?? []),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Wrap a capability's invoke with the least-authority gate. The WRAPPED
|
|
47
|
+
* invoke is what the registry stores and what activations capture, so the
|
|
48
|
+
* gate is enforced identically by the sequential and the durable engines.
|
|
49
|
+
* The gate closes over the PINNED declaration snapshot and the runtime's
|
|
50
|
+
* grants — never over the caller's definition object.
|
|
51
|
+
*/
|
|
52
|
+
export function gateCapabilityInvoke(definition, authority = {}) {
|
|
53
|
+
const names = pinAuthorityDeclarations(definition);
|
|
54
|
+
const capabilityId = definition.id;
|
|
55
|
+
const invoke = definition.invoke;
|
|
56
|
+
const grants = new Set(authority.grants ?? []);
|
|
57
|
+
const configNames = new Set([...names.configuration, ...names.requiredConfiguration]);
|
|
58
|
+
const secretNames = new Set([...names.secrets, ...names.requiredSecrets]);
|
|
59
|
+
const unavailableConfiguration = (name, reason) => new VictRuntimeError('VICT_RUNTIME_CONFIGURATION_UNAVAILABLE', `Configuration '${name}' required by capability '${capabilityId}' is unavailable: ${reason}`, { capabilityId, configurationName: name });
|
|
60
|
+
const unavailableSecret = (name, reason) => new VictRuntimeError('VICT_RUNTIME_SECRET_UNAVAILABLE', `Secret '${name}' required by capability '${capabilityId}' is unavailable: ${reason}`, { capabilityId, secretName: name });
|
|
61
|
+
return async (input, context) => {
|
|
62
|
+
// ---- Per-invocation private caches (HIGH-04-D) ------------------------
|
|
63
|
+
// These caches and the resolvers below are declared INSIDE the
|
|
64
|
+
// invocation function: every invocation gets fresh private caches, so
|
|
65
|
+
// - required/optional values are re-resolved on the NEXT invocation
|
|
66
|
+
// (rotation is observed);
|
|
67
|
+
// - a rejected provider promise dies with this invocation (a later
|
|
68
|
+
// invocation retries the provider and can recover);
|
|
69
|
+
// - concurrent invocations never share cached values or promises.
|
|
70
|
+
// The `{ value }` wrapper keeps a resolved `undefined` distinguishable
|
|
71
|
+
// from 'not yet read'.
|
|
72
|
+
const configCache = new Map();
|
|
73
|
+
const secretCache = new Map();
|
|
74
|
+
/** Resolve a configuration name at most once per invocation. */
|
|
75
|
+
const resolveConfiguration = (name) => {
|
|
76
|
+
const cached = configCache.get(name);
|
|
77
|
+
if (cached !== undefined) {
|
|
78
|
+
return cached.value;
|
|
79
|
+
}
|
|
80
|
+
let value;
|
|
81
|
+
try {
|
|
82
|
+
value = authority.configuration?.get(name);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Provider exceptions are sanitized into stable authority failures;
|
|
86
|
+
// the provider's message never propagates.
|
|
87
|
+
throw unavailableConfiguration(name, 'the configuration provider failed.');
|
|
88
|
+
}
|
|
89
|
+
configCache.set(name, { value });
|
|
90
|
+
return value;
|
|
91
|
+
};
|
|
92
|
+
/** Resolve a secret name at most once per invocation (promise-cached). */
|
|
93
|
+
const resolveSecret = (name) => {
|
|
94
|
+
const cached = secretCache.get(name);
|
|
95
|
+
if (cached !== undefined) {
|
|
96
|
+
return cached;
|
|
97
|
+
}
|
|
98
|
+
const pending = (async () => {
|
|
99
|
+
try {
|
|
100
|
+
return await authority.secrets?.get(name);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
throw unavailableSecret(name, 'the secret provider failed.');
|
|
104
|
+
}
|
|
105
|
+
})();
|
|
106
|
+
secretCache.set(name, pending);
|
|
107
|
+
return pending;
|
|
108
|
+
};
|
|
109
|
+
// ---- Permission gate: fail BEFORE the handler runs -------------------
|
|
110
|
+
for (const permissionId of names.permissions) {
|
|
111
|
+
if (!grants.has(permissionId)) {
|
|
112
|
+
throw new VictRuntimeError('VICT_RUNTIME_PERMISSION_DENIED', `Permission '${permissionId}' required by capability '${capabilityId}' is not granted in this runtime; the handler was not invoked.`, { capabilityId, permissionId });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// ---- Eager required configuration/secret resolution ------------------
|
|
116
|
+
// The resolved values are kept in THIS invocation's private caches;
|
|
117
|
+
// the handler's scoped readers return the SAME checked values.
|
|
118
|
+
for (const name of names.requiredConfiguration) {
|
|
119
|
+
if (authority.configuration === undefined) {
|
|
120
|
+
throw unavailableConfiguration(name, 'no configuration provider is configured.');
|
|
121
|
+
}
|
|
122
|
+
const value = resolveConfiguration(name);
|
|
123
|
+
if (value === undefined) {
|
|
124
|
+
throw unavailableConfiguration(name, 'it is not provisioned.');
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
for (const name of names.requiredSecrets) {
|
|
128
|
+
if (authority.secrets === undefined) {
|
|
129
|
+
throw unavailableSecret(name, 'no secret port is configured.');
|
|
130
|
+
}
|
|
131
|
+
const value = await resolveSecret(name);
|
|
132
|
+
if (value === undefined) {
|
|
133
|
+
throw unavailableSecret(name, 'it is not provisioned.');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// ---- Scoped, name-checked, invocation-scoped readers ------------------
|
|
137
|
+
let config;
|
|
138
|
+
if (authority.configuration !== undefined && configNames.size > 0) {
|
|
139
|
+
config = {
|
|
140
|
+
get(name) {
|
|
141
|
+
if (!configNames.has(name)) {
|
|
142
|
+
throw unavailableConfiguration(name, `it is not declared by capability '${capabilityId}'; undeclared configuration is unavailable.`);
|
|
143
|
+
}
|
|
144
|
+
// Optional names resolve lazily ONCE per invocation and are then
|
|
145
|
+
// cached for the remainder of THIS invocation only.
|
|
146
|
+
return resolveConfiguration(name);
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
let secrets;
|
|
151
|
+
if (authority.secrets !== undefined && secretNames.size > 0) {
|
|
152
|
+
secrets = {
|
|
153
|
+
get(name) {
|
|
154
|
+
if (!secretNames.has(name)) {
|
|
155
|
+
return Promise.reject(unavailableSecret(name, `it is not declared by capability '${capabilityId}'; undeclared secrets are unavailable.`));
|
|
156
|
+
}
|
|
157
|
+
// Optional names resolve lazily ONCE per invocation and are then
|
|
158
|
+
// cached for the remainder of THIS invocation only.
|
|
159
|
+
return resolveSecret(name);
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
return invoke(input, {
|
|
164
|
+
...context,
|
|
165
|
+
...(config !== undefined ? { config } : {}),
|
|
166
|
+
...(secrets !== undefined ? { secrets } : {}),
|
|
167
|
+
});
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=authority.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authority.js","sourceRoot":"","sources":["../src/authority.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ConformanceStores, ConformanceTestRunner } from './store-conformance.js';
|
|
2
|
+
/**
|
|
3
|
+
* Adapter-neutral durable-boundary conformance suite.
|
|
4
|
+
*
|
|
5
|
+
* Proves the Stage 02 write-ahead invariant against ANY ExecutionStore
|
|
6
|
+
* backend, through the REAL production wiring: kernel events feed
|
|
7
|
+
* `DurableRunTracker`, the tracker's writes go through the store under
|
|
8
|
+
* test, and the kernel's `beforeInvoke` port is
|
|
9
|
+
* `tracker.awaitDurableBoundary()`. The suite wraps the store's writes in
|
|
10
|
+
* explicit FIFO gates so it can hold a write open and observe what the
|
|
11
|
+
* kernel does until the write commits: nothing.
|
|
12
|
+
*
|
|
13
|
+
* Invariants proven at every invocation boundary:
|
|
14
|
+
* - run creation must commit before the FIRST capability is invoked;
|
|
15
|
+
* - a node's `node.started` transition must commit before THAT node's
|
|
16
|
+
* capability is invoked;
|
|
17
|
+
* - the preceding node-result batch must commit before the NEXT node's
|
|
18
|
+
* capability is invoked;
|
|
19
|
+
* - a store rejection at any required boundary yields ZERO capability
|
|
20
|
+
* invocations and surfaces the structured store error.
|
|
21
|
+
*
|
|
22
|
+
* Determinism: gates are deferred promises, and every await targets
|
|
23
|
+
* observable state (a write arriving at the gate, an invocation being
|
|
24
|
+
* recorded). There are no sleeps and no timing assumptions. Every
|
|
25
|
+
* capability records its invocation SYNCHRONOUSLY as its first statement,
|
|
26
|
+
* so no in-capability barrier can fake a pass.
|
|
27
|
+
*/
|
|
28
|
+
export interface BoundaryConformanceFactory {
|
|
29
|
+
/** Human-readable backend name used in test titles. */
|
|
30
|
+
readonly name: string;
|
|
31
|
+
/** Create a fresh, isolated store set backed by a disposable database. */
|
|
32
|
+
create(): Promise<ConformanceStores>;
|
|
33
|
+
}
|
|
34
|
+
export interface BoundaryGates {
|
|
35
|
+
/** Labels of writes waiting at the gate, oldest first. */
|
|
36
|
+
pendingLabels(): readonly string[];
|
|
37
|
+
/** Resolve the oldest pending write. */
|
|
38
|
+
releaseNext(): void;
|
|
39
|
+
/** Reject the oldest pending write with a structured store error. */
|
|
40
|
+
failNext(code?: string): void;
|
|
41
|
+
/** Resolves once a write whose label contains `fragment` is at the gate. */
|
|
42
|
+
waitForPending(fragment: string): Promise<void>;
|
|
43
|
+
/** Resolves once the recorded capability invocations reach `count`. */
|
|
44
|
+
waitForInvocations(count: number): Promise<void>;
|
|
45
|
+
/** Labels of writes that fully committed through the inner store, in order. */
|
|
46
|
+
readonly committed: readonly string[];
|
|
47
|
+
/** Capability ids whose bodies began, in invocation order. */
|
|
48
|
+
readonly invocations: readonly string[];
|
|
49
|
+
}
|
|
50
|
+
/** Build and run the durable-boundary suite against one backend factory. */
|
|
51
|
+
export declare function runDurableBoundarySuite(runner: ConformanceTestRunner, factory: BoundaryConformanceFactory): void;
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import { executeGraph } from '@victframework/kernel';
|
|
2
|
+
import { compileGraph, canonicalSemanticForm, computeCapabilitySetVersion, } from '@victframework/kernel';
|
|
3
|
+
import { VictStoreError } from './store-errors.js';
|
|
4
|
+
import { ACTIVATION_MANIFEST_SCHEMA } from './store-types.js';
|
|
5
|
+
import { DurableRunTracker } from './durable-run.js';
|
|
6
|
+
import { toCanonicalJson } from './serialization.js';
|
|
7
|
+
const RUN_ID = 'boundary-run';
|
|
8
|
+
/**
|
|
9
|
+
* Wrap an ExecutionStore so every write blocks at an explicit gate until the
|
|
10
|
+
* test releases it. FIFO ordering is preserved; reads pass straight through.
|
|
11
|
+
*/
|
|
12
|
+
function gatedExecutionStore(inner, invocations) {
|
|
13
|
+
const waiting = [];
|
|
14
|
+
const committed = [];
|
|
15
|
+
const pendingWaiters = [];
|
|
16
|
+
let invocationWaiters = [];
|
|
17
|
+
const notifyPending = (label) => {
|
|
18
|
+
for (let index = 0; index < pendingWaiters.length;) {
|
|
19
|
+
const waiter = pendingWaiters[index];
|
|
20
|
+
if (label.includes(waiter.fragment)) {
|
|
21
|
+
waiter.resolve();
|
|
22
|
+
pendingWaiters.splice(index, 1);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
index += 1;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const gate = async (label, write) => {
|
|
30
|
+
await new Promise((resolve, reject) => {
|
|
31
|
+
waiting.push({ label, resolve, reject });
|
|
32
|
+
notifyPending(label);
|
|
33
|
+
});
|
|
34
|
+
const result = await write();
|
|
35
|
+
committed.push(label);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
const writeLabel = (command) => {
|
|
39
|
+
const first = command.events[0];
|
|
40
|
+
const detail = command.events.length === 0
|
|
41
|
+
? 'state-only'
|
|
42
|
+
: command.events
|
|
43
|
+
.map((event) => `${event.type}@${'nodeId' in event ? (event.nodeId ?? '-') : '-'}`)
|
|
44
|
+
.join('+');
|
|
45
|
+
return `commit:${command.runId}:${first?.seq ?? '-'}:${detail}`;
|
|
46
|
+
};
|
|
47
|
+
const gated = {
|
|
48
|
+
createRun: (command) => gate(`createRun:${command.runId}`, () => inner.createRun(command)),
|
|
49
|
+
commitTransition: (command) => gate(writeLabel(command), () => inner.commitTransition(command)),
|
|
50
|
+
getRun: (runId) => inner.getRun(runId),
|
|
51
|
+
listRuns: (query) => inner.listRuns(query),
|
|
52
|
+
listEvents: (runId, afterSeq) => inner.listEvents(runId, afterSeq),
|
|
53
|
+
recoverInterruptedRuns: (command) => inner.recoverInterruptedRuns(command),
|
|
54
|
+
};
|
|
55
|
+
return Object.assign(gated, {
|
|
56
|
+
pendingLabels: () => waiting.map((write) => write.label),
|
|
57
|
+
releaseNext: () => {
|
|
58
|
+
const write = waiting.shift();
|
|
59
|
+
if (write) {
|
|
60
|
+
write.resolve();
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
failNext: (code = 'VICT_STORE_UNAVAILABLE') => {
|
|
64
|
+
const write = waiting.shift();
|
|
65
|
+
if (write) {
|
|
66
|
+
write.reject(new VictStoreError(code, 'Injected durable-boundary failure.', {
|
|
67
|
+
operation: 'boundary-conformance',
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
waitForPending: (fragment) => new Promise((resolve) => {
|
|
72
|
+
if (waiting.some((write) => write.label.includes(fragment))) {
|
|
73
|
+
resolve();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
pendingWaiters.push({ fragment, resolve });
|
|
77
|
+
}),
|
|
78
|
+
waitForInvocations: (count) => {
|
|
79
|
+
return new Promise((resolve) => {
|
|
80
|
+
if (invocations.length >= count) {
|
|
81
|
+
resolve();
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
invocationWaiters.push({ count, resolve });
|
|
85
|
+
});
|
|
86
|
+
},
|
|
87
|
+
/** Record that a capability body began (wakes invocation waiters). */
|
|
88
|
+
recordInvocation: (capabilityId) => {
|
|
89
|
+
invocations.push(capabilityId);
|
|
90
|
+
invocationWaiters = invocationWaiters.filter((waiter) => {
|
|
91
|
+
if (invocations.length >= waiter.count) {
|
|
92
|
+
waiter.resolve();
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
return true;
|
|
96
|
+
});
|
|
97
|
+
},
|
|
98
|
+
committed,
|
|
99
|
+
invocations,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
const TWO_NODE_GRAPH = {
|
|
103
|
+
id: 'boundary-graph',
|
|
104
|
+
entry: 'a',
|
|
105
|
+
nodes: [
|
|
106
|
+
{ id: 'a', capability: 'boundary.a' },
|
|
107
|
+
{ id: 'b', capability: 'boundary.b' },
|
|
108
|
+
],
|
|
109
|
+
edges: [{ from: 'a', to: 'b' }],
|
|
110
|
+
};
|
|
111
|
+
/** Compile through the same canonical path the runtime uses. */
|
|
112
|
+
function compile(definition) {
|
|
113
|
+
const result = compileGraph({
|
|
114
|
+
definition,
|
|
115
|
+
capabilities: {
|
|
116
|
+
getCapabilityDescriptor: (capabilityId) => ({
|
|
117
|
+
id: capabilityId,
|
|
118
|
+
revision: '1',
|
|
119
|
+
effect: 'pure',
|
|
120
|
+
}),
|
|
121
|
+
},
|
|
122
|
+
contracts: { has: () => false, isCompatible: () => true, get: () => undefined },
|
|
123
|
+
});
|
|
124
|
+
if (!result.ok) {
|
|
125
|
+
throw new Error(`boundary fixture graph failed to compile: ${result.issues.length} issue(s)`);
|
|
126
|
+
}
|
|
127
|
+
return result.graph;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* The exact manifest for the compiled graph's identities. The compiled
|
|
131
|
+
* capabilitySetVersion/activationVersion were computed by the kernel from
|
|
132
|
+
* the same bindings, so the store's identity validation accepts it.
|
|
133
|
+
*/
|
|
134
|
+
function manifestFor(graph) {
|
|
135
|
+
const bindings = graph.nodeIds.map((nodeId) => {
|
|
136
|
+
const node = graph.getNode(nodeId);
|
|
137
|
+
return {
|
|
138
|
+
capability: node.capability,
|
|
139
|
+
revision: '1',
|
|
140
|
+
effect: 'pure',
|
|
141
|
+
input: null,
|
|
142
|
+
output: null,
|
|
143
|
+
};
|
|
144
|
+
});
|
|
145
|
+
return {
|
|
146
|
+
manifestSchema: ACTIVATION_MANIFEST_SCHEMA,
|
|
147
|
+
graphId: graph.id,
|
|
148
|
+
graph: canonicalSemanticForm(graph.toDefinition()),
|
|
149
|
+
graphVersion: graph.graphVersion,
|
|
150
|
+
capabilitySetVersion: computeCapabilitySetVersion(bindings),
|
|
151
|
+
activationVersion: graph.activationVersion,
|
|
152
|
+
bindings,
|
|
153
|
+
contracts: [],
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Execute the two-node graph through the exact production wiring:
|
|
158
|
+
* kernel → DurableRunTracker (onEvent + awaitDurableBoundary) → store.
|
|
159
|
+
*/
|
|
160
|
+
async function openScenario(factory) {
|
|
161
|
+
const stores = await factory.create();
|
|
162
|
+
const invocations = [];
|
|
163
|
+
const store = gatedExecutionStore(stores.execution, invocations);
|
|
164
|
+
const graph = compile(TWO_NODE_GRAPH);
|
|
165
|
+
// Publish the exact activation the run will reference: stores validate
|
|
166
|
+
// run identity against the published activation (adapter-neutral rule).
|
|
167
|
+
const manifest = manifestFor(graph);
|
|
168
|
+
await stores.catalog.publish({ manifest, canonicalManifest: toCanonicalJson(manifest) });
|
|
169
|
+
const tracker = new DurableRunTracker(store, {
|
|
170
|
+
runId: RUN_ID,
|
|
171
|
+
graphId: graph.id,
|
|
172
|
+
graphVersion: graph.graphVersion,
|
|
173
|
+
capabilitySetVersion: graph.capabilitySetVersion,
|
|
174
|
+
activationVersion: graph.activationVersion,
|
|
175
|
+
mode: 'normal',
|
|
176
|
+
retention: 'summary',
|
|
177
|
+
entryNodeId: graph.entryNodeId,
|
|
178
|
+
});
|
|
179
|
+
const execution = (async () => {
|
|
180
|
+
const output = await executeGraph({
|
|
181
|
+
graph,
|
|
182
|
+
input: { n: 1 },
|
|
183
|
+
mode: 'normal',
|
|
184
|
+
ports: {
|
|
185
|
+
descriptors: {
|
|
186
|
+
getCapabilityDescriptor: (capabilityId) => ({
|
|
187
|
+
id: capabilityId,
|
|
188
|
+
revision: '1',
|
|
189
|
+
effect: 'pure',
|
|
190
|
+
}),
|
|
191
|
+
},
|
|
192
|
+
contracts: { has: () => false, isCompatible: () => true, get: () => undefined },
|
|
193
|
+
// Pin the kernel's run id to the tracker's run id — exactly what the
|
|
194
|
+
// runtime does; events and run rows must carry one run identity.
|
|
195
|
+
ids: { runId: () => RUN_ID },
|
|
196
|
+
onEvent: (event) => {
|
|
197
|
+
tracker.onEvent(event);
|
|
198
|
+
},
|
|
199
|
+
// The exact boundary the runtime installs.
|
|
200
|
+
beforeInvoke: () => tracker.awaitDurableBoundary(),
|
|
201
|
+
policy: { authorize: () => ({ allowed: true, useDouble: false }) },
|
|
202
|
+
capabilities: {
|
|
203
|
+
invoke: async (capabilityId) => {
|
|
204
|
+
// FIRST statement: a synchronous, observable side effect. If the
|
|
205
|
+
// kernel ever invoked before the durable write committed, this
|
|
206
|
+
// would record it — no in-capability barrier can mask that.
|
|
207
|
+
store.recordInvocation(capabilityId);
|
|
208
|
+
return { ok: true, value: { from: capabilityId } };
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
await tracker.finish(output);
|
|
214
|
+
})();
|
|
215
|
+
execution.catch(() => undefined); // rejections are observed through `execution`
|
|
216
|
+
return { gates: store, execution, stores };
|
|
217
|
+
}
|
|
218
|
+
/** Build and run the durable-boundary suite against one backend factory. */
|
|
219
|
+
export function runDurableBoundarySuite(runner, factory) {
|
|
220
|
+
const { test, expect } = runner;
|
|
221
|
+
test(`[${factory.name}] an unresolved createRun blocks the first capability invocation`, async () => {
|
|
222
|
+
const scenario = await openScenario(factory);
|
|
223
|
+
try {
|
|
224
|
+
// Run creation reached the store but stays gated.
|
|
225
|
+
await scenario.gates.waitForPending('createRun');
|
|
226
|
+
// The kernel awaits the durable boundary; nothing has been invoked.
|
|
227
|
+
expect(scenario.gates.invocations).toEqual([]);
|
|
228
|
+
}
|
|
229
|
+
finally {
|
|
230
|
+
await settle(scenario);
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
test(`[${factory.name}] an unresolved node.started commit blocks that node's capability`, async () => {
|
|
234
|
+
const scenario = await openScenario(factory);
|
|
235
|
+
try {
|
|
236
|
+
await scenario.gates.waitForPending('createRun');
|
|
237
|
+
scenario.gates.releaseNext();
|
|
238
|
+
// Node a's node.started write is durable-in-flight.
|
|
239
|
+
await scenario.gates.waitForPending('node.started@a');
|
|
240
|
+
expect(scenario.gates.invocations).toEqual([]);
|
|
241
|
+
}
|
|
242
|
+
finally {
|
|
243
|
+
await settle(scenario);
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
test(`[${factory.name}] resolving the node-start commit invokes the capability exactly once`, async () => {
|
|
247
|
+
const scenario = await openScenario(factory);
|
|
248
|
+
try {
|
|
249
|
+
await scenario.gates.waitForPending('createRun');
|
|
250
|
+
scenario.gates.releaseNext();
|
|
251
|
+
await scenario.gates.waitForPending('node.started@a');
|
|
252
|
+
scenario.gates.releaseNext();
|
|
253
|
+
await scenario.gates.waitForInvocations(1);
|
|
254
|
+
expect(scenario.gates.invocations).toEqual(['boundary.a']);
|
|
255
|
+
// Release the remaining durable writes as execution produces them;
|
|
256
|
+
// node b then runs — exactly once more.
|
|
257
|
+
await scenario.gates.waitForPending('node.completed@a');
|
|
258
|
+
scenario.gates.releaseNext();
|
|
259
|
+
await scenario.gates.waitForPending('node.started@b');
|
|
260
|
+
scenario.gates.releaseNext();
|
|
261
|
+
await scenario.gates.waitForInvocations(2);
|
|
262
|
+
expect(scenario.gates.invocations).toEqual(['boundary.a', 'boundary.b']);
|
|
263
|
+
}
|
|
264
|
+
finally {
|
|
265
|
+
await settle(scenario);
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
test(`[${factory.name}] a rejected createRun invokes no capability and fails structured`, async () => {
|
|
269
|
+
const scenario = await openScenario(factory);
|
|
270
|
+
try {
|
|
271
|
+
await scenario.gates.waitForPending('createRun');
|
|
272
|
+
scenario.gates.failNext('VICT_STORE_UNAVAILABLE');
|
|
273
|
+
await expect(scenario.execution).rejects.toMatchObject({ code: 'VICT_STORE_UNAVAILABLE' });
|
|
274
|
+
expect(scenario.gates.invocations).toEqual([]);
|
|
275
|
+
}
|
|
276
|
+
finally {
|
|
277
|
+
await settleSilently(scenario);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
test(`[${factory.name}] a rejected node-start transition invokes no capability`, async () => {
|
|
281
|
+
const scenario = await openScenario(factory);
|
|
282
|
+
try {
|
|
283
|
+
await scenario.gates.waitForPending('createRun');
|
|
284
|
+
scenario.gates.releaseNext();
|
|
285
|
+
await scenario.gates.waitForPending('node.started@a');
|
|
286
|
+
scenario.gates.failNext('VICT_STORE_BUSY');
|
|
287
|
+
await expect(scenario.execution).rejects.toMatchObject({ code: 'VICT_STORE_BUSY' });
|
|
288
|
+
expect(scenario.gates.invocations).toEqual([]);
|
|
289
|
+
}
|
|
290
|
+
finally {
|
|
291
|
+
await settleSilently(scenario);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
test(`[${factory.name}] the second capability waits for the first result batch and its own node.started`, async () => {
|
|
295
|
+
const scenario = await openScenario(factory);
|
|
296
|
+
try {
|
|
297
|
+
// FIFO write order: createRun, a:node.started, a:result batch,
|
|
298
|
+
// b:node.started, b:result+terminal.
|
|
299
|
+
await scenario.gates.waitForPending('createRun');
|
|
300
|
+
scenario.gates.releaseNext();
|
|
301
|
+
await scenario.gates.waitForPending('node.started@a');
|
|
302
|
+
scenario.gates.releaseNext();
|
|
303
|
+
await scenario.gates.waitForInvocations(1);
|
|
304
|
+
expect(scenario.gates.invocations).toEqual(['boundary.a']);
|
|
305
|
+
// a's result batch is now gated — b must not start.
|
|
306
|
+
await scenario.gates.waitForPending('node.completed@a');
|
|
307
|
+
expect(scenario.gates.invocations).toEqual(['boundary.a']);
|
|
308
|
+
scenario.gates.releaseNext(); // commit a's result batch
|
|
309
|
+
await scenario.gates.waitForPending('node.started@b');
|
|
310
|
+
// b's intent is enqueued but not durable — still exactly one invocation.
|
|
311
|
+
expect(scenario.gates.invocations).toEqual(['boundary.a']);
|
|
312
|
+
scenario.gates.releaseNext(); // commit b's node.started
|
|
313
|
+
await scenario.gates.waitForInvocations(2);
|
|
314
|
+
expect(scenario.gates.invocations).toEqual(['boundary.a', 'boundary.b']);
|
|
315
|
+
// Causal order: a's result batch committed before b's node.started
|
|
316
|
+
// committed — and b ran only afterwards.
|
|
317
|
+
const committed = scenario.gates.committed;
|
|
318
|
+
const batchIndex = committed.findIndex((label) => label.includes('node.completed@a'));
|
|
319
|
+
const bStartIndex = committed.findIndex((label) => label.includes('node.started@b'));
|
|
320
|
+
expect(batchIndex >= 0).toBe(true);
|
|
321
|
+
expect(bStartIndex > batchIndex).toBe(true);
|
|
322
|
+
}
|
|
323
|
+
finally {
|
|
324
|
+
await settle(scenario);
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
/* ------------------------------------------------------------------ */
|
|
329
|
+
/* Scenario settlement */
|
|
330
|
+
/* ------------------------------------------------------------------ */
|
|
331
|
+
/** Release everything still pending and let the run settle successfully. */
|
|
332
|
+
async function settle(scenario) {
|
|
333
|
+
await releaseUntilSettled(scenario);
|
|
334
|
+
await scenario.execution;
|
|
335
|
+
await scenario.stores.dispose();
|
|
336
|
+
}
|
|
337
|
+
/** Release everything still pending after an expected rejection. */
|
|
338
|
+
async function settleSilently(scenario) {
|
|
339
|
+
await releaseUntilSettled(scenario);
|
|
340
|
+
await scenario.execution.catch(() => undefined);
|
|
341
|
+
await scenario.stores.dispose();
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Release gated writes until the execution settles: each release can let
|
|
345
|
+
* execution produce the next gated write, so the loop yields and re-checks
|
|
346
|
+
* until the run promise resolves or rejects. Terminates because the write
|
|
347
|
+
* sequence of a finite graph is finite.
|
|
348
|
+
*/
|
|
349
|
+
async function releaseUntilSettled(scenario) {
|
|
350
|
+
let settled = false;
|
|
351
|
+
const done = scenario.execution.then(() => {
|
|
352
|
+
settled = true;
|
|
353
|
+
}, () => {
|
|
354
|
+
settled = true;
|
|
355
|
+
});
|
|
356
|
+
while (!settled) {
|
|
357
|
+
if (scenario.gates.pendingLabels().length > 0) {
|
|
358
|
+
scenario.gates.releaseNext();
|
|
359
|
+
}
|
|
360
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
361
|
+
}
|
|
362
|
+
await done;
|
|
363
|
+
}
|
|
364
|
+
//# sourceMappingURL=boundary-conformance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boundary-conformance.js","sourceRoot":"","sources":["../src/boundary-conformance.ts"],"names":[],"mappings":"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"}
|