@awak-app/simy-cli 0.5.10 → 0.5.11

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
@@ -424,6 +424,19 @@ Deploy this CLI and the web capability proxy before enabling the backend scope
424
424
  requirement. Older clients receive an explicit upgrade error, never an expanded
425
425
  organization-wide bundle.
426
426
 
427
+ ### Minimum functional completion
428
+
429
+ Every CLI coding-loop promotion now requires a current two-layer observation
430
+ matrix: the requested operation and result, plus independently checked final
431
+ postcondition and integration. See the [minimum completion contract](src/codex-plugins/simy/skills/agentic-delivery-loop/references/minimum-completion.md)
432
+ for the executable format. Missing mappings, mismatching observations, changed
433
+ artifacts or stale revisions block promotion even when the executor reports
434
+ success. Independent review checks original-request coverage and the test oracle.
435
+
436
+ Existing v2 run history is retained; resumed/rechecked runs need the new evidence.
437
+ The same checker ships in the standalone Delivery Loop skill, but it does not
438
+ control the host's final response or establish deployment completion.
439
+
427
440
  ### Submit repaired local delivery evidence to SQM
428
441
 
429
442
  The bundled Delivery Loop maintains an external acceptance checklist with separate
@@ -444,3 +457,13 @@ session. `--dry-run` previews the exact document without uploading it. See the
444
457
  [local evidence contract](src/codex-plugins/simy/skills/agentic-delivery-loop/references/local-sqm-evidence.md).
445
458
  The receipt identifies the source digest and analysis job; it is not a declaration
446
459
  that an incident or blocking rule has been published.
460
+
461
+ ## Delivery Loop shared specification
462
+
463
+ The [Delivery Loop system specification](docs/systems/delivery-loop/README.md)
464
+ explains its purpose, As-Is and proposed To-Be through twelve linked views. Keep
465
+ these as shared team documents; each change updates affected views and checks
466
+ cross-view consistency. The skill requires independent design, implementation-to-
467
+ To-Be and PR reviews, plus explicitly opted-in SQM before and after PR creation.
468
+ The [workflow reference](src/codex-plugins/simy/skills/agentic-delivery-loop/references/shared-system-specifications.md)
469
+ explains baseline updates, historical regression coverage and evidence limits.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awak-app/simy-cli",
3
- "version": "0.5.10",
3
+ "version": "0.5.11",
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",
43
- "check:syntax": "node --check ./src/index.js && node --check ./src/install-update.js && node --check ./src/agent.js && 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/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/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/minimum-completion.js && node --check ./src/codex-plugins/simy/skills/agentic-delivery-loop/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",
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",
@@ -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.10";
16
+ export const CLI_VERSION = "0.5.11";
17
17
  export const CLI_API_CONTRACT_VERSION = 10;
18
18
 
