Skip to content

CR-DD-017: Blocked local-only route evidence parity - #158

Merged
coreytshaffer merged 5 commits into
mainfrom
claude/cr-dd-017-blocked-route-evidence-parity
Aug 11, 2026
Merged

coreytshaffer merged 5 commits into
mainfrom
claude/cr-dd-017-blocked-route-evidence-parity

Conversation

@coreytshaffer

Copy link
Copy Markdown
Owner

Authority boundary

Proposed evidence/observability CR only. No runtime, routing, capability-resolution,
or privacy-enforcement changes are authorized by this PR.

This PR establishes the governed change request. It does not itself edit client.py or
any test file — that implementation remains separately gated behind its own approval,
per Status: Proposed / Implementation Authority: Not authorized in the document
itself.

Scope

Exactly one new documentation file, 246 insertions, zero other changes.

What this proposes

When a local_only packet's resilience-routed selection is not in the explicitly
local-safe set (local_heavy, local_fast, deterministic), client.py writes a
RouteDecisionAudit (reason_code="ambiguous_or_remote_route") and raises
LocalRouteUnavailableError — without ever calling build_route_decision_payload() or
appending a route_decision event, both of which already exist and are used two
branches later on the allowed path for exactly this purpose.

choose_resilience_route already computes the distinguishing cause internally
(ResilienceRouteDecision.reason: sensitivity_requires_human_review vs.
no_reliable_automated_route_available) — it's discarded at the point of failure, not
missing. This is precisely the gap that produced the Aug-8 trial misdiagnosis corrected
in CR-DD-016's #156: a sensitivity-driven handoff and a capability-exhaustion handoff
are indistinguishable in the durable ledger today.

Proposed fix: on that one branch, persist the existing route_decision payload via
the existing _append_route_decision_event helper — never a direct
ledger.append_event(...) call, which would silently bypass the helper's optional
route-decision signing switch to ledger.append_signed_route_decision_event(...) —
before raising. Exact evidence order: one route_audit, then one route_decision,
then the raise. No worker_result is synthesized, because no worker was attempted.

route_audit.reason_code stays exactly ambiguous_or_remote_route — this CR does not
rename, split, or parameterize it, and does not introduce a new reason-code vocabulary
for Unknown vs ObservedUnavailable capability sub-states (that distinction already
exists on the route_decision capability fields).

Deliberately out of scope

  • The sibling offload_recommended_for_local_only branch, immediately below in
    client.py, has the identical structural gap. Named here, not touched — bundling it
    would mix two separate acceptance-evidence surfaces into one CR.
  • choose_resilience_route, resolve_capability, or any routing/capability-resolution
    logic.
    This CR persists a decision already made; it does not change how any decision
    is made.
  • Privacy enforcement, execution gating, or whether execution proceeds.

Acceptance criteria (full list in the CR doc)

  • route_audit.reason_code unchanged.
  • A route_decision event persisted via the existing helper, in exact order (audit →
    decision → raise), no synthesized worker_result.
  • Two end-to-end tests against the real choose_resilience_route — the existing tests
    (test_local_only_remote_route_blocked_audit, test_ambiguous_route_blocked_audit)
    mock it with reason="", which is the same blind spot this CR closes: a sensitivity
    case and a capability-exhaustion case, each asserting both the route_audit code and
    the route_decision.reason.
  • No new reason-code vocabulary; no change to routing/capability/privacy behavior; all
    six stated invariants hold.

Numbering

CR-DD-015 remains reserved for the separate comparative-lane track. Verified via
git ls-tree across origin/main and every local/remote branch before drafting — no
CR-DD-015 or CR-DD-017+ exists anywhere. This CR takes CR-DD-017.

🤖 Generated with Claude Code

Requirements-contract proposal only. Grants no implementation
authority.

When choose_resilience_route selects a non-local-safe route for a
local_only packet, client.py writes a RouteDecisionAudit
(reason_code=ambiguous_or_remote_route) and raises before ever
calling build_route_decision_payload() or appending a route_decision
event -- both of which already exist and are used two branches later
on the allowed path. The router already computes the distinguishing
cause (ResilienceRouteDecision.reason: sensitivity_requires_human_
review vs. no_reliable_automated_route_available); it's discarded,
not missing. This is what produced the Aug-8 misdiagnosis corrected
in CR-DD-016's #156.

Proposes persisting the existing route_decision payload on that one
branch via the existing _append_route_decision_event helper --
preserving its optional route-decision signing switch, never a
direct ledger.append_event bypass -- before raising
LocalRouteUnavailableError. reason_code stays exactly
ambiguous_or_remote_route; no new vocabulary for Unknown vs
ObservedUnavailable; no routing, capability-resolution, or privacy
behavior changes. Acceptance requires two end-to-end tests against
the real choose_resilience_route (the existing tests mock it with
reason="", which is the same blind spot this CR closes) plus an
exact evidence-order/integrity criterion: one route_audit, one
route_decision, then raise, no synthesized worker_result.

Status: Proposed. Implementation authority: Not authorized.
@netlify

netlify Bot commented Aug 11, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for poetic-quokka-0fd859 ready!

Name Link
🔨 Latest commit 99c4b51
🔍 Latest deploy log https://app.netlify.com/projects/poetic-quokka-0fd859/deploys/6a7ba884e2f82a00081d7148
😎 Deploy Preview https://deploy-preview-158--poetic-quokka-0fd859.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coreytshaffer
coreytshaffer merged commit 3d62350 into main Aug 11, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant