@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 +23 -0
- package/package.json +2 -2
- package/src/cli-contract.js +1 -1
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/SKILL.md +58 -9
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/acceptance-evidence.md +3 -2
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/delivery-levels.md +5 -1
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/minimum-completion.md +137 -0
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/shared-system-specifications.md +138 -0
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/state-and-receipts.md +3 -0
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/scripts/check-acceptance.mjs +5 -3
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/scripts/check-minimum-completion.mjs +221 -0
- package/src/orchestrator/audit.js +17 -2
- package/src/orchestrator/completion-contract.js +1 -1
- package/src/orchestrator/evidence.js +9 -1
- package/src/orchestrator/independent-audit.js +13 -1
- package/src/orchestrator/instruction.js +13 -1
- package/src/orchestrator/loop.js +34 -4
- package/src/orchestrator/minimum-completion.js +108 -0
- package/src/orchestrator/result.js +7 -0
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.
|
|
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",
|
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.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.
|
|
11
|
-
|
|
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
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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
|
|
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.
|
|
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
|
|
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,
|
package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/acceptance-evidence.md
CHANGED
|
@@ -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
|
|
130
|
-
completion
|
|
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;
|
|
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.
|
package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/state-and-receipts.md
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
|
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";
|
package/src/codex-plugins/simy/skills/agentic-delivery-loop/scripts/check-minimum-completion.mjs
ADDED
|
@@ -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
|
-
:
|
|
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.",
|
package/src/orchestrator/loop.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
296
|
+
async function recheckPrReadinessOwned({ snapshot, collectEvidence, checkSqm = null, onUpdate }) {
|
|
280
297
|
const attempt = snapshot.attempts.at(-1);
|
|
281
|
-
|
|
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
|
|
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; } }
|