@riddledc/riddle-proof 0.2.0 → 0.4.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/README.md CHANGED
@@ -8,7 +8,7 @@ Proof standardizes evidence, proof assessment, ship gates, terminal results,
8
8
  and integration metadata.
9
9
 
10
10
  This package includes the reusable runner harness that drives a request through
11
- setup, implementation, proof capture, judgment, shipping, and notification
11
+ preflight, setup, implementation, proof capture, judgment, shipping, and notification
12
12
  adapters. The current OpenClaw `proofed_change_run` implementation remains the
13
13
  reference workflow while adapter implementations are extracted behind parity
14
14
  tests.
@@ -19,7 +19,9 @@ tests.
19
19
  - Evidence bundle and proof assessment types
20
20
  - Adapter interfaces
21
21
  - State/event helpers for wrappers that need a stable run envelope
22
- - Runner harness for setup -> implement -> prove -> judge -> ship -> notify
22
+ - Runner harness for preflight -> setup -> implement -> prove -> judge -> ship -> notify
23
+ - Stage heartbeat and run status snapshot helpers
24
+ - Worktree metadata and proof artifact role contracts
23
25
  - Terminal ship metadata normalization
24
26
  - Stable result helpers
25
27
  - OpenClaw parameter normalization via `@riddledc/riddle-proof/openclaw`
@@ -59,9 +61,14 @@ credentials or a coding agent. It calls adapters supplied by the host
59
61
  integration:
60
62
 
61
63
  ```text
62
- setup -> implement -> prove -> judge -> ship -> notify
64
+ preflight -> setup -> implement -> prove -> judge -> ship -> notify
63
65
  ```
64
66
 
67
+ The preflight adapter checks model/tool availability before proof work starts.
68
+ The setup adapter should report the isolated worktree path, branch, and cleanup
69
+ policy it chose. During the run, wrappers can emit `appendStageHeartbeat`
70
+ events and return `createRunStatusSnapshot` for cheap observer status.
71
+
65
72
  The proof adapter is where a host wires Riddle server-backed capture. The ship
66
73
  adapter is where a host commits, pushes, opens or updates a PR, and waits for CI
67
74
  when configured. The notification adapter is where a host updates Discord,
