@gate-forge/pack-playwright 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/LICENSE +202 -0
- package/bin/gateforge-witness.js +40 -0
- package/dist/attestation/proxy.d.ts +40 -0
- package/dist/attestation/proxy.d.ts.map +1 -0
- package/dist/attestation/proxy.js +78 -0
- package/dist/attestation/proxy.js.map +1 -0
- package/dist/constants.d.ts +130 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +138 -0
- package/dist/constants.js.map +1 -0
- package/dist/discovery/adapters.d.ts +167 -0
- package/dist/discovery/adapters.d.ts.map +1 -0
- package/dist/discovery/adapters.js +276 -0
- package/dist/discovery/adapters.js.map +1 -0
- package/dist/discovery/discover.d.ts +57 -0
- package/dist/discovery/discover.d.ts.map +1 -0
- package/dist/discovery/discover.js +544 -0
- package/dist/discovery/discover.js.map +1 -0
- package/dist/discovery/index.d.ts +15 -0
- package/dist/discovery/index.d.ts.map +1 -0
- package/dist/discovery/index.js +15 -0
- package/dist/discovery/index.js.map +1 -0
- package/dist/discovery/inference.d.ts +63 -0
- package/dist/discovery/inference.d.ts.map +1 -0
- package/dist/discovery/inference.js +173 -0
- package/dist/discovery/inference.js.map +1 -0
- package/dist/discovery/pytest-adapter.d.ts +205 -0
- package/dist/discovery/pytest-adapter.d.ts.map +1 -0
- package/dist/discovery/pytest-adapter.js +548 -0
- package/dist/discovery/pytest-adapter.js.map +1 -0
- package/dist/discovery/reconcile.d.ts +106 -0
- package/dist/discovery/reconcile.d.ts.map +1 -0
- package/dist/discovery/reconcile.js +268 -0
- package/dist/discovery/reconcile.js.map +1 -0
- package/dist/discovery/runner-env.d.ts +80 -0
- package/dist/discovery/runner-env.d.ts.map +1 -0
- package/dist/discovery/runner-env.js +139 -0
- package/dist/discovery/runner-env.js.map +1 -0
- package/dist/discovery/static-discovery.d.ts +121 -0
- package/dist/discovery/static-discovery.d.ts.map +1 -0
- package/dist/discovery/static-discovery.js +1028 -0
- package/dist/discovery/static-discovery.js.map +1 -0
- package/dist/discovery/supervised-run.d.ts +110 -0
- package/dist/discovery/supervised-run.d.ts.map +1 -0
- package/dist/discovery/supervised-run.js +328 -0
- package/dist/discovery/supervised-run.js.map +1 -0
- package/dist/discovery/trusted-config.d.ts +103 -0
- package/dist/discovery/trusted-config.d.ts.map +1 -0
- package/dist/discovery/trusted-config.js +117 -0
- package/dist/discovery/trusted-config.js.map +1 -0
- package/dist/fixture/evidence.d.ts +191 -0
- package/dist/fixture/evidence.d.ts.map +1 -0
- package/dist/fixture/evidence.js +366 -0
- package/dist/fixture/evidence.js.map +1 -0
- package/dist/fixture/fixture.d.ts +37 -0
- package/dist/fixture/fixture.d.ts.map +1 -0
- package/dist/fixture/fixture.js +38 -0
- package/dist/fixture/fixture.js.map +1 -0
- package/dist/fixture/witness-client.d.ts +164 -0
- package/dist/fixture/witness-client.d.ts.map +1 -0
- package/dist/fixture/witness-client.js +253 -0
- package/dist/fixture/witness-client.js.map +1 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/json.d.ts +16 -0
- package/dist/json.d.ts.map +1 -0
- package/dist/json.js +21 -0
- package/dist/json.js.map +1 -0
- package/dist/reporter/ledger.d.ts +105 -0
- package/dist/reporter/ledger.d.ts.map +1 -0
- package/dist/reporter/ledger.js +197 -0
- package/dist/reporter/ledger.js.map +1 -0
- package/dist/reporter/reporter.cjs +105 -0
- package/dist/reporter/reporter.cjs.map +1 -0
- package/dist/reporter/reporter.d.cts +35 -0
- package/dist/reporter/reporter.d.cts.map +1 -0
- package/dist/reporter/reporter.d.ts +167 -0
- package/dist/reporter/reporter.d.ts.map +1 -0
- package/dist/reporter/reporter.js +673 -0
- package/dist/reporter/reporter.js.map +1 -0
- package/dist/setup.d.ts +49 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +167 -0
- package/dist/setup.js.map +1 -0
- package/dist/supervisor/client.d.ts +73 -0
- package/dist/supervisor/client.d.ts.map +1 -0
- package/dist/supervisor/client.js +164 -0
- package/dist/supervisor/client.js.map +1 -0
- package/dist/supervisor/drain.d.ts +45 -0
- package/dist/supervisor/drain.d.ts.map +1 -0
- package/dist/supervisor/drain.js +235 -0
- package/dist/supervisor/drain.js.map +1 -0
- package/dist/supervisor/index.d.ts +16 -0
- package/dist/supervisor/index.d.ts.map +1 -0
- package/dist/supervisor/index.js +13 -0
- package/dist/supervisor/index.js.map +1 -0
- package/dist/supervisor/spool.d.ts +137 -0
- package/dist/supervisor/spool.d.ts.map +1 -0
- package/dist/supervisor/spool.js +263 -0
- package/dist/supervisor/spool.js.map +1 -0
- package/dist/surface.d.ts +134 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +139 -0
- package/dist/surface.js.map +1 -0
- package/dist/witness/adapter-registry.d.ts +38 -0
- package/dist/witness/adapter-registry.d.ts.map +1 -0
- package/dist/witness/adapter-registry.js +158 -0
- package/dist/witness/adapter-registry.js.map +1 -0
- package/dist/witness/bin.d.ts +21 -0
- package/dist/witness/bin.d.ts.map +1 -0
- package/dist/witness/bin.js +172 -0
- package/dist/witness/bin.js.map +1 -0
- package/dist/witness/browser.d.ts +173 -0
- package/dist/witness/browser.d.ts.map +1 -0
- package/dist/witness/browser.js +580 -0
- package/dist/witness/browser.js.map +1 -0
- package/dist/witness/classifications.d.ts +42 -0
- package/dist/witness/classifications.d.ts.map +1 -0
- package/dist/witness/classifications.js +87 -0
- package/dist/witness/classifications.js.map +1 -0
- package/dist/witness/env-attestation.d.ts +98 -0
- package/dist/witness/env-attestation.d.ts.map +1 -0
- package/dist/witness/env-attestation.js +202 -0
- package/dist/witness/env-attestation.js.map +1 -0
- package/dist/witness/loopback-pins.d.ts +79 -0
- package/dist/witness/loopback-pins.d.ts.map +1 -0
- package/dist/witness/loopback-pins.js +244 -0
- package/dist/witness/loopback-pins.js.map +1 -0
- package/dist/witness/server.d.ts +34 -0
- package/dist/witness/server.d.ts.map +1 -0
- package/dist/witness/server.js +2539 -0
- package/dist/witness/server.js.map +1 -0
- package/dist/witness/types.d.ts +643 -0
- package/dist/witness/types.d.ts.map +1 -0
- package/dist/witness/types.js +2 -0
- package/dist/witness/types.js.map +1 -0
- package/package.json +64 -0
- package/python/gateforge_persistence_intents.py +100 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The supervisor's spool drain (enforcement-review fix 3): while the
|
|
3
|
+
* supervised runner executes, the trusted CLI polls the runner-side
|
|
4
|
+
* lifecycle spool and performs the witness's SUPERVISOR calls itself —
|
|
5
|
+
* session open on `testBegin`, session close with the observed outcome
|
|
6
|
+
* on `testEnd`. The runner child holds no supervisor rights at all: it
|
|
7
|
+
* writes spool events (identities and outcomes, no secrets), and the
|
|
8
|
+
* witness accepts session lifecycle ONLY from this verifier-key-
|
|
9
|
+
* authenticated channel. On stop, the drain performs a final sweep and
|
|
10
|
+
* force-closes any session the runner left open (a crashed worker can
|
|
11
|
+
* never leave the witness holding an open session past the run).
|
|
12
|
+
*
|
|
13
|
+
* SERVER-WITNESSED persistence channel: the drain also polls the
|
|
14
|
+
* persistence-intents spool (`persistence-intents.jsonl` — claim INTENTS
|
|
15
|
+
* the supervised suite may only WRITE) and forwards each one to the
|
|
16
|
+
* witness's verifier-key surface, where the adapter SERVER PROBE runs
|
|
17
|
+
* witness-side. When `serverE2eObligations` is supplied (the trusted
|
|
18
|
+
* mapping layer's `kind: server-e2e` declarations), the drain registers
|
|
19
|
+
* them BEFORE forwarding anything: the witness then stamps witnessed
|
|
20
|
+
* `channel: 'server'` persistence records for those obligations only.
|
|
21
|
+
* A refused/failed intent resolves to a typed failure recorded here and
|
|
22
|
+
* in the logs — never to satisfaction (fail closed; the claim simply
|
|
23
|
+
* stays blocking).
|
|
24
|
+
*/
|
|
25
|
+
import { CAUSE_NEXT_ACTIONS } from '@gate-forge/core';
|
|
26
|
+
import { WitnessRequestError } from '../fixture/witness-client.js';
|
|
27
|
+
import { SupervisorClient } from './client.js';
|
|
28
|
+
import { persistenceIntentsPathFor, readPersistenceIntents, readSpoolEvents, spoolPathFor, } from './spool.js';
|
|
29
|
+
/** Default cadence between spool polls (the fixture's resolve waits 5s). */
|
|
30
|
+
export const DEFAULT_DRAIN_POLL_MS = 50;
|
|
31
|
+
/**
|
|
32
|
+
* Starts the spool drain loop for one supervised run.
|
|
33
|
+
*
|
|
34
|
+
* Args:
|
|
35
|
+
* options: stateDir + runId locate the spools; witnessUrl/runToken/
|
|
36
|
+
* verifierKey authenticate the supervisor channel; pollMs tunes the
|
|
37
|
+
* poll cadence (tests only); serverE2eObligations, when provided,
|
|
38
|
+
* are registered BEFORE any intent forwarding (the trusted mapping
|
|
39
|
+
* layer's `kind: server-e2e` declarations — the witness stamps
|
|
40
|
+
* server-channel records for these obligations only).
|
|
41
|
+
*
|
|
42
|
+
* Returns:
|
|
43
|
+
* SpoolDrainHandle: awaitable stop (final drain + force-close).
|
|
44
|
+
*/
|
|
45
|
+
export function startSupervisorSpoolDrain(options) {
|
|
46
|
+
const client = new SupervisorClient(options.witnessUrl, options.runToken, options.verifierKey);
|
|
47
|
+
const spoolFile = spoolPathFor(options.stateDir, options.runId);
|
|
48
|
+
const intentsFile = persistenceIntentsPathFor(options.stateDir, options.runId);
|
|
49
|
+
const pollMs = options.pollMs ?? DEFAULT_DRAIN_POLL_MS;
|
|
50
|
+
const openByWorker = new Map();
|
|
51
|
+
const endedTests = new Set();
|
|
52
|
+
const conflicts = [];
|
|
53
|
+
const intentFailures = [];
|
|
54
|
+
let offset = 0;
|
|
55
|
+
let intentsOffset = 0;
|
|
56
|
+
let running = true;
|
|
57
|
+
let settling = Promise.resolve();
|
|
58
|
+
const slotKey = (workerIndex, testId) => `${String(workerIndex)}\u0000${testId}`;
|
|
59
|
+
const openSessionFor = async (event) => {
|
|
60
|
+
const workerIndex = event.workerIndex;
|
|
61
|
+
const existing = openByWorker.get(workerIndex);
|
|
62
|
+
if (existing !== undefined && existing.testId === event.testId)
|
|
63
|
+
return; // idempotent re-begin
|
|
64
|
+
if (existing !== undefined) {
|
|
65
|
+
// A second begin over an open worker slot: genuine serial reporter
|
|
66
|
+
// events never do this (one test per worker at a time). The FIRST
|
|
67
|
+
// session stands (a forgery must not displace it); the collision is
|
|
68
|
+
// recorded and fails the run closed downstream.
|
|
69
|
+
conflicts.push(`lifecycle conflict: worker ${String(workerIndex)} began '${event.testId}' while ` +
|
|
70
|
+
`'${existing.testId}' was still open — a duplicate begin never occurs in a genuine ` +
|
|
71
|
+
'serial run (forged or confused lifecycle events fail closed)');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (endedTests.has(slotKey(workerIndex, event.testId))) {
|
|
75
|
+
conflicts.push(`lifecycle conflict: worker ${String(workerIndex)} re-began already-ended test ` +
|
|
76
|
+
`'${event.testId}' — a second lifecycle for the same test never occurs in a genuine ` +
|
|
77
|
+
'run (forged or confused lifecycle events fail closed)');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const opened = await client.openSession({
|
|
81
|
+
testId: event.testId,
|
|
82
|
+
workerIndex,
|
|
83
|
+
...(event.file !== null ? { file: event.file } : {}),
|
|
84
|
+
...(event.titlePath.length > 0 ? { titlePath: event.titlePath } : {}),
|
|
85
|
+
...(event.project !== null ? { project: event.project } : {}),
|
|
86
|
+
...(event.claims !== undefined && event.claims.length > 0 ? { claims: event.claims } : {}),
|
|
87
|
+
});
|
|
88
|
+
openByWorker.set(workerIndex, { sessionId: opened.sessionId, testId: event.testId });
|
|
89
|
+
};
|
|
90
|
+
const sealQuietly = async (slot, outcome) => {
|
|
91
|
+
try {
|
|
92
|
+
await client.closeSession({ sessionId: slot.sessionId, ...(outcome !== undefined ? { outcome } : {}) });
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
// Unknown/already-sealed sessions are re-delivery noise; anything
|
|
96
|
+
// else surfaces in the trace grading (an unsealable session never
|
|
97
|
+
// reads as passed).
|
|
98
|
+
if (!(error instanceof WitnessRequestError)) {
|
|
99
|
+
console.warn(`[gateforge] supervisor session close failed: ${error.message}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
const handleEvent = async (event) => {
|
|
104
|
+
if (event.kind === 'testBegin') {
|
|
105
|
+
await openSessionFor(event);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (event.kind === 'testEnd') {
|
|
109
|
+
const slot = openByWorker.get(event.workerIndex);
|
|
110
|
+
if (slot !== undefined && slot.testId === event.testId) {
|
|
111
|
+
openByWorker.delete(event.workerIndex);
|
|
112
|
+
endedTests.add(slotKey(event.workerIndex, event.testId));
|
|
113
|
+
await sealQuietly(slot, event.outcome);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
// An end with no matching open begin: genuine reporter events are
|
|
117
|
+
// always begin/end paired. A lone end is forgery or confusion —
|
|
118
|
+
// record it and fail the run closed downstream (never open or seal
|
|
119
|
+
// anything for it).
|
|
120
|
+
conflicts.push(`lifecycle conflict: worker ${String(event.workerIndex)} ended '${event.testId}' with no ` +
|
|
121
|
+
'matching open begin — a lone end never occurs in a genuine run (forged or confused ' +
|
|
122
|
+
'lifecycle events fail closed)');
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Resolves the typed witness cause of a refused intent into its §5.4
|
|
127
|
+
* next action (the witness returns the cause code on the error
|
|
128
|
+
* `detail`); unmapped causes still surface verbatim — never silently.
|
|
129
|
+
*/
|
|
130
|
+
const nextActionFor = (cause) => {
|
|
131
|
+
if (cause === null)
|
|
132
|
+
return null;
|
|
133
|
+
return cause in CAUSE_NEXT_ACTIONS ? CAUSE_NEXT_ACTIONS[cause] : null;
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Forwards one drained persistence intent to the witness. Every
|
|
137
|
+
* refusal is a TYPED failure recorded for the run report: the claim
|
|
138
|
+
* stays blocking (no witnessed record exists), and the failure text
|
|
139
|
+
* names the cause and next action — an intent never resolves to
|
|
140
|
+
* satisfaction on probe/adapter/declaration/replay trouble.
|
|
141
|
+
*/
|
|
142
|
+
const handleIntent = async (intent) => {
|
|
143
|
+
try {
|
|
144
|
+
await client.verifyServerPersistence({
|
|
145
|
+
resourceId: intent.entity,
|
|
146
|
+
claimId: intent.claimId,
|
|
147
|
+
operation: intent.operation,
|
|
148
|
+
phase: intent.phase,
|
|
149
|
+
intent: intent.intent,
|
|
150
|
+
key: intent.key,
|
|
151
|
+
sequence: intent.sequence,
|
|
152
|
+
testId: intent.testId,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
const cause = error instanceof WitnessRequestError ? error.detail : null;
|
|
157
|
+
const nextAction = nextActionFor(cause);
|
|
158
|
+
const message = `server persistence intent (${intent.phase}, sequence ${String(intent.sequence)}) for ` +
|
|
159
|
+
`'${intent.claimId}' failed${cause !== null ? ` [${cause}]` : ''}: ` +
|
|
160
|
+
`${error instanceof Error ? error.message : String(error)}` +
|
|
161
|
+
`${nextAction !== null ? ` — next: ${nextAction}` : ''}`;
|
|
162
|
+
intentFailures.push(message);
|
|
163
|
+
console.warn(`[gateforge] ${message}`);
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
const drainOnce = async () => {
|
|
167
|
+
const { events, nextOffset } = readSpoolEvents(spoolFile, offset);
|
|
168
|
+
offset = nextOffset;
|
|
169
|
+
for (const event of events) {
|
|
170
|
+
const previous = settling;
|
|
171
|
+
settling = previous
|
|
172
|
+
.then(() => handleEvent(event))
|
|
173
|
+
.catch((error) => {
|
|
174
|
+
// A refused open (e.g. outside the registered expected set) is
|
|
175
|
+
// logged once; the witness-side refusal is the enforcement —
|
|
176
|
+
// the suite's submissions then fail closed on their own.
|
|
177
|
+
console.warn(`[gateforge] supervisor drain could not process a '${event.kind}' event for ` +
|
|
178
|
+
`'${event.testId}': ${error.message}`);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
// Persistence claim intents (server-witnessed channel): forwarded in
|
|
182
|
+
// file order under the same serialization as the lifecycle events,
|
|
183
|
+
// so per-claim sequences are enforced in order.
|
|
184
|
+
const drainedIntents = readPersistenceIntents(intentsFile, intentsOffset);
|
|
185
|
+
intentsOffset = drainedIntents.nextOffset;
|
|
186
|
+
for (const intent of drainedIntents.intents) {
|
|
187
|
+
const previous = settling;
|
|
188
|
+
settling = previous
|
|
189
|
+
.then(() => handleIntent(intent))
|
|
190
|
+
.catch((error) => {
|
|
191
|
+
console.warn(`[gateforge] supervisor drain could not forward a persistence intent for ` +
|
|
192
|
+
`'${intent.claimId}': ${error.message}`);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
// PRE-RUN fact: register the server-e2e declarations (the trusted
|
|
197
|
+
// mapping layer's kind resolution) before any intent can be forwarded.
|
|
198
|
+
// A refusal is a supervisor setup error and fails the run closed via
|
|
199
|
+
// the conflict channel.
|
|
200
|
+
if (options.serverE2eObligations !== undefined) {
|
|
201
|
+
const previous = settling;
|
|
202
|
+
settling = previous
|
|
203
|
+
.then(async () => {
|
|
204
|
+
await client.registerServerE2eDeclarations({
|
|
205
|
+
obligations: [...options.serverE2eObligations],
|
|
206
|
+
});
|
|
207
|
+
})
|
|
208
|
+
.catch((error) => {
|
|
209
|
+
const message = `supervisor drain could not register the server-e2e declarations: ${error.message}`;
|
|
210
|
+
conflicts.push(message);
|
|
211
|
+
console.warn(`[gateforge] ${message}`);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
const loop = (async () => {
|
|
215
|
+
while (running) {
|
|
216
|
+
await drainOnce();
|
|
217
|
+
await new Promise((resolveSleep) => setTimeout(resolveSleep, pollMs));
|
|
218
|
+
}
|
|
219
|
+
})();
|
|
220
|
+
return {
|
|
221
|
+
stop: async () => {
|
|
222
|
+
running = false;
|
|
223
|
+
await loop.catch(() => undefined);
|
|
224
|
+
await drainOnce();
|
|
225
|
+
await settling;
|
|
226
|
+
// Force-close anything the runner left open (crash, lost contact):
|
|
227
|
+
// sealed with NO outcome — the trace grades it not-passed.
|
|
228
|
+
const leftover = [...openByWorker.values()];
|
|
229
|
+
openByWorker.clear();
|
|
230
|
+
await Promise.all(leftover.map((slot) => sealQuietly(slot, undefined)));
|
|
231
|
+
return { conflicts: [...conflicts], intentFailures: [...intentFailures] };
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=drain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drain.js","sourceRoot":"","sources":["../../src/supervisor/drain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EAAE,kBAAkB,EAAkB,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EACL,yBAAyB,EACzB,sBAAsB,EACtB,eAAe,EACf,YAAY,GAGb,MAAM,YAAY,CAAC;AAEpB,4EAA4E;AAC5E,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,CAAC;AAyBxC;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAQzC;IACC,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/F,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAChE,MAAM,WAAW,GAAG,yBAAyB,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAC/E,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,qBAAqB,CAAC;IACvD,MAAM,YAAY,GAAG,IAAI,GAAG,EAAoB,CAAC;IACjD,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,IAAI,QAAQ,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;IAEhD,MAAM,OAAO,GAAG,CAAC,WAAmB,EAAE,MAAc,EAAU,EAAE,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC,SAAS,MAAM,EAAE,CAAC;IAEzG,MAAM,cAAc,GAAG,KAAK,EAAE,KAAiB,EAAiB,EAAE;QAChE,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;QACtC,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC/C,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM;YAAE,OAAO,CAAC,sBAAsB;QAC9F,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,mEAAmE;YACnE,kEAAkE;YAClE,oEAAoE;YACpE,gDAAgD;YAChD,SAAS,CAAC,IAAI,CACZ,8BAA8B,MAAM,CAAC,WAAW,CAAC,WAAW,KAAK,CAAC,MAAM,UAAU;gBAChF,IAAI,QAAQ,CAAC,MAAM,iEAAiE;gBACpF,8DAA8D,CACjE,CAAC;YACF,OAAO;QACT,CAAC;QACD,IAAI,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;YACvD,SAAS,CAAC,IAAI,CACZ,8BAA8B,MAAM,CAAC,WAAW,CAAC,+BAA+B;gBAC9E,IAAI,KAAK,CAAC,MAAM,qEAAqE;gBACrF,uDAAuD,CAC1D,CAAC;YACF,OAAO;QACT,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC;YACtC,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,WAAW;YACX,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpD,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrE,GAAG,CAAC,KAAK,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7D,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC3F,CAAC,CAAC;QACH,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACvF,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,KAAK,EAAE,IAAc,EAAE,OAA2B,EAAiB,EAAE;QACvF,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,YAAY,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAC1G,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,kEAAkE;YAClE,kEAAkE;YAClE,oBAAoB;YACpB,IAAI,CAAC,CAAC,KAAK,YAAY,mBAAmB,CAAC,EAAE,CAAC;gBAC5C,OAAO,CAAC,IAAI,CAAC,gDAAiD,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;YAC3F,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,KAAK,EAAE,KAAiB,EAAiB,EAAE;QAC7D,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC/B,MAAM,cAAc,CAAC,KAAK,CAAC,CAAC;YAC5B,OAAO;QACT,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;YACjD,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC;gBACvD,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;gBACvC,UAAU,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;gBACzD,MAAM,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;gBACvC,OAAO;YACT,CAAC;YACD,kEAAkE;YAClE,gEAAgE;YAChE,mEAAmE;YACnE,oBAAoB;YACpB,SAAS,CAAC,IAAI,CACZ,8BAA8B,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,WAAW,KAAK,CAAC,MAAM,YAAY;gBACxF,qFAAqF;gBACrF,+BAA+B,CAClC,CAAC;QACJ,CAAC;IACH,CAAC,CAAC;IAEF;;;;OAIG;IACH,MAAM,aAAa,GAAG,CAAC,KAAoB,EAAiB,EAAE;QAC5D,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAChC,OAAQ,KAAmB,IAAI,kBAAkB,CAAC,CAAC,CAAC,kBAAkB,CAAC,KAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACpG,CAAC,CAAC;IAEF;;;;;;OAMG;IACH,MAAM,YAAY,GAAG,KAAK,EAAE,MAAyB,EAAiB,EAAE;QACtE,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,uBAAuB,CAAC;gBACnC,UAAU,EAAE,MAAM,CAAC,MAAM;gBACzB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,GAAG,EAAE,MAAM,CAAC,GAAG;gBACf,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,KAAK,YAAY,mBAAmB,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;YACzE,MAAM,UAAU,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;YACxC,MAAM,OAAO,GACX,8BAA8B,MAAM,CAAC,KAAK,cAAc,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ;gBACvF,IAAI,MAAM,CAAC,OAAO,WAAW,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI;gBACpE,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;gBAC3D,GAAG,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAC3D,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC7B,OAAO,CAAC,IAAI,CAAC,eAAe,OAAO,EAAE,CAAC,CAAC;QACzC,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,KAAK,IAAmB,EAAE;QAC1C,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,eAAe,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAClE,MAAM,GAAG,UAAU,CAAC;QACpB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,QAAQ,GAAG,QAAQ,CAAC;YAC1B,QAAQ,GAAG,QAAQ;iBAChB,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;iBAC9B,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;gBACxB,+DAA+D;gBAC/D,6DAA6D;gBAC7D,yDAAyD;gBACzD,OAAO,CAAC,IAAI,CACV,qDAAqD,KAAK,CAAC,IAAI,cAAc;oBAC3E,IAAI,KAAK,CAAC,MAAM,MAAO,KAAe,CAAC,OAAO,EAAE,CACnD,CAAC;YACJ,CAAC,CAAC,CAAC;QACP,CAAC;QACD,qEAAqE;QACrE,mEAAmE;QACnE,gDAAgD;QAChD,MAAM,cAAc,GAAG,sBAAsB,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;QAC1E,aAAa,GAAG,cAAc,CAAC,UAAU,CAAC;QAC1C,KAAK,MAAM,MAAM,IAAI,cAAc,CAAC,OAAO,EAAE,CAAC;YAC5C,MAAM,QAAQ,GAAG,QAAQ,CAAC;YAC1B,QAAQ,GAAG,QAAQ;iBAChB,IAAI,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;iBAChC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;gBACxB,OAAO,CAAC,IAAI,CACV,0EAA0E;oBACxE,IAAI,MAAM,CAAC,OAAO,MAAO,KAAe,CAAC,OAAO,EAAE,CACrD,CAAC;YACJ,CAAC,CAAC,CAAC;QACP,CAAC;IACH,CAAC,CAAC;IAEF,kEAAkE;IAClE,uEAAuE;IACvE,qEAAqE;IACrE,wBAAwB;IACxB,IAAI,OAAO,CAAC,oBAAoB,KAAK,SAAS,EAAE,CAAC;QAC/C,MAAM,QAAQ,GAAG,QAAQ,CAAC;QAC1B,QAAQ,GAAG,QAAQ;aAChB,IAAI,CAAC,KAAK,IAAI,EAAE;YACf,MAAM,MAAM,CAAC,6BAA6B,CAAC;gBACzC,WAAW,EAAE,CAAC,GAAG,OAAO,CAAC,oBAAyC,CAAC;aACpE,CAAC,CAAC;QACL,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;YACxB,MAAM,OAAO,GAAG,oEAAqE,KAAe,CAAC,OAAO,EAAE,CAAC;YAC/G,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,eAAe,OAAO,EAAE,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACP,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,KAAK,IAAI,EAAE;QACvB,OAAO,OAAO,EAAE,CAAC;YACf,MAAM,SAAS,EAAE,CAAC;YAClB,MAAM,IAAI,OAAO,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,UAAU,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;QACxE,CAAC;IACH,CAAC,CAAC,EAAE,CAAC;IAEL,OAAO;QACL,IAAI,EAAE,KAAK,IAAgE,EAAE;YAC3E,OAAO,GAAG,KAAK,CAAC;YAChB,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YAClC,MAAM,SAAS,EAAE,CAAC;YAClB,MAAM,QAAQ,CAAC;YACf,mEAAmE;YACnE,2DAA2D;YAC3D,MAAM,QAAQ,GAAG,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;YAC5C,YAAY,CAAC,KAAK,EAAE,CAAC;YACrB,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;YACxE,OAAO,EAAE,SAAS,EAAE,CAAC,GAAG,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC,GAAG,cAAc,CAAC,EAAE,CAAC;QAC5E,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supervisor surface of the Playwright evidence pack (enforcement-
|
|
3
|
+
* review fixes 2a/3): the pieces the TRUSTED CLI process uses to hold
|
|
4
|
+
* the session-lifecycle authority the runner child must never have.
|
|
5
|
+
* The persistence-intents spool + forwarding add the server-witnessed
|
|
6
|
+
* persistence channel: the suite may only WRITE intents; the witness
|
|
7
|
+
* (verifier-key surface) probes and stamps.
|
|
8
|
+
*/
|
|
9
|
+
export { appendSpoolEvent, readSpoolEvents, spoolPathFor } from './spool.js';
|
|
10
|
+
export type { SpoolEvent, SpoolEventKind } from './spool.js';
|
|
11
|
+
export { appendPersistenceIntent, readPersistenceIntents, persistenceIntentsPathFor, } from './spool.js';
|
|
12
|
+
export type { PersistenceIntent, PersistenceIntentOperation, PersistenceIntentPhase, PersistenceIntentExpectation, } from './spool.js';
|
|
13
|
+
export { SupervisorClient } from './client.js';
|
|
14
|
+
export { startSupervisorSpoolDrain, DEFAULT_DRAIN_POLL_MS } from './drain.js';
|
|
15
|
+
export type { SpoolDrainHandle } from './drain.js';
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/supervisor/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC7E,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,iBAAiB,EACjB,0BAA0B,EAC1B,sBAAsB,EACtB,4BAA4B,GAC7B,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAC9E,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supervisor surface of the Playwright evidence pack (enforcement-
|
|
3
|
+
* review fixes 2a/3): the pieces the TRUSTED CLI process uses to hold
|
|
4
|
+
* the session-lifecycle authority the runner child must never have.
|
|
5
|
+
* The persistence-intents spool + forwarding add the server-witnessed
|
|
6
|
+
* persistence channel: the suite may only WRITE intents; the witness
|
|
7
|
+
* (verifier-key surface) probes and stamps.
|
|
8
|
+
*/
|
|
9
|
+
export { appendSpoolEvent, readSpoolEvents, spoolPathFor } from './spool.js';
|
|
10
|
+
export { appendPersistenceIntent, readPersistenceIntents, persistenceIntentsPathFor, } from './spool.js';
|
|
11
|
+
export { SupervisorClient } from './client.js';
|
|
12
|
+
export { startSupervisorSpoolDrain, DEFAULT_DRAIN_POLL_MS } from './drain.js';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/supervisor/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE7E,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,YAAY,CAAC;AAOpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/** Which runner lifecycle transition the event represents. */
|
|
2
|
+
export type SpoolEventKind = 'testBegin' | 'testEnd';
|
|
3
|
+
/** One runner lifecycle event (spool line). */
|
|
4
|
+
export interface SpoolEvent {
|
|
5
|
+
/** The transition: a test started or ended. */
|
|
6
|
+
kind: SpoolEventKind;
|
|
7
|
+
/** The runner-assigned test id. */
|
|
8
|
+
testId: string;
|
|
9
|
+
/** The worker running (or that ran) the test. */
|
|
10
|
+
workerIndex: number;
|
|
11
|
+
/** Repo-relative posix file of the test (identity join key). */
|
|
12
|
+
file: string | null;
|
|
13
|
+
/** Catalog-identity title path (describes + title). */
|
|
14
|
+
titlePath: string[];
|
|
15
|
+
/** Runner project name, or null when the runner exposes none. */
|
|
16
|
+
project: string | null;
|
|
17
|
+
/** testEnd only: the observed outcome ('passed' | 'failed' | …). */
|
|
18
|
+
outcome?: string;
|
|
19
|
+
/** testEnd only: 1-based attempt number (1 = first attempt). */
|
|
20
|
+
attempt?: number;
|
|
21
|
+
/** The mapped/annotated obligation claims declared for this test. */
|
|
22
|
+
claims?: string[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Resolves the spool events file for one run.
|
|
26
|
+
*
|
|
27
|
+
* Args:
|
|
28
|
+
* stateDir: absolute run-state directory.
|
|
29
|
+
* runId: the run identity both sides agree on (env-carried).
|
|
30
|
+
*
|
|
31
|
+
* Returns:
|
|
32
|
+
* string: absolute `<stateDir>/spool/<runId>/events.jsonl` path.
|
|
33
|
+
*/
|
|
34
|
+
export declare function spoolPathFor(stateDir: string, runId: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Appends one lifecycle event to the run's spool (runner-side; the
|
|
37
|
+
* reporter calls this). The event is sanitized: string fields are
|
|
38
|
+
* coerced/validated, unknown statuses ride as strings, and canonical
|
|
39
|
+
* JSON escapes every control character (NUL included) — the line is
|
|
40
|
+
* NUL-safe by construction. A failed append never crashes the run: the
|
|
41
|
+
* CLI drain then simply never opens that session and the witness
|
|
42
|
+
* rejects the suite's submissions fail-closed.
|
|
43
|
+
*
|
|
44
|
+
* Args:
|
|
45
|
+
* spoolFile: absolute spool events file (see {@link spoolPathFor}).
|
|
46
|
+
* event: the lifecycle event to append.
|
|
47
|
+
*/
|
|
48
|
+
export declare function appendSpoolEvent(spoolFile: string, event: SpoolEvent): void;
|
|
49
|
+
/**
|
|
50
|
+
* Reads every COMPLETE spool line past the given byte offset (CLI-side
|
|
51
|
+
* drain). A trailing fragment without its terminating newline is left
|
|
52
|
+
* for the next poll — partial writes are never parsed.
|
|
53
|
+
*
|
|
54
|
+
* Args:
|
|
55
|
+
* spoolFile: absolute spool events file.
|
|
56
|
+
* offset: byte offset to read from (0 = from the start).
|
|
57
|
+
*
|
|
58
|
+
* Returns:
|
|
59
|
+
* {events, nextOffset}: parsed events in file order and the offset to
|
|
60
|
+
* resume from (equal to `offset` when nothing complete was added).
|
|
61
|
+
*/
|
|
62
|
+
export declare function readSpoolEvents(spoolFile: string, offset: number): {
|
|
63
|
+
events: SpoolEvent[];
|
|
64
|
+
nextOffset: number;
|
|
65
|
+
};
|
|
66
|
+
/** Which CRUD operation a persistence intent serves. */
|
|
67
|
+
export type PersistenceIntentOperation = 'create' | 'read' | 'update' | 'delete';
|
|
68
|
+
/** Whether the intent precedes the mutation (witness before-state) or follows it (the graded observation). */
|
|
69
|
+
export type PersistenceIntentPhase = 'pre' | 'post';
|
|
70
|
+
/** What the suite expects the witness to observe (expectations never grade — observations do). */
|
|
71
|
+
export type PersistenceIntentExpectation = 'expect-present' | 'expect-absent';
|
|
72
|
+
/**
|
|
73
|
+
* One persistence claim intent (spool line). `sequence` is 1-based and
|
|
74
|
+
* strictly increasing PER `claimId` — the witness refuses replayed or
|
|
75
|
+
* out-of-order sequences, so a duplicated line can never re-drive a
|
|
76
|
+
* stale observation. `testId` must be the claiming test's identity (the
|
|
77
|
+
* claim join key: the runner test id for native claims, the sidecar
|
|
78
|
+
* logical key for mapped tests).
|
|
79
|
+
*
|
|
80
|
+
* TIMING CONTRACT for `pre` intents: the trusted drain observes the
|
|
81
|
+
* state at its NEXT poll (bounded by `pollMs`, default 50ms), so a suite
|
|
82
|
+
* writes the pre intent, allows one drain tick, THEN mutates — the
|
|
83
|
+
* witness records whatever is true when IT looks, so a mutation racing
|
|
84
|
+
* ahead of the probe honestly grades absent-before=false (the create
|
|
85
|
+
* postcondition then fails closed; it never silently passes).
|
|
86
|
+
*/
|
|
87
|
+
export interface PersistenceIntent {
|
|
88
|
+
/** The obligated resource id, e.g. `tenant.lead_push_outbox`. */
|
|
89
|
+
entity: string;
|
|
90
|
+
/** The persistence operation the claim requires. */
|
|
91
|
+
operation: PersistenceIntentOperation;
|
|
92
|
+
/** `pre` = before the mutation (create/update); `post` = the graded observation. */
|
|
93
|
+
phase: PersistenceIntentPhase;
|
|
94
|
+
/** The suite's expectation; the witness records what it ACTUALLY observes. */
|
|
95
|
+
intent: PersistenceIntentExpectation;
|
|
96
|
+
/** The entity key: scalar for single-column primary keys, column-keyed object for composite. */
|
|
97
|
+
key: unknown;
|
|
98
|
+
/** The claimed obligation id `<entity>:persistence:<operation>`. */
|
|
99
|
+
claimId: string;
|
|
100
|
+
/** The claiming test's id (the claim join key). */
|
|
101
|
+
testId: string;
|
|
102
|
+
/** 1-based, strictly increasing per claimId. */
|
|
103
|
+
sequence: number;
|
|
104
|
+
}
|
|
105
|
+
/** Resolves the intents spool file for one run (`<stateDir>/spool/<runId>/persistence-intents.jsonl`). */
|
|
106
|
+
export declare function persistenceIntentsPathFor(stateDir: string, runId: string): string;
|
|
107
|
+
/**
|
|
108
|
+
* Appends one persistence intent to the run's intents spool (test-side
|
|
109
|
+
* helper; the CONTRACT is the JSONL line, this writer only keeps it
|
|
110
|
+
* canonical and NUL-safe). A failed append never crashes the test: the
|
|
111
|
+
* drain then simply never forwards the intent and the claim grades
|
|
112
|
+
* fail-closed without its witnessed record.
|
|
113
|
+
*
|
|
114
|
+
* Args:
|
|
115
|
+
* intentsFile: absolute intents spool file (see {@link persistenceIntentsPathFor}).
|
|
116
|
+
* intent: the claim intent to append.
|
|
117
|
+
*/
|
|
118
|
+
export declare function appendPersistenceIntent(intentsFile: string, intent: PersistenceIntent): void;
|
|
119
|
+
/**
|
|
120
|
+
* Reads every COMPLETE intent line past the given byte offset (CLI-side
|
|
121
|
+
* drain). Trailing fragments without their newline are left for the next
|
|
122
|
+
* poll; structurally invalid lines are skipped (the claim simply never
|
|
123
|
+
* resolves — fail closed, never crash the drain).
|
|
124
|
+
*
|
|
125
|
+
* Args:
|
|
126
|
+
* intentsFile: absolute intents spool file.
|
|
127
|
+
* offset: byte offset to read from (0 = from the start).
|
|
128
|
+
*
|
|
129
|
+
* Returns:
|
|
130
|
+
* {intents, nextOffset}: parsed intents in file order and the offset to
|
|
131
|
+
* resume from.
|
|
132
|
+
*/
|
|
133
|
+
export declare function readPersistenceIntents(intentsFile: string, offset: number): {
|
|
134
|
+
intents: PersistenceIntent[];
|
|
135
|
+
nextOffset: number;
|
|
136
|
+
};
|
|
137
|
+
//# sourceMappingURL=spool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spool.d.ts","sourceRoot":"","sources":["../../src/supervisor/spool.ts"],"names":[],"mappings":"AAqBA,8DAA8D;AAC9D,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,SAAS,CAAC;AAErD,+CAA+C;AAC/C,MAAM,WAAW,UAAU;IACzB,+CAA+C;IAC/C,IAAI,EAAE,cAAc,CAAC;IACrB,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,uDAAuD;IACvD,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,iEAAiE;IACjE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,CAkC3E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb;IAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAuC9C;AAWD,wDAAwD;AACxD,MAAM,MAAM,0BAA0B,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEjF,8GAA8G;AAC9G,MAAM,MAAM,sBAAsB,GAAG,KAAK,GAAG,MAAM,CAAC;AAEpD,kGAAkG;AAClG,MAAM,MAAM,4BAA4B,GAAG,gBAAgB,GAAG,eAAe,CAAC;AAE9E;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,iBAAiB;IAChC,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,SAAS,EAAE,0BAA0B,CAAC;IACtC,oFAAoF;IACpF,KAAK,EAAE,sBAAsB,CAAC;IAC9B,8EAA8E;IAC9E,MAAM,EAAE,4BAA4B,CAAC;IACrC,gGAAgG;IAChG,GAAG,EAAE,OAAO,CAAC;IACb,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,0GAA0G;AAC1G,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAuB5F;AAyBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,GACb;IAAE,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAkCtD"}
|