fix(spec): section 6 forbade a case the corpus ships, and the predicate under it was wrong too
The normative spec read "Such a payload MUST NOT be given a discriminated case id" while manifest.json defined case_id_derivation.variant_suffix and conformance/hybrid-xss__script-tag--src-no-close/ sat on disk under it. The manifest was the correct party: the derivation was extended in corpus 0.3.0 and the spec was never updated. No data moves here, only the text describing it. The derivation block now carries the optional '--' suffix and the truncating reverse, with the '--'-absence measurement stated as the reason the reverse stays LEXICAL - re-measured at this commit rather than copied from 0.3.0's numbers, and scoped to id spaces because '--' does occur inside pattern values. The part that would have passed review while still being wrong: fixing only the permission. Section 6 also reasoned that equal in-scope finding sets mean the second case "cannot fail in any way the first does not" - and the shipped variant falsifies exactly that. It expects the same single finding, same scope, same match, and still gates what the base cannot, because the base input matches the pattern under both its published and its superseded stricter form. The discriminating signal is INSIDE the scope, in the form of the scoped rule. So the MUST NOT is replaced by a predicate about failure surface rather than finding sets, checked in both directions: it admits the shipped variant and still excludes the omitted markdown-image payload, whose only distinguisher lives in a table this repository does not publish. manifest.json is untouched and stays at 0.5.0; no case directory moved. The spec has no version of its own - "Through version 0.1.1" in section 4 is the CORPUS version, verified against CHANGELOG [0.2.0] before acting, because the session brief said otherwise. Section 6's stable-id and BREAKING sentences were read, not edited. Verified in scratchpad, never in the repo: the amended derivation transcribed into a checker that reads all 94 cases back from disk, derives each pattern id, round-trips it forward, and asserts the case expects it. All 94 reproduce. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M4xrxV3EXbSALqvB23kpeY
This commit is contained in:
parent
e6ca5ae5ee
commit
cb784fea6f
3 changed files with 157 additions and 14 deletions
|
|
@ -211,8 +211,10 @@ Reading that absence as "this runtime emits nothing else" would be a claim nobod
|
|||
## 6. Case ids
|
||||
|
||||
```
|
||||
case_id = pattern_id with ":" replaced by "__"
|
||||
pattern_id = case_id with "__" replaced by ":"
|
||||
case_id = pattern_id with ":" replaced by "__",
|
||||
optionally followed by "--" and a variant slug of [a-z0-9-]
|
||||
pattern_id = case_id truncated at the first "--" if present,
|
||||
then "__" replaced by ":"
|
||||
```
|
||||
|
||||
`:` is not a legal filename character on Windows, and fork-and-own is a supported use of
|
||||
|
|
@ -220,18 +222,53 @@ this repository, so the id space cannot reach the filesystem unchanged. `__` doe
|
|||
anywhere in the ratified id space, so the transform is one-to-one — verified collision-free
|
||||
across all cases rather than assumed.
|
||||
|
||||
The transform carries a consequence that is easy to miss: **a case id is derived from a
|
||||
pattern id alone, so the corpus holds at most one case per `pattern_id` in single-finding
|
||||
scopes.** There is nowhere in the name to put a second one. That is a real constraint, not a
|
||||
formality — a source runtime's own test matrix may well drive two payloads at the same
|
||||
pattern, as one of the seeding runtimes does for `active:markdown-image`. When it does, the
|
||||
two payloads MUST be compared *within the case's scope* before a second case is minted: if
|
||||
their in-scope finding sets are equal, the second case cannot fail in any way the first does
|
||||
not, and its distinguishing signal lies outside the scope where this corpus makes no claim.
|
||||
Such a payload MUST NOT be given a discriminated case id; the derivation rule is the
|
||||
contract, and a suffix would break the reverse transform. It SHOULD instead be recorded as
|
||||
a named omission in `conformance/manifest.json`, so the drop is visible rather than
|
||||
inferred from a count.
|
||||
`--` does not occur there either: the ratified ids use single hyphens throughout, measured
|
||||
across every id space this repository publishes and every case id in the corpus. That
|
||||
measurement is what keeps the reverse transform **lexical**. A runtime recovers a
|
||||
`pattern_id` by splitting the string, and MUST NOT need a lookup against the published id
|
||||
list to find where the id ends and the variant begins — a reverse transform that has to ask
|
||||
which of two readings is real is a different rule from the one written above, and it fails
|
||||
on the first id space that is vendored without its lookup table.
|
||||
|
||||
**A `pattern_id` may carry more than one case.** Through corpus version 0.2.0 this section
|
||||
said the opposite: that a case id derives from a pattern id alone, so a single-finding scope
|
||||
holds at most one case per pattern id, with nowhere in the name to put a second. Corpus
|
||||
version 0.3.0 extended the derivation with the optional suffix above, and the corpus has
|
||||
shipped a case under it since (`hybrid-xss__script-tag--src-no-close`, whose own `$comment`
|
||||
carries the rationale for that one). The superseded sentence is named here rather than edited
|
||||
away, because it was the stated ground on which a real payload was dropped —
|
||||
`omitted_payloads` in [`conformance/manifest.json`](../conformance/manifest.json) records
|
||||
that ground as withdrawn and a second, independent ground as still standing.
|
||||
|
||||
The bar for minting a second case is neither that the two inputs differ, nor that their
|
||||
in-scope finding sets differ:
|
||||
|
||||
> A variant case MAY be minted when the second input can fail, **within the case's scope**,
|
||||
> under a change to a scoped data file that the first input would pass. Where no edit to a
|
||||
> published table separates the two inputs, the second case cannot fail in any way the first
|
||||
> does not, and it MUST NOT be minted.
|
||||
|
||||
Equal in-scope finding sets do not settle that question, and reading them as if they did is
|
||||
the error this paragraph replaces. The corpus's first variant case expects exactly the
|
||||
finding set its base case expects — one `pattern_id`, one scope, one `match` — and still
|
||||
gates something the base cannot: the base input matches the scoped pattern both in its
|
||||
published form and in the stricter form that preceded it, so reinstating the stricter form
|
||||
leaves it passing, while the variant input matches only the published form and fails. The
|
||||
distinguishing signal is *inside* the scope, in the form of the scoped rule itself, which is
|
||||
exactly what a finding-set comparison cannot see.
|
||||
|
||||
The payload that stays out is the mirror image. A source runtime's own test matrix may drive
|
||||
two payloads at the same pattern, as one of the seeding runtimes does for
|
||||
`active:markdown-image`, whose only difference is a signal from a table this repository does
|
||||
not publish. No edit to any scoped file separates them, so the second case could not fail
|
||||
where the first passes. Such a payload SHOULD be recorded as a named omission in
|
||||
`conformance/manifest.json`, so the drop is visible rather than inferred from a count.
|
||||
|
||||
A variant case MUST be scoped and matched exactly like its base case, and MUST expect the
|
||||
same `pattern_id`. **The suffix distinguishes inputs, never findings.** It is not a licence
|
||||
to record a second, different verdict for one rule: two cases at one pattern id expecting
|
||||
different findings within the same scope are not a variant pair, they are the corpus
|
||||
contradicting itself.
|
||||
|
||||
**A case id is a stable identifier. Changing one is a BREAKING change** and requires a major
|
||||
bump of the corpus version, exactly like changing a pattern id. Consumers name cases in
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue