@awak-app/simy-cli 0.5.11 → 0.5.13
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/package.json +1 -1
- package/src/cli-contract.js +1 -1
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/SKILL.md +78 -25
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/acceptance-evidence.md +37 -1
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/delivery-levels.md +21 -7
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/minimum-completion.md +16 -7
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/shared-system-specifications.md +50 -28
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/state-and-receipts.md +14 -2
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/scripts/check-acceptance.mjs +23 -5
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/scripts/check-minimum-completion.mjs +56 -2
- package/src/codex-plugins/simy/skills/agentic-delivery-loop/scripts/production-contract.mjs +158 -0
- package/src/orchestrator/completion-contract.js +54 -4
- package/src/orchestrator/contract.js +12 -1
- package/src/orchestrator/independent-audit.js +9 -5
- package/src/orchestrator/instruction.js +12 -3
- package/src/orchestrator/minimum-completion.js +1 -1
package/package.json
CHANGED
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.13";
|
|
17
17
|
export const CLI_API_CONTRACT_VERSION = 10;
|
|
18
18
|
|
|
19
19
|
export function withCliContract(
|
|
@@ -33,15 +33,31 @@ external-message authority and never weakens repository-required gates.
|
|
|
33
33
|
|
|
34
34
|
## Freeze the delivery charter
|
|
35
35
|
|
|
36
|
+
Start with the beneficiary's experience, not the proposed solution. Read-only
|
|
37
|
+
discovery may supply facts, but before solution design or coding freeze a compact
|
|
38
|
+
experience contract: who is in what situation, what they are trying to achieve,
|
|
39
|
+
the complete usable outcome, what they should understand and do next at each
|
|
40
|
+
observable moment, recovery and forbidden experiences, and how each moment will
|
|
41
|
+
be observed. Give each moment a stable UX/acceptance ID and carry those same IDs
|
|
42
|
+
through the shared To-Be, implementation mapping, and results matrix. Do not use
|
|
43
|
+
a list of components, endpoints, screens, or tasks as a substitute for the
|
|
44
|
+
end-to-end experience.
|
|
45
|
+
|
|
36
46
|
Before material action, record:
|
|
37
47
|
|
|
38
|
-
- objective and user-visible
|
|
48
|
+
- objective, beneficiary, and the frozen experience contract with user-visible
|
|
49
|
+
success conditions;
|
|
39
50
|
- authoritative acceptance sources that are independent of the candidate
|
|
40
51
|
implementation, plus architecture boundaries and dependency direction;
|
|
41
52
|
- repositories, latest base branches, dedicated worktrees, environments, and
|
|
42
53
|
the exact user journey;
|
|
43
54
|
- required evidence, applicable change boundaries, risk tier, and the few
|
|
44
55
|
critical invariants that must block integration;
|
|
56
|
+
- for every production-relevant experience ID, outcome and guardrail measures
|
|
57
|
+
with signal, independent source, observation window, threshold, decision and
|
|
58
|
+
owner; if no production outcome is in scope, record that once with a reason;
|
|
59
|
+
- when release is in scope, staged exposure and deterministic promote, hold,
|
|
60
|
+
abort and rollback criteria, rollback mechanism, kill switch and owner;
|
|
45
61
|
- requested and effective delivery levels, the risk-based safety ceiling, and
|
|
46
62
|
the chat confirmation receipt;
|
|
47
63
|
- exclusions and authority boundaries, especially commit, push, Draft PR
|
|
@@ -58,32 +74,38 @@ changes the requested result.
|
|
|
58
74
|
|
|
59
75
|
Before implementation, read [shared system specifications](references/shared-system-specifications.md).
|
|
60
76
|
Find the team's canonical specification for this system; create it once if absent.
|
|
61
|
-
|
|
62
|
-
|
|
77
|
+
Reconcile the frozen experience contract with the current As-Is, then update only
|
|
78
|
+
the affected To-Be views. Preserve the purpose, beneficiary, current pain,
|
|
79
|
+
intended user experience, observable success, and stable UX/acceptance IDs.
|
|
63
80
|
Maintain the twelve-view inventory, stable IDs and cross-view impact links in the
|
|
64
81
|
shared source, not twelve new task-local copies. Unaffected views retain their
|
|
65
82
|
version; unknown As-Is facts remain unknown. Review changes through the team's
|
|
66
83
|
normal version control and preserve concurrent work.
|
|
67
84
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
85
|
+
Freeze and follow the risk-proportionate review plan from the selected delivery
|
|
86
|
+
level. Level 3 may consolidate design, implementation-to-To-Be, affected-view and
|
|
87
|
+
final evidence review into one independent final-candidate review. Inspect changed
|
|
88
|
+
views and their dependency links; retain unrelated views by exact revision. Fix
|
|
89
|
+
findings and independently re-review the affected behavior. A changed bound input
|
|
72
90
|
invalidates affected approval; do not rewrite To-Be to disguise a failed result.
|
|
73
91
|
|
|
74
|
-
|
|
75
|
-
reference. Announce
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
that historical failures cannot recur.
|
|
92
|
+
When SQM is explicitly opted in, apply the identity-aware SQM plan described in
|
|
93
|
+
the reference. Announce its applicability when starting Delivery Loop. Reuse a
|
|
94
|
+
verifiable proof only for exactly unchanged bound inputs; rerun for changed identity
|
|
95
|
+
or newly applicable PR-only checks. If required access is absent, retain the unmet
|
|
96
|
+
gate and continue independent work. Ordinary PR work outside Delivery Loop does
|
|
97
|
+
not activate SQM. Record known and unknown incident coverage separately; zero
|
|
98
|
+
applicable rules do not prove that historical failures cannot recur.
|
|
81
99
|
|
|
82
100
|
## Maintain the acceptance checklist outside the conversation
|
|
83
101
|
|
|
84
102
|
Before implementation, read [acceptance evidence](references/acceptance-evidence.md)
|
|
85
103
|
and persist a criterion-by-criterion checklist. Bind the criteria and both
|
|
86
104
|
verification layers to independent acceptance sources in a frozen charter.
|
|
105
|
+
Use the experience contract as the user-facing slice of these same criteria, not
|
|
106
|
+
as a parallel checklist. Every observable moment from the real trigger through a
|
|
107
|
+
usable outcome and applicable recovery path must map to at least one criterion;
|
|
108
|
+
working components do not prove that the combined experience is complete.
|
|
87
109
|
Use a separate current-results matrix for observations, status, evidence,
|
|
88
110
|
unmet reasons, and next actions. Render a readable table alongside the JSON;
|
|
89
111
|
checklists held only in chat or the model's memory are insufficient.
|
|
@@ -100,6 +122,15 @@ values, ownership, authorization, and duplication. HTTP 500/network failures are
|
|
|
100
122
|
failure evidence; absence of a 500 or presence of a 200 does not prove persistence.
|
|
101
123
|
Record justified non-applicability before execution, not after a failed test.
|
|
102
124
|
|
|
125
|
+
After building the exact candidate in the production-like local environment,
|
|
126
|
+
execute the complete experience and regenerate the readable table. It must let a
|
|
127
|
+
reviewer compare, for every stable ID, the persona/context and expected visible
|
|
128
|
+
outcome, the actual user observation, the independent technical postcondition or
|
|
129
|
+
integration result, evidence, status, and the next repair. Inspect the table as a
|
|
130
|
+
whole to catch gaps between individually working parts. Any missing, pending,
|
|
131
|
+
failed, stale, or unverifiable applicable experience row blocks
|
|
132
|
+
`user_like_local_verified` and returns the loop to the smallest affected repair.
|
|
133
|
+
|
|
103
134
|
Run the packaged acceptance validator before promoting a relevant verification
|
|
104
135
|
gate and before issuing the completion receipt. A missing, pending, failed, stale,
|
|
105
136
|
or unverifiable applicable row prevents promotion. Matrix completeness is one
|
|
@@ -114,7 +145,7 @@ For persistence, require reload/session return and stored values/ownership. A
|
|
|
114
145
|
working control, success message or HTTP 200 alone is insufficient.
|
|
115
146
|
|
|
116
147
|
The bundled minimum checker extends the acceptance matrix with structured
|
|
117
|
-
observations. Compare the original request to the
|
|
148
|
+
observations. Compare the original request to the stable criterion-ID list independently so
|
|
118
149
|
omitted requirements cannot disappear before validation. A missing, failed or
|
|
119
150
|
stale floor check prevents verified completion at any level. The CLI now enforces
|
|
120
151
|
this before implementation/PR promotion and on recheck; the standalone command
|
|
@@ -265,10 +296,11 @@ Run focused regression tests first, then formatting, lint, type checking, unit
|
|
|
265
296
|
tests, and the actual affected runtime. Apply only the relevant lanes from
|
|
266
297
|
[the change-boundary matrix](references/change-boundary-matrix.md).
|
|
267
298
|
|
|
268
|
-
After local verification
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
299
|
+
After local verification, execute the frozen review plan for the effective level
|
|
300
|
+
and governing repository. The independent reviewer compares the implementation
|
|
301
|
+
and observed outcomes to the frozen To-Be and original request, including affected
|
|
302
|
+
cross-view links, omissions and applicable historical regressions. Fix findings
|
|
303
|
+
narrowly and independently re-review the affected behavior.
|
|
272
304
|
|
|
273
305
|
Give the independent verifier the acceptance sources and raw evidence, not just
|
|
274
306
|
the implementer's summary. Use a separate session/agent for every review; another model can help but model count is not quality evidence.
|
|
@@ -283,11 +315,14 @@ production configuration, and CI or security-policy changes.
|
|
|
283
315
|
|
|
284
316
|
### 4. Coordinate through Draft PR and integration state
|
|
285
317
|
|
|
286
|
-
Before creating a PR, pass the independent To-Be review and pre-PR SQM loop.
|
|
287
318
|
After authority for the required remote changes exists, record reproduction,
|
|
288
319
|
tests, evidence, companion revisions, skipped checks, and remaining gates in the
|
|
289
|
-
Draft PR
|
|
290
|
-
|
|
320
|
+
Draft PR so the exact remote candidate can be inspected. Before Ready or merge,
|
|
321
|
+
pass the reviews and explicitly opted-in SQM gates required by the frozen plan.
|
|
322
|
+
Rerun a review or SQM gate only when its bound head,
|
|
323
|
+
base, diff, specification, policy, evidence, environment or SQM bundle changed,
|
|
324
|
+
or when a PR-only check became applicable. Otherwise retain the verified receipt
|
|
325
|
+
and record its exact identity instead of duplicating ceremony.
|
|
291
326
|
Before Ready or merge, combine the latest base with required companion
|
|
292
327
|
and parallel changes, rerun the affected path, and confirm current CI and
|
|
293
328
|
mergeability. Without combined-state proof, report `pr_only_verified`, not
|
|
@@ -301,6 +336,12 @@ the charter permits, then have Codex operate the user's Chrome through the
|
|
|
301
336
|
browser extension as a normal user. Do not replace this gate with direct API
|
|
302
337
|
calls or a fixed selector-only test.
|
|
303
338
|
|
|
339
|
+
Immediately after the journey, refresh and inspect the experience/acceptance table
|
|
340
|
+
for the same candidate revision, environment, fixture, and input. Compare the
|
|
341
|
+
entire trigger-to-usable-outcome path, including what the user understands and can
|
|
342
|
+
do next, with the frozen experience contract. Do not promote the local journey
|
|
343
|
+
because its individual controls, requests, or services worked in isolation.
|
|
344
|
+
|
|
304
345
|
Read [Codex Chrome user verification](references/chrome-user-verification.md)
|
|
305
346
|
before running this phase.
|
|
306
347
|
|
|
@@ -311,6 +352,13 @@ remote merge result. Wait until the target environment reports the exact merge
|
|
|
311
352
|
revision or a verifiably derived image digest. Confirm health and runtime
|
|
312
353
|
identity before live verification.
|
|
313
354
|
|
|
355
|
+
For a production-impacting change, release through the frozen stages. At each
|
|
356
|
+
stage observe the named outcome and guardrail signals for the frozen window, then
|
|
357
|
+
apply the deterministic decision: promote only when all promotion thresholds pass;
|
|
358
|
+
hold when evidence is incomplete; abort or rollback when a halt threshold fires.
|
|
359
|
+
Verify the rollback mechanism and kill switch before exposure. Record the owner
|
|
360
|
+
and a receipt for every decision. A release plan is not evidence that a stage ran.
|
|
361
|
+
|
|
314
362
|
### 7. Verify the deployed user journey
|
|
315
363
|
|
|
316
364
|
Repeat the relevant Chrome journey against the deployed environment. Include
|
|
@@ -323,6 +371,10 @@ history or claim `done`. Save the exact revision, environment, input, Run ID,
|
|
|
323
371
|
timestamps, visible state, network evidence, and logs, then add a boundary
|
|
324
372
|
regression before re-entering implementation.
|
|
325
373
|
|
|
374
|
+
After the frozen observation window, evaluate the production outcome and guardrail
|
|
375
|
+
measures for the same experience IDs. A functioning deployment is not successful
|
|
376
|
+
delivery when the intended outcome misses its threshold or a guardrail is breached.
|
|
377
|
+
|
|
326
378
|
### Feed repaired delivery failures back into SQM
|
|
327
379
|
|
|
328
380
|
When an observed failure was repaired, prepare one bounded `delivery.json` record
|
|
@@ -343,10 +395,11 @@ and validation ordering still require Delivery Loop execution controls.
|
|
|
343
395
|
|
|
344
396
|
Remove scoped fixtures and prove the residual count is zero. Deliver a compact
|
|
345
397
|
completion receipt containing shared-spec baseline/To-Be revisions and status,
|
|
346
|
-
|
|
347
|
-
coverage gaps, repository revisions, PR and CI, independent
|
|
398
|
+
the frozen review plan and identity-bound review results, applicable SQM proofs
|
|
399
|
+
and their reuse/rerun decision, historical coverage gaps, repository revisions, PR and CI, independent
|
|
348
400
|
review, container/runtime results, local Chrome evidence, merge and deployment
|
|
349
|
-
identity,
|
|
401
|
+
identity, rollout-stage and outcome/guardrail results, deployed Chrome evidence,
|
|
402
|
+
artifacts, cleanup, skipped gates, and
|
|
350
403
|
residual risk. Convert recurring findings into the smallest maintainable rule,
|
|
351
404
|
test, static check, or source-of-truth update selected by the five-response
|
|
352
405
|
comparison. Bound debt cleanup by scope, change size, and completion criteria;
|
package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/acceptance-evidence.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## Before implementation
|
|
4
4
|
|
|
5
|
+
Freeze the user experience before proposing the solution. Read-only discovery may
|
|
6
|
+
inform it, but the first authored success record states the beneficiary and
|
|
7
|
+
context, their goal, the complete usable outcome, what they should see,
|
|
8
|
+
understand, and be able to do next at each observable moment, applicable recovery
|
|
9
|
+
and forbidden experiences, and how those moments will be observed. Assign stable
|
|
10
|
+
UX/acceptance IDs. A screen, component, endpoint, task, or stored row is an
|
|
11
|
+
implementation detail unless it is tied to this experience.
|
|
12
|
+
|
|
5
13
|
The controller externalizes every acceptance condition with a stable ID, observable
|
|
6
14
|
outcome, source independent of the candidate, and required checks. For each
|
|
7
15
|
verification gate, freeze its applicable criteria in `charter.json` and record the
|
|
@@ -9,6 +17,20 @@ SHA-256 of the exact file bytes in the controller-owned snapshot. Reconcile the
|
|
|
9
17
|
gate charters against the overall delivery charter so no requirement disappears.
|
|
10
18
|
Do not choose a convenient subset after observing failures.
|
|
11
19
|
|
|
20
|
+
Use these criteria as the structured form of the experience contract rather than
|
|
21
|
+
creating a second UX checklist. Cover the full path from its real trigger to its
|
|
22
|
+
usable outcome and the applicable recovery path. When several parts must work
|
|
23
|
+
together for the beneficiary to succeed, include an end-to-end criterion in
|
|
24
|
+
addition to narrower diagnostic criteria. Independent coverage review compares
|
|
25
|
+
the experience contract and original request to the frozen rows before coding.
|
|
26
|
+
|
|
27
|
+
For production-relevant experience IDs, extend the same charter with outcome and
|
|
28
|
+
guardrail measures. Each measure names the signal, independent source,
|
|
29
|
+
observation window, threshold, resulting decision and owner. A rollout policy
|
|
30
|
+
references those measure IDs for promotion and halt decisions. These fields are
|
|
31
|
+
part of the same acceptance source and readable results view, not a second
|
|
32
|
+
success checklist.
|
|
33
|
+
|
|
12
34
|
Each criterion has two layers:
|
|
13
35
|
|
|
14
36
|
- `user`: a goal-driven user journey with visible interactions and evidence of the
|
|
@@ -49,6 +71,20 @@ After every evaluated action (test, repair, review or changed inputs):
|
|
|
49
71
|
All rows, including pending/failed ones, stay visible. A green matrix cannot advance
|
|
50
72
|
an unrelated gate or prove merge/deployment. Validate again for the final environment.
|
|
51
73
|
|
|
74
|
+
During staged release, append the stage, exposure, observed window, measure
|
|
75
|
+
results and deterministic `promote`, `hold`, `abort` or `rollback` decision to
|
|
76
|
+
the current results and receipt. Planned thresholds are not observations. A
|
|
77
|
+
healthy deployment cannot replace a missed outcome or breached guardrail.
|
|
78
|
+
|
|
79
|
+
After the exact candidate is built in a production-like local environment, run
|
|
80
|
+
the complete experience and regenerate `checklist.md` for that same revision,
|
|
81
|
+
environment, fixture, and input. Read the user and system rows together as a
|
|
82
|
+
single experience table: expected outcome, actual user observation, independent
|
|
83
|
+
postcondition/integration result, evidence, status, and next repair. Missing,
|
|
84
|
+
pending, failed, stale, or unverifiable applicable rows prevent
|
|
85
|
+
`user_like_local_verified`. Individually working components cannot override a
|
|
86
|
+
failed or absent end-to-end row.
|
|
87
|
+
|
|
52
88
|
## File contract
|
|
53
89
|
|
|
54
90
|
Charter example (illustrative values must be replaced with actual requirements):
|
|
@@ -59,7 +95,7 @@ Charter example (illustrative values must be replaced with actual requirements):
|
|
|
59
95
|
"run_id": "save-run-42",
|
|
60
96
|
"criteria": [{
|
|
61
97
|
"id": "SAVE-1",
|
|
62
|
-
"outcome": "
|
|
98
|
+
"outcome": "An owner returning to the task sees the saved note, understands it was retained, and can continue editing",
|
|
63
99
|
"acceptance_source": "Approved issue acceptance criteria, revision 3",
|
|
64
100
|
"layers": {
|
|
65
101
|
"user": {"applicability": "required", "method": "Save in Chrome, reload, sign in again and compare the note"},
|
|
@@ -37,11 +37,11 @@ messages.
|
|
|
37
37
|
|
|
38
38
|
| Level | Name | Intended work | Verification and review policy |
|
|
39
39
|
| --- | --- | --- | --- |
|
|
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
|
|
41
|
-
| 2 | Protected | Persistence, permissions, shared contracts, external side effects, cross-repository changes, and medium-risk migrations | Verify both evidence layers
|
|
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
|
|
43
|
-
| 4 | Fast | Small, isolated, reversible UI or implementation changes | Run the direct regression and real affected path
|
|
44
|
-
| 5 | Fastest | Copy, documentation, comments, metadata, or similarly trivial changes with no runtime/data/security effect | Verify the
|
|
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. Use separate independent design, implementation-boundary, and final PR/evidence reviews plus every repository gate. |
|
|
41
|
+
| 2 | Protected | Persistence, permissions, shared contracts, external side effects, cross-repository changes, and medium-risk migrations | Verify both evidence layers, shared boundaries, retry/idempotency, staged rollout and recovery. Require independent boundary/design and final candidate/integration review; combine them only when the reviewed inputs are exactly identical. |
|
|
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. One independent final-candidate review may cover design, implementation, affected views and evidence; repeat only when its bound identity changes. |
|
|
43
|
+
| 4 | Fast | Small, isolated, reversible UI or implementation changes | Run the direct regression and real affected path, adding shared-boundary checks only when touched. Use a scoped independent diff/actual-path review when repository policy or material ambiguity requires it. |
|
|
44
|
+
| 5 | Fastest | Copy, documentation, comments, metadata, or similarly trivial changes with no runtime/data/security effect | Verify the artifact, final diff, packaging/link integrity and repository-mandated checks. Independent review is needed only when governing policy requires it or material ambiguity remains. |
|
|
45
45
|
|
|
46
46
|
Level 3 is the recommendation when no task-specific signal favors another level.
|
|
47
47
|
Faster levels reduce work only by declaring genuinely unaffected lanes not
|
|
@@ -69,8 +69,9 @@ 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
|
|
73
|
-
-
|
|
72
|
+
- shared system As-Is/To-Be and consistency of affected cross-view links;
|
|
73
|
+
- the frozen risk-proportionate review plan and every governing repository review;
|
|
74
|
+
- SQM only under explicit opt-in, with identity-bound proof and historical coverage reported;
|
|
74
75
|
- honest state transitions and current revision/context binding;
|
|
75
76
|
- required user/system evidence for applicable outcomes;
|
|
76
77
|
- protection of user work, secrets, data integrity, and tenant boundaries;
|
|
@@ -78,3 +79,16 @@ Every level preserves:
|
|
|
78
79
|
- repository-required tests, reviews, CI, and approval/authority boundaries.
|
|
79
80
|
|
|
80
81
|
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.
|
|
82
|
+
|
|
83
|
+
## Reuse instead of duplicate ceremony
|
|
84
|
+
|
|
85
|
+
Freeze the review and SQM plan in the charter. Reuse a passing review or SQM
|
|
86
|
+
proof only when its repository, head, base, working-tree/diff, specification,
|
|
87
|
+
policy, knowledge bundle, evidence and relevant environment identities are exactly
|
|
88
|
+
unchanged and the proof remains verifiable. A PR URL alone is not a changed input.
|
|
89
|
+
Rerun the affected review or SQM phase when any bound identity changes or when a
|
|
90
|
+
PR-only scanner, policy or integration check first becomes applicable.
|
|
91
|
+
|
|
92
|
+
Do not reopen or re-attest every shared view. Inspect the changed views and their
|
|
93
|
+
declared dependency links; retain unchanged views by exact revision. Do not turn a
|
|
94
|
+
failed, unavailable or applicable gate into `not_applicable` to save time.
|
package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/minimum-completion.md
CHANGED
|
@@ -9,19 +9,25 @@ in an executor result or assurance-level selection disables the gate.
|
|
|
9
9
|
## Collect real observations
|
|
10
10
|
|
|
11
11
|
Before implementation, reconcile the original request, acceptance criteria and
|
|
12
|
-
planned operations
|
|
12
|
+
planned operations against the frozen experience contract. Preserve every
|
|
13
|
+
observable moment from the real trigger to a usable result, including applicable
|
|
14
|
+
recovery and forbidden experiences; a missing requirement must
|
|
13
15
|
be added through the controller's charter process, not omitted from the matrix.
|
|
14
16
|
The independent auditor compares original-request coverage and checks the oracle
|
|
15
17
|
against raw evidence. Machine mapping checks cannot discover an omitted idea in
|
|
16
18
|
natural language or authenticate what an evidence collector observed.
|
|
17
19
|
|
|
18
|
-
For each
|
|
20
|
+
For each stable criterion ID record implementation_refs (repository-relative file
|
|
21
|
+
paths). New UX-first charters preserve the IDs supplied by the experience
|
|
22
|
+
contract; legacy charters without explicit IDs retain deterministic `AC-N` IDs.
|
|
23
|
+
Then:
|
|
19
24
|
|
|
20
25
|
- user/operation: operate the actual UI or CLI/consumer. Expected is true; actual
|
|
21
26
|
is whether the intended operation really executed, not just whether a click
|
|
22
27
|
command succeeded. Include screenshots/traces where relevant.
|
|
23
28
|
- user/result: observe the requested visible outcome, including reload and session
|
|
24
|
-
return for a saving feature. Compare expected and actual values
|
|
29
|
+
return for a saving feature. Compare expected and actual values, user
|
|
30
|
+
understanding, and the next action the experience makes available.
|
|
25
31
|
- system/postcondition: independently inspect the final state; for persistence,
|
|
26
32
|
include the saved values and ownership, not a toast or HTTP status.
|
|
27
33
|
- system/integration: inspect the necessary combined path through APIs, storage,
|
|
@@ -33,6 +39,8 @@ For document-only work these mean opening the actual consumer and checking conte
|
|
|
33
39
|
links and packaged bytes. No DB/API is required if none participates. Both generic
|
|
34
40
|
layers remain required; there is no post-failure waiver. Tests, permissions or
|
|
35
41
|
runtime unavailable means pending/blocked. Never fabricate expected/actual equality.
|
|
42
|
+
Passing narrower rows for controls, APIs, services, or artifacts cannot substitute
|
|
43
|
+
for the end-to-end row when the requested experience depends on their combination.
|
|
36
44
|
|
|
37
45
|
## Executable contract
|
|
38
46
|
|
|
@@ -59,7 +67,8 @@ identities in the evidence; the independent reviewer must validate their current
|
|
|
59
67
|
identity. Do not claim that this single-checkout gate automatically re-reads a
|
|
60
68
|
companion service's Git HEAD or production environment.
|
|
61
69
|
|
|
62
|
-
Every matrix row
|
|
70
|
+
Every matrix row uses the same stable criterion ID and adds
|
|
71
|
+
`implementation_refs: ["src/example.js"]`. Each required
|
|
63
72
|
user/system cell's **first** evidence file is JSON with this shape (user example):
|
|
64
73
|
|
|
65
74
|
```json
|
|
@@ -128,10 +137,10 @@ external provider calls are introduced.
|
|
|
128
137
|
|
|
129
138
|
## Shared specifications and independent review
|
|
130
139
|
|
|
131
|
-
The floor's
|
|
140
|
+
The floor's stable criterion rows trace back to requirement IDs in the team's shared
|
|
132
141
|
As-Is/To-Be specification. Follow [shared system specifications](shared-system-specifications.md)
|
|
133
|
-
for purpose, user experience, cross-view consistency, independent
|
|
134
|
-
|
|
142
|
+
for purpose, user experience, cross-view consistency, risk-proportionate independent
|
|
143
|
+
reviews and explicitly opted-in, identity-aware SQM. These are controller workflow obligations, not fields magically
|
|
135
144
|
validated by the minimum checker. The CLI gate verifies minimum structured evidence;
|
|
136
145
|
it does not launch every design review or SQM phase on its own. Standalone hosts
|
|
137
146
|
remain responsible for executing this skill and cannot claim an enforced host hook.
|
|
@@ -15,22 +15,37 @@ An old design or green PR is not proof of current production behavior.
|
|
|
15
15
|
|
|
16
16
|
At the start of each run:
|
|
17
17
|
|
|
18
|
-
1.
|
|
18
|
+
1. Freeze the experience contract from the original request before proposing a
|
|
19
|
+
solution: beneficiary/context, goal, complete usable outcome, observable
|
|
20
|
+
moments with what the person sees, understands, and can do next, recovery and
|
|
21
|
+
forbidden experiences, and the observation method. Read-only discovery may
|
|
22
|
+
inform this record. Give every moment a stable UX/acceptance ID.
|
|
23
|
+
2. Read the existing index and current linked views. Reconcile relevant As-Is with
|
|
19
24
|
code and actual behavior; label unknowns, cite evidence, and correct documented
|
|
20
25
|
drift without claiming that the drift was part of the requested feature.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
3. Reconcile why the change matters against that contract: current difficulty,
|
|
27
|
+
observable success, and non-goals. Preserve the user's original request as an
|
|
28
|
+
independent acceptance source; do not replace their outcome with a component
|
|
29
|
+
or implementation inventory.
|
|
30
|
+
4. Prepare a proposed To-Be on a branch/change proposal linked from the shared
|
|
25
31
|
system index. Record its baseline revision, affected stable IDs, before/after
|
|
26
32
|
behavior, dependencies and acceptance oracles. Reuse unchanged views by reference;
|
|
27
33
|
do not copy the whole specification into every run or generate empty diagrams.
|
|
28
|
-
|
|
34
|
+
5. Link each experience ID to workflow, screen/control, state/sequence, API/event,
|
|
29
35
|
data/relationship, permission and runtime boundaries as applicable. Map these
|
|
30
|
-
stable system IDs to the run's
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
stable system IDs to the run's criterion rows and implementation/evidence locations.
|
|
37
|
+
6. Freeze the delivery-level review plan. At levels that require a separate
|
|
38
|
+
design review, obtain it before implementation; at level 3 the independent
|
|
39
|
+
final-candidate review may cover design, implementation and evidence together.
|
|
40
|
+
Supply the original request, shared baseline, To-Be and affected links. Missing
|
|
41
|
+
evidence or contradictory views remains pending/failed, never silently accepted.
|
|
42
|
+
|
|
43
|
+
After the exact local candidate is built, update the existing acceptance matrix
|
|
44
|
+
and its readable table for those same experience IDs. Compare expected experience,
|
|
45
|
+
actual user observation, independent system result, evidence, status, and next
|
|
46
|
+
repair across the whole journey. This is a view of the canonical acceptance data,
|
|
47
|
+
not another specification. A gap between working parts blocks local user-journey
|
|
48
|
+
promotion even if every part passed a narrower test.
|
|
34
49
|
|
|
35
50
|
The twelve-view index must account for every category: present (with a canonical
|
|
36
51
|
link), unchanged (with a revision), not applicable (with a reason), or unknown
|
|
@@ -55,13 +70,15 @@ interface views; do not invent application screens, APIs, tables or infrastructu
|
|
|
55
70
|
|
|
56
71
|
## Review evidence and neutral agents
|
|
57
72
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
73
|
+
Required reviews use independent agents/sessions; an agent must not approve work
|
|
74
|
+
it authored. Follow the risk-proportionate plan in `delivery-levels.md` instead of
|
|
75
|
+
creating design, cross-view, implementation and PR reviews by default. A reviewer
|
|
76
|
+
may cover several review kinds in one receipt when the candidate inputs are the
|
|
77
|
+
same, and can re-review fixes it did not implement. Supply raw sources, not desired
|
|
78
|
+
answers; require inspected references, discrepancies, uncertainty and a reasoned
|
|
79
|
+
verdict. Use the repository-required model (gpt-5.5 / xhigh where mandated and
|
|
80
|
+
available). If a required independent review is unavailable, report that gate as
|
|
81
|
+
blocked.
|
|
65
82
|
|
|
66
83
|
Persist a compact review receipt: reviewer/session identity, review kind, original
|
|
67
84
|
request and shared baseline/To-Be references, candidate revisions, inspected views
|
|
@@ -109,17 +126,22 @@ Use concrete regressions for relevant uncovered incidents and have an independen
|
|
|
109
126
|
reviewer assess coverage; keep missing incident history or untested boundaries
|
|
110
127
|
visible. No finite test promises absence of all future bugs.
|
|
111
128
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
129
|
+
Draft creation: after authority and local regressions, publish a Draft so the exact
|
|
130
|
+
remote candidate can be inspected. Draft existence is not gate approval.
|
|
131
|
+
|
|
132
|
+
Before Ready or merge, pass the frozen review plan. When the explicitly opted-in
|
|
133
|
+
plan requires SQM, run it against the final candidate; repair findings within the
|
|
134
|
+
bounded loop and rerun affected gates. On an unavailable/failed required proof,
|
|
135
|
+
retain Draft/not-ready and report the exact blocker while continuing independent
|
|
136
|
+
authorized preparation.
|
|
137
|
+
|
|
138
|
+
Post-PR: fetch and verify the actual PR head/base and current CI. Reuse the pre-PR
|
|
139
|
+
SQM proof only when repository, head, base, working-tree/diff, specification,
|
|
140
|
+
policy, knowledge bundle, evidence and relevant environment identities are exactly
|
|
141
|
+
unchanged and the signed proof verifies. Rerun into a new path when any identity
|
|
142
|
+
changed or a PR-only scanner/policy becomes applicable. Apply the same rule to
|
|
143
|
+
independent review. If a required gate fails, retain the PR as draft/not-ready,
|
|
144
|
+
repair and rerun affected gates. Preserve superseded receipts as history.
|
|
123
145
|
Promote Ready only with current required gates, including applicable combined-state
|
|
124
146
|
verification. Merge and deployment still require their own authority and evidence.
|
|
125
147
|
|
package/src/codex-plugins/simy/skills/agentic-delivery-loop/references/state-and-receipts.md
CHANGED
|
@@ -9,6 +9,8 @@ Persist one controller-owned snapshot with at least:
|
|
|
9
9
|
|
|
10
10
|
- `run_id`, `state`, monotonic `revision`, and terminal disposition;
|
|
11
11
|
- immutable explicit conditions and their stable digest;
|
|
12
|
+
- frozen experience-contract identities, their mapping to acceptance rows, and
|
|
13
|
+
the current readable local-experience table path and digest;
|
|
12
14
|
- acceptance-source identities and digests, architecture boundaries, applicable
|
|
13
15
|
rule decisions, risk tier, requested/effective delivery levels, the safety
|
|
14
16
|
ceiling reason, and chat-confirmation receipt;
|
|
@@ -20,7 +22,8 @@ Persist one controller-owned snapshot with at least:
|
|
|
20
22
|
- frozen acceptance charter digest, current matrix/table paths and digests,
|
|
21
23
|
superseded matrix snapshots, and the acceptance validator result for each gate;
|
|
22
24
|
- verification-boundary changes, deferred-debt references, and applicable
|
|
23
|
-
outcome and guardrail measures
|
|
25
|
+
outcome and guardrail measures, rollout policy, current rollout stage and
|
|
26
|
+
latest deterministic release decision;
|
|
24
27
|
- attempt number, retry/time/cost budgets, and failure fingerprints;
|
|
25
28
|
- append-only receipt IDs, evidence references, timestamps, and cleanup state.
|
|
26
29
|
|
|
@@ -44,6 +47,8 @@ Use the smallest applicable receipts rather than free-form completion claims:
|
|
|
44
47
|
- `ChromeUserJourneyReceipt`
|
|
45
48
|
- `MergeReceipt`
|
|
46
49
|
- `DeploymentIdentityReceipt`
|
|
50
|
+
- `RolloutStageReceipt`
|
|
51
|
+
- `OutcomeEvaluationReceipt`
|
|
47
52
|
- `HealthReceipt`
|
|
48
53
|
- `LiveEvidenceReceipt`
|
|
49
54
|
- `CleanupReceipt`
|
|
@@ -106,6 +111,8 @@ Evidence is revision-bound:
|
|
|
106
111
|
| Merge SHA changes | Deployment identity and live evidence |
|
|
107
112
|
| Deployed revision changes | Health and live evidence |
|
|
108
113
|
| Browser profile, tenant, or fixture changes | Affected user-journey evidence |
|
|
114
|
+
| Outcome/guardrail signal, source, window, threshold, decision, or owner changes | Affected release and outcome evidence |
|
|
115
|
+
| Rollout stage, exposure, recovery control, or kill switch changes | Affected rollout and later live evidence |
|
|
109
116
|
|
|
110
117
|
Do not discard historical receipts; mark them superseded for the current gate.
|
|
111
118
|
|
|
@@ -144,11 +151,13 @@ done =
|
|
|
144
151
|
&& deployed_exact_revision
|
|
145
152
|
&& health_verified
|
|
146
153
|
&& live_verified
|
|
154
|
+
&& production_outcome_evaluated
|
|
147
155
|
&& cleanup_verified
|
|
148
156
|
&& completion_receipt_created
|
|
149
157
|
```
|
|
150
158
|
|
|
151
|
-
Remove only genuinely non-applicable terms and record why
|
|
159
|
+
Remove only genuinely non-applicable terms and record why; production outcome
|
|
160
|
+
evaluation is non-applicable when no production-impacting release is in scope. If merge or deploy
|
|
152
161
|
is outside current authority, stop at the highest proven pre-authority state.
|
|
153
162
|
|
|
154
163
|
Acceptance evidence must cover every applicable criterion for the target gate,
|
|
@@ -156,5 +165,8 @@ with current context and the required user/system layers. After each evaluated
|
|
|
156
165
|
action, refresh the JSON matrix and its readable table; append a receipt for the
|
|
157
166
|
update. Keep the frozen charter distinct from mutable results. A charter patch
|
|
158
167
|
supersedes the old digest only after the controller verifies its authority.
|
|
168
|
+
For `user_like_local_verified`, the current table must cover the frozen experience
|
|
169
|
+
contract from real trigger to usable outcome for the exact local candidate. A
|
|
170
|
+
collection of narrower passing rows does not waive a missing end-to-end row.
|
|
159
171
|
|
|
160
172
|
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.
|
|
@@ -25,7 +25,15 @@ function requireValue(condition, message) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
function validateCharter(charter) {
|
|
28
|
-
requireValue(object(charter) && charter.schema_version
|
|
28
|
+
requireValue(object(charter) && [1, 2].includes(charter.schema_version) && text(charter.run_id), "Invalid charter header");
|
|
29
|
+
if (charter.schema_version === 2) {
|
|
30
|
+
requireValue(object(charter.experience), "Experience contract required");
|
|
31
|
+
for (const field of ["beneficiary", "situation", "goal", "usable_outcome", "recovery"])
|
|
32
|
+
requireValue(text(charter.experience[field]), `Experience contract needs ${field}`);
|
|
33
|
+
requireValue(Array.isArray(charter.experience.forbidden_experiences) &&
|
|
34
|
+
charter.experience.forbidden_experiences.length > 0 &&
|
|
35
|
+
charter.experience.forbidden_experiences.every(text), "Experience contract needs forbidden experiences");
|
|
36
|
+
}
|
|
29
37
|
requireValue(Array.isArray(charter.criteria) && charter.criteria.length > 0, "Charter requires criteria");
|
|
30
38
|
const ids = new Set();
|
|
31
39
|
for (const criterion of charter.criteria) {
|
|
@@ -88,15 +96,24 @@ export async function readEvidenceArtifact(root, artifact) {
|
|
|
88
96
|
const tableText = (value) => String(value ?? "").replaceAll("|", "\\|").replace(/[\r\n]+/g, " ");
|
|
89
97
|
|
|
90
98
|
export function renderChecklist(report) {
|
|
99
|
+
const experienceContext = report.experience
|
|
100
|
+
? `${report.experience.beneficiary} / ${report.experience.situation}`
|
|
101
|
+
: "Legacy charter: persona and situation not recorded";
|
|
91
102
|
const header = [
|
|
92
|
-
"|
|
|
93
|
-
"| --- | --- | --- | --- | --- | --- |",
|
|
103
|
+
"| Experience criterion / expected outcome | Persona / situation | Layer / method | Status | Actual observation | Evidence | Unmet reason / next repair |",
|
|
104
|
+
"| --- | --- | --- | --- | --- | --- | --- |",
|
|
94
105
|
];
|
|
95
106
|
const rows = report.checks.map((row) => "| " + [
|
|
96
|
-
`${row.id}: ${row.outcome}`,
|
|
107
|
+
`${row.id}: ${row.outcome}`, experienceContext,
|
|
108
|
+
`${row.layer}: ${row.method}`, row.status,
|
|
97
109
|
row.observation, row.evidence.join(", "), [row.reason, row.next_action].filter(Boolean).join(" / "),
|
|
98
110
|
].map(tableText).join(" | ") + " |");
|
|
111
|
+
const context = report.context;
|
|
112
|
+
const candidate = context
|
|
113
|
+
? `Candidate context: stage=${tableText(context.stage)}; environment=${tableText(context.environment)}; fixture=${tableText(context.fixture_id)}; input_sha256=${tableText(context.input_sha256)}; source_revisions=${tableText(JSON.stringify(context.source_revisions))}`
|
|
114
|
+
: "Candidate context: unavailable";
|
|
99
115
|
return [...header, ...rows, "", `Validator: ${report.status}`,
|
|
116
|
+
candidate,
|
|
100
117
|
...report.errors.map((error) => `- ${tableText(error)}`)].join("\n") + "\n";
|
|
101
118
|
}
|
|
102
119
|
|
|
@@ -111,7 +128,8 @@ export async function checkAcceptance({ charterBytes, matrix, expectedCharterSha
|
|
|
111
128
|
requireValue(contextDigest(matrix.context) === expectedContextSha256, "Current context digest mismatch");
|
|
112
129
|
requireValue(Array.isArray(matrix.results), "Matrix requires results");
|
|
113
130
|
const root = await realpath(evidenceRoot);
|
|
114
|
-
const report = { status: "evidence_incomplete",
|
|
131
|
+
const report = { status: "evidence_incomplete", experience: charter.experience ?? null,
|
|
132
|
+
context: matrix.context, checks: [], errors: [] };
|
|
115
133
|
const results = new Map();
|
|
116
134
|
const expectedIds = new Set(charter.criteria.map((criterion) => criterion.id));
|
|
117
135
|
for (const row of matrix.results) {
|
package/src/codex-plugins/simy/skills/agentic-delivery-loop/scripts/check-minimum-completion.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import { lstat, readFile, realpath } from "node:fs/promises";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { isDeepStrictEqual } from "node:util";
|
|
7
|
+
import { normalizeProductionContract } from "./production-contract.mjs";
|
|
7
8
|
import {
|
|
8
9
|
checkAcceptance,
|
|
9
10
|
contextDigest,
|
|
@@ -35,13 +36,23 @@ export function minimumCharter(charter) {
|
|
|
35
36
|
charter.completion_contract.minimum_scope || charter.acceptance_criteria,
|
|
36
37
|
non_goals: charter.completion_contract.non_goals || [],
|
|
37
38
|
};
|
|
39
|
+
const ids = criterionIds(
|
|
40
|
+
charter.completion_contract.criterion_ids,
|
|
41
|
+
charter.acceptance_criteria.length,
|
|
42
|
+
);
|
|
43
|
+
const experience = minimumExperience(
|
|
44
|
+
charter.completion_contract.experience,
|
|
45
|
+
charter.completion_contract.user_outcome || charter.requirement,
|
|
46
|
+
);
|
|
38
47
|
return {
|
|
39
|
-
schema_version:
|
|
48
|
+
schema_version: 2,
|
|
40
49
|
minimum_completion_version: MINIMUM_COMPLETION_VERSION,
|
|
41
50
|
run_id: charter.id,
|
|
42
51
|
source,
|
|
52
|
+
experience,
|
|
53
|
+
...normalizeProductionContract(charter.completion_contract, ids),
|
|
43
54
|
criteria: charter.acceptance_criteria.map((outcome, index) => ({
|
|
44
|
-
id:
|
|
55
|
+
id: ids[index],
|
|
45
56
|
outcome,
|
|
46
57
|
acceptance_source: `request:${contextDigest(source)}`,
|
|
47
58
|
layers: {
|
|
@@ -60,6 +71,49 @@ export function minimumCharter(charter) {
|
|
|
60
71
|
};
|
|
61
72
|
}
|
|
62
73
|
|
|
74
|
+
function criterionIds(value, count) {
|
|
75
|
+
if (value === undefined || value === null)
|
|
76
|
+
return Array.from({ length: count }, (_, index) => `AC-${index + 1}`);
|
|
77
|
+
if (!Array.isArray(value)) throw new Error("Invalid acceptance criterion IDs");
|
|
78
|
+
const ids = value.map((id) => (text(id) ? id.trim() : ""));
|
|
79
|
+
if (
|
|
80
|
+
ids.length !== count ||
|
|
81
|
+
new Set(ids).size !== ids.length ||
|
|
82
|
+
ids.some(
|
|
83
|
+
(id) => !/^[A-Za-z][A-Za-z0-9]*(?:[-_.][A-Za-z0-9]+)*$/.test(id),
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
throw new Error("Invalid acceptance criterion IDs");
|
|
87
|
+
return ids;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function minimumExperience(value, userOutcome) {
|
|
91
|
+
const source = object(value) ? value : {};
|
|
92
|
+
return {
|
|
93
|
+
beneficiary: text(source.beneficiary)
|
|
94
|
+
? source.beneficiary.trim()
|
|
95
|
+
: "The requester",
|
|
96
|
+
situation: text(source.situation)
|
|
97
|
+
? source.situation.trim()
|
|
98
|
+
: "Using the requested changed behavior",
|
|
99
|
+
goal: text(source.goal) ? source.goal.trim() : userOutcome,
|
|
100
|
+
usable_outcome: text(source.usable_outcome)
|
|
101
|
+
? source.usable_outcome.trim()
|
|
102
|
+
: userOutcome,
|
|
103
|
+
recovery: text(source.recovery)
|
|
104
|
+
? source.recovery.trim()
|
|
105
|
+
: "Unmet acceptance rows remain visible with the next repair.",
|
|
106
|
+
forbidden_experiences:
|
|
107
|
+
Array.isArray(source.forbidden_experiences) &&
|
|
108
|
+
source.forbidden_experiences.length > 0 &&
|
|
109
|
+
source.forbidden_experiences.every(text)
|
|
110
|
+
? source.forbidden_experiences.map((item) => item.trim())
|
|
111
|
+
: [
|
|
112
|
+
"Reporting completion from components or commands without the end-to-end outcome",
|
|
113
|
+
],
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
63
117
|
export function minimumContext(charter, headSha) {
|
|
64
118
|
const frozen = minimumCharter(charter);
|
|
65
119
|
return {
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
// Shared by the CLI and the independently installed skill. Keep this module
|
|
2
|
+
// self-contained so validation never depends on the repository checkout.
|
|
3
|
+
const cleanString = value => typeof value === "string" ? value.trim() : "";
|
|
4
|
+
const record = value => value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
5
|
+
const uniqueStrings = value => [...new Set(Array.isArray(value) ? value.map(cleanString).filter(Boolean) : [])];
|
|
6
|
+
const criterionIdPattern = /^[A-Za-z][A-Za-z0-9]*(?:[-_.][A-Za-z0-9]+)*$/;
|
|
7
|
+
|
|
8
|
+
export function normalizeProductionContract(source, ids) {
|
|
9
|
+
const outcome_contract = normalizeOutcomeContract(source.outcome_contract, ids);
|
|
10
|
+
return { outcome_contract, rollout_policy: normalizeRolloutPolicy(source.rollout_policy, outcome_contract) };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function normalizeOutcomeContract(value, criterionIds) {
|
|
14
|
+
const source = record(value);
|
|
15
|
+
const criteria = new Set(criterionIds);
|
|
16
|
+
const outcomeMeasures = normalizeMeasures(
|
|
17
|
+
source.outcome_measures,
|
|
18
|
+
criteria,
|
|
19
|
+
new Set(["promote", "hold"]),
|
|
20
|
+
"outcome",
|
|
21
|
+
);
|
|
22
|
+
const guardrailMeasures = normalizeMeasures(
|
|
23
|
+
source.guardrail_measures,
|
|
24
|
+
criteria,
|
|
25
|
+
new Set(["hold", "abort", "rollback"]),
|
|
26
|
+
"guardrail",
|
|
27
|
+
);
|
|
28
|
+
const allIds = [
|
|
29
|
+
...outcomeMeasures.map((measure) => measure.id),
|
|
30
|
+
...guardrailMeasures.map((measure) => measure.id),
|
|
31
|
+
];
|
|
32
|
+
if (new Set(allIds).size !== allIds.length) {
|
|
33
|
+
throw new Error("Duplicate outcome or guardrail measure IDs");
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
outcome_measures: outcomeMeasures,
|
|
37
|
+
guardrail_measures: guardrailMeasures,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function normalizeMeasures(value, criterionIds, allowedDecisions, kind) {
|
|
42
|
+
if (value === undefined || value === null) return [];
|
|
43
|
+
if (!Array.isArray(value)) throw new Error(`Invalid ${kind} measures`);
|
|
44
|
+
const measures = value.map((item) => {
|
|
45
|
+
const source = record(item);
|
|
46
|
+
const measure = {
|
|
47
|
+
id: cleanString(source.id),
|
|
48
|
+
criterion_id: cleanString(source.criterion_id),
|
|
49
|
+
signal: cleanString(source.signal),
|
|
50
|
+
source: cleanString(source.source),
|
|
51
|
+
window: cleanString(source.window),
|
|
52
|
+
threshold: cleanString(source.threshold),
|
|
53
|
+
decision: cleanString(source.decision).toLowerCase(),
|
|
54
|
+
owner: cleanString(source.owner),
|
|
55
|
+
};
|
|
56
|
+
if (
|
|
57
|
+
!criterionIdPattern.test(measure.id) ||
|
|
58
|
+
!criterionIds.has(measure.criterion_id) ||
|
|
59
|
+
!measure.signal ||
|
|
60
|
+
!measure.source ||
|
|
61
|
+
!measure.window ||
|
|
62
|
+
!measure.threshold ||
|
|
63
|
+
!allowedDecisions.has(measure.decision) ||
|
|
64
|
+
!measure.owner
|
|
65
|
+
) {
|
|
66
|
+
throw new Error(`Invalid ${kind} measure`);
|
|
67
|
+
}
|
|
68
|
+
return measure;
|
|
69
|
+
});
|
|
70
|
+
if (new Set(measures.map((measure) => measure.id)).size !== measures.length) {
|
|
71
|
+
throw new Error(`Duplicate ${kind} measure IDs`);
|
|
72
|
+
}
|
|
73
|
+
return measures;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function normalizeRolloutPolicy(value, outcomeContract) {
|
|
77
|
+
const source = record(value);
|
|
78
|
+
const required = source.required === true;
|
|
79
|
+
if (!required) {
|
|
80
|
+
return {
|
|
81
|
+
required: false,
|
|
82
|
+
reason: cleanString(source.reason) || "No production rollout is in scope",
|
|
83
|
+
stages: [],
|
|
84
|
+
promotion_requires: [],
|
|
85
|
+
halt_on: [],
|
|
86
|
+
rollback: null,
|
|
87
|
+
kill_switch: null,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const stages = normalizeRolloutStages(source.stages);
|
|
91
|
+
const outcomeIds = new Set(
|
|
92
|
+
outcomeContract.outcome_measures.map((measure) => measure.id),
|
|
93
|
+
);
|
|
94
|
+
const guardrailIds = new Set(
|
|
95
|
+
outcomeContract.guardrail_measures.map((measure) => measure.id),
|
|
96
|
+
);
|
|
97
|
+
const promotionRequires = uniqueStrings(source.promotion_requires);
|
|
98
|
+
const haltOn = uniqueStrings(source.halt_on);
|
|
99
|
+
const rollback = normalizeRecoveryControl(source.rollback, "rollback");
|
|
100
|
+
const killSwitch = normalizeRecoveryControl(source.kill_switch, "kill switch");
|
|
101
|
+
if (
|
|
102
|
+
stages.length < 2 ||
|
|
103
|
+
outcomeIds.size === 0 ||
|
|
104
|
+
promotionRequires.length !== outcomeIds.size ||
|
|
105
|
+
promotionRequires.some((id) => !outcomeIds.has(id)) ||
|
|
106
|
+
guardrailIds.size === 0 ||
|
|
107
|
+
haltOn.length !== guardrailIds.size ||
|
|
108
|
+
haltOn.some((id) => !guardrailIds.has(id))
|
|
109
|
+
) {
|
|
110
|
+
throw new Error("Invalid progressive rollout policy");
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
required: true,
|
|
114
|
+
reason: cleanString(source.reason) || "Production impact requires progressive exposure",
|
|
115
|
+
stages,
|
|
116
|
+
promotion_requires: promotionRequires,
|
|
117
|
+
halt_on: haltOn,
|
|
118
|
+
rollback,
|
|
119
|
+
kill_switch: killSwitch,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function normalizeRolloutStages(value) {
|
|
124
|
+
if (!Array.isArray(value)) throw new Error("Invalid rollout stages");
|
|
125
|
+
const stages = value.map((item) => {
|
|
126
|
+
const source = record(item);
|
|
127
|
+
const stage = {
|
|
128
|
+
id: cleanString(source.id),
|
|
129
|
+
exposure: cleanString(source.exposure),
|
|
130
|
+
observation_window: cleanString(source.observation_window),
|
|
131
|
+
};
|
|
132
|
+
if (
|
|
133
|
+
!criterionIdPattern.test(stage.id) ||
|
|
134
|
+
!stage.exposure ||
|
|
135
|
+
!stage.observation_window
|
|
136
|
+
) {
|
|
137
|
+
throw new Error("Invalid rollout stage");
|
|
138
|
+
}
|
|
139
|
+
return stage;
|
|
140
|
+
});
|
|
141
|
+
if (new Set(stages.map((stage) => stage.id)).size !== stages.length) {
|
|
142
|
+
throw new Error("Duplicate rollout stage IDs");
|
|
143
|
+
}
|
|
144
|
+
return stages;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function normalizeRecoveryControl(value, label) {
|
|
148
|
+
const source = record(value);
|
|
149
|
+
const control = {
|
|
150
|
+
mechanism: cleanString(source.mechanism),
|
|
151
|
+
owner: cleanString(source.owner),
|
|
152
|
+
};
|
|
153
|
+
if (!control.mechanism || !control.owner) {
|
|
154
|
+
throw new Error(`Invalid ${label} control`);
|
|
155
|
+
}
|
|
156
|
+
return control;
|
|
157
|
+
}
|
|
158
|
+
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { normalizeProductionContract } from "../codex-plugins/simy/skills/agentic-delivery-loop/scripts/production-contract.mjs";
|
|
1
2
|
import { cleanString, stringArray } from "./shared.js";
|
|
2
3
|
|
|
3
4
|
export const COMPLETION_CONTRACT_VERSION = 2;
|
|
5
|
+
const criterionIdPattern = /^[A-Za-z][A-Za-z0-9]*(?:[-_.][A-Za-z0-9]+)*$/;
|
|
4
6
|
|
|
5
7
|
export function buildCompletionContract({
|
|
6
8
|
inherited,
|
|
@@ -12,11 +14,18 @@ export function buildCompletionContract({
|
|
|
12
14
|
const source = record(inherited);
|
|
13
15
|
const minimumScope = stringArray(source.minimum_scope);
|
|
14
16
|
const proofRequired = stringArray(source.proof_required);
|
|
17
|
+
const criteria = stringArray(acceptanceCriteria);
|
|
18
|
+
const userOutcome = cleanString(source.user_outcome) || cleanString(requirement);
|
|
19
|
+
const ids = criterionIds(source.criterion_ids, criteria.length);
|
|
20
|
+
const productionContract = normalizeProductionContract(source, ids);
|
|
15
21
|
return {
|
|
16
22
|
version: COMPLETION_CONTRACT_VERSION,
|
|
17
|
-
user_outcome:
|
|
23
|
+
user_outcome: userOutcome,
|
|
18
24
|
minimum_scope:
|
|
19
|
-
minimumScope.length > 0 ? minimumScope :
|
|
25
|
+
minimumScope.length > 0 ? minimumScope : criteria,
|
|
26
|
+
criterion_ids: ids,
|
|
27
|
+
experience: normalizeExperience(source.experience, userOutcome),
|
|
28
|
+
...productionContract,
|
|
20
29
|
non_goals: stringArray(nonGoals),
|
|
21
30
|
proof_required: uniqueStrings([
|
|
22
31
|
"criterion_evidence",
|
|
@@ -29,12 +38,53 @@ export function buildCompletionContract({
|
|
|
29
38
|
}
|
|
30
39
|
|
|
31
40
|
export function acceptanceCriterionRows(charter) {
|
|
32
|
-
|
|
33
|
-
|
|
41
|
+
const statements = stringArray(charter?.acceptance_criteria);
|
|
42
|
+
const ids = criterionIds(
|
|
43
|
+
record(charter?.completion_contract).criterion_ids,
|
|
44
|
+
statements.length,
|
|
45
|
+
);
|
|
46
|
+
return statements.map((statement, index) => ({
|
|
47
|
+
id: ids[index],
|
|
34
48
|
statement,
|
|
35
49
|
}));
|
|
36
50
|
}
|
|
37
51
|
|
|
52
|
+
function criterionIds(value, count) {
|
|
53
|
+
if (value === undefined || value === null) {
|
|
54
|
+
return Array.from({ length: count }, (_, index) => `AC-${index + 1}`);
|
|
55
|
+
}
|
|
56
|
+
if (!Array.isArray(value)) throw new Error("Invalid acceptance criterion IDs");
|
|
57
|
+
const ids = value.map(cleanString);
|
|
58
|
+
if (
|
|
59
|
+
ids.length !== count ||
|
|
60
|
+
new Set(ids).size !== ids.length ||
|
|
61
|
+
ids.some((id) => !criterionIdPattern.test(id))
|
|
62
|
+
) {
|
|
63
|
+
throw new Error("Invalid acceptance criterion IDs");
|
|
64
|
+
}
|
|
65
|
+
return ids;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function normalizeExperience(value, userOutcome) {
|
|
69
|
+
const source = record(value);
|
|
70
|
+
return {
|
|
71
|
+
beneficiary: cleanString(source.beneficiary) || "The requester",
|
|
72
|
+
situation:
|
|
73
|
+
cleanString(source.situation) || "Using the requested changed behavior",
|
|
74
|
+
goal: cleanString(source.goal) || userOutcome,
|
|
75
|
+
usable_outcome: cleanString(source.usable_outcome) || userOutcome,
|
|
76
|
+
recovery:
|
|
77
|
+
cleanString(source.recovery) ||
|
|
78
|
+
"Unmet acceptance rows remain visible with the next repair.",
|
|
79
|
+
forbidden_experiences:
|
|
80
|
+
stringArray(source.forbidden_experiences).length > 0
|
|
81
|
+
? stringArray(source.forbidden_experiences)
|
|
82
|
+
: [
|
|
83
|
+
"Reporting completion from components or commands without the end-to-end outcome",
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
38
88
|
export function normalizeUncertaintyVerification(value) {
|
|
39
89
|
const source = record(value);
|
|
40
90
|
return {
|
|
@@ -65,6 +65,7 @@ export function createCodingLoopSnapshot({ runId, request, metadata = {} }) {
|
|
|
65
65
|
const inheritedArtifacts = stringArray(charterContext.artifacts_required);
|
|
66
66
|
const inheritedAssumptions = stringArray(charterContext.assumptions);
|
|
67
67
|
const inheritedCompletionContract = record(charterContext.completion_contract);
|
|
68
|
+
const inheritedExperienceContract = record(charterContext.experience_contract);
|
|
68
69
|
const finalAcceptanceCriteria =
|
|
69
70
|
acceptanceCriteria.length > 0
|
|
70
71
|
? acceptanceCriteria
|
|
@@ -157,7 +158,17 @@ export function createCodingLoopSnapshot({ runId, request, metadata = {} }) {
|
|
|
157
158
|
visual_review_required: browserEvidenceRequired,
|
|
158
159
|
},
|
|
159
160
|
completion_contract: buildCompletionContract({
|
|
160
|
-
inherited:
|
|
161
|
+
inherited: {
|
|
162
|
+
...inheritedCompletionContract,
|
|
163
|
+
...(Object.keys(inheritedExperienceContract).length > 0
|
|
164
|
+
? {
|
|
165
|
+
experience: inheritedExperienceContract,
|
|
166
|
+
criterion_ids:
|
|
167
|
+
inheritedExperienceContract.criterion_ids ??
|
|
168
|
+
inheritedCompletionContract.criterion_ids,
|
|
169
|
+
}
|
|
170
|
+
: {}),
|
|
171
|
+
},
|
|
161
172
|
requirement: cleanString(charterContext.user_goal) || cleanString(request.requirement),
|
|
162
173
|
acceptanceCriteria: finalAcceptanceCriteria,
|
|
163
174
|
nonGoals: finalNonGoals,
|
|
@@ -27,7 +27,8 @@ export function buildIndependentAuditInstruction(charter, attempt) {
|
|
|
27
27
|
[
|
|
28
28
|
`Requirement: ${charter.requirement}`,
|
|
29
29
|
`Original request: ${charter.thread_state?.original_request || charter.requirement}`,
|
|
30
|
-
`Acceptance criteria:\n${bullets(charter.
|
|
30
|
+
`Acceptance criteria:\n${bullets(acceptanceCriterionRows(charter).map(row => `${row.id}: ${row.statement}`))}`,
|
|
31
|
+
`Frozen experience (controller-owned): ${JSON.stringify(charter.completion_contract?.experience ?? null)}`,
|
|
31
32
|
`User-visible outcome: ${charter.completion_contract?.user_outcome || charter.requirement}`,
|
|
32
33
|
`Minimum scope:\n${bullets(charter.completion_contract?.minimum_scope || charter.acceptance_criteria)}`,
|
|
33
34
|
`Risk level: ${charter.risk.level}`,
|
|
@@ -62,8 +63,11 @@ export function buildIndependentAuditInstruction(charter, attempt) {
|
|
|
62
63
|
"Inspect the final diff and related code directly from the repository.",
|
|
63
64
|
"Look for unmet acceptance criteria, regressions, security issues, data and concurrency risks, missing tests, and unrelated changes.",
|
|
64
65
|
"Treat executor claims as untrusted until supported by repository evidence.",
|
|
65
|
-
"Compare the original request to the complete
|
|
66
|
-
"For every
|
|
66
|
+
"Compare the original request and frozen experience to the complete stable criterion-ID 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.",
|
|
67
|
+
"For every stable criterion ID, return a criterion_results entry only after directly checking its cited proof and observed outcome.",
|
|
68
|
+
"For production-relevant criteria, verify that each outcome and guardrail measure names its signal, independent source, observation window, threshold, decision, owner, and criterion ID.",
|
|
69
|
+
"When rollout_policy.required=true, verify that staged exposure and deterministic promote, hold, abort, rollback, and kill-switch controls are frozen before release. Do not treat a rollout plan as deployed evidence.",
|
|
70
|
+
"Apply the frozen delivery-level review plan: reuse a prior review only when its exact head, base, specification, policy, evidence, and environment identities are unchanged; otherwise review the affected boundary again.",
|
|
67
71
|
charter.evidence_policy?.browser_required
|
|
68
72
|
? "Open and inspect the actual local screenshots or videos. Return visual_review.inspected=true only after checking their visible content against the acceptance criteria."
|
|
69
73
|
: "Do not require visual evidence when the Charter does not require browser evidence.",
|
|
@@ -75,9 +79,9 @@ export function buildIndependentAuditInstruction(charter, attempt) {
|
|
|
75
79
|
[
|
|
76
80
|
"Finish with exactly one line beginning SIMY_AUDIT_JSON: followed by one JSON object.",
|
|
77
81
|
"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,
|
|
82
|
+
"coverage_review must contain requirements_complete (boolean), unmapped_requirements (array), and observation explaining the comparison of the original request, frozen experience, stable criterion-ID list, implementation and raw user/system proof. Use false and list gaps when anything is missing or unverified.",
|
|
79
83
|
"Each finding candidate must contain passed, code, severity, target, explanation, and repairability.",
|
|
80
|
-
"criterion_results must contain one entry per
|
|
84
|
+
"criterion_results must contain one entry per stable criterion ID with criterion_id, passed, verification_method, evidence_refs, and observed_result.",
|
|
81
85
|
"visual_review must contain inspected, artifacts, and acceptance_observations.",
|
|
82
86
|
"Only passed=false entries are findings. Omit passing checks, and never report passed=true evidence as a finding.",
|
|
83
87
|
"Use passed=false when a blocker or major finding remains, or when evidence is unavailable.",
|
|
@@ -37,6 +37,15 @@ export function buildCodingInstruction(
|
|
|
37
37
|
"completion_contract",
|
|
38
38
|
[
|
|
39
39
|
`User-visible outcome: ${charter.completion_contract?.user_outcome || charter.thread_state.user_goal}`,
|
|
40
|
+
`Beneficiary: ${charter.completion_contract?.experience?.beneficiary || "not recorded"}`,
|
|
41
|
+
`Situation: ${charter.completion_contract?.experience?.situation || "not recorded"}`,
|
|
42
|
+
`Experience goal: ${charter.completion_contract?.experience?.goal || "not recorded"}`,
|
|
43
|
+
`Usable outcome: ${charter.completion_contract?.experience?.usable_outcome || "not recorded"}`,
|
|
44
|
+
`Recovery experience: ${charter.completion_contract?.experience?.recovery || "not recorded"}`,
|
|
45
|
+
`Forbidden experiences:\n${bullets(charter.completion_contract?.experience?.forbidden_experiences || [])}`,
|
|
46
|
+
`Outcome measures: ${JSON.stringify(charter.completion_contract?.outcome_contract?.outcome_measures || [])}`,
|
|
47
|
+
`Guardrail measures: ${JSON.stringify(charter.completion_contract?.outcome_contract?.guardrail_measures || [])}`,
|
|
48
|
+
`Progressive rollout policy: ${JSON.stringify(charter.completion_contract?.rollout_policy || { required: false })}`,
|
|
40
49
|
`Minimum scope:\n${bullets(charter.completion_contract?.minimum_scope || charter.acceptance_criteria)}`,
|
|
41
50
|
`Non-goals:\n${bullets(charter.completion_contract?.non_goals || charter.thread_state.non_goals)}`,
|
|
42
51
|
`Proof required:\n${bullets(charter.completion_contract?.proof_required || [])}`,
|
|
@@ -52,10 +61,10 @@ export function buildCodingInstruction(
|
|
|
52
61
|
),
|
|
53
62
|
),
|
|
54
63
|
section("minimum_completion_evidence", [
|
|
55
|
-
"All delivery levels require this floor. Before implementation reconcile every original requirement with the
|
|
64
|
+
"All delivery levels require this floor. Before implementation reconcile every original requirement and frozen experience with the stable criterion-ID list; report omissions instead of silently dropping them.",
|
|
56
65
|
"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
66
|
"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
|
|
67
|
+
"For each stable criterion ID 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
68
|
"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
69
|
"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
70
|
`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 } })}`,
|
|
@@ -145,7 +154,7 @@ export function buildCodingInstruction(
|
|
|
145
154
|
"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.",
|
|
146
155
|
problemSolvingResultContract(),
|
|
147
156
|
"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.",
|
|
148
|
-
"criterion_evidence must contain one entry for every
|
|
157
|
+
"criterion_evidence must contain one entry for every stable criterion ID with criterion_id, passed, verification_method, evidence_refs, and observed_result. Only set passed=true when the evidence directly proves that criterion.",
|
|
149
158
|
"For UI or browser-extension work, visual_review must contain inspected=true, the local screenshot or video paths in artifacts, and concrete acceptance_observations from viewing the actual content. Capturing a file without viewing it does not count.",
|
|
150
159
|
"Use null for unavailable scalar values and [] for unavailable arrays. Do not claim evidence that was not observed.",
|
|
151
160
|
].join("\n"),
|
|
@@ -69,7 +69,7 @@ export async function collectMinimumCompletion({
|
|
|
69
69
|
return {
|
|
70
70
|
status: "evidence_incomplete",
|
|
71
71
|
errors: [
|
|
72
|
-
"Minimum completion evidence missing, invalid or stale; verify the actual operation, result, postcondition and integration for every
|
|
72
|
+
"Minimum completion evidence missing, invalid or stale; verify the actual operation, result, postcondition and integration for every stable criterion ID.",
|
|
73
73
|
],
|
|
74
74
|
};
|
|
75
75
|
}
|