Skip to content

feat: bind local capability evidence to tc run#116

Merged
coreytshaffer merged 1 commit into
mainfrom
claude/cr-dd-013-capability-binding
Jul 26, 2026
Merged

feat: bind local capability evidence to tc run#116
coreytshaffer merged 1 commit into
mainfrom
claude/cr-dd-013-capability-binding

Conversation

@coreytshaffer

Copy link
Copy Markdown
Owner

Implements CR-DD-013 by binding existing local-backend capability evidence into the tc run route-input path.

The change:

  • adds validated ObservedAvailable, ObservedUnavailable, Configured, and Unknown capability variants;
  • consumes an optional recorded probe artifact without introducing automatic probing;
  • adds explicit [capability] declarations for local_fast and local_heavy;
  • uses a configurable 300-second freshness threshold;
  • prevents missing, disabled, stale, invalid, or insufficient evidence from masquerading as observed health;
  • lets fresh observed unavailability override operator declarations;
  • keeps runtime reachability and configured route-class availability separate in route-decision evidence;
  • preserves existing direct ResilienceRouteInput callers and router semantics.

Includes 43 focused regression tests and updates the merged CR-DD-013 document with the approved implementation decisions.

No CR-YK, provider, circuit-breaker, token-budget, reviewer-burden, TriageDesk, session, or ledger-schema work is included.

Semantic boundary

  • runtime reachability may be observed;
  • route-class availability may be configured;
  • those sources remain distinct in evidence;
  • Unknown cannot carry a positive capability claim.

For a fresh reachable record plus declare_local_heavy = true, evidence reads:

{ "capability_state": "observed_available",
  "capability_supported_route_classes": [],
  "capability_declared_route_classes": ["local_heavy"] }

supported_route_classes stays empty because the probe record carries no class-specific evidence, so a declared class is never attributed to the probe. Pinned by test_mixed_observation_and_declaration_keeps_provenance_separate.

Behavior matrix

Input State lm_studio_ok fast heavy
Fresh reachable observed_available True declared declared
Fresh unreachable observed_unavailable False False False
Declaration, no observation configured True declared declared
No record unknown(missing) False False False
probe_disabled unknown(probe_disabled) False False False
Older than 300s unknown(stale) False False False
Malformed unknown(invalid_record) False False False

Review focus

  • Capability-variant constructors in triage_core/capability_evidence.py. Configured has no observed_at or evidence_tier field and Unknown has no route-class field, so impossible combinations raise TypeError at construction rather than being merely unused.
  • test_mixed_observation_and_declaration_keeps_provenance_separate in tests/test_capability_binding.py.

Compatibility

Binding happens at the tc run boundary. TriageClient.run_task accepts an optional capability; when absent — every existing library caller — the previous route-input literals are preserved exactly. choose_resilience_route is unmodified and still reads only the booleans.

tc run behavior does change for operators with neither a recorded observation nor a declaration: local-only work now fails closed instead of assuming local health. That is the point of the CR, and [capability] declarations are the supported remedy.

Verification

  • Full suite: 1297 passed, 5 skipped, 1 xfailed (1254 baseline + 43 new; zero regressions)
  • Focused capability suite: 43 passed
  • Ruff on the six new/edited files: clean. client.py / tc_cli.py hold 11 pre-existing findings at baseline and 11 after — none added, none fixed (out of scope)
  • git diff --check origin/main...HEAD: clean
  • git diff --name-only origin/main...HEAD: exactly nine files

The lone xfail (tests/test_authz.py::test_concurrent_consume_race_documented) is pre-existing, strict, and unrelated.

Known limitations

  • Class availability is declarative, not observed; G3 still owns class-to-model binding.
  • A declaration sets lm_studio_ok=True under Unknown, so it is trusted rather than verified.
  • Capability resolves once pre-route; runtime disappearance before execution is out of scope (G6).
  • The record is read from a configured path only — no store, discovery, or auto-probe.
  • stale covers both expiry and non-establishable freshness (a synthetic_fixture record cannot carry observed_at).

🤖 Generated with Claude Code

Implements CR-DD-013. The tc run route-input construction path no longer
synthesizes local health from unobserved literals: lm_studio_ok,
local_heavy_available, and local_fast_available now come from an observation or
an explicit operator declaration, never from an optimistic default.

Adds a validated discriminated capability-evidence union (ObservedAvailable,
ObservedUnavailable, Configured, Unknown) built as a projection of the existing
local_backend_probe_record.v1. Semantically impossible combinations are rejected
at construction: Configured has no observed_at or evidence_tier field, and
Unknown has no route-class field.

Resolution precedence: a fresh observed-unavailable runtime suppresses every
dependent route and cannot be overridden by a declaration; a fresh reachable
runtime confirms reachability only; route-class availability requires an
explicit declare_local_fast / declare_local_heavy declaration; missing,
probe_disabled, stale, invalid, and insufficient-model evidence resolve to
Unknown. Local-only work with unknown capability fails closed; cloud-permitted
work may consider a configured remote route while evidence and operator output
state that local capability was unknown.

Adds a [capability] configuration section with a 300-second configurable
freshness default; the applied threshold is recorded in evidence. Provenance
rides the existing open route_decision payload -- no new ledger schema and no
schema-version bump, and route-worker-ledger.v1 is untouched. Observation-backed
and declaration-backed route classes stay in separate evidence fields so a
declared class is never attributed to the probe.

No probe is added and none is performed: capability comes from an
already-recorded file or an injected record. Direct callers of run_task that
supply no capability keep their previous behavior exactly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@netlify

netlify Bot commented Jul 26, 2026

Copy link
Copy Markdown

Deploy Preview for poetic-quokka-0fd859 ready!

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

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

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

@coreytshaffer
coreytshaffer merged commit 98df9c1 into main Jul 26, 2026
7 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