Skip to content

Stabilize Tool contracts across Runtime recovery - #945

Open
Y1fe1Zh0u wants to merge 4 commits into
dataelement:mainfrom
Y1fe1Zh0u:002-tool-runtime-contract
Open

Stabilize Tool contracts across Runtime recovery#945
Y1fe1Zh0u wants to merge 4 commits into
dataelement:mainfrom
Y1fe1Zh0u:002-tool-runtime-contract

Conversation

@Y1fe1Zh0u

@Y1fe1Zh0u Y1fe1Zh0u commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

What changed

  • freeze the model-visible Tool Workset and accepted execution binding in checkpoint state
  • separate Provider Call IDs, Runtime Call Instances, execution Receipts, and business idempotency
  • route schema validation, authorization decisions, and sanitized failure feedback through the durable Tool boundary
  • keep the existing independent Tool repair/retry counters, but set every Tool-related limit to 10: generic malformed-JSON repair, write_file malformed/truncated-JSON repair, safe-read replay, repeated failure fingerprints, and per-Tool repair episodes
  • add operation-specific deadlines, cancellation propagation, lease renewal/fencing, and unknown-write reconciliation
  • introduce an incremental RegisteredTool completeness gate and observable legacy compatibility deletion gate
  • fix set_trigger validation, read_document truncation reporting, invisible Tool description drift, and Provider parallel-call capability modeling

Why

The Runtime could re-resolve a different Tool set after a model had already selected a valid Tool, reuse Provider-local Call IDs across Assistant turns, hide repairable failure details from the model, and mix repair budgets with transport or lifecycle retries. Long-running operations also lacked one consistent separation between deadlines, cancellation, Receipt ownership, and uncertain external writes.

This change makes the accepted Tool contract checkpoint-stable while preserving live actor/resource/credential/cancel safety checks and old-checkpoint recovery. The retry-limit follow-up intentionally changes only the existing numeric ceilings; counter-structure unification remains deferred.

Impact

  • accepted calls remain stable across assignment/readiness drift and Worker recovery
  • repairable failures return one bounded, call-linked Tool Result to the model
  • unknown possible writes are never automatically replayed
  • all existing Tool-related repair/retry ceilings are 10, while Provider retry, pending, cancel, and unknown-write states retain independent semantics
  • legacy adapters remain available only through an observable compatibility path until the explicit deletion gate is satisfied

Validation

  • 911 passed across the updated Runtime and Tool regression suite
  • prior focused migration and contract verification remains valid because the follow-up changes no database schema
  • single Alembic head: f062_tool_execution_identity
  • Alembic offline upgrade and downgrade generated successfully for f061 <-> f062
  • scoped Ruff, fatal-level Ruff for the legacy caller, and py_compile passed
  • Architecture Guard passed all P0 checks on the original contract change
  • git diff --check passed

Known validation boundary

Live Provider credentials were not exercised. The local PostgreSQL role could not create an isolated verification database, and the existing user database is behind current main, so online upgrade/downgrade was intentionally not run against user data.

Freeze the model-visible Workset and accepted execution binding in checkpoint state, separate Provider correlation from Runtime identity, and give repairable failures a sanitized model-visible result. Add independent 10/20 repair budgets, operation-specific deadline/cancel/lease controls, and an incremental RegisteredTool compatibility boundary.

Constraint: Existing checkpoints and nullable Receipt rows must remain recoverable during mixed-version rollout
Rejected: Re-resolve enabled assignments in Tool Step | changes an already accepted model decision
Rejected: Reuse Provider-local call IDs as Runtime identity | IDs repeat across Assistant turns
Confidence: high
Scope-risk: broad
Reversibility: clean
Directive: Do not remove the legacy resolver until its zero-usage release and rollback-window gate is satisfied
Tested: 834 Runtime/Tool pytest cases; 9 migration/contract cases; Alembic f061-f062 offline upgrade and downgrade; scoped Ruff; Architecture Guard; git diff check
Not-tested: Live Provider credentials and online migration against an isolated PostgreSQL database
@Y1fe1Zh0u Y1fe1Zh0u closed this Aug 11, 2026
@Y1fe1Zh0u Y1fe1Zh0u reopened this Aug 11, 2026
Drone clones only the target repository before checking out the fork PR SHA. Publish this no-op descendant to both repositories so the synchronize build can resolve the commit without changing the reviewed tree.

Constraint: Drone build 487 failed in clone before any test because the fork-only SHA was absent from dataelement/Clawith
Rejected: Ignore the failed required check | would leave PR health ambiguous
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: This empty commit carries no release behavior and need not be merged separately into v1.11.4
Tested: Underlying tree is identical to 1dbad6d
Not-tested: Drone rerun until remote status is observed
Fresh installs create the enterprise_info target shape from current ORM metadata before Alembic replays f061. Inspecting the live schema keeps that replay idempotent while preserving the legacy upgrade path, and the unified-schema assertion now leaves f062-owned Tool identity columns to their dedicated migration contract.

Constraint: Fresh bootstrap derives tables from current ORM metadata before replaying historical revisions

Rejected: Skip the failing CI migration lane | would leave a documented v1.11.4 P0 release blocker unresolved

Confidence: high

Scope-risk: narrow

Directive: Keep provider_call_id and contract_version owned by f062 rather than backporting them into the unified baseline revision

Tested: 836 Runtime, Tool, and migration tests; scoped Ruff; py_compile

Not-tested: Fresh PostgreSQL bootstrap locally because Docker is unavailable; Drone will provide that evidence
Set the existing protocol repair, safe-read replay, and model-visible Tool episode limits to ten while preserving their current independent state and execution semantics. Update focused tests and planning artifacts to make the off-by-one behavior explicit.

Constraint: Tool-related retry and repair limits must be ten without restructuring the existing counters

Rejected: Unify protocol, Receipt, and model-visible repair state now | counter redesign is intentionally deferred

Confidence: high

Scope-risk: moderate

Directive: Keep the independent counters until the planned repair-control refactor; do not infer identical attempt semantics from the shared numeric limit

Tested: 911 Runtime and Tool pytest cases; scoped Ruff; fatal-level caller Ruff; py_compile; git diff --check

Not-tested: Live Provider credentials
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