RS-TKT-1 (Phase 1) · 04 TKT Base Fail-Closed Forbidden-Output Contract
RS-TKT-1 (Phase 1) · 04 — TKT Base Fail-Closed Forbidden-Output Contract
Lane: RS-TKT-1 — Phase 1 TKT Base Design Package (design-only)
Date: 2026-06-22
Gate: REGISTRATION_HOLD · REGISTRATION_CAN_PROCEED = NO · 0 runtime mutations (KB design-doc writes only)
Authority: NON_AUTHORITY · may_gate=false · decision_effect=NONE · design-only
Inherits exactly: RS-TKT-0A-PATCH2 01 (P1, the Codex-CLOSED BLOCKER). This Phase-1 contract reproduces PATCH2 P1 verbatim in substance and may not weaken it. It adds only the two PATCH2 caveats (§7) that Phase 1 was told to resolve.
1. The safe predicate (six conjuncts — PATCH2, unchanged)
For invalid input, the run is safe iff all six hold:
invalid_input_safe =
exit_code != 0
AND structured_forbidden_grant_event_emitted == false
AND unstructured_reserved_grant_token_emitted == false
AND forbidden_authority_artifact_created == false
AND forbidden_cert_or_seal_file_created == false
AND forbidden_authority_digest_created == false
If any one fails → invalid input is unsafe → FAIL. exit_code != 0 is necessary, not sufficient; forbidden_*==false is necessary, not sufficient. Both the token/artifact checks and the exit check are conjunctive — neither substitutes for the other.
2. Mandatory rule (the source-level closure of the fail-open)
Bare stdout/stderr/result-file grant-like output is forbidden on invalid input
even if the process exits nonzero and even if no structured GRANT event exists.
No future implementation may choose whether bare PASS is dangerous — it is forbidden by contract. "No structured event" is not an escape hatch (PATCH2 rule 5). A nonzero exit never erases dangerous output (PATCH2 rule 4).
3. Reserved grant-like token floor (PATCH2 minimum) — and the caveat-§5 closure
The detector maintains a reserved grant-like token list. The minimum floor is:
PASS · CERT · CERTIFICATE · SEAL · APPROVED · ACCEPTED · DIGEST
AUTHORITY_GRANTED · REGISTRATION_GRANTED · CAN_PROCEED=YES
REGISTRATION_CAN_PROCEED = YES · PRODUCTION_PASS · IMPLEMENTATION_PASS
SEMANTIC_TEXT_AS_CODE_PASS · IU_TRACEABILITY_PASS · RELEASE_BUNDLE_PASS
This list is a floor, never a ceiling: Phase-1 design may extend it but may never shrink it below this floor.
Closure of Codex caveat §5 (reserved-token floor must be versioned config, normalization defined, not a permanently closed hardcoded list):
token_floor_config:
storage : versioned metadata/config artifact (NOT hardcoded in a binary); carries a config_version.
monotonicity : a new config_version may only ADD tokens or tighten matching; removing a floor token is a forbidden config change (rejected by review).
normalization (applied before matching, deterministic):
- Unicode NFC; strip ANSI/escape sequences; collapse internal whitespace runs to one space; trim ends.
- case-insensitive compare for ASCII letters; "=" comparisons normalize spaces around "=" (CAN_PROCEED=YES == "CAN_PROCEED = YES").
tokenization :
- scan each channel as text; a "bare token" = a floor token that appears NOT strictly inside a whitelisted *_REJECTED marker within a valid REJECTION/NONE envelope (§5).
- substring-inside-a-larger-identifier is still a hit unless covered by the safe-rejection-context guard (§5).
The floor is open-ended and config-versioned; it is never "permanently closed."
4. Structured vs unstructured rule (PATCH2 §4, unchanged)
1. Structured GRANT event on invalid input => FAIL.
2. Authority artifact on invalid input => FAIL.
3. Bare reserved grant-like token in stdout/stderr/result file/generated artifact on invalid input
=> FAIL, unless a valid safe-rejection context (§5).
4. A nonzero exit code does NOT erase dangerous output.
5. Absence of a structured event does NOT make bare stdout safe.
5. Safe-rejection context (false-positive guard — PATCH2 §5, unchanged)
Whitelisted rejection markers: PASS_REJECTED · SEAL_REJECTED · CERT_REJECTED · ORACLE_CLAIMS_SEAL_REJECTED · AUTHORITY_CLAIM_REJECTED · FORBIDDEN_TOKEN_DETECTED. A safe rejection context is valid only when all hold:
event_type = REJECTION
authority_effect = NONE
exit_code != 0
no cert/seal/authority artifact created
no authority digest created
A reserved token strictly inside a whitelisted *_REJECTED marker within a valid REJECTION/NONE envelope is safe; a bare token is not.
6. Detector scan surface and order (PATCH2 §6/§7, unchanged)
scan surface : stdout · stderr · result.json · result.md · exit_codes.json · all declared generated output paths · all files in the declared run-output directory · negative_tests outputs.
if incomplete : return HOLD_OUTPUT_SURFACE_UNAVAILABLE. Never PASS/SAFE_REJECT when the full surface is not visible.
detector order:
1. collect scan surface
2. detect generated forbidden artifacts (cert/seal/authority-digest files)
3. validate structured event namespace (event_type / authority_effect)
4. scan unstructured reserved grant-like tokens across the full surface
5. apply safe-rejection-context exceptions (§5)
6. check exit code <-- LAST; cannot override a forbidden token/artifact found in steps 2–4
7. emit invalid_input_safe result
7. Deterministic outcome vocabulary (PATCH2 §8, unchanged)
SAFE_REJECT — all six §1 conjuncts hold (rejected cleanly)
FAIL_UNSTRUCTURED_FORBIDDEN_TOKEN — a bare reserved grant-like token outside a valid safe-rejection context
FAIL_FORBIDDEN_AUTHORITY_ARTIFACT — a cert/seal/authority-digest artifact or a structured GRANT event
FAIL_INVALID_EXIT_ZERO — exited 0 on invalid input
HOLD_OUTPUT_SURFACE_UNAVAILABLE — scan surface incomplete; could not assess safely
8. Mandatory fixtures BAD-FC-001..008 (PATCH2 §9, verbatim outcomes)
| Fixture | Behaviour on invalid input | Expected outcome |
|---|---|---|
| BAD-FC-001 | prints bare PASS to stdout, exits 3 |
FAIL_UNSTRUCTURED_FORBIDDEN_TOKEN |
| BAD-FC-002 | writes seal/cert/authority-digest artifact, exits 3 | FAIL_FORBIDDEN_AUTHORITY_ARTIFACT |
| BAD-FC-003 | prints ORACLE_CLAIMS_SEAL_REJECTED with event_type=REJECTION, authority_effect=NONE, exits 3, no artifact |
SAFE_REJECT |
| BAD-FC-004 | exits 0, no forbidden token/artifact | FAIL_INVALID_EXIT_ZERO |
| BAD-FC-005 | exits nonzero, no grant token/artifact, structured event REJECTION/NONE |
SAFE_REJECT |
| BAD-FC-006 | prints bare SEMANTIC_TEXT_AS_CODE_PASS, exits 3 |
FAIL_UNSTRUCTURED_FORBIDDEN_TOKEN |
| BAD-FC-007 | writes result.md containing REGISTRATION_CAN_PROCEED = YES, exits 3 |
FAIL_UNSTRUCTURED_FORBIDDEN_TOKEN |
| BAD-FC-008 | scan surface missing stdout/stderr/result artifacts | HOLD_OUTPUT_SURFACE_UNAVAILABLE |
These are required L2 probes; they extend (do not replace) old P1–P10 ∪ pilot BAD-1..15. An ordinary evidence hash is explicitly not an authority digest and does not trip forbidden_authority_digest_created.
9. Weakening test (for the self-validation in 18)
The contract is weakened — and Phase 1 must REJECT — if any of these appears: an exit==0-only escape hatch returns; the token floor is shrunk; "no structured event ⇒ safe stdout" reappears; a missing scan surface maps to PASS instead of HOLD; or any BAD-FC outcome is softened. None is present here; the contract is inherited intact.