@@ -52,7 +52,11 @@ function createRunResult(input) {
52
52
  return compactRecord({
53
53
  ok,
54
54
  status,
55
+ run_id: state.run_id,
55
56
  state_path: input.state_path ?? state.state_path ?? null,
57
+ worktree_path: state.worktree_path ?? null,
58
+ branch: state.branch ?? null,
59
+ current_stage: state.current_stage ?? null,
56
60
  iterations: state.iterations,
57
61
  last_checkpoint: state.last_checkpoint ?? null,
58
62
  last_summary: input.last_summary ?? null,
@@ -2,13 +2,24 @@ import {
2
2
  compactRecord,
3
3
  nonEmptyString,
4
4
  recordValue
5
- } from "./chunk-2ZQNXVQC.js";
5
+ } from "./chunk-5DC6YXN4.js";
6
6
 
7
7
  // src/state.ts
8
8
  var RIDDLE_PROOF_RUN_STATE_VERSION = "riddle-proof.run-state.v1";
9
9
  function timestamp() {
10
10
  return (/* @__PURE__ */ new Date()).toISOString();
11
11
  }
12
+ function createRunId(createdAt) {
13
+ const stamp = createdAt.replace(/\D/g, "").slice(0, 14) || "unknown";
14
+ const entropy = Math.random().toString(36).slice(2, 8) || "run";
15
+ return `rp_${stamp}_${entropy}`;
16
+ }
17
+ function elapsedMs(start, end) {
18
+ const startMs = start ? Date.parse(start) : NaN;
19
+ const endMs = end ? Date.parse(end) : NaN;
20
+ if (!Number.isFinite(startMs) || !Number.isFinite(endMs)) return void 0;
21
+ return Math.max(0, endMs - startMs);
22
+ }
12
23
  function normalizeIntegrationContext(input, fallbackSource) {
13
24
  const value = recordValue(input);
14
25
  if (!value) {
@@ -52,6 +63,11 @@ function normalizeRunParams(input) {
52
63
  color_scheme: input.color_scheme,
53
64
  wait_for_selector: input.wait_for_selector,
54
65
  ship_mode: input.ship_mode,
66
+ engine_state_path: input.engine_state_path,
67
+ harness_state_path: input.harness_state_path,
68
+ max_iterations: input.max_iterations,
69
+ auto_approve: input.auto_approve,
70
+ dry_run: input.dry_run,
55
71
  integration_context: normalizeIntegrationContext(input.integration_context)
56
72
  });
57
73
  }
@@ -59,7 +75,12 @@ function createRunState(input) {
59
75
  const createdAt = input.created_at || timestamp();
60
76
  return compactRecord({
61
77
  version: RIDDLE_PROOF_RUN_STATE_VERSION,
78
+ run_id: input.run_id || createRunId(createdAt),
62
79
  state_path: input.state_path,
80
+ worktree_path: input.worktree_path,
81
+ branch: input.branch || input.request.branch,
82
+ current_stage: input.current_stage ?? null,
83
+ stage_started_at: input.stage_started_at ?? null,
63
84
  status: input.status || "running",
64
85
  created_at: createdAt,
65
86
  updated_at: input.updated_at || createdAt,
@@ -87,9 +108,49 @@ function appendRunEvent(state, input) {
87
108
  details: event.details
88
109
  }));
89
110
  if (input.checkpoint !== void 0) state.last_checkpoint = input.checkpoint;
111
+ if (input.stage !== void 0) {
112
+ if (state.current_stage !== input.stage) state.stage_started_at = event.ts;
113
+ state.current_stage = input.stage;
114
+ }
90
115
  state.updated_at = event.ts;
91
116
  return state;
92
117
  }
118
+ function appendStageHeartbeat(state, input) {
119
+ const at = input.ts || timestamp();
120
+ return appendRunEvent(state, {
121
+ ts: at,
122
+ kind: "stage.heartbeat",
123
+ checkpoint: input.checkpoint || `${input.stage}_heartbeat`,
124
+ stage: input.stage,
125
+ summary: input.summary || `${input.stage} stage is active.`,
126
+ details: compactRecord({
127
+ elapsed_ms: elapsedMs(state.created_at, at),
128
+ stage_elapsed_ms: elapsedMs(state.stage_started_at, at),
129
+ wait_reason: input.wait_reason,
130
+ blocker: input.blocker,
131
+ ...input.details
132
+ })
133
+ });
134
+ }
135
+ function createRunStatusSnapshot(state, at = timestamp()) {
136
+ const latestEvent = state.events[state.events.length - 1];
137
+ const runId = state.run_id || "unknown";
138
+ return compactRecord({
139
+ run_id: runId,
140
+ status: state.status,
141
+ current_stage: state.current_stage ?? null,
142
+ state_path: state.state_path ?? null,
143
+ worktree_path: state.worktree_path ?? null,
144
+ branch: state.branch ?? null,
145
+ iterations: state.iterations,
146
+ last_checkpoint: state.last_checkpoint ?? null,
147
+ updated_at: state.updated_at,
148
+ elapsed_ms: elapsedMs(state.created_at, at),
149
+ stage_elapsed_ms: elapsedMs(state.stage_started_at, at),
150
+ blocker: state.blocker,
151
+ latest_event: latestEvent
152
+ });
153
+ }
93
154
  function setRunStatus(state, status, at = timestamp()) {
94
155
  state.status = status;
95
156
  state.ok = status !== "blocked" && status !== "failed";
@@ -103,5 +164,7 @@ export {
103
164
  normalizeRunParams,
104
165
  createRunState,
105
166
  appendRunEvent,
167
+ appendStageHeartbeat,
168
+ createRunStatusSnapshot,
106
169
  setRunStatus
107
170
  };
@@ -1,11 +1,12 @@
1
1
  import {
2
2
  appendRunEvent,
3
+ appendStageHeartbeat,
3
4
  createRunState,
4
5
  setRunStatus
5
- } from "./chunk-EPVZKWUS.js";
6
+ } from "./chunk-5FHUOSNO.js";
6
7
  import {
7
8
  createRunResult
8
- } from "./chunk-2ZQNXVQC.js";
9
+ } from "./chunk-5DC6YXN4.js";
9
10
 
10
11
  // src/runner.ts
11
12
  function errorDetails(error) {
@@ -84,7 +85,8 @@ async function notifyIfConfigured(input) {
84
85
  async function runRiddleProof(input) {
85
86
  const state = input.state || createRunState({
86
87
  request: input.request,
87
- state_path: input.state_path
88
+ state_path: input.state_path,
89
+ worktree_path: input.workdir
88
90
  });
89
91
  const adapters = input.adapters || {};
90
92
  const maxIterations = Math.max(1, Math.trunc(input.max_iterations ?? 1));
@@ -94,12 +96,70 @@ async function runRiddleProof(input) {
94
96
  stage: "setup",
95
97
  summary: "Riddle Proof run started.",
96
98
  details: {
99
+ run_id: state.run_id,
100
+ state_path: state.state_path,
101
+ worktree_path: state.worktree_path,
102
+ branch: state.branch,
97
103
  max_iterations: maxIterations,
98
104
  ship_mode: state.request.ship_mode || "none"
99
105
  }
100
106
  });
107
+ appendStageHeartbeat(state, {
108
+ stage: "setup",
109
+ summary: "Setup stage is active.",
110
+ details: {
111
+ run_id: state.run_id,
112
+ state_path: state.state_path,
113
+ worktree_path: state.worktree_path,
114
+ branch: state.branch
115
+ }
116
+ });
101
117
  let workdir = input.workdir;
102
118
  let evidenceContext;
119
+ if (adapters.preflight) {
120
+ appendRunEvent(state, {
121
+ kind: "preflight.started",
122
+ checkpoint: "preflight_started",
123
+ stage: "preflight",
124
+ summary: "Riddle Proof preflight adapter started."
125
+ });
126
+ try {
127
+ const preflight = await adapters.preflight.preflight({ request: state.request, state });
128
+ if (!preflight.ok) {
129
+ return blockRun({
130
+ state,
131
+ stage: "preflight",
132
+ blocker: adapterBlocker(
133
+ "preflight_failed",
134
+ "The preflight adapter found blocking tool or model configuration issues.",
135
+ "preflight_failed",
136
+ {
137
+ blockers: preflight.blockers,
138
+ warnings: preflight.warnings,
139
+ degraded_capabilities: preflight.degraded_capabilities
140
+ }
141
+ ),
142
+ raw: { preflight }
143
+ });
144
+ }
145
+ appendRunEvent(state, {
146
+ kind: "preflight.completed",
147
+ checkpoint: "preflight_completed",
148
+ stage: "preflight",
149
+ summary: "Riddle Proof preflight adapter completed.",
150
+ details: {
151
+ warnings: preflight.warnings,
152
+ degraded_capabilities: preflight.degraded_capabilities
153
+ }
154
+ });
155
+ } catch (error) {
156
+ return blockRun({
157
+ state,
158
+ stage: "preflight",
159
+ blocker: adapterBlocker("preflight_exception", "The preflight adapter threw an exception.", "preflight_failed", errorDetails(error))
160
+ });
161
+ }
162
+ }
103
163
  if (adapters.setup) {
104
164
  appendRunEvent(state, {
105
165
  kind: "setup.started",
@@ -122,7 +182,9 @@ async function runRiddleProof(input) {
122
182
  raw: { setup }
123
183
  });
124
184
  }
125
- workdir = setup.workdir || workdir;
185
+ workdir = setup.worktree_path || setup.workdir || workdir;
186
+ state.worktree_path = setup.worktree_path || setup.workdir || state.worktree_path;
187
+ state.branch = setup.branch || state.branch;
126
188
  evidenceContext = setup.evidence_context;
127
189
  appendRunEvent(state, {
128
190
  kind: "setup.completed",
@@ -131,6 +193,9 @@ async function runRiddleProof(input) {
131
193
  summary: "Riddle Proof setup adapter completed.",
132
194
  details: {
133
195
  has_workdir: Boolean(workdir),
196
+ worktree_path: state.worktree_path,
197
+ branch: state.branch,
198
+ cleanup_policy: setup.cleanup_policy,
134
199
  has_evidence_context: Boolean(evidenceContext)
135
200
  }
136
201
  });
@@ -183,6 +248,11 @@ async function runRiddleProof(input) {
183
248
  let assessment;
184
249
  for (let attempt = 0; attempt < maxIterations; attempt += 1) {
185
250
  state.iterations += 1;
251
+ appendStageHeartbeat(state, {
252
+ stage: "implement",
253
+ summary: "Implementation stage is active.",
254
+ details: { iteration: state.iterations }
255
+ });
186
256
  appendRunEvent(state, {
187
257
  kind: "implementation.started",
188
258
  checkpoint: "implementation_started",
@@ -229,6 +299,13 @@ async function runRiddleProof(input) {
229
299
  tests_run: implementation.tests_run
230
300
  }
231
301
  });
302
+ appendStageHeartbeat(state, {
303
+ stage: "prove",
304
+ summary: "Proof capture stage is active.",
305
+ details: {
306
+ verification_mode: state.request.verification_mode
307
+ }
308
+ });
232
309
  appendRunEvent(state, {
233
310
  kind: "proof.started",
234
311
  checkpoint: "proof_started",
@@ -278,6 +355,13 @@ async function runRiddleProof(input) {
278
355
  stage: "verify",
279
356
  summary: "Judge adapter started."
280
357
  });
358
+ appendStageHeartbeat(state, {
359
+ stage: "verify",
360
+ summary: "Verification stage is active.",
361
+ details: {
362
+ verification_mode: evidenceBundle.verification_mode
363
+ }
364
+ });
281
365
  try {
282
366
  assessment = await adapters.judge.assessProof({ state, evidence_bundle: evidenceBundle });
283
367
  state.proof_decision = assessment.decision;
@@ -367,6 +451,10 @@ async function runRiddleProof(input) {
367
451
  stage: "ship",
368
452
  summary: "Ship adapter started."
369
453
  });
454
+ appendStageHeartbeat(state, {
455
+ stage: "ship",
456
+ summary: "Ship stage is active."
457
+ });
370
458
  let metadata;
371
459
  try {
372
460
  metadata = await adapters.ship.ship({ state, assessment });