@markstanden/opencode-test-container 0.0.0-stage → 0.1.1

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.
Files changed (123) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +263 -2
  3. package/container/Containerfile +24 -0
  4. package/container/README.md +29 -0
  5. package/dist/adapters/opencode/events.d.ts +90 -0
  6. package/dist/adapters/opencode/events.js +213 -0
  7. package/dist/adapters/opencode/runtime.d.ts +87 -0
  8. package/dist/adapters/opencode/runtime.js +136 -0
  9. package/dist/adapters/podman/container.d.ts +62 -0
  10. package/dist/adapters/podman/container.js +119 -0
  11. package/dist/adapters/podman/image.d.ts +50 -0
  12. package/dist/adapters/podman/image.js +124 -0
  13. package/dist/adapters/process.d.ts +38 -0
  14. package/dist/adapters/process.js +71 -0
  15. package/dist/campaign/assess.d.ts +45 -0
  16. package/dist/campaign/assess.js +208 -0
  17. package/dist/campaign/close.d.ts +17 -0
  18. package/dist/campaign/close.js +112 -0
  19. package/dist/campaign/evidence-guard.d.ts +24 -0
  20. package/dist/campaign/evidence-guard.js +49 -0
  21. package/dist/campaign/freeze.d.ts +94 -0
  22. package/dist/campaign/freeze.js +297 -0
  23. package/dist/campaign/inventory.d.ts +62 -0
  24. package/dist/campaign/inventory.js +192 -0
  25. package/dist/campaign/judge.d.ts +209 -0
  26. package/dist/campaign/judge.js +1285 -0
  27. package/dist/campaign/ledger.d.ts +64 -0
  28. package/dist/campaign/ledger.js +149 -0
  29. package/dist/campaign/prepare.d.ts +129 -0
  30. package/dist/campaign/prepare.js +483 -0
  31. package/dist/campaign/primary.d.ts +96 -0
  32. package/dist/campaign/primary.js +189 -0
  33. package/dist/campaign/run.d.ts +151 -0
  34. package/dist/campaign/run.js +562 -0
  35. package/dist/campaign/status.d.ts +76 -0
  36. package/dist/campaign/status.js +237 -0
  37. package/dist/cli/otc.d.ts +51 -0
  38. package/dist/cli/otc.js +435 -0
  39. package/dist/contracts/canonical.d.ts +21 -0
  40. package/dist/contracts/canonical.js +44 -0
  41. package/dist/contracts/types.d.ts +261 -0
  42. package/dist/contracts/types.js +9 -0
  43. package/dist/contracts/validate.d.ts +72 -0
  44. package/dist/contracts/validate.js +1021 -0
  45. package/dist/contracts/version.d.ts +44 -0
  46. package/dist/contracts/version.js +147 -0
  47. package/dist/evaluators/docs/analysis/accounting.d.ts +140 -0
  48. package/dist/evaluators/docs/analysis/accounting.js +237 -0
  49. package/dist/evaluators/docs/analysis/blinding.d.ts +40 -0
  50. package/dist/evaluators/docs/analysis/blinding.js +80 -0
  51. package/dist/evaluators/docs/analysis/bounds.d.ts +40 -0
  52. package/dist/evaluators/docs/analysis/bounds.js +31 -0
  53. package/dist/evaluators/docs/analysis/budget.d.ts +137 -0
  54. package/dist/evaluators/docs/analysis/budget.js +305 -0
  55. package/dist/evaluators/docs/analysis/closure.d.ts +175 -0
  56. package/dist/evaluators/docs/analysis/closure.js +251 -0
  57. package/dist/evaluators/docs/analysis/decision.d.ts +59 -0
  58. package/dist/evaluators/docs/analysis/decision.js +161 -0
  59. package/dist/evaluators/docs/analysis/freeze.d.ts +201 -0
  60. package/dist/evaluators/docs/analysis/freeze.js +395 -0
  61. package/dist/evaluators/docs/analysis/guardrails.d.ts +51 -0
  62. package/dist/evaluators/docs/analysis/guardrails.js +194 -0
  63. package/dist/evaluators/docs/analysis/journal.d.ts +150 -0
  64. package/dist/evaluators/docs/analysis/journal.js +475 -0
  65. package/dist/evaluators/docs/analysis/ledger.d.ts +78 -0
  66. package/dist/evaluators/docs/analysis/ledger.js +145 -0
  67. package/dist/evaluators/docs/analysis/measures.d.ts +302 -0
  68. package/dist/evaluators/docs/analysis/measures.js +1069 -0
  69. package/dist/evaluators/docs/analysis/model.d.ts +236 -0
  70. package/dist/evaluators/docs/analysis/model.js +740 -0
  71. package/dist/evaluators/docs/analysis/pairing.d.ts +68 -0
  72. package/dist/evaluators/docs/analysis/pairing.js +95 -0
  73. package/dist/evaluators/docs/analysis/records.d.ts +229 -0
  74. package/dist/evaluators/docs/analysis/records.js +935 -0
  75. package/dist/evaluators/docs/analysis/recovery.d.ts +225 -0
  76. package/dist/evaluators/docs/analysis/recovery.js +507 -0
  77. package/dist/evaluators/docs/analysis/render.d.ts +235 -0
  78. package/dist/evaluators/docs/analysis/render.js +566 -0
  79. package/dist/evaluators/docs/analysis/replay.d.ts +15 -0
  80. package/dist/evaluators/docs/analysis/replay.js +1272 -0
  81. package/dist/evaluators/docs/analysis/screening/inventory.d.ts +136 -0
  82. package/dist/evaluators/docs/analysis/screening/inventory.js +307 -0
  83. package/dist/evaluators/docs/analysis/screening/noteVersion.d.ts +15 -0
  84. package/dist/evaluators/docs/analysis/screening/noteVersion.js +46 -0
  85. package/dist/evaluators/docs/analysis/screening/reconcile.d.ts +38 -0
  86. package/dist/evaluators/docs/analysis/screening/reconcile.js +40 -0
  87. package/dist/evaluators/docs/analysis/screening/rules.d.ts +163 -0
  88. package/dist/evaluators/docs/analysis/screening/rules.js +330 -0
  89. package/dist/evaluators/docs/analysis/screening/scan.d.ts +72 -0
  90. package/dist/evaluators/docs/analysis/screening/scan.js +362 -0
  91. package/dist/evaluators/docs/analysis/selector.d.ts +68 -0
  92. package/dist/evaluators/docs/analysis/selector.js +123 -0
  93. package/dist/evaluators/docs/assess.d.ts +129 -0
  94. package/dist/evaluators/docs/assess.js +433 -0
  95. package/dist/evaluators/docs/campaign.d.ts +133 -0
  96. package/dist/evaluators/docs/campaign.js +222 -0
  97. package/dist/evaluators/docs/index.d.ts +25 -0
  98. package/dist/evaluators/docs/index.js +25 -0
  99. package/dist/evaluators/docs/journal.d.ts +150 -0
  100. package/dist/evaluators/docs/journal.js +475 -0
  101. package/dist/evaluators/docs/scoring.d.ts +367 -0
  102. package/dist/evaluators/docs/scoring.js +662 -0
  103. package/dist/evaluators/skills/assess.d.ts +94 -0
  104. package/dist/evaluators/skills/assess.js +207 -0
  105. package/dist/index.d.ts +46 -0
  106. package/dist/index.js +29 -0
  107. package/dist/legacy/prod014.d.ts +86 -0
  108. package/dist/legacy/prod014.js +209 -0
  109. package/dist/reporting/report.d.ts +79 -0
  110. package/dist/reporting/report.js +242 -0
  111. package/docs/architecture.md +106 -0
  112. package/docs/capability-matrix.md +84 -0
  113. package/docs/offline-rehearsal.md +75 -0
  114. package/docs/parity-record.md +81 -0
  115. package/docs/pr-description.md +103 -0
  116. package/docs/release-0.1.0.md +52 -0
  117. package/docs/releasing.md +82 -0
  118. package/docs/schema.md +97 -0
  119. package/examples/skills/README.md +13 -0
  120. package/examples/skills/campaign.json +73 -0
  121. package/examples/skills/skills/otel-helper/SKILL.md +10 -0
  122. package/examples/skills/suite.json +29 -0
  123. package/package.json +45 -5
