Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/workflows/conformance.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: conformance

# The parity number in the README is only worth what a third party can re-run.
# This pins the suite commit and the spec digest, demands the full 140/140, and
# This pins the suite commit and the spec digest, demands the full 149/149, and
# compares a fresh run against the checked-in evidence, so the repository cannot
# drift away from its own claim.
on:
Expand All @@ -14,8 +14,8 @@ permissions:
contents: read

env:
SUITE_COMMIT: cf0d5402327ae5a451efebc914852d1c687753ca
SPEC_DIGEST: d3872a02875b2da8de0263e93fb92ca6f5ab0fd75f07ed3762a1b18b0c1712a3
SUITE_COMMIT: ea25a1e218e94843e018dffc0eae4f3fcab1749e
SPEC_DIGEST: 39233b27b7f27b94ed727a3852030c69c7a64e5706b73519848a2b02f244e661

jobs:
parity:
Expand Down Expand Up @@ -67,11 +67,11 @@ jobs:
# something is already wrong, so it gets held shut here.
run: python3 tests/test_compare_report.py

- name: Full corpus, 140/140 required
- name: Full corpus, 149/149 required
run: |
set -euo pipefail
cargo run --locked --release -- aee-conformance/vectors --json fresh.json | tee run.txt
grep -q 'parity: accepts 35/35, rejects 105/105' run.txt
grep -q 'parity: accepts 35/35, rejects 114/114' run.txt

- name: Fresh run must match the checked-in evidence
run: python3 scripts/compare-report.py fresh.json reports/suite-revision-3.json
run: python3 scripts/compare-report.py fresh.json reports/suite-revision-5.json
34 changes: 30 additions & 4 deletions NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@
| 1 | `1bc6a5a2362260514d35fe3757f35dcc8723f6b6` | — (byte-identical to branch head `4a36b197`, see below) | 125 | 125/125 |
| 2 | `55ee73321cd40edd2b4a814948506a60074543a2` | `d3872a02875b2da8de0263e93fb92ca6f5ab0fd75f07ed3762a1b18b0c1712a3` | 138 | 138/138 |
| 3 | `cf0d5402327ae5a451efebc914852d1c687753ca` | `d3872a02875b2da8de0263e93fb92ca6f5ab0fd75f07ed3762a1b18b0c1712a3` (unchanged) | 140 | 140/140 |
| 4 | `b886c0a` | — | — | not run here |
| 5 | `ea25a1e218e94843e018dffc0eae4f3fcab1749e` | `39233b27b7f27b94ed727a3852030c69c7a64e5706b73519848a2b02f244e661` | 149 | 149/149 (148/149 unchanged) |

Revision 4 vendored the new encoding and nesting rules into the spec and this
checker was never run against it, so there is no record for it and the table
says so rather than leaving the gap to be read as a skipped number. Revision 5
adds the byte-level vector tier that exercises them.

The revision-1 run was blind. The revision-2 run was not, though the order
matters: the six differing behaviours came out of the baseline run, which named
Expand All @@ -19,10 +26,29 @@ Against revision 2, the revision-1 build scored 132/138 unchanged. The before an
the after of *that* boundary are `reports/suite-revision-2-baseline.json` and
`reports/suite-revision-2.json`, both against suite `55ee7332`;
`reports/suite-revision-1.json` is the earlier corpus and is not the before-record
here. `reports/INDEX.json` names the checker and suite behind each of the four records.
All four are inspectable and reproducible by hand from those pins; only the
revision-3 run at 140/140 is re-verified continuously by CI, which follows the
current suite pin.
here. `reports/INDEX.json` names the checker and suite behind each of the five records.

The revision-5 run was not blind either, and in the opposite direction from
revision 2: the maintainer reported the miss before it was run, naming both the
vector and the constant. What that report did not contain, and what the run and
the source did, is that the constant was the smaller half. This parser counted
depth per parsed value where the revision states per open container, so it sat
one level away from the spec rule on every document in the corpus: measured on
the raw bytes, which needs no parser and so covers the deliberately ill-formed
vectors too, the offset is one on all 149 statements and every record payload
inside them, because every deepest path in the corpus ends in a scalar. Setting
the constant alone reaches 149/149 and is still wrong at depth 128. What makes
the corpus unable to separate the two is not its maximum depth — `bad-741`'s
payload sits at 130 — but that no document in it sits at 128, which is the one
depth where the two readings disagree. A scalar leaf inside 128 open containers
reads as 129 to a per-value counter and 128 to a per-container one; at 129 both
reject, and at 128 with an empty-container leaf both accept. The boundary
therefore lives in `src/json.rs`'s own tests.

All five are inspectable and reproducible by hand from those pins; the
revision-5 run at 149/149 is the one re-verified continuously by CI, which
follows the current suite pin. Revision 3 was continuously verified until
revision 5 replaced it and remains reproducible from its own pins.

