@awak-app/simy-cli 0.5.29 → 0.5.30
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 +8 -0
- package/package.json +2 -2
- package/src/agent.js +115 -2
- package/src/cli-contract.js +1 -1
- package/src/codex-plugins/simy/skills/sqm-loop/SKILL.md +3 -1
- package/src/coding-run-store.js +69 -0
- package/src/local-task.js +2 -0
- package/src/orchestrator/audit.js +3 -0
- package/src/orchestrator/checklist-continuation.js +3 -3
- package/src/orchestrator/completion-contract.js +7 -0
- package/src/orchestrator/contract.js +6 -4
- package/src/orchestrator/delivery/WORKFLOW.md +93 -6
- package/src/orchestrator/delivery/references/acceptance-evidence.md +9 -5
- package/src/orchestrator/delivery/references/change-boundary-matrix.md +20 -1
- package/src/orchestrator/delivery/references/desktop-monitor-triggers.md +35 -0
- package/src/orchestrator/delivery/references/shared-system-specifications.md +3 -0
- package/src/orchestrator/delivery/references/state-and-receipts.md +19 -0
- package/src/orchestrator/execution-io.js +15 -0
- package/src/orchestrator/independent-audit.js +14 -1
- package/src/orchestrator/instruction.js +3 -0
- package/src/orchestrator/loop.js +71 -0
- package/src/orchestrator/outcome-monitor.js +123 -0
- package/src/runner.js +112 -16
- package/src/sqm/agent-skill.js +3 -2
- package/src/sqm/command.js +13 -0
- package/src/sqm/report.js +23 -0
- package/src/workflow-reporting.js +35 -0
- package/src/workflow-reporting.md +137 -0
package/README.md
CHANGED
|
@@ -342,6 +342,14 @@ SQM deliberately has two identity-bound stages:
|
|
|
342
342
|
state transitions, invariants, stress/strength expectations, and scenarios,
|
|
343
343
|
writes `proof.json`, and signs that proof with the local device identity.
|
|
344
344
|
|
|
345
|
+
The full-check summary reports applicable modules, evaluated rules, scenario
|
|
346
|
+
statuses and blocking/advisory scope. `passed` with `no_applicable_rules` or zero
|
|
347
|
+
scenario evaluations does not establish feature or historical incident coverage.
|
|
348
|
+
Scenario statuses come from deterministic rule evaluation, not browser/provider
|
|
349
|
+
execution. Keep concrete regression and delivery acceptance evidence separately.
|
|
350
|
+
If knowledge is unavailable, the command returns exit 2 with the service cause
|
|
351
|
+
and writes no new proof; any older artifact is not evidence for that attempt.
|
|
352
|
+
|
|
345
353
|
Normal runs do not require a separate sync command: the CLI
|
|
346
354
|
uses a verified local cache and revalidates it with TTL and ETag semantics.
|
|
347
355
|
The Agentic Loop runs min-check after each code modification and the full check
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@awak-app/simy-cli",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.30",
|
|
4
4
|
"description": "Local SIMY executor for non-coding Local Tasks and Agentic Loop runs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"check:auto-update": "node --check ./src/auto-update.js && node --check ./scripts/auto-update-e2e.js && npm run check:sqm",
|
|
41
41
|
"check:sqm": "node --check ./src/sqm/canonical.js && node --check ./src/sqm/validation.js && node --check ./src/sqm/reliability.js && node --check ./src/sqm/repository.js && node --check ./src/sqm/checkers.js && node --check ./src/sqm/bundle-store.js && node --check ./src/sqm/proof.js && node --check ./src/sqm/evidence-client.js && node --check ./src/sqm/session.js && node --check ./src/sqm/index.js && node --check ./src/sqm/command.js && node --check ./src/sqm/agent-skill.js && node --check ./src/sqm/workflow-onboarding.js && node --check ./src/sqm/workflow-update.js && node --check ./src/sqm/review-worker.js && node --check ./scripts/sqm-complete-loop-e2e.js && node --check ./scripts/sqm-local-review-e2e.js",
|
|
42
42
|
"check:real-provider-syntax": "node --check ./scripts/real-codex-probe.js && node --check ./scripts/real-claude-probe.js && node --check ./scripts/real-provider-console-fixture.js && node --check ./scripts/real-provider-console-e2e.js && node --check ./scripts/claude-parity-runtime-e2e.js && node --check ./scripts/claude-plugin-runtime-e2e.js",
|
|
43
|
-
"check:syntax": "node --check ./src/index.js && node --check ./src/install-update.js && node --check ./src/agent.js && node --check ./src/connection-discovery.js && node --check ./src/codex-plugins/simy/hooks/connection-reminder.mjs && node --check ./src/browser.js && node --check ./src/web-api.js && node --check ./src/durable-local-task-worker.js && node --check ./src/durable-local-task-steps-contract.js && node --check ./src/bounded-local-task-subtasks-contract.js && node --check ./src/bounded-local-task-subtask-pool.js && node --check ./src/local-task-artifact-contract.js && node --check ./src/execution-capability-contract.js && node --check ./src/shutdown.js && node --check ./src/run-registry.js && node --check ./src/direct-executor.js && node --check ./src/execution-guardrail.js && node --check ./src/backend-executable.js && node --check ./src/provider-stream.js && node --check ./src/console/index.js && node --check ./src/console/app.js && node --check ./src/console/commands.js && node --check ./src/local-attachments.js && node --check ./src/repository-inventory.js && node --check ./src/session-store.js && node --check ./src/web-origin.js && node --check ./src/workspace-context.js && node --check ./src/orchestrator/index.js && node --check ./src/orchestrator/shared.js && node --check ./src/orchestrator/recovery.js && node --check ./src/orchestrator/risk.js && node --check ./src/orchestrator/contract.js && node --check ./src/orchestrator/completion-contract.js && node --check ./src/orchestrator/pr-preparation.js && node --check ./src/orchestrator/minimum-completion.js && node --check ./src/orchestrator/delivery/scripts/check-minimum-completion.mjs && node --check ./src/orchestrator/instruction.js && node --check ./src/orchestrator/problem-solving.js && node --check ./src/orchestrator/budget.js && node --check ./src/orchestrator/execution-io.js && node --check ./src/orchestrator/presentation.js && node --check ./src/orchestrator/result.js && node --check ./src/orchestrator/retry.js && node --check ./src/orchestrator/evidence.js && node --check ./src/orchestrator/independent-audit.js && node --check ./src/orchestrator/audit.js && node --check ./src/orchestrator/loop.js && node --check ./src/runner.js && node --check ./scripts/fixtures/completion-contract-fixture.js && node --check ./scripts/fixtures/fake-coding-backend.js && node --check ./scripts/e2e-terminal-evidence.js && node --check ./scripts/audit-gate-e2e.js && node --check ./scripts/completion-contract-e2e.js && node --check ./scripts/retry-circuit-e2e.js && node --check ./scripts/follow-up-charter-e2e.js && node --check ./scripts/task-routing-e2e.js && node --check ./scripts/executor-version-preflight-e2e.js && node --check ./scripts/blocked-recovery-e2e.js && node --check ./scripts/process-localization-e2e.js && node --check ./scripts/hypothesis-retries-e2e.js && node --check ./scripts/budget-enforcement-e2e.js && node --check ./scripts/local-task-default-workspace-e2e.js && node --check ./scripts/local-task-idempotency-e2e.js && node --check ./scripts/console-e2e-fixture.js && node --check ./scripts/console-e2e.js && node --check ./scripts/console-recovery-e2e-fixture.js && node --check ./scripts/console-recovery-e2e.js && node --check ./scripts/real-provider-console-fixture.js && node --check ./scripts/real-provider-console-e2e.js && node --check ./scripts/fullstack-cli-smoke.js && node --check ./scripts/check-package-contents.js",
|
|
43
|
+
"check:syntax": "node --check ./src/index.js && node --check ./src/install-update.js && node --check ./src/agent.js && node --check ./src/connection-discovery.js && node --check ./src/codex-plugins/simy/hooks/connection-reminder.mjs && node --check ./src/browser.js && node --check ./src/web-api.js && node --check ./src/durable-local-task-worker.js && node --check ./src/durable-local-task-steps-contract.js && node --check ./src/bounded-local-task-subtasks-contract.js && node --check ./src/bounded-local-task-subtask-pool.js && node --check ./src/local-task-artifact-contract.js && node --check ./src/execution-capability-contract.js && node --check ./src/shutdown.js && node --check ./src/run-registry.js && node --check ./src/direct-executor.js && node --check ./src/execution-guardrail.js && node --check ./src/backend-executable.js && node --check ./src/provider-stream.js && node --check ./src/console/index.js && node --check ./src/console/app.js && node --check ./src/console/commands.js && node --check ./src/local-attachments.js && node --check ./src/repository-inventory.js && node --check ./src/session-store.js && node --check ./src/web-origin.js && node --check ./src/workspace-context.js && node --check ./src/orchestrator/index.js && node --check ./src/orchestrator/shared.js && node --check ./src/orchestrator/recovery.js && node --check ./src/orchestrator/risk.js && node --check ./src/orchestrator/contract.js && node --check ./src/orchestrator/completion-contract.js && node --check ./src/orchestrator/pr-preparation.js && node --check ./src/orchestrator/minimum-completion.js && node --check ./src/orchestrator/delivery/scripts/check-minimum-completion.mjs && node --check ./src/orchestrator/instruction.js && node --check ./src/orchestrator/problem-solving.js && node --check ./src/orchestrator/budget.js && node --check ./src/orchestrator/execution-io.js && node --check ./src/orchestrator/presentation.js && node --check ./src/orchestrator/result.js && node --check ./src/orchestrator/retry.js && node --check ./src/orchestrator/evidence.js && node --check ./src/orchestrator/independent-audit.js && node --check ./src/orchestrator/audit.js && node --check ./src/orchestrator/loop.js && node --check ./src/runner.js && node --check ./src/coding-run-store.js && node --check ./scripts/fixtures/completion-contract-fixture.js && node --check ./scripts/fixtures/fake-coding-backend.js && node --check ./scripts/e2e-terminal-evidence.js && node --check ./scripts/audit-gate-e2e.js && node --check ./scripts/completion-contract-e2e.js && node --check ./scripts/retry-circuit-e2e.js && node --check ./scripts/follow-up-charter-e2e.js && node --check ./scripts/task-routing-e2e.js && node --check ./scripts/executor-version-preflight-e2e.js && node --check ./scripts/blocked-recovery-e2e.js && node --check ./scripts/process-localization-e2e.js && node --check ./scripts/hypothesis-retries-e2e.js && node --check ./scripts/budget-enforcement-e2e.js && node --check ./scripts/local-task-default-workspace-e2e.js && node --check ./scripts/local-task-idempotency-e2e.js && node --check ./scripts/console-e2e-fixture.js && node --check ./scripts/console-e2e.js && node --check ./scripts/console-recovery-e2e-fixture.js && node --check ./scripts/console-recovery-e2e.js && node --check ./scripts/real-provider-console-fixture.js && node --check ./scripts/real-provider-console-e2e.js && node --check ./scripts/fullstack-cli-smoke.js && node --check ./scripts/check-package-contents.js",
|
|
44
44
|
"check:package": "node ./scripts/check-package-contents.js",
|
|
45
45
|
"build:macos-installer:dev": "bash packaging/build-macos-arm64.sh --unsigned-dev",
|
|
46
46
|
"build:macos-installer": "bash packaging/build-macos-arm64.sh --production",
|
package/src/agent.js
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
createRun,
|
|
11
11
|
increaseLocalCodingRunProviderTokenBudget,
|
|
12
12
|
LocalRunRegistry,
|
|
13
|
+
markCodingRunMonitorFailure,
|
|
13
14
|
isLocalRepositoryApprovalPending,
|
|
14
15
|
pauseLocalCodingRun,
|
|
15
16
|
queueLocalCodingGuidance,
|
|
@@ -19,10 +20,12 @@ import {
|
|
|
19
20
|
restoreRun,
|
|
20
21
|
resumeLocalCodingRun,
|
|
21
22
|
startLocalCodingRun,
|
|
23
|
+
syncLocalCodingRun,
|
|
22
24
|
stopLocalCodingRun,
|
|
23
25
|
toCompatibleCodingLoopState,
|
|
24
26
|
toLedgerSnapshot,
|
|
25
27
|
} from "./runner.js";
|
|
28
|
+
import { codingRunsRoot, loadCodingRunSnapshots, saveCodingRunSnapshot } from "./coding-run-store.js";
|
|
26
29
|
import {
|
|
27
30
|
expiresAtFromNow,
|
|
28
31
|
isSessionValid,
|
|
@@ -134,6 +137,7 @@ import {
|
|
|
134
137
|
} from "./connection-discovery.js";
|
|
135
138
|
|
|
136
139
|
const DEVICE_HEARTBEAT_INTERVAL_MS = 20_000;
|
|
140
|
+
const CODING_RUN_MONITOR_INTERVAL_MS = 5 * 60_000;
|
|
137
141
|
|
|
138
142
|
export async function startAgent({
|
|
139
143
|
requestedPort = 0,
|
|
@@ -148,6 +152,7 @@ export async function startAgent({
|
|
|
148
152
|
} = {}) {
|
|
149
153
|
const apiOrigin = resolveWebOrigin(webOrigin);
|
|
150
154
|
const registry = new LocalRunRegistry();
|
|
155
|
+
const codingRunStateRoot = codingRunsRoot(sessionRoot);
|
|
151
156
|
const directRegistry = new DirectTaskRegistry();
|
|
152
157
|
const localTaskRegistry = new LocalTaskRegistry();
|
|
153
158
|
const taskStorageRoot = localTasksRoot(
|
|
@@ -217,6 +222,8 @@ export async function startAgent({
|
|
|
217
222
|
let port = requestedPort;
|
|
218
223
|
let heartbeatTimer = null;
|
|
219
224
|
let heartbeatInFlight = null;
|
|
225
|
+
let codingRunMonitorTimer = null;
|
|
226
|
+
let codingRunMonitorInFlight = null;
|
|
220
227
|
let shuttingDown = false;
|
|
221
228
|
const notifyDesktopStatusChange = () => {
|
|
222
229
|
if (shuttingDown) return;
|
|
@@ -296,6 +303,14 @@ export async function startAgent({
|
|
|
296
303
|
return loginUrl.toString();
|
|
297
304
|
};
|
|
298
305
|
|
|
306
|
+
const publishOrSyncRestoredRun = async (run) => {
|
|
307
|
+
if (run.restoredFromState || run.restoredObjectiveUnverified) {
|
|
308
|
+
await publishRestoredLocalCodingRun(run);
|
|
309
|
+
} else {
|
|
310
|
+
syncLocalCodingRun(run);
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
|
|
299
314
|
const restoreRemoteRuns = async () => {
|
|
300
315
|
if (shuttingDown || !isSessionValid(session, Date.now(), apiOrigin) || !session?.device_id) return;
|
|
301
316
|
const snapshots = dependencies.listRemoteRuns
|
|
@@ -309,24 +324,113 @@ export async function startAgent({
|
|
|
309
324
|
apiBaseUrl: session.api_base_url,
|
|
310
325
|
token: session.token,
|
|
311
326
|
});
|
|
327
|
+
const remoteIds = new Set();
|
|
312
328
|
let restored = false;
|
|
313
329
|
for (const snapshot of snapshots) {
|
|
314
330
|
if (shuttingDown) return;
|
|
315
|
-
if (!snapshot?.id
|
|
331
|
+
if (!snapshot?.id) continue;
|
|
332
|
+
remoteIds.add(snapshot.id);
|
|
333
|
+
if (registry.has(snapshot.id)) {
|
|
334
|
+
const localRun = registry.get(snapshot.id);
|
|
335
|
+
localRun.session = session;
|
|
336
|
+
localRun.apiOrigin = apiOrigin;
|
|
337
|
+
const remoteTime = Date.parse(snapshot.updated_at || "") || 0;
|
|
338
|
+
const localTime = Date.parse(localRun.snapshot.updated_at || "") || 0;
|
|
339
|
+
if (remoteTime > localTime) {
|
|
340
|
+
const repository = findRepository(repositoryInventory, snapshot.charter?.repository);
|
|
341
|
+
const remoteRun = restoreRun({
|
|
342
|
+
snapshot, session, apiOrigin,
|
|
343
|
+
localPath: repository?.local_path || null,
|
|
344
|
+
localStateRoot: codingRunStateRoot,
|
|
345
|
+
});
|
|
346
|
+
Object.assign(localRun, {
|
|
347
|
+
request: remoteRun.request,
|
|
348
|
+
status: remoteRun.status,
|
|
349
|
+
snapshot: remoteRun.snapshot,
|
|
350
|
+
controlState: remoteRun.controlState,
|
|
351
|
+
completedAt: remoteRun.completedAt,
|
|
352
|
+
restoredFromState: remoteRun.restoredFromState,
|
|
353
|
+
restoredObjectiveUnverified: remoteRun.restoredObjectiveUnverified,
|
|
354
|
+
});
|
|
355
|
+
await saveCodingRunSnapshot(codingRunStateRoot, localRun.snapshot);
|
|
356
|
+
await publishRestoredLocalCodingRun(localRun);
|
|
357
|
+
} else {
|
|
358
|
+
await publishOrSyncRestoredRun(localRun);
|
|
359
|
+
}
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
316
362
|
const repository = findRepository(repositoryInventory, snapshot.charter?.repository);
|
|
317
363
|
const restoredRun = restoreRun({
|
|
318
364
|
snapshot,
|
|
319
365
|
session,
|
|
320
366
|
apiOrigin,
|
|
321
367
|
localPath: repository?.local_path || null,
|
|
368
|
+
localStateRoot: codingRunStateRoot,
|
|
322
369
|
});
|
|
323
370
|
registry.create(restoredRun);
|
|
324
371
|
restored = true;
|
|
325
372
|
await publishRestoredLocalCodingRun(restoredRun);
|
|
326
373
|
}
|
|
374
|
+
for (const localRun of registry.list()) {
|
|
375
|
+
if (!remoteIds.has(localRun.id)) await publishOrSyncRestoredRun(localRun);
|
|
376
|
+
}
|
|
327
377
|
if (restored) notifyDesktopStatusChange();
|
|
328
378
|
};
|
|
329
379
|
|
|
380
|
+
const restoreLocalCodingRuns = async () => {
|
|
381
|
+
const { snapshots, errors } = await loadCodingRunSnapshots(codingRunStateRoot);
|
|
382
|
+
for (const error of errors) {
|
|
383
|
+
reportStartupConnectionError(new Error(`Coding run ${error.id}: ${error.message}`), quiet);
|
|
384
|
+
}
|
|
385
|
+
for (const snapshot of snapshots) {
|
|
386
|
+
const boundDevice = snapshot?.metadata?.execution_device_id;
|
|
387
|
+
if (boundDevice && boundDevice !== session?.device_id) continue;
|
|
388
|
+
if (registry.has(snapshot.id)) {
|
|
389
|
+
const existing = registry.get(snapshot.id);
|
|
390
|
+
existing.session = session;
|
|
391
|
+
existing.apiOrigin = apiOrigin;
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
try {
|
|
395
|
+
const repository = findRepository(repositoryInventory, snapshot.charter?.repository);
|
|
396
|
+
const run = restoreRun({
|
|
397
|
+
snapshot, session, apiOrigin,
|
|
398
|
+
localPath: repository?.local_path || null,
|
|
399
|
+
localStateRoot: codingRunStateRoot,
|
|
400
|
+
});
|
|
401
|
+
// Keep the persisted timestamp until the Web ledger has been compared.
|
|
402
|
+
// Publishing recovery here would make an older local record look newest.
|
|
403
|
+
registry.create(run);
|
|
404
|
+
} catch (error) {
|
|
405
|
+
reportStartupConnectionError(error, quiet);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
const monitorCodingRuns = () => {
|
|
411
|
+
if (!daemon || !isSessionValid(session, Date.now(), apiOrigin)) return Promise.resolve();
|
|
412
|
+
if (codingRunMonitorInFlight) return codingRunMonitorInFlight;
|
|
413
|
+
codingRunMonitorInFlight = (async () => {
|
|
414
|
+
for (const run of registry.list()) {
|
|
415
|
+
if (!["pr_ready_for_review", "merge_ready"].includes(run.status) || run.operation || run.child) continue;
|
|
416
|
+
try {
|
|
417
|
+
await (dependencies.recheckCodingRun || recheckLocalCodingRun)(run);
|
|
418
|
+
} catch (error) {
|
|
419
|
+
await markCodingRunMonitorFailure(run, error);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
})().finally(() => { codingRunMonitorInFlight = null; });
|
|
423
|
+
return codingRunMonitorInFlight;
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
const startCodingRunMonitor = () => {
|
|
427
|
+
if (!daemon || codingRunMonitorTimer) return;
|
|
428
|
+
codingRunMonitorTimer = setInterval(() => {
|
|
429
|
+
void monitorCodingRuns().catch((error) => reportStartupConnectionError(error, quiet));
|
|
430
|
+
}, dependencies.codingRunMonitorIntervalMs || CODING_RUN_MONITOR_INTERVAL_MS);
|
|
431
|
+
codingRunMonitorTimer.unref();
|
|
432
|
+
};
|
|
433
|
+
|
|
330
434
|
const heartbeat = () => {
|
|
331
435
|
if (shuttingDown || !isSessionValid(session, Date.now(), apiOrigin)) return Promise.resolve(false);
|
|
332
436
|
if (heartbeatInFlight) return heartbeatInFlight;
|
|
@@ -406,7 +510,9 @@ export async function startAgent({
|
|
|
406
510
|
reportHeartbeatError(error, quiet);
|
|
407
511
|
}
|
|
408
512
|
try {
|
|
513
|
+
await restoreLocalCodingRuns();
|
|
409
514
|
await restoreRemoteRuns();
|
|
515
|
+
startCodingRunMonitor();
|
|
410
516
|
} catch (error) {
|
|
411
517
|
reportStartupConnectionError(error, quiet);
|
|
412
518
|
}
|
|
@@ -1389,8 +1495,10 @@ export async function startAgent({
|
|
|
1389
1495
|
},
|
|
1390
1496
|
session,
|
|
1391
1497
|
apiOrigin,
|
|
1498
|
+
localStateRoot: codingRunStateRoot,
|
|
1392
1499
|
});
|
|
1393
1500
|
try {
|
|
1501
|
+
await saveCodingRunSnapshot(codingRunStateRoot, run.snapshot);
|
|
1394
1502
|
registry.create(run);
|
|
1395
1503
|
} catch (error) {
|
|
1396
1504
|
await cleanupRunAttachments(stagedAttachments);
|
|
@@ -1678,8 +1786,10 @@ export async function startAgent({
|
|
|
1678
1786
|
await refreshAuthorizedRepositoryInventory();
|
|
1679
1787
|
if (shuttingDown) return;
|
|
1680
1788
|
await heartbeat();
|
|
1789
|
+
await restoreLocalCodingRuns();
|
|
1681
1790
|
if (shuttingDown) return;
|
|
1682
1791
|
await restoreRemoteRuns();
|
|
1792
|
+
startCodingRunMonitor();
|
|
1683
1793
|
} catch (error) {
|
|
1684
1794
|
reportStartupConnectionError(error, quiet);
|
|
1685
1795
|
}
|
|
@@ -1703,6 +1813,8 @@ export async function startAgent({
|
|
|
1703
1813
|
shuttingDown = true;
|
|
1704
1814
|
shutdownPromise = (async () => {
|
|
1705
1815
|
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
1816
|
+
if (codingRunMonitorTimer) clearInterval(codingRunMonitorTimer);
|
|
1817
|
+
if (codingRunMonitorInFlight) await codingRunMonitorInFlight;
|
|
1706
1818
|
updateManager?.stop?.();
|
|
1707
1819
|
await sqmLocalReviewWorker?.close?.();
|
|
1708
1820
|
await durableLocalTaskWorker?.close?.();
|
|
@@ -1824,7 +1936,8 @@ export async function startAgent({
|
|
|
1824
1936
|
});
|
|
1825
1937
|
const runId = String(remoteRun?.id || "");
|
|
1826
1938
|
if (!runId) throw new Error("SIMY Web did not return an Agentic Loop run id.");
|
|
1827
|
-
const run = createRun({ runId, request, session, apiOrigin });
|
|
1939
|
+
const run = createRun({ runId, request, session, apiOrigin, localStateRoot: codingRunStateRoot });
|
|
1940
|
+
await saveCodingRunSnapshot(codingRunStateRoot, run.snapshot);
|
|
1828
1941
|
registry.create(run);
|
|
1829
1942
|
void startLocalCodingRun(run, runOptions);
|
|
1830
1943
|
return run;
|
package/src/cli-contract.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
} from "./durable-local-task-steps-contract.js";
|
|
14
14
|
import { buildExecutionCapabilityContract } from "./execution-capability-contract.js";
|
|
15
15
|
|
|
16
|
-
export const CLI_VERSION = "0.5.
|
|
16
|
+
export const CLI_VERSION = "0.5.30";
|
|
17
17
|
export const CLI_API_CONTRACT_VERSION = 10;
|
|
18
18
|
|
|
19
19
|
export function withCliContract(
|
|
@@ -14,7 +14,9 @@ Treat the current Codex thread, its attachments, and the active repository as th
|
|
|
14
14
|
3. Run `simy sqm min-check` from the repository root.
|
|
15
15
|
4. Run `simy sqm check --proof proof.json --signed-evidence proof.json.signed.json`.
|
|
16
16
|
5. Read `proof.json` and require `outcome.status` to be `passed` before reporting success or proposing a pull request.
|
|
17
|
-
6.
|
|
17
|
+
6. Verify the proof's repository, base, HEAD and working-tree/diff identity against the candidate, and verify its bound signature with SQM tooling. Use separate artifact paths outside the diff; do not edit between min-check and check or reuse stale proof after a candidate change.
|
|
18
|
+
7. Report outcome reasons, matched modules, evaluated rules and scenario statuses from `executions`, separating blocking and advisory results. `passed` with `no_applicable_rules`, zero scenario evaluations, or advisory-only checks is not feature or incident coverage. Scenario statuses are deterministic evaluations, not evidence that a browser, provider or deployed journey ran. Record relevant uncovered review findings and their concrete regression evidence or remaining gap.
|
|
19
|
+
8. Report the checked repository/revision, proof paths, outcome, blockers, and any evidence gap. Keep delivery acceptance pending for unverified applicable paths even when SQM passes.
|
|
18
20
|
|
|
19
21
|
If implementation is required before the check can pass, obtain or confirm the user's change authorization and make the smallest relevant repair. A request to run SQM alone does not authorize unrelated edits, a PR, merge, deployment, or external messages.
|
|
20
22
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { mkdir, readFile, readdir, rename, writeFile } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
|
|
6
|
+
import { redactExecutionValue } from "./orchestrator/execution-io.js";
|
|
7
|
+
|
|
8
|
+
const RUN_ID = /^[A-Za-z0-9_-]{1,160}$/;
|
|
9
|
+
const writes = new Map();
|
|
10
|
+
|
|
11
|
+
export function codingRunsRoot(sessionRoot) {
|
|
12
|
+
return path.resolve(sessionRoot || path.join(homedir(), ".simy"), "coding-runs");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function saveCodingRunSnapshot(root, snapshot) {
|
|
16
|
+
const id = String(snapshot?.id || "");
|
|
17
|
+
if (!RUN_ID.test(id)) throw new Error("Invalid coding run ID for durable storage.");
|
|
18
|
+
// Capture at enqueue time: later mutations must not rewrite a queued version.
|
|
19
|
+
snapshot = redactExecutionValue(snapshot);
|
|
20
|
+
const directory = path.resolve(root);
|
|
21
|
+
const key = path.join(directory, id);
|
|
22
|
+
const previous = writes.get(key) || Promise.resolve();
|
|
23
|
+
const current = previous.catch(() => undefined).then(async () => {
|
|
24
|
+
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
25
|
+
const body = JSON.stringify(snapshot);
|
|
26
|
+
const document = JSON.stringify({
|
|
27
|
+
version: 1,
|
|
28
|
+
sha256: createHash("sha256").update(body).digest("hex"),
|
|
29
|
+
snapshot,
|
|
30
|
+
});
|
|
31
|
+
const target = `${key}.json`;
|
|
32
|
+
const temporary = `${target}.${process.pid}.${randomUUID()}.tmp`;
|
|
33
|
+
await writeFile(temporary, `${document}\n`, { mode: 0o600 });
|
|
34
|
+
await rename(temporary, target);
|
|
35
|
+
});
|
|
36
|
+
writes.set(key, current);
|
|
37
|
+
try { await current; } finally {
|
|
38
|
+
if (writes.get(key) === current) writes.delete(key);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function loadCodingRunSnapshots(root) {
|
|
43
|
+
let files;
|
|
44
|
+
try {
|
|
45
|
+
files = await readdir(root, { withFileTypes: true });
|
|
46
|
+
} catch (error) {
|
|
47
|
+
if (error?.code === "ENOENT") return { snapshots: [], errors: [] };
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
const snapshots = [];
|
|
51
|
+
const errors = [];
|
|
52
|
+
for (const file of files) {
|
|
53
|
+
if (!file.isFile() || !file.name.endsWith(".json")) continue;
|
|
54
|
+
const id = file.name.slice(0, -5);
|
|
55
|
+
if (!RUN_ID.test(id)) continue;
|
|
56
|
+
try {
|
|
57
|
+
const document = JSON.parse(await readFile(path.join(root, file.name), "utf8"));
|
|
58
|
+
const body = JSON.stringify(document.snapshot);
|
|
59
|
+
const hash = createHash("sha256").update(body).digest("hex");
|
|
60
|
+
if (document.version !== 1 || document.sha256 !== hash || document.snapshot?.id !== id) {
|
|
61
|
+
throw new Error("Coding run record failed integrity check.");
|
|
62
|
+
}
|
|
63
|
+
snapshots.push(document.snapshot);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
errors.push({ id, message: error instanceof Error ? error.message : String(error) });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return { snapshots, errors };
|
|
69
|
+
}
|
package/src/local-task.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { buildWorkflowReportingInstruction } from "./workflow-reporting.js";
|
|
1
2
|
import { execFile } from "node:child_process";
|
|
2
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
3
4
|
import { EventEmitter, once } from "node:events";
|
|
@@ -957,6 +958,7 @@ function localTaskProviderInstruction(task) {
|
|
|
957
958
|
: null;
|
|
958
959
|
return [
|
|
959
960
|
"You are the local executor for a SIMY Local Task, not an Agentic Loop.",
|
|
961
|
+
buildWorkflowReportingInstruction(),
|
|
960
962
|
"Complete this bounded task once. Do not create Git branches, commits, pull requests, audits, or automatic retries.",
|
|
961
963
|
`Permission mode: ${task.permission_mode}.`,
|
|
962
964
|
`Task workspace: ${task.workspace_path}`,
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from "./pr-preparation.js";
|
|
17
17
|
import {
|
|
18
18
|
completionEvidenceChecks,
|
|
19
|
+
hasUserOutcomeProof,
|
|
19
20
|
normalizeVisualReview,
|
|
20
21
|
} from "./completion-contract.js";
|
|
21
22
|
|
|
@@ -340,6 +341,8 @@ export function evaluatePrReadiness(charter, attempt) {
|
|
|
340
341
|
readinessCheck("minimum_independent_binding",
|
|
341
342
|
Boolean(independentAudit?.evidence_identity_sha256 && independentAudit.evidence_identity_sha256 === independentAuditEvidenceIdentity(attempt)),
|
|
342
343
|
"Independent review must cover the current head, base, CI, skips, preparation rows, companion revisions, and minimum evidence."),
|
|
344
|
+
readinessCheck("user_outcome_proven", hasUserOutcomeProof(independentAudit?.coverage_review),
|
|
345
|
+
"Independent review must observe the original user outcome and cite its evidence."),
|
|
343
346
|
readinessCheck("implementation_gate", attempt.audit?.passed === true, "Implementation gate must pass."),
|
|
344
347
|
readinessCheck("pr_preparation_gate", preparation.passed, preparation.detail),
|
|
345
348
|
readinessCheck(
|
|
@@ -8,12 +8,12 @@ export const ACCEPTANCE_EVIDENCE_PATH = fileURLToPath(
|
|
|
8
8
|
export function buildChecklistContinuationInstruction({ auditor = false } = {}) {
|
|
9
9
|
return section("checklist_continuation_contract", [
|
|
10
10
|
`The table is a progress checkpoint, not the deliverable or a stopping condition. Read: ${ACCEPTANCE_EVIDENCE_PATH}`,
|
|
11
|
-
"
|
|
12
|
-
"After
|
|
11
|
+
"Maintain the complete 依頼チェックリスト with columns #, ご依頼, 現状, 判定 in the evidence record after chartering, each evaluated attempt, and in the final receipt. User-facing reporting follows workflow_reporting_contract; show the full table only when requested or when it is the most useful requested answer, never as mandatory commentary. Preserve stable criterion IDs, all rows and both applicable evidence layers. ✅ requires current valid passing evidence for every applicable layer; ❌ means an observed failure; 🟡 means pending, missing, stale, blocked or unverifiable evidence. Retain counts and highest proven state in that record.",
|
|
12
|
+
"After observing any non-green row, classify its cause and immediately take the next safe authorized action: implement missing behavior, repair a failure, exercise an untested path, collect missing evidence, or rerun stale verification. Re-observe the same criterion against the current candidate, run the validator, update the table, and repeat until every applicable requested outcome and gate for the authorized endpoint is verified. A next-action list without performing feasible actions is not completion. Never require another continue request merely because a table was shown.",
|
|
13
13
|
"For CI or other in-progress dependencies, use the available bounded wait/recheck or approved monitoring mechanism and maintain progress communication. Unchanged external state is not itself a blocker. Do not start duplicate jobs or busy-poll. Recheck current revision/results, repair authorized failures, and keep waiting only within the existing time, attempt and cost limits. If waiting cannot continue, report the concrete limit and explicit resumption condition; do not silently abandon it or promise an unscheduled follow-up.",
|
|
14
14
|
"If a row genuinely requires new authority, credentials, a user/product decision, an unavailable dependency or an exhausted safety budget, retain it as non-green and record affected IDs, evidence of the blocker, safe alternatives attempted, exact missing input, owner and resumption trigger. Continue independent in-scope work. Stop with blocked, best_available, failed or cancelled as appropriate, explicitly unfinished, not verified_complete. Never raise budgets, bypass a stop, or expand authority to force green.",
|
|
15
15
|
"Do not end successfully while a safe authorized repair, verification or bounded wait remains. All-green applies to the frozen authorized endpoint: PR-only work does not authorize merge/deploy, but a PR URL, an improvement PR, an issue, a narrower test or a future plan does not satisfy an unmet outcome. Never drop/merge away rows, weaken criteria, relabel applicable checks as not_applicable, recolor unknowns, or copy new digests onto old evidence to force green. Do not change the requested endpoint to match the work already completed.",
|
|
16
|
-
"Before the final response, independently reconcile the original request with all criterion IDs and current evidence, check remaining endpoint gates, and
|
|
16
|
+
"Before the final response, independently reconcile the original request with all criterion IDs and current evidence, check remaining endpoint gates, and preserve the full table and explicit disposition in the evidence record. Distinguish a partial artifact from verified completion and disclose material remaining outcomes in the requested response format; keep yellow/red counts in the record. A pr_ready_for_review or blocked controller state is not proof of overall completion. These instructions strengthen continuation and reporting; they do not add a background scheduler or remove controller limits.",
|
|
17
17
|
auditor
|
|
18
18
|
? "Remain read-only. Check that the executor performed feasible follow-up actions after non-green tables. Report premature stopping, omitted rows, unsupported green claims, or a blocker without evidence as findings, alongside exact criterion IDs and the necessary next action. Do not approve from a table's colors or the executor's completion wording."
|
|
19
19
|
: "Execute the continuation within this attempt instead of merely returning a yellow table or delegating feasible remaining work to the requester. Return control honestly at a genuine boundary; never fabricate completion evidence.",
|
|
@@ -4,6 +4,13 @@ import { cleanString, stringArray } from "./shared.js";
|
|
|
4
4
|
export const COMPLETION_CONTRACT_VERSION = 2;
|
|
5
5
|
const criterionIdPattern = /^[A-Za-z][A-Za-z0-9]*(?:[-_.][A-Za-z0-9]+)*$/;
|
|
6
6
|
|
|
7
|
+
export function hasUserOutcomeProof(coverage) {
|
|
8
|
+
const proof = coverage?.user_outcome;
|
|
9
|
+
return proof?.passed === true && Boolean(cleanString(proof.verification_method)) &&
|
|
10
|
+
Boolean(cleanString(proof.observed_result)) && Array.isArray(proof.evidence_refs) &&
|
|
11
|
+
proof.evidence_refs.some((ref) => Boolean(cleanString(ref)));
|
|
12
|
+
}
|
|
13
|
+
|
|
7
14
|
export function buildCompletionContract({
|
|
8
15
|
inherited,
|
|
9
16
|
requirement,
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { budgetState, resolveRunBudgets } from "./budget.js";
|
|
11
11
|
import { classifyRisk } from "./risk.js";
|
|
12
12
|
import { buildCompletionContract } from "./completion-contract.js";
|
|
13
|
+
import { freezeObjective } from "./outcome-monitor.js";
|
|
13
14
|
import { defaultPrPreparationContract } from "./pr-preparation.js";
|
|
14
15
|
import {
|
|
15
16
|
DESKTOP_EXECUTION_TARGET,
|
|
@@ -56,11 +57,11 @@ export function createCodingLoopSnapshot({ runId, request, metadata = {} }) {
|
|
|
56
57
|
cleanString(charterContext.acceptance_criteria_source) === "explicit"
|
|
57
58
|
? "explicit"
|
|
58
59
|
: acceptanceCriteria.length > 0 &&
|
|
59
|
-
cleanString(charterContext.acceptance_criteria_source) === "
|
|
60
|
-
? "
|
|
60
|
+
cleanString(charterContext.acceptance_criteria_source) === "request"
|
|
61
|
+
? "request"
|
|
61
62
|
: acceptanceCriteria.length > 0
|
|
62
63
|
? "explicit"
|
|
63
|
-
: "
|
|
64
|
+
: "request";
|
|
64
65
|
const inheritedRequiredChecks = stringArray(charterContext.required_checks);
|
|
65
66
|
const inheritedNonGoals = stringArray(charterContext.non_goals);
|
|
66
67
|
const inheritedArtifacts = stringArray(charterContext.artifacts_required);
|
|
@@ -71,7 +72,7 @@ export function createCodingLoopSnapshot({ runId, request, metadata = {} }) {
|
|
|
71
72
|
acceptanceCriteria.length > 0
|
|
72
73
|
? acceptanceCriteria
|
|
73
74
|
: [
|
|
74
|
-
|
|
75
|
+
cleanString(request.requirement),
|
|
75
76
|
"Relevant tests pass and are recorded.",
|
|
76
77
|
`A pull request targets ${baseBranch}.`,
|
|
77
78
|
];
|
|
@@ -216,6 +217,7 @@ export function createCodingLoopSnapshot({ runId, request, metadata = {} }) {
|
|
|
216
217
|
updated_at: now,
|
|
217
218
|
};
|
|
218
219
|
snapshot.budget = budgetState(snapshot);
|
|
220
|
+
freezeObjective(snapshot.charter);
|
|
219
221
|
return snapshot;
|
|
220
222
|
}
|
|
221
223
|
|
|
@@ -30,6 +30,28 @@ deployment, exact-revision verification, and cleanup gates in this workflow. Do
|
|
|
30
30
|
push these development-only gates into every personal workflow merely because
|
|
31
31
|
they are required here.
|
|
32
32
|
|
|
33
|
+
## Report outcomes in the requested form
|
|
34
|
+
|
|
35
|
+
Apply the common [outcome reporting contract](../../workflow-reporting.md) to
|
|
36
|
+
executor progress, user-facing summaries and independent review. The runtime
|
|
37
|
+
injects the same instruction into Coding execution/audit and non-coding Local
|
|
38
|
+
Tasks; this is a model instruction, not a semantic output filter or a new gate.
|
|
39
|
+
Keep the outcome contract, execution evidence and response contract distinct.
|
|
40
|
+
Reporting-only corrections do not waive acceptance, change the goal or grant
|
|
41
|
+
new authority. Preserve requested questions/order/omissions on retry and resume.
|
|
42
|
+
Respond to the user's decisions and outcomes; keep routine diagnostics and
|
|
43
|
+
unchanged waits in the existing evidence record. Follow requested cadence and
|
|
44
|
+
host-required liveness updates without inventing progress.
|
|
45
|
+
|
|
46
|
+
## Confirm asynchronous handoffs and recover safely
|
|
47
|
+
|
|
48
|
+
Apply the common asynchronous handoff contract in [outcome reporting](../../workflow-reporting.md).
|
|
49
|
+
Submission accepted is not execution started. Keep the original operation identity,
|
|
50
|
+
resolve the canonical resource and verify the requested start/outcome boundary.
|
|
51
|
+
Missing list entries are inconclusive. Reconcile before resubmitting; use supported
|
|
52
|
+
idempotent recovery and bounded waits, and report an actual blocker when recovery
|
|
53
|
+
cannot proceed. A promise to investigate does not satisfy the recovery obligation.
|
|
54
|
+
|
|
33
55
|
## Confirm the delivery level in chat
|
|
34
56
|
|
|
35
57
|
Before material implementation, read [delivery levels](references/delivery-levels.md),
|
|
@@ -147,11 +169,12 @@ checklists held only in chat or the model's memory are insufficient.
|
|
|
147
169
|
Update the matrix and table after every evaluated test, repair, review, or scope,
|
|
148
170
|
revision, or environment change. Preserve prior snapshots/receipts and reset
|
|
149
171
|
invalidated rows to pending; never delete a failed criterion to make the table
|
|
150
|
-
green.
|
|
172
|
+
green. Record the new highest proven state and the remaining rows internally;
|
|
173
|
+
user-facing updates follow the response contract.
|
|
151
174
|
|
|
152
|
-
Use the compact request checklist as the
|
|
175
|
+
Use the compact request checklist as the evidence record's status surface.
|
|
153
176
|
After freezing the charter, after each evaluated attempt, and in the final
|
|
154
|
-
receipt,
|
|
177
|
+
evidence receipt, maintain a Markdown table headed `依頼チェックリスト` with
|
|
155
178
|
these columns: `#`, `ご依頼`, `現状`, `判定`. Render one numbered row per frozen
|
|
156
179
|
criterion, combining its user and system verification layers into one honest
|
|
157
180
|
status:
|
|
@@ -176,7 +199,10 @@ make the presentation green.
|
|
|
176
199
|
|
|
177
200
|
### Continue after the table; do not stop at yellow
|
|
178
201
|
|
|
179
|
-
The table is an intermediate checkpoint
|
|
202
|
+
The evidence table is an intermediate checkpoint, not mandatory chat output.
|
|
203
|
+
Show it when requested or when it best answers the request; a specified response
|
|
204
|
+
format takes precedence. Otherwise report the outcome and material gaps concisely.
|
|
205
|
+
Immediately classify each non-green row
|
|
180
206
|
and perform the next safe authorized action: implementation or repair for missing
|
|
181
207
|
or failed behavior, execution/evidence collection for untested paths, and fresh
|
|
182
208
|
verification for stale results. Re-observe the same criterion, run the validator,
|
|
@@ -201,8 +227,10 @@ non-green. All-green targets only the authorized endpoint, not unrequested merge
|
|
|
201
227
|
or deployment. Never weaken criteria or raise budgets to force green.
|
|
202
228
|
|
|
203
229
|
Before the final response, reconcile original requirements, all IDs, current
|
|
204
|
-
evidence and endpoint gates;
|
|
205
|
-
and disposition
|
|
230
|
+
evidence and endpoint gates; retain the full table, counts, highest proven state
|
|
231
|
+
and disposition in the evidence receipt. The user-facing answer follows the response
|
|
232
|
+
contract and discloses material unmet outcomes. Independent audit checks premature
|
|
233
|
+
stopping, answer relevance and hidden limitations as well as evidence.
|
|
206
234
|
|
|
207
235
|
For user-facing outcomes, require both goal-driven user interaction and technical
|
|
208
236
|
invariant checks against the same run and context. For saving, test save/reload/
|
|
@@ -395,6 +423,65 @@ from an earlier one. In particular:
|
|
|
395
423
|
|
|
396
424
|
## Run one controlled loop
|
|
397
425
|
|
|
426
|
+
The controller freezes the original user goal, outcome, minimum scope, proof
|
|
427
|
+
requirements, non-goals, finish line, and stable acceptance IDs in the persisted
|
|
428
|
+
charter. If explicit acceptance criteria are absent, the user's goal itself is
|
|
429
|
+
the first acceptance criterion; tests and PR creation cannot replace that
|
|
430
|
+
outcome. Direct human changes create a successor version with the old contract
|
|
431
|
+
preserved. An unrecorded edit blocks execution and PR recheck. An approved
|
|
432
|
+
revision invalidates the previous independent outcome assessment; do not reuse
|
|
433
|
+
old evidence to claim the revised goal was met.
|
|
434
|
+
Even when a caller supplies its own acceptance list, independent review must
|
|
435
|
+
separately prove the original user goal with an observed operation and
|
|
436
|
+
postcondition. A process-only acceptance list cannot waive that goal.
|
|
437
|
+
|
|
438
|
+
After each attempt the controller records which acceptance IDs were positively
|
|
439
|
+
supported by the independent auditor. If no independent review occurred, report
|
|
440
|
+
insufficient evidence. When a further reviewed attempt leaves the same user
|
|
441
|
+
outcomes unproven without adding any independently supported outcome, stop
|
|
442
|
+
automatic retries and require a revised approach against the approved objective.
|
|
443
|
+
Changed code, passing tests, and additional review comments do not themselves
|
|
444
|
+
count as outcome progress. Each state transition is written to a private local
|
|
445
|
+
run record before it is published; failed Web ledger updates are retried. On
|
|
446
|
+
restart, an unverifiable objective cannot retain completion status. An
|
|
447
|
+
authenticated SIMY CLI daemon rechecks PR-ready runs every five minutes,
|
|
448
|
+
including after the chat ends. It revokes a completion claim when current
|
|
449
|
+
verification is unavailable. Monitoring requires the daemon and host to remain
|
|
450
|
+
running; it does not monitor unrelated Codex Desktop tasks or execute repairs
|
|
451
|
+
without an authorized run.
|
|
452
|
+
|
|
453
|
+
For a Codex Desktop task whose requested outcome must be checked after the
|
|
454
|
+
conversation ends, register a Codex app heartbeat against that task before
|
|
455
|
+
claiming it is monitored. Preserve the original outcome, acceptance evidence,
|
|
456
|
+
the exact task or operation identity, the requested completion boundary, and
|
|
457
|
+
the response preferences, cadence, time/attempt/cost limits, and stop or
|
|
458
|
+
ask-user conditions in the heartbeat prompt. Verify that the automation
|
|
459
|
+
is active and bound to the intended task. On each run, use the Codex app's
|
|
460
|
+
supported task status and wait/read operations to distinguish a queued creation
|
|
461
|
+
ID, a resolved task ID, execution start, and the actual result. An absent list
|
|
462
|
+
entry or an idle label alone is not a terminal result. Reconcile the exact
|
|
463
|
+
operation before any retry; do not create a replacement while its fate is
|
|
464
|
+
unknown. Report an actionable blocker if identity, access, or evidence cannot
|
|
465
|
+
be resolved. Stay quiet on unchanged non-actionable state, and stop the
|
|
466
|
+
heartbeat when the accepted outcome is proved or monitoring is explicitly
|
|
467
|
+
cancelled. On authoritative failure, exhausted limits, or an unresolved
|
|
468
|
+
terminal identity/access blocker, report the evidence and pause or stop the
|
|
469
|
+
heartbeat pending a human decision. This is a separately registered,
|
|
470
|
+
task-scoped Codex app monitor;
|
|
471
|
+
the CLI daemon does not automatically register it or cover every Desktop task.
|
|
472
|
+
For a delegated implementation task, compare monitoring cadence with actual
|
|
473
|
+
execution. If its canonical task is idle and authorized acceptance work remains,
|
|
474
|
+
record a stall rather than a quiet unchanged status. With explicit recovery
|
|
475
|
+
authority and supported task tools, wake the same task once and verify its
|
|
476
|
+
execution starts; keep the outcome open
|
|
477
|
+
until independent acceptance evidence changes. A read-only monitor reports the
|
|
478
|
+
stall and owner instead. If a task is active but acceptance evidence has not
|
|
479
|
+
advanced over the agreed window, inspect its work and external waits before
|
|
480
|
+
calling it stalled. Never describe monitoring or an attempted wake as delivery.
|
|
481
|
+
Use the [Desktop task monitoring triggers](references/desktop-monitor-triggers.md)
|
|
482
|
+
when choosing an observation cadence, stall threshold, resume action, notification,
|
|
483
|
+
and duplicate-prevention rule for a Codex app heartbeat.
|
|
484
|
+
|
|
398
485
|
For each attempt:
|
|
399
486
|
|
|
400
487
|
1. **Observe:** load the current snapshot and revision-bound evidence.
|
|
@@ -110,11 +110,15 @@ Show green/yellow/red counts, the highest proven state, and validator status
|
|
|
110
110
|
immediately below the compact table. In a terminal receipt,
|
|
111
111
|
the controller also prints its disposition there.
|
|
112
112
|
|
|
113
|
-
The compact table is
|
|
114
|
-
frozen, after every evaluated attempt, and in the final receipt.
|
|
115
|
-
also retains the detailed layer table so evidence, methods, and
|
|
116
|
-
reviewable.
|
|
117
|
-
|
|
113
|
+
The compact table is maintained in the evidence record after the charter is
|
|
114
|
+
frozen, after every evaluated attempt, and in the final evidence receipt.
|
|
115
|
+
`checklist.md` also retains the detailed layer table so evidence, methods, and
|
|
116
|
+
repairs remain reviewable. User-facing reporting follows the common
|
|
117
|
+
[outcome reporting contract](../../../workflow-reporting.md). Show the table when
|
|
118
|
+
requested or when it best answers the request, not after every internal step.
|
|
119
|
+
An A/B-only or no-test-detail instruction takes precedence over the default table.
|
|
120
|
+
Keep every non-green row internally and disclose any material effect on the
|
|
121
|
+
requested answers or completion claim; brevity cannot hide incomplete delivery. Do not turn `pr_ci_green`, a healthy service,
|
|
118
122
|
or a passing narrow check into a green request row unless every applicable layer
|
|
119
123
|
for that criterion passed against the current charter and context.
|
|
120
124
|
|