@@ -0,0 +1,222 @@
1
+ /**
2
+ * Pure primitives for the arm-blind automatic-notetaking campaign.
3
+ *
4
+ * These are the parts that must be identical across every review and rerun:
5
+ * the seeded schedule, arm-to-directory resolution, the documentation-change
6
+ * classification, the packet label guard and the tolerant JSON extraction.
7
+ * They are pure so a test can pin them without spawning anything.
8
+ */
9
+ import { blindingFindings } from "./analysis/blinding.js";
10
+ /** The frozen schedule seed for the 2026-11-10 six-arm campaign. */
11
+ export const CAMPAIGN_SEED = 20261110;
12
+ /** Native-description arms, in the frozen arm-id order. */
13
+ export const ARMS = ["A", "B", "C", "D", "E", "F"];
14
+ /** Screening scenarios (the four NOTE cases). */
15
+ export const NOTE_CASES = ["NOTE-01", "NOTE-02", "NOTE-03", "NOTE-04"];
16
+ /** Confirmation scenarios, sealed for the 2026-11-10 campaign only. */
17
+ export const HELD_OUT = ["H01", "H02", "H03", "H04"];
18
+ /**
19
+ * A deterministic 32-bit PRNG (mulberry32), so a schedule is reproducible
20
+ * from its seed alone.
21
+ * @param seed The integer seed.
22
+ * @returns A function yielding successive floats in [0, 1).
23
+ */
24
+ export function mulberry32(seed) {
25
+ let state = seed >>> 0;
26
+ return () => {
27
+ state = (state + 0x6d2b79f5) >>> 0;
28
+ let t = state;
29
+ t = Math.imul(t ^ (t >>> 15), t | 1);
30
+ t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
31
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
32
+ };
33
+ }
34
+ /**
35
+ * Fisher–Yates shuffle with an injected random source.
36
+ * @param random The random source.
37
+ * @param items The items to shuffle.
38
+ * @returns A shuffled copy.
39
+ */
40
+ export function shuffle(random, items) {
41
+ const copy = [...items];
42
+ for (let index = copy.length - 1; index > 0; index -= 1) {
43
+ const swap = Math.floor(random() * (index + 1));
44
+ const carried = copy[index];
45
+ copy[index] = copy[swap];
46
+ copy[swap] = carried;
47
+ }
48
+ return copy;
49
+ }
50
+ /**
51
+ * Rotate a list left by `by` positions.
52
+ * @param items The items.
53
+ * @param by The rotation offset.
54
+ * @returns The rotated list.
55
+ */
56
+ export function rotate(items, by) {
57
+ return items.map((_, index) => items[(index + by) % items.length]);
58
+ }
59
+ /**
60
+ * Build both frozen stages of the campaign schedule.
61
+ *
62
+ * Screening runs every arm once in a seeded order inside each
63
+ * scenario/repetition block, with scenario order rotated across repetitions.
64
+ * Confirmation alternates the finalist/control pair on (scenario index +
65
+ * repetition) mod 2 and rotates scenario order by repetition.
66
+ * @param seed The schedule seed; the campaign froze 20261110.
67
+ * @returns The screening and confirmation slot lists.
68
+ */
69
+ export function buildSchedule(seed = CAMPAIGN_SEED) {
70
+ const random = mulberry32(seed);
71
+ const screening = [];
72
+ let slot = 0;
73
+ for (let repetition = 1; repetition <= 2; repetition += 1) {
74
+ for (const scenario of rotate(NOTE_CASES, repetition - 1)) {
75
+ for (const arm of shuffle(random, ARMS)) {
76
+ slot += 1;
77
+ screening.push({
78
+ stage: "screening",
79
+ slot,
80
+ block: `${repetition}-${scenario}`,
81
+ repetition,
82
+ scenario,
83
+ arm,
84
+ stamp: `fr-${arm}-s${repetition}-${scenario}`,
85
+ });
86
+ }
87
+ }
88
+ }
89
+ const confirmation = [];
90
+ for (let repetition = 0; repetition <= 4; repetition += 1) {
91
+ for (const scenario of rotate(HELD_OUT, repetition)) {
92
+ const scenarioIndex = HELD_OUT.indexOf(scenario);
93
+ const roles = (scenarioIndex + repetition) % 2 === 0
94
+ ? ["F", "A"]
95
+ : ["A", "F"];
96
+ for (const role of roles) {
97
+ slot += 1;
98
+ confirmation.push({
99
+ stage: "confirmation",
100
+ slot,
101
+ block: `${repetition}-${scenario}`,
102
+ repetition,
103
+ scenario,
104
+ role,
105
+ stamp: `fc-${role}-r${repetition}-${scenario}`,
106
+ });
107
+ }
108
+ }
109
+ }
110
+ return { seed, screening, confirmation };
111
+ }
112
+ /**
113
+ * Resolve one arm letter to its external worktree directory.
114
+ *
115
+ * The arm letter is case-insensitive and must belong to the frozen set; a
116
+ * runner that silently accepted an unknown letter or mixed case in a path is
117
+ * exactly the defect that invalidated 20 confirmation slots in the original
118
+ * campaign.
119
+ * @param root The campaign root holding the arm worktrees.
120
+ * @param arm The arm letter, either case.
121
+ * @returns The arm's absolute-ish directory path.
122
+ */
123
+ export function armDir(root, arm) {
124
+ const letter = String(arm).toLowerCase();
125
+ if (!/^[a-f]$/.test(letter)) {
126
+ throw new Error(`unknown arm ${JSON.stringify(arm)}: expected A-F`);
127
+ }
128
+ return `${root}/arms/${letter}`;
129
+ }
130
+ /**
131
+ * Classify documentation changes between two knowledge-lake snapshots.
132
+ * @param beforeDocs Markdown documents before the trial ({path, contents}).
133
+ * @param afterDocs Markdown documents after the trial ({path, contents}).
134
+ * @returns The created, modified and removed paths and a change flag.
135
+ */
136
+ export function docChanges(beforeDocs, afterDocs) {
137
+ const before = new Map(beforeDocs.map((doc) => [doc.path, doc.contents]));
138
+ const after = new Map(afterDocs.map((doc) => [doc.path, doc.contents]));
139
+ const createdPaths = [...after.keys()].filter((path) => !before.has(path));
140
+ const modifiedPaths = [...after.keys()].filter((path) => before.has(path) && before.get(path) !== after.get(path));
141
+ const removedPaths = [...before.keys()].filter((path) => !after.has(path));
142
+ return {
143
+ documentsChanged: createdPaths.length > 0 ||
144
+ modifiedPaths.length > 0 ||
145
+ removedPaths.length > 0,
146
+ createdPaths,
147
+ modifiedPaths,
148
+ removedPaths,
149
+ };
150
+ }
151
+ /**
152
+ * Patterns that must never reach a judge: campaign and host paths, and the
153
+ * words that frame an experiment. Arm and stamp detection is shared with the
154
+ * trial boundary through `blindingFindings`.
155
+ */
156
+ export const LABEL_PATTERNS = [
157
+ /docs-desc-fresh/,
158
+ /recording-confirm/,
159
+ /\/home\/[^/\s]+/,
160
+ /fr-[A-F]-[sr]\d/,
161
+ /fc-[AF]-r\d/,
162
+ /cc-[AB]-r\d/,
163
+ /(?:^|\W)arm[_ -]?[A-F](?:\W|$)/i,
164
+ /candidate/i,
165
+ /control arm/i,
166
+ ];
167
+ /**
168
+ * Refuse a judge request that carries any experiment label.
169
+ * @param surfaces Every judge-bound text surface: packet, neutral paths, the
170
+ * request context. No surface is exempt.
171
+ * @returns The matched pattern sources; empty means arm-blind.
172
+ */
173
+ export function labelLeaks(...surfaces) {
174
+ const text = surfaces.join("\n");
175
+ const generic = LABEL_PATTERNS.filter((pattern) => pattern.test(text)).map((pattern) => String(pattern));
176
+ const arm = blindingFindings("judge", text).map((finding) => finding.fragment);
177
+ return [...new Set([...generic, ...arm])];
178
+ }
179
+ /**
180
+ * Extract the first balanced JSON object from text, string- and
181
+ * escape-aware, so trailing prose containing braces cannot corrupt the parse.
182
+ * @param text The judge answer.
183
+ * @returns The raw object text, or undefined when there is none.
184
+ */
185
+ export function firstBalancedObject(text) {
186
+ const start = text.indexOf("{");
187
+ if (start === -1)
188
+ return undefined;
189
+ let depth = 0;
190
+ let inString = false;
191
+ let escaped = false;
192
+ for (let index = start; index < text.length; index += 1) {
193
+ const char = text[index];
194
+ if (inString) {
195
+ ({ inString, escaped } = stepInString(char, escaped));
196
+ continue;
197
+ }
198
+ if (char === '"')
199
+ inString = true;
200
+ else if (char === "{")
201
+ depth += 1;
202
+ else if (char === "}") {
203
+ depth -= 1;
204
+ if (depth === 0)
205
+ return text.slice(start, index + 1);
206
+ }
207
+ }
208
+ return undefined;
209
+ }
210
+ /**
211
+ * Advance the string-literal state by one character.
212
+ * @param char The current character.
213
+ * @param escaped Whether the previous character was an escape.
214
+ * @returns The next string and escape state.
215
+ */
216
+ function stepInString(char, escaped) {
217
+ if (escaped)
218
+ return { inString: true, escaped: false };
219
+ if (char === "\\")
220
+ return { inString: true, escaped: true };
221
+ return { inString: char !== '"', escaped: false };
222
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The docs evaluator: checked recording, utility, retrieval, preservation,
3
+ * guardrails, pairing, bounds, screening, decision and rendering semantics.
4
+ *
5
+ * These modules are the established analysis implementation, migrated from
6
+ * the docs plugin with their tests. They consume recorded evidence only; none
7
+ * of them calls a model.
8
+ */
9
+ export { runAnalysis } from "./analysis/replay.ts";
10
+ export * from "./analysis/accounting.ts";
11
+ export * from "./analysis/bounds.ts";
12
+ export * from "./analysis/decision.ts";
13
+ export * from "./analysis/guardrails.ts";
14
+ export * from "./analysis/measures.ts";
15
+ export * from "./analysis/model.ts";
16
+ export * from "./analysis/pairing.ts";
17
+ export * from "./analysis/records.ts";
18
+ export * from "./analysis/render.ts";
19
+ export * from "./analysis/screening/rules.ts";
20
+ export * from "./analysis/screening/scan.ts";
21
+ export * from "./analysis/screening/inventory.ts";
22
+ export * from "./analysis/screening/reconcile.ts";
23
+ export { DOCUMENTATION_OUTCOMES, PRESERVATION_CASE, buildAcPrompt, finalistQualifies, judgeFailureClass, parseAcJudgement, rankCandidates, sensitivity, summariseArm, validateAcJudgement, type DocumentationOutcome, type JudgeFailureClass, type PreservationState, } from "./scoring.ts";
24
+ export { assessDocsTrial } from "./assess.ts";
25
+ export { verifyOperationsJournal } from "./journal.ts";
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The docs evaluator: checked recording, utility, retrieval, preservation,
3
+ * guardrails, pairing, bounds, screening, decision and rendering semantics.
4
+ *
5
+ * These modules are the established analysis implementation, migrated from
6
+ * the docs plugin with their tests. They consume recorded evidence only; none
7
+ * of them calls a model.
8
+ */
9
+ export { runAnalysis } from "./analysis/replay.js";
10
+ export * from "./analysis/accounting.js";
11
+ export * from "./analysis/bounds.js";
12
+ export * from "./analysis/decision.js";
13
+ export * from "./analysis/guardrails.js";
14
+ export * from "./analysis/measures.js";
15
+ export * from "./analysis/model.js";
16
+ export * from "./analysis/pairing.js";
17
+ export * from "./analysis/records.js";
18
+ export * from "./analysis/render.js";
19
+ export * from "./analysis/screening/rules.js";
20
+ export * from "./analysis/screening/scan.js";
21
+ export * from "./analysis/screening/inventory.js";
22
+ export * from "./analysis/screening/reconcile.js";
23
+ export { DOCUMENTATION_OUTCOMES, PRESERVATION_CASE, buildAcPrompt, finalistQualifies, judgeFailureClass, parseAcJudgement, rankCandidates, sensitivity, summariseArm, validateAcJudgement, } from "./scoring.js";
24
+ export { assessDocsTrial } from "./assess.js";
25
+ export { verifyOperationsJournal } from "./journal.js";
@@ -0,0 +1,150 @@
1
+ /**
2
+ * The one checked evidence boundary for the plugin's operation journal.
3
+ *
4
+ * The plugin can write an opt-in, HMAC-signed journal of served docs
5
+ * operations. That journal is the only record of a nested Code Mode call, so
6
+ * it is also the easiest evidence to forge. This module decides what the
7
+ * journal proves, and nothing else in the harness or analyser may credit a
8
+ * journal line it did not verify.
9
+ *
10
+ * Trust boundary: the signing key and the journal are both harness output,
11
+ * copied after the trial process exits. A trial tool cannot acquire the key
12
+ * during the run, so a correctly signed line with this run's session, message
13
+ * and execute identities, matching a host-recorded dispatch one-to-one, is
14
+ * evidence the plugin served that call. The key is held locally beside the
15
+ * evidence; possession of that key is possession of the ability to forge, so
16
+ * the verification is tamper-evident, not tamper-proof.
17
+ */
18
+ /** The session and message identities observed in one run's CLI trail. */
19
+ export interface JournalIdentity {
20
+ /** Session ids the run emitted. */
21
+ sessions: ReadonlySet<string>;
22
+ /** Message ids the run emitted. */
23
+ messages: ReadonlySet<string>;
24
+ }
25
+ /** One docs call the host recorded, native or nested. */
26
+ export interface JournalDispatch {
27
+ /** The journal's registered tool name (`docs` or `docs_search`). */
28
+ tool: string;
29
+ /** The dispatch status the host recorded. */
30
+ status: string;
31
+ /** The dispatch input the host recorded. */
32
+ input: unknown;
33
+ /** The host call id (native) or parent execute id (nested). */
34
+ callId: string | null;
35
+ }
36
+ /** One credited journal line. */
37
+ export interface CreditedJournalRecord {
38
+ /** The zero-based line index. */
39
+ index: number;
40
+ /** The verified record, including its MAC. */
41
+ record: Record<string, unknown>;
42
+ }
43
+ /** One rejected journal line and why. */
44
+ export interface RejectedJournalRecord {
45
+ /** The zero-based line index. */
46
+ index: number;
47
+ /** A stable reason slug, suitable for diagnostics. */
48
+ reason: "not-json" | "not-served-twin" | "bad-mac" | "unattributed" | "no-host-dispatch";
49
+ }
50
+ /** The explicit result of verifying a journal. */
51
+ export type JournalVerification = {
52
+ /** No journal was captured: the pre-instrumentation status quo. */
53
+ state: "absent";
54
+ credited: [];
55
+ rejected: [];
56
+ problems: string[];
57
+ } | {
58
+ /** A journal exists but its signing key does not. Nothing is credited. */
59
+ state: "unverifiable-key";
60
+ credited: [];
61
+ rejected: RejectedJournalRecord[];
62
+ problems: string[];
63
+ } | {
64
+ /** The journal was verified; `credited` is the only usable evidence. */
65
+ state: "verified";
66
+ credited: CreditedJournalRecord[];
67
+ rejected: RejectedJournalRecord[];
68
+ problems: string[];
69
+ };
70
+ /** Whether a record names a served docs call on either registration surface. */
71
+ export declare function isServedRecord(record: Record<string, unknown>): boolean;
72
+ /**
73
+ * Whether a record's MAC matches the given key. The MAC covers every field
74
+ * except `mac`, in the record's own member order, exactly as the plugin writes
75
+ * it.
76
+ * @param record The journal record.
77
+ * @param key The run's signing key.
78
+ * @returns True when the MAC is well formed and matches.
79
+ */
80
+ export declare function journalMacValid(record: Record<string, unknown>, key: string): boolean;
81
+ /**
82
+ * Whether a record carries this run's observed identity and names an execute
83
+ * call present in its trail.
84
+ * @param record The journal record.
85
+ * @param identity The run's observed session/message ids.
86
+ * @param callIds The execute call ids in the run's trail.
87
+ * @returns True when every identity matches exactly.
88
+ */
89
+ export declare function journalRecordAttributed(record: Record<string, unknown>, identity: JournalIdentity, callIds: ReadonlySet<string>): boolean;
90
+ /**
91
+ * Verify one captured journal against this run's identity and host dispatches.
92
+ *
93
+ * Order matters: shape, then MAC, then identity, then one-to-one dispatch
94
+ * matching. A line failing any step is rejected with its reason and is never
95
+ * credited. If a journal exists but no usable key does, nothing is credited
96
+ * and the state says why.
97
+ * @param input The captured lines, key and run observations.
98
+ * @param input.lines The captured journal lines, or undefined when absent.
99
+ * @param input.key The run's signing key, or null when unavailable.
100
+ * @param input.identity The run's observed session and message ids.
101
+ * @param input.callIds The execute call ids in the run's trail.
102
+ * @param input.nativeCalls The docs calls the host recorded directly.
103
+ * @param input.dispatches The nested docs dispatches the host recorded.
104
+ * @returns The explicit verification result.
105
+ */
106
+ export declare function verifyOperationsJournal(input: {
107
+ lines: readonly string[] | undefined;
108
+ key: string | null | undefined;
109
+ identity: JournalIdentity;
110
+ callIds: ReadonlySet<string>;
111
+ nativeCalls?: readonly JournalDispatch[];
112
+ dispatches: readonly JournalDispatch[];
113
+ }): JournalVerification;
114
+ /**
115
+ * Collect the session and message identities a saved CLI trail observed.
116
+ * @param stdoutText The saved `stdout.jsonl` bytes.
117
+ * @returns The identity sets; empty when the trail is unreadable.
118
+ */
119
+ export declare function journalIdentityFromTrail(stdoutText: string): JournalIdentity;
120
+ /** The host half of journal attribution, read from a saved tools trail. */
121
+ export interface HostDispatches {
122
+ /** Host call ids present in the trail, native and execute. */
123
+ callIds: Set<string>;
124
+ /** Native docs calls the host recorded directly. */
125
+ nativeCalls: JournalDispatch[];
126
+ /** Nested docs dispatches the host recorded inside execute results. */
127
+ dispatches: JournalDispatch[];
128
+ }
129
+ /**
130
+ * Extract the host dispatches and execute call ids from a saved `tools.jsonl`.
131
+ * @param toolsText The saved tools trail bytes.
132
+ * @returns The host half of attribution; empty when the trail is unreadable.
133
+ */
134
+ export declare function hostDispatchesFromTrail(toolsText: string): HostDispatches;
135
+ /**
136
+ * Check a captured answer against the producer's `meta.answerHash`.
137
+ *
138
+ * The harness hashes the exact final-answer text as bytes (`sha256(text)`),
139
+ * so the analyser must hash the recorded `final.md` bytes, never a normalised
140
+ * rendering. A missing hash leaves the answer unbound rather than trusted.
141
+ * @param answer The recorded answer bytes.
142
+ * @param answerHash The producer's recorded hash, when present.
143
+ * @param settings The optional binding settings.
144
+ * @param settings.allowUnbound Explicit read-only coverage for legacy evidence
145
+ * written before the producer recorded a hash.
146
+ * @returns A problem, or null when the answer is bound.
147
+ */
148
+ export declare function answerIdentityProblem(answer: string, answerHash: unknown, settings?: {
149
+ allowUnbound?: boolean;
150
+ }): string | null;