RS-TKT-0A-PATCH1 · 01 Fail-Closed Forbidden-Output Contract Patch (P1)
RS-TKT-0A-PATCH1 · 01 — Fail-Closed Forbidden-Output Contract Patch (P1)
Lane: RS-TKT-0A-PATCH1 · Date: 2026-06-21
Gate: REGISTRATION_HOLD · REGISTRATION_CAN_PROCEED = NO · 0 runtime mutations (KB writes only)
Authority: NON_AUTHORITY · may_gate=false · decision_effect=NONE · design-only
Supersedes: the global "Detector-correctness rule" in 04 §0 (and its echoes in 04 TKT-L2-FAIL-CLOSED, 06 global invariants, 08 §8a-5 / §8b-Q1). Those said a PASS/seal/cert token counts as emitted only when the producing process exits 0. That is fail-open and is withdrawn.
1. The defect (Codex P1, BLOCKER)
a PASS/seal token counts as emitted only if exit == 0.
Under that rule, an invalid input could print PASS/cert/digest/seal-like output — or create such an artifact — then exit nonzero, and be classified as "did not emit." The old detector-correctness rule was an anti-false-positive fix (stop *_REJECTED substrings from counting as grants). It was wrongly generalized into the only gate, which inverted it into a fail-open.
2. Corrected contract (conjunctive, not substitutes)
For invalid input, the run is safe iff all of the following hold:
invalid_input_safe =
exit_code != 0
AND forbidden_grant_event_emitted == false
AND forbidden_authority_artifact_created == false
AND forbidden_cert_or_seal_file_created == false
AND forbidden_authority_digest_created == false
- Any forbidden PASS/cert/digest/seal-like token or artifact is a FAIL regardless of process exit.
- Exit must also be nonzero. The token/artifact check and the exit check are conjunctive — neither substitutes for the other.
exit_code != 0is necessary, not sufficient.forbidden_*==falseis necessary, not sufficient. Both must hold.
3. Structured detection (not raw substring matching)
Detection uses structured event namespaces and artifact-file checks, not bare substring search.
event_type = GRANT | REJECTION | EVIDENCE | ERROR | INFO
authority_effect = NONE | CLAIMED | GRANTED
Distinctions that must be encoded (so rejection text is never mistaken for a grant):
ordinary evidence hash != authority digest
rejection event containing "SEAL" != seal grant
"PASS_REJECTED" != PASS grant
"ORACLE_CLAIMS_SEAL_REJECTED" != SEAL grant
A token only counts as a forbidden grant when it is carried by a GRANT event with authority_effect=GRANTED, or when a forbidden artifact file is created. Rejection markers live in the REJECTION namespace with authority_effect=NONE and are safe.
4. Forbidden for invalid input (any one ⇒ FAIL)
event_type = GRANT
authority_effect = GRANTED
cert_file_created = true
seal_file_created = true
authority_digest_created = true
pass_grant_token = true
5. New output fields (added to the 04 shared schema for fail-closed checks)
any_pass_grant_token_for_invalid : bool # printed PASS as a grant
any_cert_emitted_for_invalid : bool # cert file/event
any_authority_digest_emitted_for_invalid : bool # authority digest (NOT an ordinary evidence hash)
any_forbidden_artifact_file_for_invalid: bool # cert/seal/digest file on disk
any_invalid_exit0 : bool # exited 0 on bad input
Safe iff: any_invalid_exit0=false AND any_pass_grant_token_for_invalid=false AND any_cert_emitted_for_invalid=false AND any_authority_digest_emitted_for_invalid=false AND any_forbidden_artifact_file_for_invalid=false. An ordinary evidence hash is explicitly not an authority digest and does not trip any_authority_digest_emitted_for_invalid.
6. Mandatory negative fixtures (design specification)
| Fixture | Behaviour on bad input | Expected verdict | Why |
|---|---|---|---|
| BAD-FC-001 | prints PASS then exits 3 |
FAIL | token present even though exit≠0 |
| BAD-FC-002 | writes cert/seal/digest artifact file then exits 3 | FAIL | forbidden artifact created even though exit≠0 |
| BAD-FC-003 | rejection marker contains "SEAL" but event_type=REJECTION, authority_effect=NONE, no artifact |
safe reject | rejection ≠ grant |
| BAD-FC-004 | exits 0 without any forbidden artifact | FAIL | nonzero-exit requirement violated |
| BAD-FC-005 | exits nonzero and emits no grant artifact/event | safe reject | both conditions met |
These become required L2 probes; they extend (do not replace) the old P1–P10 ∪ pilot BAD-1..15 catalog.
7. Corrected self-check answers (supersedes 08 §8 Q1/Q5/Q6)
- Q1 — Can a bad package still get TKT PASS? Under the original exit==0-only rule: a fail-open path existed (BAD-FC-001/002). Under this PATCH1 conjunctive contract: NO — a forbidden token/artifact fails regardless of exit, and exit must also be nonzero.
- Q5 — Can an old object registry become a mega-registry? unchanged: NO (see
02/03original; routed to one-roof). - Q6 — Can a checker become a hidden production gate? unchanged: NO (
may_gate=false,decision_effect=NONE, advisory aggregate) — and now also: a checker cannot launder a grant past detection by exiting nonzero.
The original 08 "NO fail-open" conclusion is only valid once PATCH1 is applied; as originally written (exit==0-only) it was unsupported. PATCH1 makes it true at the contract source.