19
19
  export function withCliContract(
@@ -7,8 +7,11 @@ description: Drive complex repository changes from a frozen success charter and
7
7
 
8
8
  Use one Codex task as the controller for the complete delivery lifecycle. Shell,
9
9
  browser, API, log, database, and artifact operations may all run in the same
10
- task. Treat implementer, user actor, evidence collector, and verifier as logical
11
- roles; they do not require separate agents.
10
+ task. The controller coordinates implementation and evidence collection. Every
11
+ review verdict must come from an independent agent/session that did not author
12
+ the reviewed implementation or specification; self-checks are useful diagnostics,
13
+ not review approval. Give reviewers original sources and raw evidence, not a
14
+ prescribed conclusion. The controller retains transition and authority ownership.
12
15
 
13
16
  ## Confirm the delivery level in chat
14
17
 
@@ -51,6 +54,31 @@ Do not silently weaken explicit conditions. Add discoveries as a charter patch.
51
54
  A scope or success-condition change needs user direction when it materially
52
55
  changes the requested result.
53
56
 
57
+ ## Maintain the system's shared specification
58
+
59
+ Before implementation, read [shared system specifications](references/shared-system-specifications.md).
60
+ Find the team's canonical specification for this system; create it once if absent.
61
+ Record purpose, beneficiary, current pain, intended user experience and observable
62
+ success. Reference the current As-Is revision and update only affected To-Be views.
63
+ Maintain the twelve-view inventory, stable IDs and cross-view impact links in the
64
+ shared source, not twelve new task-local copies. Unaffected views retain their
65
+ version; unknown As-Is facts remain unknown. Review changes through the team's
66
+ normal version control and preserve concurrent work.
67
+
68
+ Use independent agents for design review (including consistency across diagram
69
+ kinds), implementation-to-To-Be review, and final PR/evidence review at **every**
70
+ level. Reviewers inspect the full affected path and unchanged linked views. Fix
71
+ findings and obtain independent re-review. A changed requirement or baseline
72
+ invalidates affected approval; do not rewrite To-Be to disguise a failed result.
73
+
74
+ PR creation and post-creation verification include the SQM loop described in the
75
+ reference. Announce this requirement when starting Delivery Loop. Running SQM
76
+ still follows its explicit opt-in/authority rules; if opt-in or access is absent,
77
+ retain the unmet SQM gate and continue independent work. Ordinary PR work outside
78
+ Delivery Loop does not activate this workflow. Record known incident coverage and
79
+ unknown coverage separately; a green proof with no applicable rules does not prove
80
+ that historical failures cannot recur.
81
+
54
82
  ## Maintain the acceptance checklist outside the conversation
55
83
 
56
84
  Before implementation, read [acceptance evidence](references/acceptance-evidence.md)
@@ -77,6 +105,22 @@ gate and before issuing the completion receipt. A missing, pending, failed, stal
77
105
  or unverifiable applicable row prevents promotion. Matrix completeness is one
78
106
  necessary gate, not proof of deployment, authority, or overall completion.
79
107
 
108
+ ## Enforce the minimum functional floor
109
+
110
+ At every delivery level, use [minimum completion](references/minimum-completion.md)
111
+ for requested-outcome verification. Map all requirements to implementation and
112
+ actual operation/result plus independent postcondition/integration observations.
113
+ For persistence, require reload/session return and stored values/ownership. A
114
+ working control, success message or HTTP 200 alone is insufficient.
115
+
116
+ The bundled minimum checker extends the acceptance matrix with structured
117
+ observations. Compare the original request to the AC-N list independently so
118
+ omitted requirements cannot disappear before validation. A missing, failed or
119
+ stale floor check prevents verified completion at any level. The CLI now enforces
120
+ this before implementation/PR promotion and on recheck; the standalone command
121
+ validates evidence but cannot intercept the host application's final response.
122
+ Do not call a standalone result host-enforced completion or overall delivery.
123
+
80
124
  ## Check existing rules before implementation
81
125
 
82
126
  Before implementation, publish a compact rule inventory in the charter record.
@@ -221,13 +265,13 @@ Run focused regression tests first, then formatting, lint, type checking, unit
221
265
  tests, and the actual affected runtime. Apply only the relevant lanes from
222
266
  [the change-boundary matrix](references/change-boundary-matrix.md).
223
267
 
224
- For medium/high-risk work, run an independent blocker/P1 review after local
225
- verification. Fix findings narrowly and re-review only the fixes and directly
226
- affected behavior.
268
+ After local verification at every level, have an independent agent compare the
269
+ implementation and observed user outcomes to the frozen To-Be and original request.
270
+ Include cross-view consistency, omissions and applicable historical regressions.
271
+ Fix findings narrowly and independently re-review the affected behavior.
227
272
 
228
273
  Give the independent verifier the acceptance sources and raw evidence, not just
229
- the implementer's summary. Use a separate session/agent as required by risk and
230
- repository rules; another model can help but model count is not quality evidence.
274
+ the implementer's summary. Use a separate session/agent for every review; another model can help but model count is not quality evidence.
231
275
 
232
276
  Treat deleted tests, weakened assertions, changed expected values, disabled
233
277
  checks, and relaxed CI or security policy as changes to the verification
@@ -239,9 +283,12 @@ production configuration, and CI or security-policy changes.
239
283
 
240
284
  ### 4. Coordinate through Draft PR and integration state
241
285
 
286
+ Before creating a PR, pass the independent To-Be review and pre-PR SQM loop.
242
287
  After authority for the required remote changes exists, record reproduction,
243
288
  tests, evidence, companion revisions, skipped checks, and remaining gates in the
244
- Draft PR. Before Ready or merge, combine the latest base with required companion
289
+ Draft PR. After creation, run a fresh SQM loop bound to the actual PR head/base
290
+ and have an independent agent review the PR diff, proofs and incident coverage.
291
+ Before Ready or merge, combine the latest base with required companion
245
292
  and parallel changes, rerun the affected path, and confirm current CI and
246
293
  mergeability. Without combined-state proof, report `pr_only_verified`, not
247
294
  `integration_verified`.
@@ -295,7 +342,9 @@ and validation ordering still require Delivery Loop execution controls.
295
342
  ### 8. Clean up and issue the receipt
296
343
 
297
344
  Remove scoped fixtures and prove the residual count is zero. Deliver a compact
298
- completion receipt containing repository revisions, PR and CI, independent
345
+ completion receipt containing shared-spec baseline/To-Be revisions and status,
346
+ cross-view and implementation review results, pre/post-PR SQM proofs and historical
347
+ coverage gaps, repository revisions, PR and CI, independent
299
348
  review, container/runtime results, local Chrome evidence, merge and deployment
300
349
  identity, deployed Chrome evidence, artifacts, cleanup, skipped gates, and
301
350
  residual risk. Convert recurring findings into the smallest maintainable rule,
@@ -126,5 +126,6 @@ a collector told the truth, a criterion is adequate, or a system is deployed.
126
126
  Hashes are not signatures. The controller must protect the frozen digest, verify
127
127
  requirement coverage and genuine non-applicability, and inspect raw evidence.
128
128
  Independent review checks the oracle and findings; the validator is an additional
129
- gate within this skill, not a globally installed hook or the CLI orchestrator's
130
- completion authority.
129
+ gate within this skill, not a globally installed hook. The CLI now additionally
130
+ uses [minimum completion](minimum-completion.md) to enforce current functional
131
+ evidence at its promotion boundary; this basic validator alone is insufficient.
@@ -39,7 +39,7 @@ messages.
39
39
  | --- | --- | --- | --- |
40
40
  | 1 | Maximum assurance | Authentication, payments, destructive or irreversible changes, production security/configuration, sensitive data, and risky migrations | Exercise all affected and adjacent invariants, failure/recovery and rollback paths; require the broadest applicable independent review and repository gates. |
41
41
  | 2 | Protected | Persistence, permissions, shared contracts, external side effects, cross-repository changes, and medium-risk migrations | Verify both evidence layers for every affected outcome, shared boundaries, retry/idempotency and recovery; require independent review of the change and affected integrations. |
42
- | 3 | Balanced (default) | Normal features and bug fixes with bounded, reversible impact | Run focused regressions, applicable static checks, the real affected runtime and main user journey; use risk- and repository-required independent review. |
42
+ | 3 | Balanced (default) | Normal features and bug fixes with bounded, reversible impact | Run focused regressions, applicable static checks, the real affected runtime and main user journey; require independent design/To-Be/PR review, scoped to the affected path. |
43
43
  | 4 | Fast | Small, isolated, reversible UI or implementation changes | Run the direct regression and real affected path; add broader checks only for touched shared boundaries; keep mandatory review and evidence gates. |
44
44
  | 5 | Fastest | Copy, documentation, comments, metadata, or similarly trivial changes with no runtime/data/security effect | Verify the changed artifact, final diff, packaging/link integrity where applicable, and every repository-mandated check; do not claim untested runtime behavior. |
45
45
 
@@ -69,8 +69,12 @@ always choose a lower numbered, safer level.
69
69
  Every level preserves:
70
70
 
71
71
  - frozen success criteria and independent acceptance sources;
72
+ - shared system As-Is/To-Be, cross-view consistency and independent agent reviews;
73
+ - pre/post-PR SQM gates under explicit opt-in, with historical coverage reported;
72
74
  - honest state transitions and current revision/context binding;
73
75
  - required user/system evidence for applicable outcomes;
74
76
  - protection of user work, secrets, data integrity, and tenant boundaries;
75
77
  - explicit failure, pending, skipped, and non-applicable reporting;
76
78
  - repository-required tests, reviews, CI, and approval/authority boundaries.
79
+
80
+ All levels retain the [minimum functional floor](minimum-completion.md): requirement mapping, actual operation/result, and independent postcondition/integration observations. Persistence requires reload and stored-state checks. Non-runtime work verifies its real consumer/artifact; no imaginary DB or API checks are added. The minimum checker has no level-based bypass.
@@ -0,0 +1,137 @@
1
+ # Minimum functional completion
2
+
3
+ Every level must prove that the requested work exists, actual operations reach
4
+ the intended result, and necessary persistence/integration works. Speed changes
5
+ adjacent verification breadth, never this floor. The CLI requires this matrix for
6
+ all coding-loop attempts, including legacy v2 resumes/rechecks. No opt-out field
7
+ in an executor result or assurance-level selection disables the gate.
8
+
9
+ ## Collect real observations
10
+
11
+ Before implementation, reconcile the original request, acceptance criteria and
12
+ planned operations. Preserve every requested outcome; a missing requirement must
13
+ be added through the controller's charter process, not omitted from the matrix.
14
+ The independent auditor compares original-request coverage and checks the oracle
15
+ against raw evidence. Machine mapping checks cannot discover an omitted idea in
16
+ natural language or authenticate what an evidence collector observed.
17
+
18
+ For each AC-N record implementation_refs (repository-relative file paths), then:
19
+
20
+ - user/operation: operate the actual UI or CLI/consumer. Expected is true; actual
21
+ is whether the intended operation really executed, not just whether a click
22
+ command succeeded. Include screenshots/traces where relevant.
23
+ - user/result: observe the requested visible outcome, including reload and session
24
+ return for a saving feature. Compare expected and actual values.
25
+ - system/postcondition: independently inspect the final state; for persistence,
26
+ include the saved values and ownership, not a toast or HTTP status.
27
+ - system/integration: inspect the necessary combined path through APIs, storage,
28
+ workers or consumers. Job acceptance is not job completion. Use the same input
29
+ and execution context across layers; cite trace/runtime identities in subject
30
+ and additional evidence.
31
+
32
+ For document-only work these mean opening the actual consumer and checking content,
33
+ links and packaged bytes. No DB/API is required if none participates. Both generic
34
+ layers remain required; there is no post-failure waiver. Tests, permissions or
35
+ runtime unavailable means pending/blocked. Never fabricate expected/actual equality.
36
+
37
+ ## Executable contract
38
+
39
+ `check-minimum-completion.mjs` and `check-acceptance.mjs` ship together under the
40
+ installed skill's scripts directory. The CLI instruction supplies controller input
41
+ JSON; save it as charter.json for the standalone command. It contains id,
42
+ requirement, repository, acceptance_criteria, completion_contract (version 2), and
43
+ thread_state.original_request. For standalone use the controller freezes the same
44
+ fields independently of implementation. The matrix otherwise follows
45
+ [acceptance evidence](acceptance-evidence.md).
46
+
47
+ To derive the frozen specification/context, import `minimumCharter(charter)` and
48
+ `minimumContext(charter, fullHeadSha)` from the minimum script; import `sha256`
49
+ and `contextDigest` from check-acceptance.mjs. The charter digest is
50
+ `sha256(Buffer.from(JSON.stringify(minimumCharter(charter))))`.
51
+ The context digest is `contextDigest(minimumContext(charter, fullHeadSha))`.
52
+ The CLI derives both itself; it never takes expected digests from executor output.
53
+
54
+ The current CLI context is one local checkout, its full HEAD, controller charter
55
+ ID and request digest. A clean checkout is required and checked again after
56
+ collection. This is not automatic multi-repository deployment identity discovery.
57
+ For companion services, verify the combined path and record the pinned service
58
+ identities in the evidence; the independent reviewer must validate their current
59
+ identity. Do not claim that this single-checkout gate automatically re-reads a
60
+ companion service's Git HEAD or production environment.
61
+
62
+ Every matrix row adds `implementation_refs: ["src/example.js"]`. Each required
63
+ user/system cell's **first** evidence file is JSON with this shape (user example):
64
+
65
+ ```json
66
+ {
67
+ "criterion_id": "AC-1",
68
+ "context_sha256": "<current context digest>",
69
+ "checks": {
70
+ "operation": {"subject": "Save clicked and request observed for fixture run", "expected": true, "actual": true},
71
+ "result": {"subject": "Note after reload and session return", "expected": "requested text", "actual": "requested text"}
72
+ }
73
+ }
74
+ ```
75
+
76
+ The system file uses `postcondition` and `integration` instead. Each has `subject`,
77
+ non-null `expected` and actual observed `actual`. Values may be objects/arrays to
78
+ compare saved values and ownership together. The checker compares values exactly;
79
+ missing fields or mismatches fail regardless of a cell's passed flag. Additional
80
+ cell evidence may contain screenshots or logs; all artifact hashes are validated.
81
+ Keep raw evidence local and use synthetic data, never credentials/personal data.
82
+
83
+ Store matrix and evidence under ui_evidence_root, or under repository `.artifacts`
84
+ when no root was specified. All artifact paths are relative to the matrix directory.
85
+ Return `delivery_evidence_path` in SIMY_RESULT_JSON, absolute under that root or
86
+ relative to it. Source mappings must resolve to files inside the current repository.
87
+ Evidence must be bounded regular files; path escapes/symlinks are rejected.
88
+
89
+ Standalone invocation, with controller-owned trusted digests:
90
+
91
+ ```text
92
+ node <installed-skill>/scripts/check-minimum-completion.mjs charter.json matrix.json context.json <trusted-charter-sha256> <trusted-context-sha256>
93
+ ```
94
+
95
+ Exit 0 is evidence_complete; 1 is evidence_incomplete; 2 means invalid/unavailable
96
+ inputs. JSON includes a readable checklist and floor failures. Check the top-level
97
+ status, not only individual base-matrix rows. The standalone checker validates
98
+ mapping structure; only the CLI additionally resolves mappings in its checkout.
99
+ Neither file hashes nor a passed report authenticate the collector or prove an
100
+ oracle matches the original requirement. Independent coverage/oracle review is
101
+ required by the CLI and must inspect the raw evidence. The standalone command
102
+ cannot stop Codex/Claude's final chat response and does not install global hooks.
103
+
104
+ ## State, review and recovery
105
+
106
+ The CLI's implementation gate includes the minimum report before independent
107
+ review. The review returns coverage_review with requirements_complete,
108
+ unmapped_requirements and a concrete observation. The controller binds that
109
+ review to the matrix digest, then recollects evidence. Changing the matrix after
110
+ review requires a new review; changing HEAD or dirtying the tree invalidates the
111
+ proof. A concurrent call using the same run ID is rejected, including cloned snapshots.
112
+ A repeated start rechecks evidence without executing the implementation again;
113
+ explicit resume remains the repair path. Cross-process
114
+ execution remains subject to existing runner/host ownership controls.
115
+
116
+ PR recheck clears prior completion flags and reruns the floor. Missing evidence
117
+ never promotes an old successful audit. The old history is retained; do not rewrite
118
+ it as verified under the new floor. Fix the named criterion, collect fresh evidence
119
+ and resume within the retry budget. Reconcile ambiguous external side effects
120
+ before retrying. The minimum pass is a prerequisite for existing CI/review/authority
121
+ gates, not merge, deployment or a complete production delivery.
122
+
123
+ Rollback: restoring the older CLI removes this additional enforcement. Retain the
124
+ versioned evidence/history and report that limitation; never relabel old evidence
125
+ as verified by this floor. Monitor minimum-completion findings and subsequent
126
+ reviewer-discovered gaps through existing local run records; no new telemetry or
127
+ external provider calls are introduced.
128
+
129
+ ## Shared specifications and independent review
130
+
131
+ The floor's AC-N rows trace back to stable requirement IDs in the team's shared
132
+ As-Is/To-Be specification. Follow [shared system specifications](shared-system-specifications.md)
133
+ for purpose, user experience, cross-view consistency, independent reviews and
134
+ pre/post-PR SQM. These are controller workflow obligations, not fields magically
135
+ validated by the minimum checker. The CLI gate verifies minimum structured evidence;
136
+ it does not launch every design review or SQM phase on its own. Standalone hosts
137
+ remain responsible for executing this skill and cannot claim an enforced host hook.
@@ -0,0 +1,138 @@
1
+ # Shared system specifications and delivery review
2
+
3
+ Read before planning a Delivery Loop change. The specification belongs to the
4
+ system and its team, not to a single run. Use existing team paths and conventions;
5
+ if none exist, start `docs/systems/<system-id>/` with an index and the applicable
6
+ views below. Repository paths here are a convention, not a demand to move existing
7
+ documents or to create a new service. Keep one canonical source for each concept.
8
+
9
+ ## Shared baseline and proposed change
10
+
11
+ The system index records its owner/maintainers, repository/document links, stable
12
+ system ID, As-Is source revision(s) and environment, verified date, and gaps.
13
+ Distinguish source-code behavior, locally observed behavior, and deployed behavior.
14
+ An old design or green PR is not proof of current production behavior.
15
+
16
+ At the start of each run:
17
+
18
+ 1. Read the existing index and current linked views. Reconcile relevant As-Is with
19
+ code and actual behavior; label unknowns, cite evidence, and correct documented
20
+ drift without claiming that the drift was part of the requested feature.
21
+ 2. State why the change matters: beneficiary, current difficulty, what they can
22
+ do after the change, observable success, and non-goals. Preserve the user's
23
+ original request as an independent acceptance source.
24
+ 3. Prepare a proposed To-Be on a branch/change proposal linked from the shared
25
+ system index. Record its baseline revision, affected stable IDs, before/after
26
+ behavior, dependencies and acceptance oracles. Reuse unchanged views by reference;
27
+ do not copy the whole specification into every run or generate empty diagrams.
28
+ 4. Link the requirement to workflow, screen/control, state/sequence, API/event,
29
+ data/relationship, permission and runtime boundaries as applicable. Map these
30
+ stable system IDs to the run's AC-N rows and implementation/evidence locations.
31
+ 5. Obtain independent design review before implementation. Supply the original
32
+ request, shared baseline, To-Be and linked unchanged views. Missing evidence or
33
+ contradictory views remains pending/failed, never silently accepted.
34
+
35
+ The twelve-view index must account for every category: present (with a canonical
36
+ link), unchanged (with a revision), not applicable (with a reason), or unknown
37
+ (with an owner/next action). Only create/update a diagram where it describes a
38
+ real system concept. For CLI/skill systems, chat/terminal interactions can be the
39
+ interface views; do not invent application screens, APIs, tables or infrastructure.
40
+
41
+ | View | Primary content | Consistency checks against other views |
42
+ | --- | --- | --- |
43
+ | art-01-screen-inventory-final | Screens or user interaction surfaces and stable IDs | Every referenced screen/control in workflows, transitions and wireframes exists |
44
+ | art-02-screen-transitions | Navigation, entry/exit, failure/recovery | Reachable inventory entries, correct permission guards and state conditions |
45
+ | art-03-wireframes | Controls, content, empty/loading/error/success states | Each action has a requirement, transition and downstream sequence; no dead control |
46
+ | art-04-functional-requirements | Purpose, beneficiary, outcomes, invariants, acceptance | Every request maps to implementation and evidence through the other affected views |
47
+ | art-05-state-machines | Legal states, guards, terminal outcomes, retry/cancel | Sequences/events trigger legal transitions; UI messages match actual final state |
48
+ | art-06-permissions | Actor/role, action, resource, authority boundary | UI guards, API checks, ownership and execution roles agree |
49
+ | art-07-user-workflows | User goal, steps, completion and recovery experience | Requirements covered end to end through screens, APIs, persistence and runtime |
50
+ | art-08-data-dictionary | Fields, meaning, type, requiredness, lifecycle and owner | API/event payloads, ER cardinality and state invariants use the same definitions |
51
+ | art-09-sequences | Calls/events through components, errors, asynchronous completion | API names/payloads, states, authorization and deployed component boundaries agree |
52
+ | art-10-api-design | Existing APIs, commands or file contracts, errors and compatibility | Sequence inputs/outputs, data meanings and permission checks agree |
53
+ | art-11-er-diagram | Entities, relationships, ownership and cardinality | Dictionary and API reads/writes agree; label logical artifact models as non-DB |
54
+ | art-12-infrastructure | Repositories, execution environments, services and trust boundaries | Every sequence participant has an actual host/owner; revision/rollout dependencies align |
55
+
56
+ ## Review evidence and neutral agents
57
+
58
+ All reviews use independent agents/sessions, including design, cross-view
59
+ consistency, implementation-versus-To-Be, verification changes and PR review.
60
+ An agent must not approve work it authored. A reviewer can re-review fixes to its
61
+ findings if it did not implement the fixes. Supply raw sources, not desired answers;
62
+ require inspected references, discrepancies, uncertainty and a reasoned verdict.
63
+ Use the repository-required model (gpt-5.5 / xhigh where mandated and available).
64
+ If independent review is unavailable, report that gate as blocked.
65
+
66
+ Persist a compact review receipt: reviewer/session identity, review kind, original
67
+ request and shared baseline/To-Be references, candidate revisions, inspected views
68
+ and evidence, findings, result, and re-review links. An independent reviewer checks:
69
+
70
+ - coverage of the original request, user benefit and acceptance oracles;
71
+ - consistency for every affected cross-view link, including unchanged neighbors;
72
+ - behavior after actual operation, reload/session return and final persistence or
73
+ integration outcome where applicable;
74
+ - implementation and tests against the proposed To-Be, not just against each other;
75
+ - missing/extra functionality, stale evidence and unresolved historical regressions.
76
+
77
+ A diagram syntax/link checker helps, but cannot replace semantic cross-view review.
78
+ Do not declare neutral review merely by renaming the implementer's role.
79
+
80
+ ## SQM before and after PR creation
81
+
82
+ Use the installed SQM loop skill. Respect explicit SQM opt-in, existing session and
83
+ service authority. Explain unavailable gates; do not install global hooks, weaken
84
+ rules, force an upload or switch organizations to obtain a pass.
85
+
86
+ For each phase use fresh, separate local paths outside the diff (for example an
87
+ ignored `.artifacts/delivery/<run>/sqm/pre-pr/` or `post-pr/` directory):
88
+
89
+ ```sh
90
+ simy sqm min-check --base <actual-pr-base> --output <phase>/min.json
91
+ simy sqm check --base <actual-pr-base> --min-result <phase>/min.json --proof <phase>/proof.json --signed-evidence <phase>/proof.json.signed.json
92
+ ```
93
+
94
+ Use supported no-upload options when required by the authorized sharing scope.
95
+ Read the proof and verify its repository, head, base, working-tree/diff identity,
96
+ knowledge bundle version/digest and `outcome.status == passed`; verify the bound
97
+ signature using SQM tooling. Exit zero alone is insufficient. Do not edit or commit
98
+ between min-check and check. Pin the commit before the pre-PR check; writing proof
99
+ into the committed diff would invalidate its identity.
100
+
101
+ Before the pre-PR phase, inventory relevant known incidents from the team's shared
102
+ incident records, SQM knowledge and repository regression history. Record incident
103
+ or source ID, failure boundary, applicable/unaffected/unknown classification,
104
+ regression command and result, SQM rule match/coverage, and residual gaps. Link this
105
+ ledger from the shared specification so the next task can reuse and improve it.
106
+ Separate confirmed incidents from synthetic risk scenarios; never invent history.
107
+ A zero-match/no-applicable-rules proof does not establish historical coverage.
108
+ Use concrete regressions for relevant uncovered incidents and have an independent
109
+ reviewer assess coverage; keep missing incident history or untested boundaries
110
+ visible. No finite test promises absence of all future bugs.
111
+
112
+ Pre-PR: implementation-to-To-Be review and relevant regressions pass, then run SQM;
113
+ repair findings within the bounded loop, re-review changed work, and rerun against
114
+ the final candidate before creation. On unavailable/failed proof, withhold creation
115
+ and report the exact blocker while continuing independent authorized preparation.
116
+
117
+ Post-PR: fetch the actual PR head/base and check out/verify that combination, run
118
+ both SQM phases again into new paths, inspect proof and current CI, and obtain
119
+ independent PR/evidence review. The pre-PR proof cannot stand in for this run.
120
+ If it fails, retain the PR as draft/not-ready with unmet gates recorded, repair and
121
+ rerun affected independent reviews and SQM. A changed head/base/spec or relevant
122
+ bundle invalidates affected approvals and proofs; preserve old receipts as history.
123
+ Promote Ready only with current required gates, including applicable combined-state
124
+ verification. Merge and deployment still require their own authority and evidence.
125
+
126
+ ## Team maintenance after verification
127
+
128
+ Merge reviewed specification changes with the corresponding implementation through
129
+ the normal team review process. Record proposed, implemented locally, merged and
130
+ verified-in-environment status separately. Advance As-Is only for the revision and
131
+ environment actually verified; a merged To-Be is not automatically production As-Is.
132
+ Preserve the prior baseline and decisions in version history. If another change
133
+ updates a shared view, reconcile its semantics and re-review affected links even
134
+ when Git reports no textual conflict. Do not overwrite concurrent edits.
135
+
136
+ Each run stores pointers, deltas and evidence in its receipt, not another competing
137
+ master specification. Record unresolved drift with an owner, source and next action.
138
+ Never lower the intended outcome merely to make an implementation match a diagram.
@@ -135,6 +135,7 @@ For the full delivery mode:
135
135
  done =
136
136
  reproduction_verified
137
137
  && acceptance_evidence_complete
138
+ && minimum_functional_evidence_verified
138
139
  && locally_verified
139
140
  && pr_ci_green
140
141
  && integration_verified
@@ -155,3 +156,5 @@ with current context and the required user/system layers. After each evaluated
155
156
  action, refresh the JSON matrix and its readable table; append a receipt for the
156
157
  update. Keep the frozen charter distinct from mutable results. A charter patch
157
158
  supersedes the old digest only after the controller verifies its authority.
159
+
160
+ The CLI records minimum evidence in observed_evidence.minimum_completion, independently of executor status. The independent audit is bound to its matrix digest. Legacy v2 histories remain readable, but missing minimum evidence cannot be reused as passing evidence on resume/recheck. Missing or unsupported charters require a refresh; they do not disable verification.
@@ -60,7 +60,7 @@ function validateContext(context, runId) {
60
60
  }
61
61
  }
