Skip to content

[Proposal] Ship negative conformance vectors in v0.2 #53

Description

@rocklambros

Negative vectors belong in v0.2.

That answers the go/no-go @tyche-dev asked for on #29 on August 21, which @avp9-nexus held implementation waiting on. Sixteen days is too long for a scope question. There's an item below aimed at stopping that from recurring.

Why v0.2

The MUST list is still moving. #21 is open and relaxes MODIFY, system/ping, and wrapped MCP to SHOULD in docs/spec/conformance.md. #33 flags the same inconsistency as unresolved. Falsification needs something settled to falsify, so any must-reject vector written this month gets rewritten when #21 lands.

Two smaller reasons back that up. We already told readers this was v0.2 work in docs/topics/faq.md:340, so shipping a conformance/ directory at 0.1.1 contradicts our own site. The other reason is that a partial suite feeds the problem #19 was filed about: "19/19" reads stronger than "self-attested" while resting on identical trust, and a number stops people asking what it covers.

Work that shouldn't wait

The two-verdict idea belongs in the spec. A refusal because evidence was measured and found wrong differs from a refusal because evidence couldn't be measured, and the operator does something different in each case. @avp9-nexus and @astrogilda arrived at this separately from opposite directions. ACS already has most of it in DEFER, which carries resolution_timeout_ms, required_context, and a timeout_decision whose enum has no allow path. The job is to write that down in normative text, where it costs nothing to maintain and survives every revision.

The six classes from #29 should anchor the v0.2 corpus, since they outlast spec changes: valid-but-out-of-mandate, replayed authorization, expired or revoked mandate, wrong-context approval, malformed evidence with a fail-open consumer, and stripped observability.

An earlier version of this issue recommended adopting #35's SHA-256 manifest pinning and its capability profiles. A premortem of #35 has since falsified both recommendations, and the detail is in the first comment below. In short: the manifest pins itself, so a hostile PR that edits a vector and regenerates the digests passes every CI step; and an empty capability profile scores zero vectors and exits 0. Neither mechanism should be copied as-is. What survives from #35 is the shape of the questions it asks, not its answers.

What the v0.2 suite has to get right

These came out of a premortem on #30, run against the branch rather than read off it. Writing them down so the next attempt starts here.

  1. A published corpus can't prove enforcement. An adapter whose first statement discards the input scored 19/19 and exited 0, because the vector id encodes the verdict class. Redacting the id doesn't fix it. We emptied the question to {}, handing the adapter nothing whatsoever, and a seven-line sys._getframe walk still passed every vector. Only a held-out corpus tells a real implementation from a lookup table, and holding vectors back conflicts with publishing them. So the suite has to describe itself as a self-certification aid, the way MLPerf and SPEC do.

  2. The gate needs negative controls of its own. Mutating the reference adapter measures the vectors. The runner goes untested. Nineteen runner mutants found five guards with nothing behind them, two exploitable, one of which silently restores a defect a reviewer had already caught and the author had already fixed.

  3. Structural rules need their mirror. Add conformance/negative/: vectors, failure codes, and runner (closes the suite gap for the enforcement layer) #30 requires a positive control in every category, which is correct. Nothing requires a negative one, so a positives-only corpus certifies an adapter that allows everything, exit 0.

  4. Adapters can't own the runner's process. sys.exit(0) inside an adapter gave exit 0 with no output at all, since except Exception misses SystemExit. Adapters need to run out of process, one child per run. Per-vector children break any implementation with real state, which includes anything that actually detects replay.

  5. A constant can't be measured. All 19 vectors asserted signature: "VALID", so an implementation with no signature verification passed everything. Signatures are the one thing ACS-Core requires unconditionally.

  6. Positive controls need tighter review than negatives. A positive control is a mandatory allow. One contributed vector can quietly demand a bypass, at which point the runner flags the honest implementation as the broken one.

  7. Assert codes, never prose. Substring matching against operator messages failed correct implementations that worded things differently and passed lies naming the wrong cause. specification.md:129 already tells implementers to switch on codes.

  8. Every vector needs a requirement ID and a spec version. Nothing in Add conformance/negative/: vectors, failure codes, and runner (closes the suite gap for the enforcement layer) #30 ties a vector to any ACS requirement, which means it can't drift. It stays quietly wrong. This is the argument for building the v0.2 suite the way [Proposal] Milestone: full ACS-Core conformance (requirement ledger + behavioral tests, beyond adapter emission) #33 scopes it, as a ledger over the MUSTs where CI fails when an applicable MUST has no falsifying test. Then a spec change tells you which test it broke.

Before the OWASP relaunch

Separate from the suite, cheaper, and aimed at what the relaunch actually exposes.

Related: #19, #21, #22, #29, #30, #33, #35, #52

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    scope:deferredReal work, tracked, lands after Day 90. Maintainers onlytype:proposalNew feature or request

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions