Skip to content

fix(stack): publish scoped observations and drift atomically - #4820

Open
ScriptedAlchemy wants to merge 8 commits into
masterfrom
fix/4436-atomic-stack-drift-observations
Open

ScriptedAlchemy wants to merge 8 commits into
masterfrom
fix/4436-atomic-stack-drift-observations

Conversation

@ScriptedAlchemy

@ScriptedAlchemy ScriptedAlchemy commented Nov 8, 2026 •

Copy link
Copy Markdown
Owner

Scope

Refs #4436 — eliminate the split ownership of a stack's current observation and open drift intervals. This is a focused correctness/ownership slice, not full scope-lifetime retirement.

Previously store_observation read the prior snapshot under one mutex, calculated and updated drift under a second mutex, then published the observation after reacquiring the first mutex. Concurrent equivalent provider updates could both calculate drift from the same previous snapshot, emit duplicate transition observations, and race the interval frontier.

This change:

  • Replaces the separate observations and drift_intervals maps with a single ScopeObservationState entry holding both under the existing coordinator owner.
  • Serializes prior-snapshot comparison, drift update and snapshot publication as one in-memory transition, without holding the lock across network or database I/O.
  • Computes new drift intervals before replacing prior intervals, so failed identity derivation leaves the previous intervals unchanged.
  • Keeps persisted interval restoration under the same owner.
  • Prevents an unavailable policy snapshot prepared before a provider result from overwriting a newly published enabled/degraded provider observation (without changing the behavior of a real provider-unavailable response).

Behavioral regression

concurrent_identical_provider_publications_have_one_drift_transition starts 24 real threads behind a barrier, publishes the same changed stack head, and checks exactly one stack-tip transition and one opening BaseAdvanced interval, plus validation of every emitted drift receipt. This targets the prior read/modify/publish race rather than testing source shape.

Existing typed provider-state, drift close/restore and preflight tests remain.

Verification and limits

  • Independently reviewed the exact two-commit, three-file diff against master 91c72aba; no generated contracts or unrelated contributor paths changed.
  • At 3f5a11389c, all 89 tests in the macOS Bazel application integration suite passed. The crate formatting target and Clippy for both the production library and test suite passed.
  • Disabling and reenabling a provider between observations previously returned its prior enabled snapshot. The regression returned Enabled before the fix and now returns Unavailable until a fresh provider observation arrives. Policy registration, snapshot reuse and final publication now check the same scope state. The previous timestamp still fences late responses.
  • Remaining simplify(stack): replace parallel scope registries with one lifetime-owned coordinator state #4436 acceptance: consolidate the policy/circuit registrations and pass a lifetime-owned scope handle, refuse late cleanup from prior registrations, retire state only after the last owner/in-flight settlement, verify durable drift recovery, and measure bounded scope retention. This PR must stay draft until reviewed and validated; it does not close the issue.

No Kev/decision model, release, infrastructure, secret, beta.99 or mixed #4776 changes.

@changeset-bot

changeset-bot Bot commented Nov 8, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: ca153b6

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@ScriptedAlchemy
ScriptedAlchemy marked this pull request as ready for review November 9, 2026 23:55
devin-ai-integration[bot]

This comment was marked as resolved.

A provider stack read authorized under one registration could publish
after the scope was disabled and re-enabled: the policy compared equal
again and the completion timestamp passed the fence, so a stale enabled
snapshot became the re-enabled scope's current observation.

Each policy change now creates a new scope registration identity.
authorize_provider_read captures it in a single-use read token before
network I/O; observe_provider consumes the token and, under the
observation-state lock, refuses a replaced registration as Superseded
before touching the snapshot or drift intervals. Policy observations
carry the same identity, which replaces the policy-changed flag as the
drift-baseline rule. Re-registering an unchanged policy keeps the
registration and its in-flight reads. Identities are compared by
allocation, so a retired one can never match a successor while held.

The review runtime owner is the sole production caller and now passes
the token from authorization to completion; should_read_provider_stack
and the provider-to-policy fallback are removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
devin-ai-integration[bot]

This comment was marked as resolved.

Refresh disabled scopes and superseded provider reads through the current policy authority so prior enabled observations and drift do not remain open. Publish policy-only source bindings through the existing anchor and observability paths; keep stale provider completions refused.

Two real HTTP runtime-owner journeys prove disabled publication and settled drift. Both fail when the policy-update calls are removed. Bazel: 585 unit tests and 92 integration tests passed; Clippy and pinned formatting passed.

This branch has not been deployed

No deployments
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