You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
3 of 6 InspectionResult values are declared but unreachable #764
InspectionResult in cmcp_runtime.audit.chain declares six Literal values, but only three are ever assigned to response_inspection_result anywhere in the codebase:
Value
Emitted?
Where
size_exceeded
✅
proxy.py — size-check terminal path
injection_detected
✅
proxy.py — injection-scan terminal path
n/a
✅
chain.py — _append_session_start default
schema_violation
❌
Stage 2 schema violations flow to policy_decision, never to response_inspection_result
surplus_stripped
❌
Schema redaction emits policy_decision="redact", not a response_inspection_result
pass
❌
Inspection pipeline returns "allow"/"deny" as decisions; "pass" is never written
# from repo root, at main HEAD
rg '"schema_violation"|"surplus_stripped"' src/cmcp_runtime/ --type py
# returns zero matches for response_inspection_result assignment
rg '"pass"' src/cmcp_runtime/audit/ --type py
# only match is the "pass" literal inside the Literal[] type itself
Impact
Downstream consumers that branch on "schema_violation" or "surplus_stripped" from a TRACE claim or audit record will never see those values.
The type overstates the vocabulary the gateway actually emits, which is a spec-vs-implementation drift.
Options
Implement the missing paths — wire Stage 2 schema violations to emit response_inspection_result="schema_violation", surplus-field stripping to "surplus_stripped", and clean inspection passes to "pass".
Trim the type — remove the three unreachable values from InspectionResult and document that schema violations are recorded only in policy_decision.
Intentional forward-reservation — if these are placeholders for planned inspection stages, document that in the type or a # TODO so the gap is explicit.
Independent reproduction at main 19895e4 (Linux/Python 3.12.14) confirms the gateway emission gap, with a useful qualification: these labels are not globally unreachable. AuditChain.append accepts all six declared values; I appended each and verified the resulting hash chain. They are absent from the gateway's own emitting paths.
Observed gateway case (mocked upstream/scanner)
allowed
policy_decision
response_inspection_result
Clean response
true
allow
null
Scanner-sanitized response
true
allow
null
Scanner refusal
false
deny
injection_detected
Oversized response
false
deny
size_exceeded
AST inspection across src/cmcp_runtime finds three constant-producing call sites: session_start -> n/a, proxy size refusal -> size_exceeded, proxy scanner refusal -> injection_detected. The other call sites forward the caller-supplied value. The standalone InspectionPipeline separately reports schema denial through final_decision/stage_results and redaction through stripped_fields/modified_response; its result is a different class from audit.chain.InspectionResult. It is not evidence that the gateway emits schema_violation or surplus_stripped.
Recommendation for a bounded next change: retain reader/type compatibility while the maintainer decides whether pass/schema_violation/surplus_stripped are reserved or must be wired to explicitly defined producer paths. Do not equate generic scanner sanitization with schema-surplus stripping, or delete historical vocabulary merely because the current producer omits it. Please rule the producer contract and whether clean calls should emit pass versus null before a runtime change.
This is source inspection plus executed synthetic software controls, not live-provider or TRACE conformance acceptance. No production code or audit semantics changed; #764 remains open for that decision.
@saintmalik confirmed, and @dinakarjs's reproduction matches. Wire all three and keep the type: an inspected response that passed writes pass, schema-surplus stripping writes surplus_stripped, a schema refusal writes schema_violation. null stays only where no inspection ran, so "not inspected" and "inspected and clean" read differently. Scanner sanitization is not surplus stripping; say in the PR what it writes.
Want to take it? Each value needs a positive and a refusal case, and audit/ is a security path, so two approvals.
Activity
dinakarjs commentedon Oct 16, 2026
Independent reproduction at main 19895e4 (Linux/Python 3.12.14) confirms the gateway emission gap, with a useful qualification: these labels are not globally unreachable. AuditChain.append accepts all six declared values; I appended each and verified the resulting hash chain. They are absent from the gateway's own emitting paths.
AST inspection across src/cmcp_runtime finds three constant-producing call sites: session_start -> n/a, proxy size refusal -> size_exceeded, proxy scanner refusal -> injection_detected. The other call sites forward the caller-supplied value. The standalone InspectionPipeline separately reports schema denial through final_decision/stage_results and redaction through stripped_fields/modified_response; its result is a different class from audit.chain.InspectionResult. It is not evidence that the gateway emits schema_violation or surplus_stripped.
Recommendation for a bounded next change: retain reader/type compatibility while the maintainer decides whether pass/schema_violation/surplus_stripped are reserved or must be wired to explicitly defined producer paths. Do not equate generic scanner sanitization with schema-surplus stripping, or delete historical vocabulary merely because the current producer omits it. Please rule the producer contract and whether clean calls should emit pass versus null before a runtime change.
This is source inspection plus executed synthetic software controls, not live-provider or TRACE conformance acceptance. No production code or audit semantics changed; #764 remains open for that decision.
imran-siddique commentedon Oct 16, 2026
@saintmalik confirmed, and @dinakarjs's reproduction matches. Wire all three and keep the type: an inspected response that passed writes
pass, schema-surplus stripping writessurplus_stripped, a schema refusal writesschema_violation.nullstays only where no inspection ran, so "not inspected" and "inspected and clean" read differently. Scanner sanitization is not surplus stripping; say in the PR what it writes.Want to take it? Each value needs a positive and a refusal case, and
audit/is a security path, so two approvals.saintmalik commentedon Nov 9, 2026
@imran-siddique Thank you, i believe @dinakarjs is already working on it