## Vendored spec vs branch head

Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ An independent validity-gate checker for the **Adversarial Execution Evidence (A

**suiteRevision 3: 140/140** (35/35, 105/105) on the first run with the checker unchanged. The revision adds two forcing vectors for the reason-map side of the coverage-partition rule; this checker's rule for it came from the spec text and predates them, so the two met rather than one driving the other.

**suiteRevision 5: 149/149** (35/35, 114/114) after a parser fix. The unchanged revision-3 build scored **148/149** against it, and the single miss is worth stating plainly because the causation runs the other way this time: the revision pins a nesting bound the earlier text did not state, this checker had picked 256, and the new `bad-741` vector found it. Not blind, and not a case of the two meeting. The bound was only the visible half. The revision also states the counting rule, and this parser had been incrementing per parsed value rather than per open container, which read exactly one level deeper than the spec rule on **every document in the corpus** — all 149 statements and every record payload inside them, measured on the raw bytes so the deliberately ill-formed vectors are covered too — because every deepest path in the corpus ends in a scalar. Changing only the constant scores 149/149 as well, and still rejects a statement at depth 128 that the spec calls valid. What keeps the corpus from telling the two fixes apart is not its maximum depth, since `bad-741`'s payload sits at 130, but that nothing in it sits at 128, the one depth where the two readings disagree: a scalar leaf inside 128 open containers reads as 129 to a per-value counter and 128 to a per-container one, and at 129 both reject. That boundary is pinned in this parser's own tests instead. The revision's other half, the encoding rules, needed no change here: this checker rejected ill-formed UTF-8, CESU-8, overlong forms and unpaired surrogate escapes from the first build.

[PARITY-REPORT.md](PARITY-REPORT.md) carries the scores, the interpretation decisions the spec text forced, the four formerly-open corners and how each was closed, and the from-spec discipline attestation listing exactly what was and was not read for each revision. [NOTES.md](NOTES.md) compares the vendored spec against the branch-head spec.

No dependency on the reference implementation: this crate carries its own strict I-JSON parser, RFC 8785 canonicalization with ECMAScript number formatting, RFC 6962 domain-separated Merkle root over DSSE PAE bytes, run-binding derivation, and Ed25519 tier verification against the suite's seed-derived test key.
Expand All @@ -16,13 +18,13 @@ No dependency on the reference implementation: this crate carries its own strict

```
git clone https://github.com/astrogilda/aee-conformance
git -C aee-conformance checkout cf0d5402327ae5a451efebc914852d1c687753ca
git -C aee-conformance checkout ea25a1e218e94843e018dffc0eae4f3fcab1749e
cargo run --locked --release -- aee-conformance/vectors --json fresh.json
python3 scripts/compare-report.py fresh.json reports/suite-revision-3.json
python3 scripts/compare-report.py fresh.json reports/suite-revision-5.json
```

The checkout is pinned deliberately. `main` moves, and a later revision would run
a different corpus against the 140/140 claim on this page, which is the one thing
a different corpus against the 149/149 claim on this page, which is the one thing
a reproduction recipe must not do quietly. Earlier revisions are reproducible the
same way by taking their suite pin and checker commit from
[`reports/INDEX.json`](reports/INDEX.json).
Expand Down
16 changes: 15 additions & 1 deletion reports/INDEX.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,22 @@
"vectors": 140,
"acceptParity": "35/35",
"rejectParity": "105/105",
"continuouslyVerified": false,
"note": "First run against revision 3, by the unchanged revision-2 checker. Its reason-map membership rule was derived from the spec text and predates bad-731 and bad-732 by about an hour and three quarters, so the two new vectors met a rule that was already there rather than driving it.",
"checkerCommit": "0cf46c1fa61517c955fc8f5283be4d435010765c"
},
{
"file": "suite-revision-5.json",
"reportSha256": "sha256:1300debcf8ca4acfb34d3515ecb17863ebbb1368e75b3f6e0dfa33ce4b65a8a4",
"checkerSourceDigest": "sha256:7eb8839f8bb37dde8e049bf642084977b362f16c0ff91824ee34c4b2218a90c9",
"suiteRevision": 5,
"suiteCommit": "ea25a1e218e94843e018dffc0eae4f3fcab1749e",
"specDigest": "sha256:39233b27b7f27b94ed727a3852030c69c7a64e5706b73519848a2b02f244e661",
"vectors": 149,
"acceptParity": "35/35",
"rejectParity": "114/114",
"continuouslyVerified": true,
"note": "First run against revision 3, by the unchanged revision-2 checker. Its reason-map membership rule was derived from the spec text and predates bad-731 and bad-732 by about an hour and three quarters, so the two new vectors met a rule that was already there rather than driving it."
"note": "Revision 5 pins the two things the v0.6 text left open, encoding and nesting depth. The unchanged revision-3 checker scored 148/149 against it, missing only bad-741: this implementation had picked 256 where the text now says 128, and counted depth per parsed value where the text now says per open container. Both halves are fixed here. The constant alone would also have scored 149/149, which is why the boundary the corpus does not reach is pinned in the parser's own tests instead."
}
]
}
Loading