eval-quality 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +142 -67
- package/corpus/dev/README.md +20 -13
- package/corpus/dev/compile-seal-example/brief.json +1 -1
- package/corpus/dev/compile-seal-example/contract.json +1 -1
- package/corpus/dev/contracts/absent-collection-locations.json +1 -1
- package/corpus/dev/contracts/absent-sibling-groups.json +1 -1
- package/corpus/dev/contracts/absent-success-indicator.json +1 -1
- package/corpus/dev/contracts/empty-channel-roles.json +1 -1
- package/corpus/dev/contracts/empty-collection-locations.json +1 -1
- package/corpus/dev/contracts/empty-request-shapes.json +1 -1
- package/corpus/dev/contracts/empty-sibling-groups.json +1 -1
- package/corpus/dev/contracts/fragment-selection.json +1 -0
- package/corpus/dev/contracts/no-collection-quantifier.json +1 -1
- package/corpus/dev/contracts/no-operation-inventory.json +1 -1
- package/corpus/dev/contracts/no-read-back-relation.json +1 -1
- package/corpus/dev/contracts/no-state-change-marker.json +1 -1
- package/corpus/dev/contracts/no-type-violating-step.json +1 -1
- package/corpus/dev/contracts/per-key-split-oracles.json +1 -1
- package/corpus/dev/contracts/review-corpus.json +1 -0
- package/corpus/dev/contracts/satisfied-declarations.json +1 -1
- package/corpus/dev/contracts/single-required-response-key.json +1 -1
- package/corpus/dev/contracts/split-indicator-oracle.json +1 -1
- package/corpus/dev/contracts/unaddressed-parameter-sibling.json +1 -1
- package/corpus/dev/contracts/unnamed-reference-set.json +1 -1
- package/corpus/dev/contracts/wrong-cardinality-form.json +1 -1
- package/corpus/dev/index.json +1 -1
- package/dist/application/index.d.ts +2 -0
- package/dist/application/index.js +1 -0
- package/dist/application/score.d.ts +48 -0
- package/dist/application/score.js +186 -0
- package/dist/cli/arguments.d.ts +7 -3
- package/dist/cli/arguments.js +73 -5
- package/dist/cli/exit-codes.d.ts +6 -2
- package/dist/cli/exit-codes.js +8 -9
- package/dist/cli/main.js +9 -0
- package/dist/cli/render.d.ts +3 -6
- package/dist/cli/render.js +57 -5
- package/dist/cli/run.d.ts +13 -3
- package/dist/cli/run.js +136 -16
- package/dist/core/canonical/canonicalize.d.ts +12 -0
- package/dist/core/canonical/canonicalize.js +18 -4
- package/dist/core/compile/bindings.d.ts +89 -0
- package/dist/core/compile/bindings.js +334 -0
- package/dist/core/compile/compile.d.ts +17 -0
- package/dist/core/compile/compile.js +37 -1
- package/dist/core/compile/excluded-content.d.ts +11 -0
- package/dist/core/compile/excluded-content.js +42 -0
- package/dist/core/compile/expression-legality.d.ts +49 -0
- package/dist/core/compile/expression-legality.js +158 -38
- package/dist/core/compile/forbidden-inputs.d.ts +8 -1
- package/dist/core/compile/forbidden-inputs.js +16 -3
- package/dist/core/compile/interface-inventory.d.ts +57 -2
- package/dist/core/compile/interface-inventory.js +119 -13
- package/dist/core/compile/reachability.d.ts +28 -1
- package/dist/core/compile/reachability.js +167 -35
- package/dist/core/compile/schema-version.d.ts +2 -0
- package/dist/core/compile/schema-version.js +25 -0
- package/dist/core/compile/sensitivity-witness.d.ts +31 -12
- package/dist/core/compile/sensitivity-witness.js +110 -23
- package/dist/core/compile/step-reference.d.ts +2 -0
- package/dist/core/compile/step-reference.js +49 -0
- package/dist/core/coverage/operations.d.ts +62 -0
- package/dist/core/coverage/operations.js +57 -0
- package/dist/core/coverage/relevance.d.ts +4 -2
- package/dist/core/coverage/relevance.js +22 -23
- package/dist/core/coverage/satisfaction.d.ts +2 -2
- package/dist/core/coverage/satisfaction.js +73 -48
- package/dist/core/declared-inputs.d.ts +83 -4
- package/dist/core/declared-inputs.js +105 -8
- package/dist/core/emit/emit.d.ts +9 -0
- package/dist/core/emit/emit.js +214 -0
- package/dist/core/emit/private-artifact-digest.d.ts +11 -0
- package/dist/core/emit/private-artifact-digest.js +31 -0
- package/dist/core/evaluate/evidence-resolution.d.ts +10 -3
- package/dist/core/evaluate/evidence-resolution.js +74 -11
- package/dist/core/evaluate/operators.d.ts +22 -0
- package/dist/core/evaluate/operators.js +17 -1
- package/dist/core/evaluate/resolution.d.ts +14 -3
- package/dist/core/evaluate/resolution.js +63 -3
- package/dist/core/excluded-content.d.ts +65 -0
- package/dist/core/excluded-content.js +113 -0
- package/dist/core/failure-codes.d.ts +2 -2
- package/dist/core/failure-codes.js +7 -2
- package/dist/core/ingest/conditions.d.ts +201 -0
- package/dist/core/ingest/conditions.js +48 -0
- package/dist/core/ingest/index.d.ts +13 -0
- package/dist/core/ingest/index.js +11 -0
- package/dist/core/ingest/ingest.d.ts +68 -0
- package/dist/core/ingest/ingest.js +318 -0
- package/dist/core/lineage/stage-table.d.ts +21 -4
- package/dist/core/lineage/stage-table.js +35 -3
- package/dist/core/preflight/plan.d.ts +7 -5
- package/dist/core/preflight/plan.js +75 -32
- package/dist/core/preflight/projection.d.ts +6 -3
- package/dist/core/preflight/projection.js +22 -2
- package/dist/core/preflight/reduce.js +47 -7
- package/dist/core/preflight/witness-evidence.d.ts +5 -5
- package/dist/core/preflight/witness-evidence.js +73 -20
- package/dist/core/schemas/artifact.d.ts +1049 -30
- package/dist/core/schemas/constraint-ledger.js +51 -0
- package/dist/core/schemas/defect-signature.d.ts +695 -0
- package/dist/core/schemas/defect-signature.js +175 -0
- package/dist/core/schemas/eval-contract.d.ts +550 -12
- package/dist/core/schemas/eval-contract.js +32 -2
- package/dist/core/schemas/evidence-artifact.d.ts +109 -19
- package/dist/core/schemas/evidence-artifact.js +64 -8
- package/dist/core/schemas/interface.d.ts +741 -13
- package/dist/core/schemas/interface.js +120 -7
- package/dist/core/schemas/isolation-manifest.js +16 -9
- package/dist/core/schemas/plan.d.ts +329 -3
- package/dist/core/schemas/plan.js +89 -3
- package/dist/core/schemas/pointer.d.ts +47 -1
- package/dist/core/schemas/pointer.js +89 -8
- package/dist/core/schemas/port-messages.d.ts +194 -10
- package/dist/core/schemas/port-messages.js +73 -6
- package/dist/core/schemas/probe-body.d.ts +18 -0
- package/dist/core/schemas/probe-body.js +13 -0
- package/dist/core/schemas/probe-qualification.d.ts +168 -0
- package/dist/core/schemas/probe-qualification.js +106 -0
- package/dist/core/schemas/probe.d.ts +431 -0
- package/dist/core/schemas/probe.js +6 -2
- package/dist/core/schemas/scoring-policy.d.ts +1 -0
- package/dist/core/schemas/scoring-policy.js +6 -1
- package/dist/core/schemas/sealed-evaluator-brief.d.ts +1 -0
- package/dist/core/schemas/sealed-evaluator-brief.js +4 -1
- package/dist/core/schemas/sealed-run-record.d.ts +161 -12
- package/dist/core/schemas/sealed-run-record.js +92 -15
- package/dist/core/schemas/sensitivity-witness.d.ts +108 -6
- package/dist/core/schemas/sensitivity-witness.js +61 -5
- package/dist/core/score/binding-order.d.ts +31 -0
- package/dist/core/score/binding-order.js +88 -0
- package/dist/core/score/bindings.d.ts +93 -0
- package/dist/core/score/bindings.js +309 -0
- package/dist/core/score/ladder-table.d.ts +23 -0
- package/dist/core/score/ladder-table.js +109 -0
- package/dist/core/score/ladder.d.ts +229 -0
- package/dist/core/score/ladder.js +464 -0
- package/dist/core/score/mode-agreement.d.ts +30 -0
- package/dist/core/score/mode-agreement.js +16 -0
- package/dist/core/score/outcome-table.d.ts +17 -0
- package/dist/core/score/outcome-table.js +172 -0
- package/dist/core/score/outcome.d.ts +466 -0
- package/dist/core/score/outcome.js +562 -0
- package/dist/core/score/qualification.d.ts +83 -0
- package/dist/core/score/qualification.js +645 -0
- package/dist/core/score/quotation.d.ts +56 -0
- package/dist/core/score/quotation.js +226 -0
- package/dist/core/score/reduce-trials.d.ts +80 -0
- package/dist/core/score/reduce-trials.js +90 -0
- package/dist/core/score/score.d.ts +72 -0
- package/dist/core/score/score.js +607 -0
- package/dist/core/score/selection.d.ts +80 -0
- package/dist/core/score/selection.js +98 -0
- package/dist/core/score/strength.d.ts +58 -0
- package/dist/core/score/strength.js +227 -0
- package/dist/core/score/witness.d.ts +138 -0
- package/dist/core/score/witness.js +320 -0
- package/dist/core/seal/derived-reference.d.ts +2 -9
- package/dist/core/seal/derived-reference.js +293 -46
- package/dist/core/seal/plan-index.d.ts +18 -3
- package/dist/core/seal/plan-index.js +44 -8
- package/dist/core/seal/seal.js +8 -3
- package/dist/core/stage-contracts.d.ts +62 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/ports/environment-probe-port.d.ts +60 -4
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +1 -0
- package/dist/testing/probe-conformance.d.ts +29 -0
- package/dist/testing/probe-conformance.js +34 -5
- package/package.json +12 -3
- package/schemas/eval-contract.schema.json +1787 -797
- package/schemas/evidence-artifact.schema.json +126 -9
- package/schemas/isolation-manifest.schema.json +17 -10
- package/schemas/probe.schema.json +636 -5
- package/schemas/rubric.schema.json +1 -1
- package/schemas/scoring-policy.schema.json +8 -1
- package/schemas/sealed-evaluator-brief.schema.json +11 -1
- package/schemas/sealed-run-record.schema.json +314 -40
package/README.md
CHANGED
|
@@ -1,18 +1,28 @@
|
|
|
1
1
|
# `eval-quality`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**[Documentation](https://bmad-code-org.github.io/bmad-eval-quality/)** ·
|
|
4
|
+
[Getting started](https://bmad-code-org.github.io/bmad-eval-quality/tutorials/getting-started/) ·
|
|
5
|
+
[CLI reference](https://bmad-code-org.github.io/bmad-eval-quality/reference/cli-commands/) ·
|
|
6
|
+
[npm](https://www.npmjs.com/package/eval-quality)
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npx eval-quality --help
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
### `eval-quality` does four things
|
|
4
13
|
|
|
5
14
|
1. **Compile**: validate and normalize an eval contract into a machine-readable artifact.
|
|
6
15
|
2. **Seal**: render the brief for the independent evaluator while hiding the planted bug and scoring answer.
|
|
7
16
|
3. **Preflight**: verify baseline environment readiness and probe reachability before running an evaluator.
|
|
17
|
+
4. **Score**: compare the evaluator's completed findings against the hidden bug signature and mint a versioned evidence artifact.
|
|
8
18
|
|
|
9
|
-
|
|
19
|
+
It executes nothing. No agent, no judge, and no system under test runs inside it; your harness runs the evaluation and hands over a sealed run record.
|
|
10
20
|
|
|
11
|
-
### What is the
|
|
21
|
+
### What is the evaluation contract?
|
|
12
22
|
|
|
13
23
|
It is the test.
|
|
14
24
|
|
|
15
|
-
More precisely, it is the evaluator’s instructions for how to expose a failure and what evidence counts as finding it.
|
|
25
|
+
More precisely, it is the evaluator’s instructions for how to expose a failure and what evidence counts as finding it. The long name is Behavioral Evaluation Contract; the docs shorten it to eval contract or evaluation contract.
|
|
16
26
|
|
|
17
27
|
It defines:
|
|
18
28
|
|
|
@@ -42,25 +52,35 @@ A strong eval checks the response **and** persistence, so it catches the bug.
|
|
|
42
52
|
|
|
43
53
|
Write the eval. Hide the bug. See if the eval catches it.
|
|
44
54
|
|
|
45
|
-
##
|
|
55
|
+
## The core flow, in eight nouns
|
|
56
|
+
|
|
57
|
+
Every run of an evaluation walks the same order:
|
|
46
58
|
|
|
47
|
-
|
|
59
|
+
```text
|
|
60
|
+
evaluation contract → probe → observation → preflight → evidence → oracle → rubric → score / verdict
|
|
61
|
+
```
|
|
48
62
|
|
|
49
|
-
|
|
|
63
|
+
| Noun | What it is | Example |
|
|
50
64
|
| --- | --- | --- |
|
|
51
|
-
| **
|
|
52
|
-
| **Probe**
|
|
53
|
-
| **Observation**
|
|
65
|
+
| **Evaluation contract** | What we want to measure: the behaviors, the checks, the interfaces a probe may touch, and the bounds a run stays inside. | "A PATCH that reports success has persisted the change." |
|
|
66
|
+
| **Probe** | How to poke the system to produce evidence: a test case, a call, a step. In scoring, a probe also names the defect it seeded. | "Update note n-1, then read it back." |
|
|
67
|
+
| **Observation** | What actually happened when the system was poked: the recorded status, headers, and body of one call. | `PATCH` returned 200 with the new title; the later `GET` returned the old one. |
|
|
68
|
+
| **Preflight** | Whether the environment and the observations are fit for meaningful measurement. | Both operations reachable, the fixture reset, the clean control clean. |
|
|
69
|
+
| **Evidence** | The recorded output, trajectory, and artifacts from the evaluation run: what the evaluator saw and what it claimed. | A finding citing the two observations above. |
|
|
70
|
+
| **Oracle** | The assertion: the relation that has to hold over the evidence. | The title sent equals the title read back. |
|
|
71
|
+
| **Rubric** | The grading guide for judgment-heavy quality, with anchored criteria a judge scores against. The judge runs outside the package and its scores arrive in the sealed run record. | Present only when a contract declares one. |
|
|
72
|
+
| **Score / verdict** | The combined result: did the evaluation catch the planted defect? `PASS`, `WAIVED`, `CONCERNS`, or `FAIL`, or Invalid when the run produced no verdict. | `FAIL`, exit code 2. |
|
|
54
73
|
|
|
55
|
-
|
|
74
|
+
The word evidence is used twice on purpose. The evidence in the flow is what the evaluator produced, and it reaches `score` inside a sealed run record. The evidence artifact is what `score` mints at the end: the outcomes, the verdict, the strength vector, and the exit code.
|
|
56
75
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
76
|
+
The four commands sit on that flow like this:
|
|
77
|
+
|
|
78
|
+
| Command | Reads | Writes |
|
|
79
|
+
| --- | --- | --- |
|
|
80
|
+
| `compile` | an authored contract | `eval-contract.json`, checked against the schema and the discipline rules |
|
|
81
|
+
| `seal` | a contract | `sealed-evaluator-brief.json`, the contract minus everything that would give the answer away |
|
|
82
|
+
| `preflight` | a contract, a probe list, observations | `preflight-verdict.json`, fit or unfit to measure |
|
|
83
|
+
| `score` | a sealed run record, the contract, a probe, the preflight verdict, a scoring policy, a caller-attested corpus digest, and the isolation manifest and evaluator configuration the record was produced under | `evidence-artifact.json`, and the verdict's own exit code |
|
|
64
84
|
|
|
65
85
|
## Elaboration
|
|
66
86
|
|
|
@@ -85,13 +105,7 @@ confirm the specific error, and confirm no record was created.
|
|
|
85
105
|
|
|
86
106
|
A passing eval says little when the contract never asked for the probe that would expose the failure. Testing whether the eval can catch a failure you already know about is the first check worth running.
|
|
87
107
|
|
|
88
|
-
|
|
89
|
-
product spec
|
|
90
|
-
→ Behavioral Evaluation Contract
|
|
91
|
-
→ known defect or gameability probe
|
|
92
|
-
→ independent evaluator
|
|
93
|
-
→ per-oracle evidence and a gate decision
|
|
94
|
-
```
|
|
108
|
+
The loop that does that is a twin run. Keep the contract, the probes, the oracles, and the scoring policy fixed. Run the evaluator once against the clean system and once against the same system carrying one known defect. Score both runs. The contract is strong when the clean run passes and the mutated run degrades, and it has a blind spot when both stay green.
|
|
95
109
|
|
|
96
110
|
## What each part provides
|
|
97
111
|
|
|
@@ -101,8 +115,12 @@ product spec
|
|
|
101
115
|
- the oracle vocabulary and authoring rules
|
|
102
116
|
- the contract compiler
|
|
103
117
|
- the environment pre-flight
|
|
104
|
-
- Eval Contract strength scoring
|
|
105
|
-
|
|
118
|
+
- Eval Contract strength scoring: the AD-7 rate vector and dominance relation, implemented in
|
|
119
|
+
`src/core/score/strength.ts` and reached by the `score` command
|
|
120
|
+
- PASS / WAIVED / CONCERNS / FAIL governance: both verdict ladders, implemented and total in
|
|
121
|
+
`src/core/score/ladder.ts`, and the `score` command's own exit code
|
|
122
|
+
- versioned evidence output: `evidence-artifact.json`, implemented in `src/core/emit/emit.ts` and
|
|
123
|
+
minted by the `score` command
|
|
106
124
|
|
|
107
125
|
The caller provides:
|
|
108
126
|
|
|
@@ -113,12 +131,15 @@ The caller provides:
|
|
|
113
131
|
- a sealed run record returned for ingestion
|
|
114
132
|
|
|
115
133
|
`eval-quality` executes nothing: it never spawns a process, calls a model, drives a system under test,
|
|
116
|
-
or invokes a judge. Its
|
|
117
|
-
|
|
118
|
-
|
|
134
|
+
or invokes a judge. Its six stages are compile, seal, ingest, pre-flight, score, and emit, all pure,
|
|
135
|
+
and every one is reachable through the CLI and the library alike. That list is the declared stage
|
|
136
|
+
order; on the clock, ingest follows the evaluator run, so it sits after pre-flight and just before
|
|
137
|
+
score. Compile, seal, and pre-flight each
|
|
138
|
+
have their own command and their own exported function. `ingest`, `score`, and `emit` are reached
|
|
139
|
+
through the one `score` command and the one exported `runScore` call that chains them, per AD-14's
|
|
140
|
+
rule that a command exposes no more than the library itself calls. Pre-flight probes the fixture through the environment-probe port, so a contract that declares a fixture reset
|
|
119
141
|
needs the caller's probe policy to authorize that operation's method as well as the read methods
|
|
120
|
-
every other pre-flight leg uses. Engine integration is a later adapter behind a port
|
|
121
|
-
dependency. See
|
|
142
|
+
every other pre-flight leg uses. Engine integration is a later adapter behind a port. See
|
|
122
143
|
[ADR-004](_bmad-output/planning-artifacts/architecture/architecture-eval-quality-2026-07-29/ADR-004-execution-boundary.md).
|
|
123
144
|
|
|
124
145
|
## Who it is for
|
|
@@ -145,27 +166,32 @@ Rubrics compile under the same discipline: an anchored scale, a bounded length,
|
|
|
145
166
|
|
|
146
167
|
## How Eval Contract strength scoring works
|
|
147
168
|
|
|
148
|
-
|
|
169
|
+
The `score` command and its `runScore` library call compute it; `npm run generate:worked-example`
|
|
170
|
+
runs the same functions over the committed worked chain, and
|
|
171
|
+
[the full walkthrough](https://bmad-code-org.github.io/bmad-eval-quality/how-to/author-behavioral-contracts/)
|
|
172
|
+
reads the result field by field. Do not trust a contract because it looks thorough. Put a known defect behind it, run the evaluator, and check whether the contract's oracles caused the defect to be caught.
|
|
149
173
|
|
|
150
174
|
Two probe classes go behind a contract, and a strong contract rejects both:
|
|
151
175
|
|
|
152
176
|
- **Defect probes**, where the behavior is simply wrong.
|
|
153
177
|
- **Gameability probes**, where the behavior looks compliant while dodging the oracle's intent. A test that raises coverage while asserting nothing is the familiar version of this.
|
|
154
178
|
|
|
155
|
-
Probes come from qualified historical defects or verified controlled mutations. The corpus separates a visible development set from an immutable sealed set for each scoring version.
|
|
179
|
+
Probes come from qualified historical defects or verified controlled mutations. The corpus separates a visible development set from an immutable sealed set for each scoring version. Only the development set exists today; the sealed set is part of the design and ships in no release yet.
|
|
156
180
|
|
|
157
181
|
Every required oracle check resolves to exactly one state, and the state travels with the result, so
|
|
158
182
|
"the check reported" is never sufficient on its own: `caught`, `confirmed`, `missed`,
|
|
159
183
|
`passed-clean-control`, `false-positive`, `abstained`, `bypassed`, `unreached`, `oracle-error`,
|
|
160
184
|
`judge-error`, `infrastructure-error`, or `not-applicable`.
|
|
161
185
|
|
|
162
|
-
A required oracle that missed, abstained, errored, or is absent prevents PASS, and a high overall score never overrides it. An infrastructure error or a failed environment pre-flight is not a behavioral result at all; it invalidates the run and is re-executed
|
|
186
|
+
A required oracle that missed, abstained, errored, or is absent prevents PASS, and a high overall score never overrides it. An infrastructure error or a failed environment pre-flight is not a behavioral result at all; it invalidates the run, and the run is re-executed.
|
|
187
|
+
|
|
188
|
+
Repeated runs of one probe are trials, and they reduce to one result per probe before any rate is computed. The `score` stage takes a trial set; the `score` command and `runScore` hand it one sealed run record per call, so a run scored from the published surface completes one trial, and against a policy declaring a minimum of three, as the worked example's does, its strength vector is reported and marked non-comparable.
|
|
163
189
|
|
|
164
190
|
## Using it
|
|
165
191
|
|
|
166
|
-
`eval-quality` is its own repository and package,
|
|
192
|
+
`eval-quality` is its own repository and package, with no framework around it.
|
|
167
193
|
|
|
168
|
-
The **library** is the primary surface. It exports the
|
|
194
|
+
The **library** is the primary surface. It exports the artifact types, the compiler, the pre-flight, `runScore`, the canonical digest, the lineage validator, and the failure-code and verdict registries. The Zod schemas themselves are not exported; they are published as JSON Schema under `eval-quality/schemas/*`. The published typed schema is what lets coding agents author contracts correctly by default, which is how the discipline scales beyond the people who went looking for the tool.
|
|
169
195
|
|
|
170
196
|
The **CLI** wraps the same library for callers that cannot import TypeScript: CI jobs, GitHub Actions, PR-review and unit-test bots, other frameworks' skills, and any agent permitted to run a shell command.
|
|
171
197
|
|
|
@@ -173,7 +199,8 @@ The **CLI** wraps the same library for callers that cannot import TypeScript: CI
|
|
|
173
199
|
|
|
174
200
|
- **`compile`**: Typechecks an authored `eval-contract.json`. Verifies that all behaviors, oracles, rubrics, and sensitivity witnesses comply with structural and authoring rules.
|
|
175
201
|
- **`seal`**: Generates a `sealed-evaluator-brief.json` by stripping secret defect signatures, planted answers, and author commentary. The brief carries only the directions and safety bounds the evaluator needs.
|
|
176
|
-
- **`preflight`**: Reduces caller-supplied probe observations against the contract to verify environment baseline readiness and probe reachability. Halts early with exit code `3` if the environment is unready.
|
|
202
|
+
- **`preflight`**: Reduces caller-supplied probe observations against the contract to verify environment baseline readiness and probe reachability. All four of `--contract`, `--probes`, `--observations`, and `--run-id` are required. Halts early with exit code `3` if the environment is unready. `schemas/probe.schema.json` gives the shape of one probe in the list; each observation echoes a planned leg's id back as `probeId`, and the getting-started tutorial writes six by hand.
|
|
203
|
+
- **`score`**: Chains ingest, score, and emit over one sealed run record, minting `evidence-artifact.json` and exiting with the AD-21 verdict's own exit code. `schemas/sealed-run-record.schema.json` gives the record's shape, and the committed worked chain under `_bmad-output/planning-artifacts/architecture/architecture-eval-quality-2026-07-29/spike-worked-example/` carries one, scored. `--record`, `--contract`, `--probe`, `--preflight-verdict`, `--policy`, and `--corpus-digest` are required; `--isolation-manifest` and `--evaluator-configuration` are each optional and their absence invalidates the run and the command still parses; `--private-manifest` is optional and, when given, each entry's declared digest is checked against its resolved bytes. `--corpus-root` names the directory a private reference resolves under, and is required only when `--private-manifest` or a private-storage isolation-manifest reference is actually present.
|
|
177
204
|
|
|
178
205
|
### Running the CLI
|
|
179
206
|
|
|
@@ -187,17 +214,25 @@ npx eval-quality seal --in contract.json --out ./eval-out
|
|
|
187
214
|
npx eval-quality preflight --contract contract.json \
|
|
188
215
|
--probes probes.json --observations observations.json \
|
|
189
216
|
--run-id 2026-08-28-a --out ./eval-out
|
|
217
|
+
|
|
218
|
+
npx eval-quality score --record record.json --contract contract.json \
|
|
219
|
+
--probe probe.json --preflight-verdict preflight-verdict.json \
|
|
220
|
+
--policy policy.json --corpus-digest <digest> \
|
|
221
|
+
--out ./eval-out
|
|
190
222
|
```
|
|
191
223
|
|
|
192
224
|
Every command is non-interactive: no prompt, no terminal check, and no behaviour that differs when
|
|
193
225
|
stdin is a pipe. Each one is a single call into the library plus artifact serialization.
|
|
194
226
|
|
|
195
|
-
**Input and output.**
|
|
196
|
-
|
|
227
|
+
**Input and output.** `--in` is the only input that falls back to stdin: `compile` and `seal` read it
|
|
228
|
+
when `--in` is left out. `-` names stdin explicitly on any input, and at most one input may be `-` per
|
|
229
|
+
invocation. `compile` and `seal` each take one input; `preflight` takes three, all required; `score`
|
|
230
|
+
takes eight, three of them optional (`--isolation-manifest`, `--evaluator-configuration`, and
|
|
231
|
+
`--private-manifest`). Without `--out` the artifact goes to stdout, so a command composes with a pipe.
|
|
197
232
|
An `--out` ending in `.json` is a file path; anything else is a directory, and the artifact is
|
|
198
|
-
written to `<target>/<kind>.json` where `kind` is `eval-contract`, `sealed-evaluator-brief`,
|
|
199
|
-
`preflight-verdict`. Diagnostics and errors go to stderr, always, so stdout
|
|
200
|
-
alone.
|
|
233
|
+
written to `<target>/<kind>.json` where `kind` is `eval-contract`, `sealed-evaluator-brief`,
|
|
234
|
+
`preflight-verdict`, or `evidence-artifact`. Diagnostics and errors go to stderr, always, so stdout
|
|
235
|
+
carries the artifact alone.
|
|
201
236
|
|
|
202
237
|
**Exit codes.**
|
|
203
238
|
|
|
@@ -206,18 +241,21 @@ alone.
|
|
|
206
241
|
| `0` | success, and every verdict other than FAIL or a promoted CONCERNS |
|
|
207
242
|
| `1` | CONCERNS promoted by `--strict` |
|
|
208
243
|
| `2` | FAIL |
|
|
209
|
-
| `3` | invalid: a pre-flight
|
|
244
|
+
| `3` | invalid: a failed pre-flight, or any other AD-21 invalidating condition |
|
|
210
245
|
| `4` | structural failure |
|
|
211
246
|
| `5` | runtime fault |
|
|
212
247
|
| `64` | usage error |
|
|
213
248
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
249
|
+
`--strict` never promotes a CONCERNS whose firing conditions are all evidence conditions: those
|
|
250
|
+
conditions report that the measurement fell short of the policy. Codes 1 and 2 report a verdict
|
|
251
|
+
`score`'s ladder resolved, read directly off `LadderResolution.exitCode`; every other invalidating
|
|
252
|
+
condition behind code 3 is reachable through `score` too, alongside the failed pre-flight `preflight`
|
|
253
|
+
itself reports.
|
|
217
254
|
|
|
218
255
|
`--strict` is the gate-promotion flag and is accepted on every command. `--strict-inputs` and
|
|
219
256
|
`--no-strict-inputs` are a different switch: they set the compiler's input strictness, which is on
|
|
220
|
-
by default
|
|
257
|
+
by default, and `preflight` and `score` each reject both with exit `64` because neither has a compile
|
|
258
|
+
step.
|
|
221
259
|
|
|
222
260
|
**The published JSON Schema.** A consumer that does not read TypeScript validates against the
|
|
223
261
|
twelve generated documents, published at the `eval-quality/schemas/*` subpath:
|
|
@@ -229,6 +267,17 @@ import spec from 'eval-quality/schemas/eval-contract.schema.json' with { type: '
|
|
|
229
267
|
The import attribute is required: ESM on Node 22 and 24 both throw `ERR_IMPORT_ATTRIBUTE_MISSING`
|
|
230
268
|
without it. The development corpus ships the same way, at `eval-quality/corpus/dev/`, so an adopter
|
|
231
269
|
can read real compiled contracts and one compiled-and-sealed pair without cloning this repository.
|
|
270
|
+
`eval-quality/adapters` is one of the five published subpaths, holding the three reference adapters
|
|
271
|
+
the conformance suite runs against.
|
|
272
|
+
|
|
273
|
+
Eleven of the twelve published schemas carry a `schemaVersion`. `artifact-reference` is exempt: it
|
|
274
|
+
is embedded inside other artifacts, so it has no version to break.
|
|
275
|
+
|
|
276
|
+
`schemaVersion` is declared as any integer at or above 1, so a document at an unexpected version
|
|
277
|
+
parses. The bumps in the next release each add a required field, which is why an older document
|
|
278
|
+
fails; the version itself is compared in exactly one place, `validateLineageChain`, over
|
|
279
|
+
lineage-chain members, and nowhere on the command path. The package is pre-1.0, so pin exactly.
|
|
280
|
+
`CHANGELOG.md` records what each release breaks.
|
|
232
281
|
|
|
233
282
|
## Relationship with BMad and TEA
|
|
234
283
|
|
|
@@ -241,7 +290,7 @@ graph LR
|
|
|
241
290
|
|
|
242
291
|
TEA is the reference authoring client. It reads BMad planning artifacts, notices eval-relevant work, drafts a contract, and calls this package. It is not co-installed, and `eval-quality` holds no knowledge of TEA, BMad, or any planning-artifact format.
|
|
243
292
|
|
|
244
|
-
Any human, bot, CI job, skill, or other framework can author a contract and use `eval-quality` directly. The discipline still applies, because the compiler judges the artifact
|
|
293
|
+
Any human, bot, CI job, skill, or other framework can author a contract and use `eval-quality` directly. The discipline still applies, because the compiler judges the artifact, whoever produced it.
|
|
245
294
|
|
|
246
295
|
Evaluator runs remain isolated to prevent builder-context leakage and preserve traceability. Stronger contract oracles produced the measured detection improvement.
|
|
247
296
|
|
|
@@ -249,7 +298,9 @@ Evaluator runs remain isolated to prevent builder-context leakage and preserve t
|
|
|
249
298
|
1. Author an `eval-contract.json` declaring required knowledge step files (e.g. `playwright-utils-mandate.md`).
|
|
250
299
|
2. Run `eval-quality compile --in contract.json` to validate contract structure and discipline rules.
|
|
251
300
|
3. Run `eval-quality seal --in contract.json --out ./run` to generate `sealed-evaluator-brief.json`.
|
|
252
|
-
4.
|
|
301
|
+
4. Probe the harness's environment and run `eval-quality preflight` over the observations; a verdict that does not pass is exit `3`, and the run stops there.
|
|
302
|
+
5. Pass `sealed-evaluator-brief.json` to `bmad-tea` to execute the task without seeing answer keys, once against the clean harness and once against a harness with one known step file removed.
|
|
303
|
+
6. Seal each evaluator run into a `sealed-run-record.json` and run `eval-quality score` over it with the probe that names the removed file as the seeded defect. The clean run should pass; the mutated run should degrade, and the exit code says which.
|
|
253
304
|
|
|
254
305
|
## Evidence and limitations
|
|
255
306
|
|
|
@@ -261,13 +312,13 @@ Read the [product brief](_bmad-output/planning-artifacts/briefs/brief-eval-quali
|
|
|
261
312
|
|
|
262
313
|
## Architecture status
|
|
263
314
|
|
|
264
|
-
The [architecture spine](_bmad-output/planning-artifacts/architecture/architecture-eval-quality-2026-07-29/ARCHITECTURE-SPINE.md) is split by pipeline half
|
|
315
|
+
The [architecture spine](_bmad-output/planning-artifacts/architecture/architecture-eval-quality-2026-07-29/ARCHITECTURE-SPINE.md) is split by pipeline half, and its own status line still reads that the compile-and-seal half is epic-ready while the score half is not. The code has moved past that line. Epic 7 delivered AD-21, AD-33, and AD-40 as pure functions with generated tables, and epic 8 shipped the `ingest`, `score`, and `emit` stages, the `score` command, and `runScore` over them, which closes every item the spine's *Owed to the reference implementation* section listed. The `score` stage consumes a trial set; the command and `runScore` hand it one record per call, so a run scored from the published surface completes one trial, and whenever the policy's declared minimum exceeds one its strength vector is reported and marked non-comparable. Gate C closed at zero blocking authoring points and 14 of 14 declaration-only predicates. Gate D's generated-current-fields arm matched the hand-written positive control at 3 of 3 seeded-defect catches, so `seal` joins the stage-one order without adding an evidence-precondition field.
|
|
265
316
|
|
|
266
|
-
Contract strength scoring has been open since [ADR-007](_bmad-output/planning-artifacts/architecture/architecture-eval-quality-2026-07-29/ADR-007-compile-score-split.md): three rounds of external review established that the catch rate was 1.00 by construction, because nothing matched a finding to the defect its probe seeded. That input now exists and the mapping that reads it is owed
|
|
317
|
+
Contract strength scoring has been open since [ADR-007](_bmad-output/planning-artifacts/architecture/architecture-eval-quality-2026-07-29/ADR-007-compile-score-split.md): three rounds of external review established that the catch rate was 1.00 by construction, because nothing matched a finding to the defect its probe seeded. That input now exists, and so does the mapping that reads it: `src/core/score/witness.ts` is AD-40's witness match, delivered by epic 7. What is still owed is its validation against the block-2 replication, which the spine records as committed and not yet run.
|
|
267
318
|
|
|
268
319
|
Contract compilation was declared ready in ADR-007 and a fourth review withdrew that claim in [ADR-008](_bmad-output/planning-artifacts/architecture/architecture-eval-quality-2026-07-29/ADR-008-compile-half-owed-to-calibration.md). The named calibration is now complete. The absent local-only mut2 arm was reconstructed from its recorded base, reproduced its prior black-box behavior, and ran under a pre-registered three-arm, three-repetition design. All three arms composed filters and detected the seeded defect in every valid repetition. This closes the calibration gate narrowly; it does not generalize the historical 0.33-to-1.00 effect beyond one behavior and one controlled mutation.
|
|
269
320
|
|
|
270
|
-
Both are documented as defects
|
|
321
|
+
Both are documented as defects, because four rounds have shown that a confidently worded revision is the thing that goes wrong here.
|
|
271
322
|
|
|
272
323
|
The decision record, in order: [ADR-001](_bmad-output/planning-artifacts/architecture/architecture-eval-quality-2026-07-22/ADR-001-evaluator-isolation-boundary.md) on evaluator isolation, [ADR-002](_bmad-output/planning-artifacts/architecture/architecture-eval-quality-2026-07-22/ADR-002-contract-authoring-discipline.md) on why authoring discipline is the product, [ADR-003](_bmad-output/planning-artifacts/architecture/architecture-eval-quality-2026-07-29/ADR-003-measurement-mechanics.md) on measurement mechanics, [ADR-004](_bmad-output/planning-artifacts/architecture/architecture-eval-quality-2026-07-29/ADR-004-execution-boundary.md) on why this package executes nothing, [ADR-005](_bmad-output/planning-artifacts/architecture/architecture-eval-quality-2026-07-29/ADR-005-review-round-corrections.md) and [ADR-006](_bmad-output/planning-artifacts/architecture/architecture-eval-quality-2026-07-29/ADR-006-interaction-plan.md) on what review and hand-authoring corrected, [ADR-007](_bmad-output/planning-artifacts/architecture/architecture-eval-quality-2026-07-29/ADR-007-compile-score-split.md) on the split, [ADR-008](_bmad-output/planning-artifacts/architecture/architecture-eval-quality-2026-07-29/ADR-008-compile-half-owed-to-calibration.md) on why the other half stopped claiming to be finished too, and [ADR-009](_bmad-output/planning-artifacts/architecture/architecture-eval-quality-2026-07-29/ADR-009-adversarial-gate-corrections.md) on the seventeen places where two conforming implementations still disagreed. Review triage lives in [`reviews/`](_bmad-output/planning-artifacts/architecture/architecture-eval-quality-2026-07-29/reviews/).
|
|
273
324
|
|
|
@@ -279,28 +330,38 @@ Out of scope entirely: a new eval engine, a hosted service, a dashboard or GUI,
|
|
|
279
330
|
|
|
280
331
|
## Development
|
|
281
332
|
|
|
333
|
+
Node `>=22.20.0`, which `package.json` declares as the engine floor. `zod` is the only production
|
|
334
|
+
dependency.
|
|
335
|
+
|
|
282
336
|
```bash
|
|
283
337
|
npm install
|
|
284
|
-
npm run validate # typecheck, lint, docs, shareable, spine, vectors, schemas, registries, AD-31
|
|
338
|
+
npm run validate # build, typecheck, lint, docs, doc invocations, shareable, spine, vectors, schemas, both code registries, the AD-21, AD-31 and AD-33 tables, layers, lineage, boundary, corpus, worked chain, website deps, tests with coverage
|
|
285
339
|
npm run build # emit to dist/
|
|
286
340
|
npm run lint:fix # auto-fix with Biome
|
|
287
341
|
npm run test:coverage # run the suite and fail below AD-30's 90 percent statement and branch floor on core/
|
|
288
342
|
npm run generate:schemas # rebuild schemas/*.schema.json from the Zod source
|
|
289
343
|
npm run check:schemas # fail if the committed schemas differ from the source by one byte
|
|
290
|
-
npm run check:ad5-registry # fail if the failure-code list drifts from the AD-5 table
|
|
344
|
+
npm run check:ad5-registry # fail if the compile-time failure-code list drifts from the AD-5 table
|
|
345
|
+
npm run check:ad28-registry # fail if the runtime fault-code list drifts from the AD-28 table
|
|
291
346
|
npm run check:lineage # fail if a module outside the stage table writes an artifact's lineage fields
|
|
292
347
|
npm run check:boundary # fail if anything the tarball carries references the planning system that produced it
|
|
348
|
+
npm run generate:ad21-table # rebuild docs/ad21-verdict-decision.generated.md from the two verdict ladders
|
|
349
|
+
npm run check:ad21-table # fail if the committed AD-21 table differs from the builder by one byte
|
|
293
350
|
npm run generate:ad31-table # rebuild docs/ad31-coverage-predicates.generated.md from the predicates
|
|
294
351
|
npm run check:ad31-table # fail if the committed AD-31 table differs from the builder by one byte
|
|
352
|
+
npm run generate:ad33-table # rebuild docs/ad33-outcome-decision.generated.md from the decision procedure
|
|
353
|
+
npm run check:ad33-table # fail if the committed AD-33 table differs from the builder by one byte
|
|
295
354
|
npm run generate:dev-corpus # rebuild corpus/dev/ from the contract fixtures through the shipped compile and seal
|
|
296
355
|
npm run check:corpus # fail if the committed corpus differs from the builder by one byte
|
|
356
|
+
npm run generate:worked-example # rebuild the spike worked chain by running the compile, seal, score, and emit functions over it
|
|
357
|
+
npm run check:worked-example # fail if the committed worked chain differs from the builder by one byte
|
|
297
358
|
npm run build:shareable # render the planning artifacts to self-contained HTML
|
|
298
359
|
npm run test:conformance # run the published port conformance suite against every shipped adapter
|
|
299
360
|
```
|
|
300
361
|
|
|
301
362
|
`schemas/` holds the twelve published JSON Schema documents, generated from the Zod definitions and
|
|
302
363
|
committed. They are the contract for consumers who do not read TypeScript, so they are proven
|
|
303
|
-
equivalent to the source
|
|
364
|
+
equivalent to the source: a byte-exact drift check, a rejection suite
|
|
304
365
|
asserting the validator keyword and instance path for every negative fixture, a differential check
|
|
305
366
|
comparing Zod's verdict against a third-party validator's over a generated corpus, and a
|
|
306
367
|
keyword-mutation sweep that deletes each published constraint and requires some fixture to notice.
|
|
@@ -311,15 +372,16 @@ is ES modules, which are always strict, so an attempt throws a `TypeError` there
|
|
|
311
372
|
caller sees the write fail silently. A revision is minted as a new artifact carrying its parent's
|
|
312
373
|
digest and a revision count one greater. `check:lineage` fails the build when a lineage field is
|
|
313
374
|
written outside `src/core/schemas/`, `src/core/lineage/`, and the modules the AD-24 stage table
|
|
314
|
-
names as that artifact's producer, which today are `src/core/seal/seal.ts
|
|
315
|
-
`src/core/preflight/reduce.ts`.
|
|
375
|
+
names as that artifact's producer, which today are `src/core/seal/seal.ts`,
|
|
376
|
+
`src/core/preflight/reduce.ts`, and `src/core/emit/emit.ts`.
|
|
316
377
|
|
|
317
378
|
The `eval-quality/conformance` subpath publishes the port boundary: the four port types, the message
|
|
318
|
-
shapes they carry,
|
|
379
|
+
shapes they carry, the AD-28 `RUNTIME_FAULT_CODES` registry and `RuntimeFaultCode` type a conforming
|
|
380
|
+
adapter throws against, and an executable conformance suite. An adapter is conforming when
|
|
319
381
|
`runCorpusPortConformance`, `runClockPortConformance`, `runFileSystemPortConformance`, or
|
|
320
|
-
`runEnvironmentProbePortConformance` returns a report whose `passed` is true, which is the definition
|
|
321
|
-
|
|
322
|
-
|
|
382
|
+
`runEnvironmentProbePortConformance` returns a report whose `passed` is true, which is the definition;
|
|
383
|
+
each returns a report, so the suite carries no test framework and runs under whichever one you
|
|
384
|
+
already use.
|
|
323
385
|
|
|
324
386
|
```ts
|
|
325
387
|
import { runCorpusPortConformance, type CorpusPort } from 'eval-quality/conformance'
|
|
@@ -327,20 +389,33 @@ import { runCorpusPortConformance, type CorpusPort } from 'eval-quality/conforma
|
|
|
327
389
|
|
|
328
390
|
The suite drives a subject through four scenarios and checks six assertions per port method: a
|
|
329
391
|
mechanism failure is a typed fault, exactly one underlying call happens on success and on failure, an
|
|
330
|
-
aborted signal rejects promptly, an in-band error value is thrown
|
|
392
|
+
aborted signal rejects promptly, an in-band error value is thrown as a fault, and a
|
|
331
393
|
successful call returns a response the published schema accepts. The environment-probe port adds
|
|
332
394
|
thirteen more from AD-35's default-deny target policy. `npm run test:conformance` runs the suite
|
|
333
395
|
against the three adapters this package ships and against an in-repository probe subject that exists
|
|
334
396
|
only as the suite's own subject.
|
|
335
397
|
|
|
398
|
+
`docs/ad21-verdict-decision.generated.md` holds AD-21's two published verdict ladders, production and
|
|
399
|
+
contract-scoring, emitted from the rule tables in `src/core/score/ladder.ts` together with the
|
|
400
|
+
fixtures that exercise them, and guarded by `npm run check:ad21-table`. Each row carries its
|
|
401
|
+
condition, its rung, the guard in prose, and whether `--strict` may promote it.
|
|
402
|
+
|
|
336
403
|
`docs/ad31-coverage-predicates.generated.md` holds AD-31's published predicate table, emitted from
|
|
337
404
|
the seven relevance predicates and their seven satisfaction twins run over a hand-authored contract
|
|
338
405
|
corpus. It is generated by `npm run generate:ad31-table` and guarded by `npm run check:ad31-table`,
|
|
339
406
|
a byte-exact drift check that fails when a predicate changes and the committed document does not, so
|
|
340
|
-
the table is evidence the predicates produce
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
407
|
+
the table is evidence the predicates produce. A hand edit fails the check; regenerate.
|
|
408
|
+
|
|
409
|
+
`docs/ad33-outcome-decision.generated.md` holds AD-33's published decision table: the ten
|
|
410
|
+
invalidating conditions, the twenty-row outcome ladder, the two waiver rules, the eight
|
|
411
|
+
corroboration rules, the named structural constraints with the infeasible input pairs derived from
|
|
412
|
+
them, and five censuses over the fixture set. It is generated by `npm run generate:ad33-table` and
|
|
413
|
+
guarded by `npm run check:ad33-table`, the same byte-exact drift check, and the builder refuses to
|
|
414
|
+
publish a census cell at zero, so a rule or a state losing its last fixture fails the build. AD-33
|
|
415
|
+
puts a cell-per-input-tuple table out of arithmetic reach, so what is published is the enumerated
|
|
416
|
+
output of the total function itself. A hand edit fails the check; regenerate.
|
|
417
|
+
|
|
418
|
+
`build:shareable` renders this README, the product brief, the PRD, the architecture spine, all nine ADRs, and every document those pages link to (contributing, code of conduct, security, licence, and the four experiment records) to `_bmad-output/shareable/` as standalone styled HTML for sharing outside the repo. Rendering the linked documents is what lets a recipient without repository access follow the evidence, contribution, security, and licence links; anything that has no page of its own, such as a directory, is marked in the export as needing repository access. A hand edit fails the check; regenerate: `check:shareable` fails the build when the committed export is stale or carries a repository URL that is not the canonical one. Mermaid diagrams render as code blocks there, which is a known limitation.
|
|
344
419
|
|
|
345
420
|
## Contributing
|
|
346
421
|
|
package/corpus/dev/README.md
CHANGED
|
@@ -6,8 +6,9 @@ this package without cloning the repository. Everything here is generated by
|
|
|
6
6
|
|
|
7
7
|
## What is here
|
|
8
8
|
|
|
9
|
-
- `contracts/<contractId>.json`:
|
|
10
|
-
declaration state
|
|
9
|
+
- `contracts/<contractId>.json`: twenty-one contracts. Nineteen are one per AD-20 discipline
|
|
10
|
+
rule in each declaration state, and two describe a system under test that runs behind a command
|
|
11
|
+
rather than over HTTP. Eighteen are published only after this package's own compile stage accepts
|
|
11
12
|
them, so every one of those is a contract the compiler admits. Three fail compilation by design;
|
|
12
13
|
those ship as authored input, and `index.json` records the failure code each one raises.
|
|
13
14
|
- `compile-seal-example/contract.json` and `compile-seal-example/brief.json`: one contract and
|
|
@@ -23,14 +24,20 @@ contract's strength is a separate thing this package does not ship.
|
|
|
23
24
|
## What is absent, and why
|
|
24
25
|
|
|
25
26
|
**The qualified-probe dimensions are absent.** AD-38 asks for at least one qualified probe per
|
|
26
|
-
probe class and per `expectedClean` state.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
27
|
+
probe class and per `expectedClean` state. The probe schema now carries both halves qualification
|
|
28
|
+
needs: AD-9's per-route qualification record and AD-40's machine-readable defect signature, with a
|
|
29
|
+
corpus gate that admits a probe only when the two agree with its class. The trial reducer and the
|
|
30
|
+
score stage that reads it are both shipped, so an admitted probe can be scored end to end today;
|
|
31
|
+
what is still missing is this directory's own gate widening to require at least one such probe. The
|
|
32
|
+
dimension arrives with the change that adds that gate.
|
|
33
|
+
|
|
34
|
+
**Three of the four artifacts in AD-38's end-to-end example are absent here.** The example there is
|
|
35
|
+
a sealed brief, a conforming sealed run record, an isolation manifest, and an evaluator
|
|
36
|
+
configuration. The last three are inputs the shipped `ingest` stage consumes, authored for the
|
|
37
|
+
worked example in `scripts/worked-example-target.ts` and exercised there through
|
|
38
|
+
`ingest`/`score`/`emit`. Only the run record among them is committed, as
|
|
39
|
+
`spike-worked-example/sealed-run-record.json`; the isolation manifest and the evaluator
|
|
40
|
+
configuration exist only as the authored values that build passes to `ingest`, never serialized to
|
|
41
|
+
a file. This directory still ships only the compile-and-seal pair, scoped to what a corpus of
|
|
42
|
+
contracts needs,
|
|
43
|
+
under a name that does not claim AD-38's term.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"behaviors":[{"description":"A created thing is readable back in the list of things.","id":"B-001","observableSuccessCriterion":"A list call after a create returns one element per seeded thing, carrying the name the create call sent.","oracles":["O-001","O-002","O-003","O-004","O-005","O-006","O-007"],"requirementLinks":[{"id":"REQ-1","scheme":"local"}],"riskLinks":[{"id":"RISK-1","scheme":"local-risk"}],"severity":"critical"}],"budgets":{"maxCostUsd":"0.25","maxToolCalls":20,"maxWallClockMinutes":5},"contractDigest":"sha256:
|
|
1
|
+
{"behaviors":[{"description":"A created thing is readable back in the list of things.","id":"B-001","observableSuccessCriterion":"A list call after a create returns one element per seeded thing, carrying the name the create call sent.","oracles":["O-001","O-002","O-003","O-004","O-005","O-006","O-007"],"requirementLinks":[{"id":"REQ-1","scheme":"local"}],"riskLinks":[{"id":"RISK-1","scheme":"local-risk"}],"severity":"critical"}],"budgets":{"maxCostUsd":"0.25","maxToolCalls":20,"maxWallClockMinutes":5},"contractDigest":"sha256:7ca80def8afa456f9afa171dbdbe7be9c7c9c9b799cf7bedfa5f6a0db71cd0a9","directions":[{"oracleId":"O-001","text":"Its items field from the list things endpoint (with the supplied query limit) is asserted to satisfy the declared \"covers-by-key\" condition. The declared polarity expects this relation to hold. One list call over the seeded set. A list omitting a seeded thing, or repeating one is treated as a defect."},{"oracleId":"O-002","text":"The create thing endpoint (with the supplied body name): its error field, its id field, and its ok field is asserted to satisfy every declared condition together. The declared polarity expects this relation to hold. The whole create response. A create reporting success with no identifier, or with a diagnostic beside it is treated as a defect."},{"oracleId":"O-003","text":"The list things endpoint (with the supplied query limit): its error field and its items field is asserted to satisfy every declared condition together. The declared polarity expects this relation to hold. The list response taken as a whole. A list carrying items alongside a diagnostic field is treated as a defect."},{"oracleId":"O-004","text":"Its error field from the create thing endpoint (with a malformed body name value) and its error field from the list things endpoint (with a malformed query limit value) is asserted to satisfy every declared condition together. The declared polarity expects this relation to hold. Both sibling operations, each given an input that violates its declared type. One sibling rejecting the malformed input while the other accepts it is treated as a defect."},{"oracleId":"O-005","text":"The body name value you sent to the create thing endpoint (with the supplied body name), compared with the query limit value you sent to the list things endpoint (with the supplied query limit) is asserted to satisfy every declared condition together. The declared polarity expects this relation to hold. The two sibling parameters, as sent. One parameter carried and the other dropped is treated as a defect."},{"oracleId":"O-006","text":"The body name value you sent to the create thing endpoint (with the supplied body name), compared with its items field from the list things endpoint (with the supplied query limit) is asserted to contain the declared member. The declared polarity expects this relation to hold. The list read after the create, against the name the create sent. A create reporting success whose thing never appears in a later list is treated as a defect."},{"oracleId":"O-007","text":"Every element reachable through its items field from the list things endpoint (with the supplied query limit) is asserted to meet the declared condition. The declared polarity expects this relation to hold. Every element of the returned list. A list whose first element carries an identifier and whose later elements do not is treated as a defect."}],"parentDigest":null,"permittedInterfaces":[{"kind":"api","logicalId":"thing-api"}],"principals":[],"probeStepBound":8,"revisionCount":0,"safetyLimits":["No request to any host other than the mapped thing-api target."],"schemaVersion":2,"scopedResources":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"behaviors":[{"description":"A created thing is readable back in the list of things.","id":"B-001","observableSuccessCriterion":"A list call after a create returns one element per seeded thing, carrying the name the create call sent.","oracles":["O-001","O-002","O-003","O-004","O-005","O-006","O-007"],"requirementLinks":[{"id":"REQ-1","scheme":"local"}],"riskLinks":[{"id":"RISK-1","scheme":"local-risk"}],"severity":"critical"}],"budgets":{"maxCostUsd":"0.25","maxToolCalls":20,"maxWallClockMinutes":5},"contractId":"satisfied-declarations","fixtureReset":null,"forbiddenInputs":["original-spec","source-code","repository","builder-transcript","implementation-logs","comparator-results","human-labels"],"interactionPlan":[{"after":null,"inputBinding":{"body":{"name":{"matcher":"any"}},"header":null,"path":null,"query":null},"operationId":"create-thing","stepId":"create"},{"after":"create","inputBinding":{"body":null,"header":null,"path":null,"query":{"limit":{"literal":10}}},"operationId":"list-things","stepId":"list"},{"after":null,"inputBinding":{"body":{"name":{"matcher":"type-violating"}},"header":null,"path":null,"query":null},"operationId":"create-thing","stepId":"malformed-create"},{"after":null,"inputBinding":{"body":null,"header":null,"path":null,"query":{"limit":{"matcher":"type-violating"}}},"operationId":"list-things","stepId":"malformed-list"}],"oracles":[{"check":{"actualKey":"id","expectedKey":"id","op":"covers-by-key","operands":[{"referenceSet":"expected-things"},{"pointer":"/interactions/list/response-body/items"}]},"commentary":"Reconciles the whole list against the declared set.","direction":{"evidenceTargets":["/interactions/list/response-body/items"],"negativeDomain":"A list omitting a seeded thing, or repeating one.","polarity":"expects-hold","relation":"covers-by-key","scope":"One list call over the seeded set."},"id":"O-001","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/create/response-body/ok"}]},{"op":"existence","operands":[{"pointer":"/interactions/create/response-body/id"}]},{"op":"absence","operands":[{"pointer":"/interactions/create/response-body/error"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/create/response-body/ok","/interactions/create/response-body/id","/interactions/create/response-body/error"],"negativeDomain":"A create reporting success with no identifier, or with a diagnostic beside it.","polarity":"expects-hold","relation":"all","scope":"The whole create response."},"id":"O-002","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/list/response-body/items"}]},{"op":"absence","operands":[{"pointer":"/interactions/list/response-body/error"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/list/response-body/items","/interactions/list/response-body/error"],"negativeDomain":"A list carrying items alongside a diagnostic field.","polarity":"expects-hold","relation":"all","scope":"The list response taken as a whole."},"id":"O-003","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/malformed-create/response-body/error"}]},{"op":"existence","operands":[{"pointer":"/interactions/malformed-list/response-body/error"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/malformed-create/response-body/error","/interactions/malformed-list/response-body/error"],"negativeDomain":"One sibling rejecting the malformed input while the other accepts it.","polarity":"expects-hold","relation":"all","scope":"Both sibling operations, each given an input that violates its declared type."},"id":"O-004","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/create/call-inputs/body/name"}]},{"op":"existence","operands":[{"pointer":"/interactions/list/call-inputs/query/limit"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/create/call-inputs/body/name","/interactions/list/call-inputs/query/limit"],"negativeDomain":"One parameter carried and the other dropped.","polarity":"expects-hold","relation":"all","scope":"The two sibling parameters, as sent."},"id":"O-005","polarity":"expects-hold"},{"check":{"op":"containment","operands":[{"pointer":"/interactions/list/response-body/items"},{"pointer":"/interactions/create/call-inputs/body/name"}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/list/response-body/items","/interactions/create/call-inputs/body/name"],"negativeDomain":"A create reporting success whose thing never appears in a later list.","polarity":"expects-hold","relation":"containment","scope":"The list read after the create, against the name the create sent."},"id":"O-006","polarity":"expects-hold"},{"check":{"collection":{"pointer":"/interactions/list/response-body/items"},"op":"for-all","predicate":{"op":"existence","operands":[{"pointer":"@/id"}]}},"commentary":null,"direction":{"evidenceTargets":["/interactions/list/response-body/items"],"negativeDomain":"A list whose first element carries an identifier and whose later elements do not.","polarity":"expects-hold","relation":"for-all","scope":"Every element of the returned list."},"id":"O-007","polarity":"expects-hold"}],"parentDigest":null,"permittedInterfaces":[{"kind":"api","logicalId":"thing-api","operations":[{"method":"POST","operationId":"create-thing","pathTemplate":"/things","requestShape":{"body":{"permittedKeys":["name"],"requiredKeys":["name"],"types":{"name":"string"}},"header":{"permittedKeys":[],"requiredKeys":[],"types":{}},"path":{"permittedKeys":[],"requiredKeys":[],"types":{}},"query":{"permittedKeys":[],"requiredKeys":[],"types":{}}},"responseDescriptor":{"channelRoles":{"/error":"diagnostic","/id":"payload","/ok":"success-indicator"},"collectionLocations":[],"permittedKeys":["id","ok","error"],"requiredKeys":["id","ok"],"successIndicator":"/ok","types":{"error":"string","id":"string","ok":"boolean"}},"sensitivityWitness":{"channel":"body","legs":[{"inputs":{"body":{"kind":"json","value":{"name":"alpha"}},"header":{},"path":{},"query":{}},"legId":"create-witness-a"},{"inputs":{"body":{"kind":"json","value":{"name":"beta"}},"header":{},"path":{},"query":{}},"legId":"create-witness-b"}],"relation":{"op":"not","operands":[{"op":"deep-equality","operands":[{"pointer":"/interactions/create-witness-a/response-body"},{"pointer":"/interactions/create-witness-b/response-body"}]}]},"witnessId":"create-thing-sensitivity"},"stateChangeMarker":true,"volatilePointers":["/id"]},{"method":"GET","operationId":"list-things","pathTemplate":"/things","requestShape":{"body":{"permittedKeys":[],"requiredKeys":[],"types":{}},"header":{"permittedKeys":[],"requiredKeys":[],"types":{}},"path":{"permittedKeys":[],"requiredKeys":[],"types":{}},"query":{"permittedKeys":["limit"],"requiredKeys":[],"types":{"limit":"number"}}},"responseDescriptor":{"channelRoles":{"/error":"diagnostic","/items":"collection"},"collectionLocations":[{"expectedCardinality":{"count":3,"mode":"exact"},"pointer":"/items","referenceSet":"expected-things"}],"permittedKeys":["items","error"],"requiredKeys":["items"],"successIndicator":"/items","types":{"error":"string","items":"array"}},"sensitivityWitness":{"channel":"query","legs":[{"inputs":{"body":{"kind":"absent"},"header":{},"path":{},"query":{"limit":1}},"legId":"list-witness-a"},{"inputs":{"body":{"kind":"absent"},"header":{},"path":{},"query":{"limit":2}},"legId":"list-witness-b"}],"relation":{"op":"not","operands":[{"op":"deep-equality","operands":[{"pointer":"/interactions/list-witness-a/response-body"},{"pointer":"/interactions/list-witness-b/response-body"}]}]},"witnessId":"list-things-sensitivity"},"stateChangeMarker":false,"volatilePointers":[]}]}],"probeStepBound":8,"referenceSets":{"expected-things":{"commentary":null,"keys":["id"],"members":[{"id":"t-1"},{"id":"t-2"},{"id":"t-3"}]}},"requiredEvidence":["Request and response pair for every call, in order."],"revisionCount":0,"rubrics":[{"criteria":[{"evidence":"/interactions/list/response-body/items","id":"RC-001","text":"Does the returned list carry every expected identifier?"}],"failureModePenalties":[{"description":"An expected thing is missing.","name":"omission"}],"id":"R-001","maxLength":400,"scaleLevels":[{"anchor":"Every expected thing is present.","level":1}]}],"safetyLimits":["No request to any host other than the mapped thing-api target."],"schemaVersion":
|
|
1
|
+
{"behaviors":[{"description":"A created thing is readable back in the list of things.","id":"B-001","observableSuccessCriterion":"A list call after a create returns one element per seeded thing, carrying the name the create call sent.","oracles":["O-001","O-002","O-003","O-004","O-005","O-006","O-007"],"requirementLinks":[{"id":"REQ-1","scheme":"local"}],"riskLinks":[{"id":"RISK-1","scheme":"local-risk"}],"severity":"critical"}],"budgets":{"maxCostUsd":"0.25","maxToolCalls":20,"maxWallClockMinutes":5},"contractId":"satisfied-declarations","fixtureReset":null,"forbiddenInputs":["original-spec","source-code","repository","builder-transcript","implementation-logs","comparator-results","human-labels"],"interactionPlan":[{"after":null,"cardinality":"exactly-one","inputBinding":{"body":{"name":{"matcher":"any"}},"header":null,"path":null,"query":null},"operationId":"create-thing","stepId":"create"},{"after":"create","cardinality":"exactly-one","inputBinding":{"body":null,"header":null,"path":null,"query":{"limit":{"literal":10}}},"operationId":"list-things","stepId":"list"},{"after":null,"cardinality":"exactly-one","inputBinding":{"body":{"name":{"matcher":"type-violating"}},"header":null,"path":null,"query":null},"operationId":"create-thing","stepId":"malformed-create"},{"after":null,"cardinality":"exactly-one","inputBinding":{"body":null,"header":null,"path":null,"query":{"limit":{"matcher":"type-violating"}}},"operationId":"list-things","stepId":"malformed-list"}],"oracles":[{"check":{"actualKey":"id","expectedKey":"id","op":"covers-by-key","operands":[{"referenceSet":"expected-things"},{"pointer":"/interactions/list/response-body/items"}]},"commentary":"Reconciles the whole list against the declared set.","direction":{"evidenceTargets":["/interactions/list/response-body/items"],"negativeDomain":"A list omitting a seeded thing, or repeating one.","polarity":"expects-hold","relation":"covers-by-key","scope":"One list call over the seeded set."},"id":"O-001","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/create/response-body/ok"}]},{"op":"existence","operands":[{"pointer":"/interactions/create/response-body/id"}]},{"op":"absence","operands":[{"pointer":"/interactions/create/response-body/error"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/create/response-body/ok","/interactions/create/response-body/id","/interactions/create/response-body/error"],"negativeDomain":"A create reporting success with no identifier, or with a diagnostic beside it.","polarity":"expects-hold","relation":"all","scope":"The whole create response."},"id":"O-002","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/list/response-body/items"}]},{"op":"absence","operands":[{"pointer":"/interactions/list/response-body/error"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/list/response-body/items","/interactions/list/response-body/error"],"negativeDomain":"A list carrying items alongside a diagnostic field.","polarity":"expects-hold","relation":"all","scope":"The list response taken as a whole."},"id":"O-003","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/malformed-create/response-body/error"}]},{"op":"existence","operands":[{"pointer":"/interactions/malformed-list/response-body/error"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/malformed-create/response-body/error","/interactions/malformed-list/response-body/error"],"negativeDomain":"One sibling rejecting the malformed input while the other accepts it.","polarity":"expects-hold","relation":"all","scope":"Both sibling operations, each given an input that violates its declared type."},"id":"O-004","polarity":"expects-hold"},{"check":{"op":"all","operands":[{"op":"existence","operands":[{"pointer":"/interactions/create/call-inputs/body/name"}]},{"op":"existence","operands":[{"pointer":"/interactions/list/call-inputs/query/limit"}]}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/create/call-inputs/body/name","/interactions/list/call-inputs/query/limit"],"negativeDomain":"One parameter carried and the other dropped.","polarity":"expects-hold","relation":"all","scope":"The two sibling parameters, as sent."},"id":"O-005","polarity":"expects-hold"},{"check":{"op":"containment","operands":[{"pointer":"/interactions/list/response-body/items"},{"pointer":"/interactions/create/call-inputs/body/name"}]},"commentary":null,"direction":{"evidenceTargets":["/interactions/list/response-body/items","/interactions/create/call-inputs/body/name"],"negativeDomain":"A create reporting success whose thing never appears in a later list.","polarity":"expects-hold","relation":"containment","scope":"The list read after the create, against the name the create sent."},"id":"O-006","polarity":"expects-hold"},{"check":{"collection":{"pointer":"/interactions/list/response-body/items"},"op":"for-all","predicate":{"op":"existence","operands":[{"pointer":"@/id"}]}},"commentary":null,"direction":{"evidenceTargets":["/interactions/list/response-body/items"],"negativeDomain":"A list whose first element carries an identifier and whose later elements do not.","polarity":"expects-hold","relation":"for-all","scope":"Every element of the returned list."},"id":"O-007","polarity":"expects-hold"}],"parentDigest":null,"permittedInterfaces":[{"kind":"api","logicalId":"thing-api","operations":[{"method":"POST","operationId":"create-thing","pathTemplate":"/things","requestShape":{"body":{"permittedKeys":["name"],"requiredKeys":["name"],"types":{"name":"string"}},"header":{"permittedKeys":[],"requiredKeys":[],"types":{}},"path":{"permittedKeys":[],"requiredKeys":[],"types":{}},"query":{"permittedKeys":[],"requiredKeys":[],"types":{}}},"responseDescriptor":{"channelRoles":{"/error":"diagnostic","/id":"payload","/ok":"success-indicator"},"collectionLocations":[],"permittedKeys":["id","ok","error"],"requiredKeys":["id","ok"],"successIndicator":"/ok","types":{"error":"string","id":"string","ok":"boolean"}},"sensitivityWitness":{"channel":"body","legs":[{"inputs":{"body":{"kind":"json","value":{"name":"alpha"}},"header":{},"path":{},"query":{}},"legId":"create-witness-a"},{"inputs":{"body":{"kind":"json","value":{"name":"beta"}},"header":{},"path":{},"query":{}},"legId":"create-witness-b"}],"relation":{"op":"not","operands":[{"op":"deep-equality","operands":[{"pointer":"/interactions/create-witness-a/response-body"},{"pointer":"/interactions/create-witness-b/response-body"}]}]},"witnessId":"create-thing-sensitivity"},"stateChangeMarker":true,"volatilePointers":["/id"]},{"method":"GET","operationId":"list-things","pathTemplate":"/things","requestShape":{"body":{"permittedKeys":[],"requiredKeys":[],"types":{}},"header":{"permittedKeys":[],"requiredKeys":[],"types":{}},"path":{"permittedKeys":[],"requiredKeys":[],"types":{}},"query":{"permittedKeys":["limit"],"requiredKeys":[],"types":{"limit":"number"}}},"responseDescriptor":{"channelRoles":{"/error":"diagnostic","/items":"collection"},"collectionLocations":[{"expectedCardinality":{"count":3,"mode":"exact"},"pointer":"/items","referenceSet":"expected-things"}],"permittedKeys":["items","error"],"requiredKeys":["items"],"successIndicator":"/items","types":{"error":"string","items":"array"}},"sensitivityWitness":{"channel":"query","legs":[{"inputs":{"body":{"kind":"absent"},"header":{},"path":{},"query":{"limit":1}},"legId":"list-witness-a"},{"inputs":{"body":{"kind":"absent"},"header":{},"path":{},"query":{"limit":2}},"legId":"list-witness-b"}],"relation":{"op":"not","operands":[{"op":"deep-equality","operands":[{"pointer":"/interactions/list-witness-a/response-body"},{"pointer":"/interactions/list-witness-b/response-body"}]}]},"witnessId":"list-things-sensitivity"},"stateChangeMarker":false,"volatilePointers":[]}]}],"probeStepBound":8,"referenceSets":{"expected-things":{"commentary":null,"keys":["id"],"members":[{"id":"t-1"},{"id":"t-2"},{"id":"t-3"}]}},"requiredEvidence":["Request and response pair for every call, in order."],"revisionCount":0,"rubrics":[{"criteria":[{"evidence":"/interactions/list/response-body/items","id":"RC-001","text":"Does the returned list carry every expected identifier?"}],"failureModePenalties":[{"description":"An expected thing is missing.","name":"omission"}],"id":"R-001","maxLength":400,"scaleLevels":[{"anchor":"Every expected thing is present.","level":1}]}],"safetyLimits":["No request to any host other than the mapped thing-api target."],"schemaVersion":4,"scopedResources":null,"siblingGroups":{"operations":[["create-thing","list-things"]],"parameters":[["limit","name"]]},"sourceSpecDigest":null,"testData":{"cleanup":"Delete every thing created during the run.","principals":null,"resources":null,"setup":"Seed exactly three things with identifiers t-1, t-2, t-3."},"waivers":[{"approval":"gate-c-reviewer","condition":null,"expiresAt":"2027-01-01T00:00:00Z","id":"W-001","rationale":"The upstream seed is unavailable in the sandbox environment.","rule":"omission-and-completeness"}]}
|