Skip to content

feat(context-reuse): explain invalidation with bounded internal attribution - #2586

Merged
hidb4ai merged 1 commit into
oceanbase:masterfrom
jackie-cqz:feat/context-reuse-invalidation-2522
Nov 12, 2026
Merged

hidb4ai merged 1 commit into
oceanbase:masterfrom
jackie-cqz:feat/context-reuse-invalidation-2522

Conversation

@jackie-cqz

Copy link
Copy Markdown
Contributor

Which issue or RFC does this PR close?

Closes #2522.

Design contract: RFC 2086 (docs/en/rfcs/2086-core-inference-gates-and-optional-gateway.md), section "Stable context reuse and model cache integration" and the new "Explaining a rejected reuse in process".

Rationale for this change

When a prepared-context binding stops being reusable, revalidation raised the same generic context-reuse-source-changed for a revised root, a forgotten/merged/retired root, a changed ancestor or Source, and a changed cited file, with no indication of which bound evidence changed. An in-process caller could not tell, for example, which of two roots was revised.

This PR adds a bounded, content-free explanation for in-process callers while keeping every existing decision, error code, authorization check and public output unchanged. It does not repair, re-prepare, extend the binding or follow a new head.

What changes are included in this PR?

  • ScopedContextApplication.validate_reuse failures now carry ContextReuseError.invalidation (a ContextReuseInvalidation with attribution, ordered changes and truncated) on every context-reuse-source-changed raised by revalidation, and on nothing else. Preparation never explains.
  • Early root failure (read_dependency_snapshot): the root that is no longer its active head is named with revised, forgotten, merged or retired. The lifecycle state outranks a revision written by the same operation, and an active root at a newer revision (including a restore) is revised. Validation still stops at the first failing root, so the explanation is partial and never mentions unexamined roots.
  • Final snapshot comparison: nodes are compared by identity as changed, added or removed. Only a node that is itself a bound root is named; ancestors and Sources are reported by subject only, because the binding records no root-to-dependency map. The explanation is complete only when no code was cited, since code is compared afterwards.
  • Code evidence (added in feat(context): reuse code evidence with per-file revalidation #2425): a changed or no-longer-indexable cited file is reported as code changed or removed, never with its path. context-reuse-code-unavailable carries no explanation.
  • Disclosure: explanations name only roots the caller already received as citations. They contain no ancestor or Source identity, current revision, merge target, content, digest or path. Missing, unreadable, ineligible or unauthorized evidence keeps its existing code without an explanation.
  • Bounds and fallback: at most 16 changes and 4096 UTF-8 bytes of canonical JSON (to_json), ordered roots, ancestors, Sources, with deterministic prefix truncation. Any failure while building an explanation yields unavailable and the original rejection is raised unchanged.
  • RFC 2086 (en/zh) documents the explanation, disclosure rules, bounds and fallback, and adds one acceptance item.

Unchanged: check_context still returns context-refresh-required; HTTP still maps these errors to the generic 422 without details; the binding format, encrypted envelope, five-minute retention, identity binding and 64/8 dependency bounds are untouched.

Are there any user-facing changes?

No public HTTP, OpenAPI, MCP or Receipt change, and no breaking change. The only new surface is the internal ContextReuseError.invalidation attribute (plus the ContextReuseInvalidation / ContextReuseChange types in powercontext.builtin.runtime.context_reuse) for embedded callers. Remote hosts receive no new reasons.

How was this change tested?

New and updated tests:

  • tests/builtin/runtime/test_context_reuse.py
    • two roots with only one revised/forgotten/merged/retired, through the real validate_reuse entry on SQLite;
    • a changed and an unchanged binding fail identically after access revocation;
    • ineligible evidence carries no explanation;
    • snapshot comparison names only bound roots;
    • count/byte bounds with 128-character non-ASCII IDs;
    • malformed and reordered snapshots stay rejected with unavailable.
  • tests/builtin/runtime/test_code_context_reuse.py: changed, removed and unavailable cited files against a real Git repository and code index.
  • Before the change, a probe over a git archive export of the base commit showed all four root changes raising the same code with no explanation.

Commands:

uv run --locked pytest tests/builtin/runtime/test_context_reuse.py tests/builtin/runtime/test_code_context_reuse.py tests/builtin/runtime/test_context_check.py tests/e2e/test_context_check_authorization.py tests/e2e/test_context_protection_transports.py tests/e2e/test_atomic_memory_prepare_lifecycle.py -q   # 129 passed
uv run --locked pytest tests/builtin/runtime tests/e2e -q   # 2573 passed, 617 skipped (environment-dependent)
uv run --locked prek run --files <changed files>            # passed (ruff, ruff format, ty, whitespace)
uv run --locked ty check                                    # passed
make docs-test                                              # passed
git diff --check                                            # clean

Not covered by execution: artifact-level read denial for a principal that can read the Scope is not constructible with the built-in RBAC/Casbin roles (every role with SCOPE_READ grants child ARTIFACT_READ); AuthZEN was not checked. The final-comparison branch is exercised with a replaced dependency snapshot because a real store fails the early root check first. No OceanBase or real-host acceptance was run.

AI usage statement

Implemented with Claude Code (Claude Opus 5.5). One agent context designed and wrote the change; a separate read-only Claude verification context independently reviewed the design and slice 1, the final snapshot, and the post-review edits against the issue contract, returning CONTINUE each time. The human owner made the disclosure and scope decisions.

🤖 Generated with Claude Code

Copilot AI balanced review requested due to automatic review settings November 11, 2026 02:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

@jackie-cqz

Copy link
Copy Markdown
Contributor Author

CI note: the failing jobs look unrelated to this change.

  • dsh-package: setup validates native include trees observed by a real DSH startup (integrations/dsh/plugins/powercontext/tests/runtime/setup.test.mjs:30) fails the same way on other current PRs (runs 42943237378, 42938932208), so it appears to be a pre-existing failure on master.
  • script-installation / installation (ubuntu-latest): test_install_configure_remember_and_reinstall[bootstrap-cn] timed out after 300 s in install.sh --no-hosts --version 1.2.0; macOS and Windows installation passed.

I can't re-run jobs here. Could a maintainer re-run script-installation once the DSH test is fixed? This PR only changes builtin/runtime/context_reuse.py, atomic_memory.py, their tests and RFC 2086.

@hireview001 hireview001 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • CI failed: CI result (failure).
  • CI failed: dsh-package (failure).
  • CI failed: Main (failure). Failed steps: dsh-package / Test built plugin in the real DSH runtime; CI result / Require successful selected checks.

…bution

Revalidation of a prepared-context binding now attaches a content-free
explanation to every context-reuse-source-changed it raises, readable by
in-process callers of ScopedContextApplication.validate_reuse as
ContextReuseError.invalidation. Error codes, exception types, check_context
and HTTP output, the binding format and the 64/8 bounds are unchanged.

- A bound root that is no longer its active head is named with revised,
  forgotten, merged or retired from the same authorized read; validation
  still stops at the first failing root, so the explanation is partial.
- A changed snapshot is compared node by node; only nodes that are bound
  roots are named, ancestors and Sources are reported by subject only.
- Changed or no-longer-indexable cited files are reported without paths.
- Explanations hold at most 16 changes and 4096 UTF-8 bytes of canonical
  JSON, truncate deterministically, and fall back to unavailable if they
  cannot be built, leaving the original rejection intact.

RFC 2086 (en/zh) documents the explanation, disclosure rules and bounds.

Refs oceanbase#2522

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jackie-cqz
jackie-cqz force-pushed the feat/context-reuse-invalidation-2522 branch from e5355e0 to 86d3c84 Compare November 12, 2026 03:36
Copilot AI balanced review requested due to automatic review settings November 12, 2026 03:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

@AlexStocks AlexStocks added the 1.6.0 v1.6.0 release tracking label Nov 12, 2026

@hidb4ai hidb4ai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@hidb4ai
hidb4ai merged commit bf94567 into oceanbase:master Nov 12, 2026
69 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

1.6.0 v1.6.0 release tracking

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(context-reuse): explain invalidation with bounded internal attribution

5 participants