62
62
 
63
- async function checkArtifact(root, artifact) {
63
+ export async function readEvidenceArtifact(root, artifact) {
64
64
  requireValue(object(artifact) && text(artifact.path) && hashPattern.test(artifact.sha256), "Invalid artifact reference");
65
65
  // Explicit bundle-relative paths only; never fetch URLs or execute evidence.
66
66
  const segments = artifact.path.split("/");
@@ -77,7 +77,9 @@ async function checkArtifact(root, artifact) {
77
77
  try {
78
78
  const stat = await handle.stat();
79
79
  requireValue(stat.isFile() && stat.size > 0 && stat.size <= 16 * 1024 * 1024, "Artifact must be a nonempty regular file of at most 16 MiB");
80
- requireValue(sha256(await handle.readFile()) === artifact.sha256, "Artifact digest mismatch");
80
+ const bytes = await handle.readFile();
81
+ requireValue(sha256(bytes) === artifact.sha256, "Artifact digest mismatch");
82
+ return bytes;
81
83
  } finally {
82
84
  await handle.close();
83
85
  }
@@ -150,7 +152,7 @@ export async function checkAcceptance({ charterBytes, matrix, expectedCharterSha
150
152
  requireValue(text(cell.observed_at) && /^\d{4}-\d{2}-\d{2}T.*(?:Z|[+-]\d{2}:\d{2})$/.test(cell.observed_at) &&
151
153
  Number.isFinite(Date.parse(cell.observed_at)) && Date.parse(cell.observed_at) <= Date.now(), "Invalid or future observation timestamp");
152
154
  requireValue(Array.isArray(cell.evidence) && cell.evidence.length > 0, "Passed result needs evidence");
153
- for (const artifact of cell.evidence) await checkArtifact(root, artifact);
155
+ for (const artifact of cell.evidence) await readEvidenceArtifact(root, artifact);
154
156
  row.status = "passed";
155
157
  } catch {
156
158
  row.reason = "Invalid, missing, empty, unsafe, or changed evidence; check action, observation, timestamp and artifact hashes";
@@ -0,0 +1,221 @@
1
+ #!/usr/bin/env node
2
+ // Record/observation checks, not authentication of the collector or host completion.
3
+ import { lstat, readFile, realpath } from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { isDeepStrictEqual } from "node:util";
7
+ import {
8
+ checkAcceptance,
9
+ contextDigest,
10
+ readEvidenceArtifact,
11
+ sha256,
12
+ } from "./check-acceptance.mjs";
13
+
14
+ const text = (value) => typeof value === "string" && value.trim().length > 0;
15
+ const object = (value) =>
16
+ value !== null && typeof value === "object" && !Array.isArray(value);
17
+ export const MINIMUM_COMPLETION_VERSION = 1;
18
+
19
+ export function minimumCharter(charter) {
20
+ if (
21
+ charter?.completion_contract?.version !== 2 ||
22
+ !text(charter.id) ||
23
+ !text(charter.requirement) ||
24
+ !Array.isArray(charter.acceptance_criteria) ||
25
+ !charter.acceptance_criteria.length ||
26
+ !charter.acceptance_criteria.every(text)
27
+ ) {
28
+ throw new Error("Current completion charter required");
29
+ }
30
+ const source = {
31
+ original_request:
32
+ charter.thread_state?.original_request || charter.requirement,
33
+ requirement: charter.requirement,
34
+ minimum_scope:
35
+ charter.completion_contract.minimum_scope || charter.acceptance_criteria,
36
+ non_goals: charter.completion_contract.non_goals || [],
37
+ };
38
+ return {
39
+ schema_version: 1,
40
+ minimum_completion_version: MINIMUM_COMPLETION_VERSION,
41
+ run_id: charter.id,
42
+ source,
43
+ criteria: charter.acceptance_criteria.map((outcome, index) => ({
44
+ id: `AC-${index + 1}`,
45
+ outcome,
46
+ acceptance_source: `request:${contextDigest(source)}`,
47
+ layers: {
48
+ user: {
49
+ applicability: "required",
50
+ method:
51
+ "Exercise the actual operation and observe its result; reopen/reload when persistence is required.",
52
+ },
53
+ system: {
54
+ applicability: "required",
55
+ method:
56
+ "Independently inspect the final postcondition and necessary integration; persisted values and ownership when saving.",
57
+ },
58
+ },
59
+ })),
60
+ };
61
+ }
62
+
63
+ export function minimumContext(charter, headSha) {
64
+ const frozen = minimumCharter(charter);
65
+ return {
66
+ run_id: charter.id,
67
+ stage: "locally_verified",
68
+ environment: "local",
69
+ fixture_id: charter.id,
70
+ input_sha256: contextDigest(frozen.source),
71
+ source_revisions: { [charter.repository]: headSha },
72
+ };
73
+ }
74
+
75
+ export async function loadMinimumJson(file) {
76
+ const stat = await lstat(file);
77
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1024 * 1024)
78
+ throw new Error("Invalid minimum evidence input");
79
+ return JSON.parse(await readFile(file, "utf8"));
80
+ }
81
+
82
+ export async function checkMinimumCompletion({
83
+ charter,
84
+ matrix,
85
+ context,
86
+ evidenceRoot,
87
+ }) {
88
+ const frozen = minimumCharter(charter);
89
+ const charterBytes = Buffer.from(JSON.stringify(frozen));
90
+ const charterSha = sha256(charterBytes);
91
+ const contextSha = contextDigest(context);
92
+ const report = await checkAcceptance({
93
+ charterBytes,
94
+ matrix,
95
+ expectedCharterSha256: charterSha,
96
+ expectedContextSha256: contextSha,
97
+ evidenceRoot,
98
+ });
99
+ report.minimum_completion_version = MINIMUM_COMPLETION_VERSION;
100
+ report.charter_sha256 = charterSha;
101
+ report.context_sha256 = contextSha;
102
+ report.matrix_sha256 = contextDigest(matrix);
103
+ report.head_sha = context.source_revisions[charter.repository];
104
+ const fail = (id, reason) => report.errors.push(`${id}: ${reason}`);
105
+ for (const criterion of frozen.criteria) {
106
+ const row = matrix.results.find((result) => result.id === criterion.id);
107
+ if (
108
+ !Array.isArray(row?.implementation_refs) ||
109
+ !row.implementation_refs.length ||
110
+ !row.implementation_refs.every(
111
+ (ref) =>
112
+ text(ref) &&
113
+ !path.isAbsolute(ref) &&
114
+ !ref.includes("\\") &&
115
+ ref
116
+ .split("/")
117
+ .every(
118
+ (segment) =>
119
+ segment &&
120
+ segment !== ".." &&
121
+ segment !== "." &&
122
+ !segment.includes(":"),
123
+ ),
124
+ )
125
+ ) {
126
+ fail(
127
+ criterion.id,
128
+ "Missing or unsafe requirement-to-implementation mapping",
129
+ );
130
+ }
131
+ for (const [layer, names] of Object.entries({
132
+ user: ["operation", "result"],
133
+ system: ["postcondition", "integration"],
134
+ })) {
135
+ const cell = row?.layers?.[layer];
136
+ if (cell?.status !== "passed") continue;
137
+ try {
138
+ // The first artifact is a structured observation; further artifacts may be images/logs.
139
+ const observation = JSON.parse(
140
+ (
141
+ await readEvidenceArtifact(
142
+ await realpath(evidenceRoot),
143
+ cell.evidence[0],
144
+ )
145
+ ).toString(),
146
+ );
147
+ if (
148
+ observation.criterion_id !== criterion.id ||
149
+ observation.context_sha256 !== contextSha ||
150
+ !object(observation.checks)
151
+ )
152
+ throw new Error("Wrong observation context");
153
+ for (const name of names) {
154
+ const check = observation.checks[name];
155
+ if (
156
+ !object(check) ||
157
+ !text(check.subject) ||
158
+ check.expected === null ||
159
+ check.expected === undefined ||
160
+ (name === "operation" && check.expected !== true) ||
161
+ !isDeepStrictEqual(check.expected, check.actual)
162
+ ) {
163
+ fail(
164
+ `${criterion.id}/${layer}/${name}`,
165
+ "Missing observation or expected/actual mismatch",
166
+ );
167
+ }
168
+ }
169
+ } catch {
170
+ fail(
171
+ `${criterion.id}/${layer}`,
172
+ "Missing, altered or invalid structured observation",
173
+ );
174
+ }
175
+ }
176
+ }
177
+ report.status = report.errors.length
178
+ ? "evidence_incomplete"
179
+ : "evidence_complete";
180
+ // Additional floor failures must be visible in the human-readable record too.
181
+ report.markdown += `\nMinimum completion: ${report.status}\n${report.errors.map((error) => `- ${error}`).join("\n")}\n`;
182
+ return report;
183
+ }
184
+
185
+ const entry = process.argv[1]
186
+ ? await realpath(process.argv[1]).catch(() => null)
187
+ : null;
188
+ if (entry === fileURLToPath(import.meta.url)) {
189
+ try {
190
+ const [
191
+ charterPath,
192
+ matrixPath,
193
+ contextPath,
194
+ expectedCharter,
195
+ expectedContext,
196
+ ...extra
197
+ ] = process.argv.slice(2);
198
+ if (!expectedContext || extra.length) throw new Error("Invalid arguments");
199
+ const charter = await loadMinimumJson(charterPath);
200
+ const context = await loadMinimumJson(contextPath);
201
+ if (
202
+ sha256(Buffer.from(JSON.stringify(minimumCharter(charter)))) !==
203
+ expectedCharter ||
204
+ contextDigest(context) !== expectedContext
205
+ )
206
+ throw new Error("Trusted digest mismatch");
207
+ const report = await checkMinimumCompletion({
208
+ charter,
209
+ context,
210
+ matrix: await loadMinimumJson(matrixPath),
211
+ evidenceRoot: path.dirname(path.resolve(matrixPath)),
212
+ });
213
+ process.stdout.write(JSON.stringify(report, null, 2) + "\n");
214
+ process.exitCode = report.status === "evidence_complete" ? 0 : 1;
215
+ } catch {
216
+ process.stderr.write(
217
+ "Minimum completion unavailable. Supply charter.json matrix.json context.json trusted-charter-sha256 trusted-context-sha256.\n",
218
+ );
219
+ process.exitCode = 2;
220
+ }
221
+ }
@@ -1,3 +1,4 @@
1
+ import { minimumCompletionCheck } from "./minimum-completion.js";
1
2
  import { open, readdir, stat } from "node:fs/promises";
2
3
  import path from "node:path";
3
4
 
@@ -131,7 +132,7 @@ export async function auditAttempt(charter, attempt, { previousAttempt = null, s
131
132
  }
132
133
  attempt.retry_problem_solving = retryProblemSolving;
133
134
 
134
- for (const check of completionEvidenceChecks(charter, attempt)) {
135
+ for (const check of [...completionEvidenceChecks(charter, attempt), minimumCompletionCheck(charter, attempt)]) {
135
136
  addCheck(
136
137
  check.id,
137
138
  check.label,
@@ -143,6 +144,13 @@ export async function auditAttempt(charter, attempt, { previousAttempt = null, s
143
144
  );
144
145
  }
145
146
 
147
+ if (attempt.independent_audit) {
148
+ addCheck("minimum_review_current", "Independent review covers the current evidence",
149
+ Boolean(attempt.independent_audit.minimum_matrix_sha256 &&
150
+ attempt.independent_audit.minimum_matrix_sha256 === attempt.observed_evidence?.minimum_completion?.matrix_sha256),
151
+ "Changed minimum evidence requires a fresh independent review.");
152
+ }
153
+
146
154
  const evidenceRequired = charter.expected_evidence.includes("ui_evidence_path");
147
155
  const evidenceArtifact = await inspectEvidence(charter, attempt.ui_evidence_path);
148
156
  if (evidenceRequired || attempt.ui_evidence_path) {
@@ -305,7 +313,12 @@ export function evaluatePrReadiness(charter, attempt) {
305
313
  const github = attempt.observed_evidence?.github || {};
306
314
  const local = attempt.observed_evidence?.local || {};
307
315
  const independentAudit = attempt.independent_audit;
316
+ const minimum = minimumCompletionCheck(charter, attempt);
308
317
  const checks = [
318
+ readinessCheck(minimum.id, minimum.passed, minimum.detail),
319
+ readinessCheck("minimum_independent_binding",
320
+ Boolean(independentAudit?.minimum_matrix_sha256 && independentAudit.minimum_matrix_sha256 === attempt.observed_evidence?.minimum_completion?.matrix_sha256),
321
+ "Independent review must cover the current minimum evidence matrix."),
309
322
  readinessCheck("implementation_gate", attempt.audit?.passed === true, "Implementation gate must pass."),
310
323
  readinessCheck(
311
324
  "independent_ai_audit",
@@ -372,7 +385,9 @@ export function evaluatePrReadiness(charter, attempt) {
372
385
  state: ready ? "merge_ready" : "pr_ready_for_review",
373
386
  summary: ready
374
387
  ? "PR has independently verified evidence, passing checks, and required approval."
375
- : "Implementation is complete, but the PR is not merge-ready.",
388
+ : attempt.audit?.passed && minimum.passed
389
+ ? "Implementation is verified, but the PR is not merge-ready."
390
+ : "Implementation verification is incomplete; resolve the pending evidence before promotion.",
376
391
  checks,
377
392
  pending_reasons: checks.filter((check) => !check.passed).map((check) => check.detail),
378
393
  };
@@ -76,7 +76,7 @@ export function normalizeVisualReview(value) {
76
76
 
77
77
  export function completionEvidenceChecks(charter, attempt) {
78
78
  const contract = record(charter?.completion_contract);
79
- if (contract.version !== COMPLETION_CONTRACT_VERSION) return [];
79
+ if (contract.version !== COMPLETION_CONTRACT_VERSION) return [check("completion_contract_version", "Supported completion contract required", false, "Missing or unsupported completion contract; re-charter and verify before promotion.")];
80
80
 
81
81
  const uncertainty = normalizeUncertaintyVerification(attempt?.uncertainty_verification);
82
82
  const rows = acceptanceCriterionRows(charter);
@@ -1,3 +1,4 @@
1
+ import { collectMinimumCompletion } from "./minimum-completion.js";
1
2
  import { execFile } from "node:child_process";
2
3
  import { promisify } from "node:util";
3
4
 
@@ -25,9 +26,16 @@ export async function collectPrEvidence({
25
26
  runCommand,
26
27
  });
27
28
  const github = await collectGitHubEvidence({ charter, attempt, repositoryPath, runCommand });
29
+ const minimumCompletion = await collectMinimumCompletion({ charter, attempt, repositoryPath, local });
30
+ const latest = await collectLocalGitEvidence({ baseBranch: charter.base_branch, repositoryPath, runCommand });
31
+ if (!latest.available || latest.head_sha !== local.head_sha || !latest.working_tree_clean) {
32
+ minimumCompletion.status = "evidence_incomplete";
33
+ minimumCompletion.errors = ["Checkout changed while collecting minimum evidence; verify again."];
34
+ }
28
35
  return {
36
+ minimum_completion: minimumCompletion,
29
37
  collected_at: new Date().toISOString(),
30
- local,
38
+ local: latest,
31
39
  github,
32
40
  };
33
41
  }
@@ -26,6 +26,7 @@ export function buildIndependentAuditInstruction(charter, attempt) {
26
26
  "audit_target",
27
27
  [
28
28
  `Requirement: ${charter.requirement}`,
29
+ `Original request: ${charter.thread_state?.original_request || charter.requirement}`,
29
30
  `Acceptance criteria:\n${bullets(charter.acceptance_criteria)}`,
30
31
  `User-visible outcome: ${charter.completion_contract?.user_outcome || charter.requirement}`,
31
32
  `Minimum scope:\n${bullets(charter.completion_contract?.minimum_scope || charter.acceptance_criteria)}`,
@@ -43,6 +44,8 @@ export function buildIndependentAuditInstruction(charter, attempt) {
43
44
  `Reported tests:\n${bullets(attempt.tests_run || [])}`,
44
45
  `Executor uncertainty verification: ${JSON.stringify(attempt.uncertainty_verification || {})}`,
45
46
  `Executor criterion evidence: ${JSON.stringify(attempt.criterion_evidence || [])}`,
47
+ `Minimum evidence matrix: ${attempt.observed_evidence?.minimum_completion?.evidence_path || "missing"}`,
48
+ `Minimum evidence digest: ${attempt.observed_evidence?.minimum_completion?.matrix_sha256 || "missing"}`,
46
49
  `Executor visual review: ${JSON.stringify(attempt.visual_review || {})}`,
47
50
  `Observed local branch: ${localEvidence.branch_name || "unknown"}`,
48
51
  `Observed local HEAD: ${localEvidence.head_sha || "unknown"}`,
@@ -59,6 +62,7 @@ export function buildIndependentAuditInstruction(charter, attempt) {
59
62
  "Inspect the final diff and related code directly from the repository.",
60
63
  "Look for unmet acceptance criteria, regressions, security issues, data and concurrency risks, missing tests, and unrelated changes.",
61
64
  "Treat executor claims as untrusted until supported by repository evidence.",
65
+ "Compare the original request to the complete AC-N list and implementation mapping. Report forgotten features, dead controls, unsaved results and broken integration. Open the raw minimum evidence, verify its oracle and actual runtime observations; matching expected/actual JSON and hashes alone do not prove truth. Check reload/session return and persisted values/ownership when saving is required.",
62
66
  "For every AC-N criterion, return a criterion_results entry only after directly checking its cited proof and observed outcome.",
63
67
  charter.evidence_policy?.browser_required
64
68
  ? "Open and inspect the actual local screenshots or videos. Return visual_review.inspected=true only after checking their visible content against the acceptance criteria."
@@ -70,7 +74,8 @@ export function buildIndependentAuditInstruction(charter, attempt) {
70
74
  "result_contract",
71
75
  [
72
76
  "Finish with exactly one line beginning SIMY_AUDIT_JSON: followed by one JSON object.",
73
- "Required keys: passed, summary, findings, criterion_results, visual_review.",
77
+ "Required keys: passed, summary, findings, criterion_results, visual_review, coverage_review.",
78
+ "coverage_review must contain requirements_complete (boolean), unmapped_requirements (array), and observation explaining the comparison of the original request, AC-N list, implementation and raw user/system proof. Use false and list gaps when anything is missing or unverified.",
74
79
  "Each finding candidate must contain passed, code, severity, target, explanation, and repairability.",
75
80
  "criterion_results must contain one entry per AC-N with criterion_id, passed, verification_method, evidence_refs, and observed_result.",
76
81
  "visual_review must contain inspected, artifacts, and acceptance_observations.",
@@ -195,12 +200,19 @@ export function buildIndependentAudit(execution, charter = null, attempt = null)
195
200
  auto_fix_hint: null,
196
201
  });
197
202
  }
203
+ const coverage = result.coverage_review;
204
+ if (attempt && !(coverage?.requirements_complete === true &&
205
+ Array.isArray(coverage.unmapped_requirements) && coverage.unmapped_requirements.length === 0 && cleanString(coverage.observation))) {
206
+ findings.push({ passed: false, code: "MINIMUM_REQUIREMENT_COVERAGE_UNPROVEN", severity: "blocker",
207
+ target: "coverage_review", explanation: "Original request coverage and raw minimum evidence were not independently verified.", repairability: "auto" });
208
+ }
198
209
  const requiresHuman = findings.some((item) => item.repairability === "manual");
199
210
  return {
200
211
  passed: result.passed === true && findings.length === 0,
201
212
  summary: cleanString(result.summary) || "Independent audit completed.",
202
213
  findings,
203
214
  criterion_results: criterionResults,
215
+ coverage_review: coverage || null,
204
216
  visual_review: visualReview,
205
217
  requires_human: requiresHuman,
206
218
  };
@@ -1,3 +1,4 @@
1
+ import { minimumCharter } from "../codex-plugins/simy/skills/agentic-delivery-loop/scripts/check-minimum-completion.mjs";
1
2
  import { bullets, looksLikeUiTask, section } from "./shared.js";
2
3
  import { problemSolvingResultContract } from "./problem-solving.js";
3
4
  import { acceptanceCriterionRows } from "./completion-contract.js";
@@ -50,6 +51,17 @@ export function buildCodingInstruction(
50
51
  ),
51
52
  ),
52
53
  ),
54
+ section("minimum_completion_evidence", [
55
+ "All delivery levels require this floor. Before implementation reconcile every original requirement with the AC-N list; report omissions instead of silently dropping them.",
56
+ "Save a matrix.json under the local evidence root (ui_evidence_root or repository .artifacts). Return delivery_evidence_path in SIMY_RESULT_JSON. A passed flag or tests_run string is not proof.",
57
+ "Use check-minimum-completion.mjs from the installed Delivery Loop skill. Its reference minimum-completion.md defines the matrix and structured observation format.",
58
+ "For each AC-N include real implementation_refs and required user/system evidence. Exercise the actual operation and result, then inspect postcondition and integration independently. For saving, reload/return in a new session and verify stored values and ownership. Document-only work uses the real command/consumer and artifact integrity, not imaginary API/DB checks.",
59
+ "First evidence artifact per layer must be JSON: {criterion_id, context_sha256, checks}. User checks: operation (expected=true, actual=observed boolean) and result; system checks: postcondition and integration. Each check includes subject, expected and actual. Derive expected values from the original requirement, not from the candidate output. Include screenshots/logs as additional evidence.",
60
+ "Freeze and bind observations to the current committed revision and charter before verification. Do not rehash old observations to make changed code pass. Use pending/failed for unavailable or mismatching evidence.",
61
+ `Controller input JSON: ${JSON.stringify({ id: charter.id, requirement: charter.requirement, repository: charter.repository, acceptance_criteria: charter.acceptance_criteria, completion_contract: charter.completion_contract, thread_state: { original_request: charter.thread_state.original_request } })}`,
62
+ `Controller-owned acceptance specification: ${JSON.stringify(minimumCharter(charter))}`,
63
+ `Context: run_id=${charter.id}, stage=locally_verified, environment=local, fixture_id=${charter.id}; input_sha256 is contextDigest(spec.source); source_revisions maps ${charter.repository} to current full HEAD.`,
64
+ ].join("\n")),
53
65
  section("expected_tests", bullets(charter.expected_tests)),
54
66
  section("must_not", bullets(charter.must_not)),
55
67
  ];
@@ -130,7 +142,7 @@ export function buildCodingInstruction(
130
142
  "result_contract",
131
143
  [
132
144
  "Finish with exactly one line beginning SIMY_RESULT_JSON: followed by one JSON object.",
133
- "Required keys: outcome_kind, summary, branch_name, commit_sha, commit_message_headline, pr_url, pr_number, pr_title, pr_base_branch, tests_run, tests_passed, ui_evidence_path, unrelated_changes_detected, secret_scan_passed, changed_files, residual_risks, problem_solving, uncertainty_verification, criterion_evidence, visual_review.",
145
+ "Required keys: outcome_kind, summary, branch_name, commit_sha, commit_message_headline, pr_url, pr_number, pr_title, pr_base_branch, tests_run, tests_passed, ui_evidence_path, unrelated_changes_detected, secret_scan_passed, changed_files, residual_risks, problem_solving, uncertainty_verification, criterion_evidence, visual_review, delivery_evidence_path.",
134
146
  problemSolvingResultContract(),
135
147
  "uncertainty_verification must contain top_uncertainty, first_verification, evidence_checked, observed_result, resolved, and fallback. Only set resolved=true when concrete observed evidence resolves it.",
136
148
  "criterion_evidence must contain one entry for every AC-N with criterion_id, passed, verification_method, evidence_refs, and observed_result. Only set passed=true when the evidence directly proves that criterion.",
@@ -1,3 +1,4 @@
1
+ import { minimumCharter } from "../codex-plugins/simy/skills/agentic-delivery-loop/scripts/check-minimum-completion.mjs";
1
2
  import { auditAttempt, evaluatePrReadiness } from "./audit.js";
2
3
  import {
3
4
  buildIndependentAudit,
@@ -9,7 +10,7 @@ import { buildAttempt, mergeTokenUsage } from "./result.js";
9
10
  import { evaluateRetryCircuit } from "./retry.js";
10
11
  import { appendEvent, publish } from "./shared.js";
11
12
 
12
- export async function runCodingLoop({
13
+ async function runCodingLoopOwned({
13
14
  snapshot,
14
15
  executeAttempt,
15
16
  executeIndependentAudit,
@@ -21,6 +22,19 @@ export async function runCodingLoop({
21
22
  shouldStop = () => false,
22
23
  consumeHumanGuidance = () => "",
23
24
  }) {
25
+ if (!resume && snapshot.attempts.length > 0) {
26
+ return recheckPrReadinessOwned({ snapshot, collectEvidence, checkSqm, onUpdate });
27
+ }
28
+ snapshot.implementation_gate_passed = false;
29
+ snapshot.done_gate_passed = false;
30
+ try { minimumCharter(snapshot.charter); } catch {
31
+ snapshot.final_audit = humanGate("Completion charter requires refresh before verification.", [{
32
+ code: "MINIMUM_CHARTER_REQUIRED", severity: "blocker", target: "completion_contract",
33
+ explanation: "Missing or unsupported completion charter. Preserve history, re-charter and collect current minimum evidence.", repairability: "manual",
34
+ }]);
35
+ await publish(snapshot, "waiting_human", onUpdate);
36
+ return snapshot;
37
+ }
24
38
  if (!resume || snapshot.attempts.length === 0) {
25
39
  appendEvent(snapshot, "risk_classifying", "PR risk classification completed.", {
26
40
  risk: snapshot.charter.risk,
@@ -197,6 +211,7 @@ export async function runCodingLoop({
197
211
  await publish(snapshot, "independent_auditing", onUpdate);
198
212
  if (shouldStop()) return stopCodingLoop(snapshot, onUpdate);
199
213
  const auditInstruction = buildIndependentAuditInstruction(snapshot.charter, attempt);
214
+ const reviewedMatrix = attempt.observed_evidence?.minimum_completion?.matrix_sha256;
200
215
  const auditExecution = await safeExecution(() =>
201
216
  executeIndependentAudit({
202
217
  attemptNumber,
@@ -215,6 +230,8 @@ export async function runCodingLoop({
215
230
  attempt.token_usage = mergeTokenUsage(attempt.token_usage, auditExecution.tokenUsage);
216
231
  attempt.budget = refreshBudgetState(snapshot);
217
232
 
233
+ attempt.independent_audit.minimum_matrix_sha256 = reviewedMatrix;
234
+
218
235
  // Re-collect after the read-only auditor to catch any mutated HEAD or working tree.
219
236
  attempt.observed_evidence = await safeEvidence(collectEvidence, attempt);
220
237
  attempt.sqm = await safeSqm(checkSqm, attempt, attempt.sqm);
@@ -276,9 +293,11 @@ async function stopCodingLoop(snapshot, onUpdate) {
276
293
  return snapshot;
277
294
  }
278
295
 
279
- export async function recheckPrReadiness({ snapshot, collectEvidence, checkSqm = null, onUpdate }) {
296
+ async function recheckPrReadinessOwned({ snapshot, collectEvidence, checkSqm = null, onUpdate }) {
280
297
  const attempt = snapshot.attempts.at(-1);
281
- if (!attempt || !attempt.audit?.passed || !attempt.independent_audit?.passed) return snapshot;
298
+ snapshot.implementation_gate_passed = false;
299
+ snapshot.done_gate_passed = false;
300
+ if (!attempt) return snapshot;
282
301
  appendEvent(snapshot, "checking_pr", "Refreshing GitHub review and CI evidence.", {
283
302
  attempt_number: attempt.attempt_number,
284
303
  });
@@ -296,7 +315,7 @@ export async function recheckPrReadiness({ snapshot, collectEvidence, checkSqm =
296
315
  snapshot.final_audit = aggregateAudit(
297
316
  attempt,
298
317
  attempt.pr_readiness.ready,
299
- attempt.independent_audit.findings || [],
318
+ attempt.independent_audit?.findings || [],
300
319
  );
301
320
  appendEvent(snapshot, attempt.pr_readiness.state, attempt.pr_readiness.summary, {
302
321
  pr_url: attempt.pr_url,
@@ -583,3 +602,14 @@ function humanGate(summary, findings) {
583
602
  release_gate: null,
584
603
  };
585
604
  }
605
+
606
+ const activeControllers = new Set();
607
+ async function withController(options, action) {
608
+ const owner = options.snapshot?.id;
609
+ if (typeof owner !== "string" || !owner) throw new Error("Delivery snapshot ID required");
610
+ if (activeControllers.has(owner)) throw new Error("Delivery controller is already active for this snapshot");
611
+ activeControllers.add(owner);
612
+ try { return await action(options); } finally { activeControllers.delete(owner); }
613
+ }
614
+ export const runCodingLoop = options => withController(options, runCodingLoopOwned);
615
+ export const recheckPrReadiness = options => withController(options, recheckPrReadinessOwned);
@@ -0,0 +1,108 @@
1
+ import path from "node:path";
2
+ import { lstat, realpath } from "node:fs/promises";
3
+ import {
4
+ minimumCharter,
5
+ minimumContext,
6
+ checkMinimumCompletion,
7
+ loadMinimumJson,
8
+ } from "../codex-plugins/simy/skills/agentic-delivery-loop/scripts/check-minimum-completion.mjs";
9
+ import {
10
+ contextDigest,
11
+ sha256,
12
+ } from "../codex-plugins/simy/skills/agentic-delivery-loop/scripts/check-acceptance.mjs";
13
+
14
+ export function minimumCharterDigest(charter) {
15
+ return sha256(Buffer.from(JSON.stringify(minimumCharter(charter))));
16
+ }
17
+
18
+ export async function collectMinimumCompletion({
19
+ charter,
20
+ attempt,
21
+ repositoryPath,
22
+ local,
23
+ }) {
24
+ try {
25
+ if (!local.available || !local.working_tree_clean)
26
+ throw new Error("Clean current checkout required");
27
+ const root = await realpath(
28
+ charter.ui_evidence_root || path.join(repositoryPath, ".artifacts"),
29
+ );
30
+ const requested = attempt.raw_output?.delivery_evidence_path;
31
+ if (typeof requested !== "string") throw new Error("Matrix path missing");
32
+ const file = path.resolve(root, requested);
33
+ const relative = path.relative(root, file);
34
+ if (!relative || relative.startsWith("..") || path.isAbsolute(relative))
35
+ throw new Error("Outside evidence root");
36
+ let current = root;
37
+ for (const segment of relative.split(path.sep)) {
38
+ current = path.join(current, segment);
39
+ if ((await lstat(current)).isSymbolicLink())
40
+ throw new Error("Symlink evidence path");
41
+ }
42
+ const matrix = await loadMinimumJson(file);
43
+ const report = await checkMinimumCompletion({
44
+ charter,
45
+ matrix,
46
+ context: minimumContext(charter, local.head_sha),
47
+ evidenceRoot: path.dirname(file),
48
+ });
49
+ if (report.status !== "evidence_complete") return report;
50
+ // Check mapping paths without reading source contents or following links outside the checkout.
51
+ const repo = await realpath(repositoryPath);
52
+ for (const row of matrix.results) {
53
+ for (const ref of row.implementation_refs || []) {
54
+ if (typeof ref !== "string") continue;
55
+ const target = await realpath(path.resolve(repo, ref));
56
+ const rel = path.relative(repo, target);
57
+ if (
58
+ rel.startsWith("..") ||
59
+ path.isAbsolute(rel) ||
60
+ !(await lstat(target)).isFile()
61
+ )
62
+ throw new Error("Invalid implementation mapping");
63
+ }
64
+ }
65
+ if (contextDigest(await loadMinimumJson(file)) !== report.matrix_sha256)
66
+ throw new Error("Matrix changed during verification");
67
+ return { ...report, evidence_path: file };
68
+ } catch {
69
+ return {
70
+ status: "evidence_incomplete",
71
+ errors: [
72
+ "Minimum completion evidence missing, invalid or stale; verify the actual operation, result, postcondition and integration for every AC-N.",
73
+ ],
74
+ };
75
+ }
76
+ }
77
+
78
+ export function minimumCompletionCheck(charter, attempt) {
79
+ const report = attempt.observed_evidence?.minimum_completion;
80
+ const head = attempt.observed_evidence?.local?.head_sha;
81
+ let passed = false;
82
+ try {
83
+ passed =
84
+ report?.minimum_completion_version === 1 &&
85
+ report.status === "evidence_complete" &&
86
+ report.errors?.length === 0 &&
87
+ report.charter_sha256 === minimumCharterDigest(charter) &&
88
+ report.context_sha256 === contextDigest(minimumContext(charter, head)) &&
89
+ /^[a-f0-9]{64}$/.test(report.matrix_sha256) &&
90
+ report.head_sha === head &&
91
+ attempt.observed_evidence.local.working_tree_clean === true;
92
+ } catch {
93
+ /* Unsupported/missing charters never waive this gate. */
94
+ }
95
+ return {
96
+ id: "minimum_completion",
97
+ label: "Every requested outcome has current operation and system evidence",
98
+ passed: Boolean(passed),
99
+ detail: passed
100
+ ? "Current minimum evidence verified; independent coverage/oracle review and remaining gates still apply."
101
+ : (
102
+ report?.errors || [
103
+ "Minimum completion evidence has not been verified.",
104
+ ]
105
+ ).join("; "),
106
+ evidence_refs: report?.evidence_path ? [report.evidence_path] : [],
107
+ };
108
+ }
@@ -1,3 +1,6 @@
1
+ import { minimumCharterDigest } from "./minimum-completion.js";
2
+ import { minimumContext } from "../codex-plugins/simy/skills/agentic-delivery-loop/scripts/check-minimum-completion.mjs";
3
+ import { contextDigest } from "../codex-plugins/simy/skills/agentic-delivery-loop/scripts/check-acceptance.mjs";
1
4
  import { cleanString, stringArray } from "./shared.js";
2
5
  import { normalizeProblemSolving } from "./problem-solving.js";
3
6
  import {
@@ -15,6 +18,8 @@ export function buildAttempt({ attemptNumber, charter, instruction, promptInterv
15
18
  const completed = execution.exitCode === 0 && !execution.error;
16
19
  const now = new Date().toISOString();
17
20
  return {
21
+ minimum_charter_sha256: safeDigest(() => minimumCharterDigest(charter)),
22
+ minimum_context_sha256: safeDigest(() => contextDigest(minimumContext(charter, cleanString(result.commit_sha)))),
18
23
  attempt_number: attemptNumber,
19
24
  backend: charter.backend,
20
25
  base_branch: charter.base_branch,
@@ -112,3 +117,5 @@ function buildArtifactPreviews(result) {
112
117
  function isUsageRecord(value) {
113
118
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
114
119
  }
120
+
121
+ function safeDigest(compute) { try { return compute(); } catch { return null; } }