You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug] Supervisor does not acknowledge newer sandbox policy revisions with an unchanged policy hash #2518
Possible duplicates reviewed: searched issues and pull requests for policy acknowledgement, same hash, pending revision, and supervisor polling terms; no matching report found
Findings: a newer sandbox-scoped revision can be consumed for provider/config changes while remaining permanently unacknowledged when its effective policy hash is unchanged
Remaining reason for filing: desired and current policy revisions can remain different even though the effective policy is already loaded
Description
Actual behavior: after the supervisor has loaded sandbox policy revision 1 with hash H, settings polling can return sandbox policy revision 2 with the same hash H. This occurs when revision metadata or provider attachment state changes without changing effective policy content. The supervisor may refresh provider/config state, but policy_runtime_changed is false, so it never enqueues PolicyStatusUpdate::loaded(2). The gateway continues to report desired revision 2 while current revision remains 1.
Expected behavior: a newer sandbox-scoped revision with the already-loaded effective policy hash should be acknowledged as loaded without rebuilding or reloading the identical OPA policy. If the revision also requires policy-runtime or middleware reconciliation, acknowledgement must wait for that reconciliation to succeed. Provider-environment refresh has its own revision/readiness lifecycle and should not incorrectly keep an already-loaded policy revision pending.
Reproduction Steps
Start the supervisor with sandbox policy revision 1 and effective hash H.
Persist sandbox policy revision 2 with the same effective hash H and a newer provider/config revision.
Observe that no LOADED status is reported for policy revision 2 because policy_runtime_changed is false.
Query policy status and observe desired revision 2, current revision 1, and non-converged state.
A focused unit test can construct a SettingsPollResult with source Sandbox, version 2, and the current hash, then assert that revision 2 is selected for acknowledgement while equal/older revisions, different hashes, local overrides, and non-reloading origins are rejected.
Environment
OS: Linux arm64
Runtime: Kubernetes sidecar topology
OpenShell: v0.0.91
Latest release checked: yes, v0.0.92
Possible duplicates checked: yes
Suspected Cause
The poll loop tracks current_policy_hash but not the version associated with that loaded hash. Its work gate and policy-status emission are driven by policy_runtime_changed, which intentionally remains false for identical hashes. Version convergence is therefore accidentally coupled to policy reload.
Proposed Fix
Track the currently acknowledged policy version separately from the loaded policy hash. When a polling result:
comes from PolicySource::Sandbox;
has a version newer than the acknowledged version;
has the same non-empty hash as the loaded runtime policy; and
belongs to a policy origin that reloads gateway policy,
select it for acknowledgement without an OPA reload. Enqueue PolicyStatusUpdate::loaded(version) after any required policy-runtime or middleware reconciliation succeeds, update the tracked version, and emit the normal configuration-state success event. Keep provider-environment refresh and its readiness reporting independent from policy acknowledgement.
Do not apply this shortcut to local policy overrides, different hashes, equal/older revisions, or failed reconciliation.
This is a confirmed policy-lifecycle defect, not user error. A newer sandbox-scoped revision can legitimately retain the loaded effective-policy hash, but the supervisor couples LOADED status emission to runtime policy changes, leaving the newer revision pending indefinitely.
Investigation
The current supervisor poll loop tracks current_policy_hash but not the last acknowledged sandbox policy version. gateway_policy_runtime_needs_reconciliation is intentionally false when the hash and middleware registry are unchanged, and the early work gate then skips the poll result. Even when middleware reconciliation causes the loop to proceed, PolicyStatusUpdate::loaded(result.version) remains nested under if policy_changed.
This matches the current code in crates/openshell-sandbox/src/lib.rs and the acknowledgement branch at lines 2821–2912. Existing gateway coverage also demonstrates that a provenance-only update can create a newer revision with unchanged policy content/hash, so this state is valid server behavior.
Searches found no duplicate. #2159 / #2170 fixed initial-load acknowledgement only; #2517 is complementary watcher behavior. The defect remains after v0.0.92 in the inspected main revision.
Recommendation
Track the acknowledged sandbox policy version separately from the loaded runtime hash. Acknowledge a newer same-hash sandbox revision only for gateway-reloadable policy origins and only after any required policy-runtime or middleware reconciliation succeeds. Seed and update that tracker on initial acknowledgement and successful hash-changing loads; exclude global policy, local overrides, empty hashes, and equal/older versions. Add focused supervisor coverage for same-hash newer revisions and preserve ordered status reporting.
Recommended labels: area:supervisor, area:policy. Remove state:triage-needed and assign issue type Bug. Do not apply state:agent-ready; that remains a human decision.
Agent Diagnostic
create-github-issuerepository workflowDescription
Actual behavior: after the supervisor has loaded sandbox policy revision 1 with hash
H, settings polling can return sandbox policy revision 2 with the same hashH. This occurs when revision metadata or provider attachment state changes without changing effective policy content. The supervisor may refresh provider/config state, butpolicy_runtime_changedis false, so it never enqueuesPolicyStatusUpdate::loaded(2). The gateway continues to report desired revision 2 while current revision remains 1.Expected behavior: a newer sandbox-scoped revision with the already-loaded effective policy hash should be acknowledged as loaded without rebuilding or reloading the identical OPA policy. If the revision also requires policy-runtime or middleware reconciliation, acknowledgement must wait for that reconciliation to succeed. Provider-environment refresh has its own revision/readiness lifecycle and should not incorrectly keep an already-loaded policy revision pending.
Reproduction Steps
H.Hand a newer provider/config revision.LOADEDstatus is reported for policy revision 2 becausepolicy_runtime_changedis false.A focused unit test can construct a
SettingsPollResultwith sourceSandbox, version 2, and the current hash, then assert that revision 2 is selected for acknowledgement while equal/older revisions, different hashes, local overrides, and non-reloading origins are rejected.Environment
Suspected Cause
The poll loop tracks
current_policy_hashbut not the version associated with that loaded hash. Its work gate and policy-status emission are driven bypolicy_runtime_changed, which intentionally remains false for identical hashes. Version convergence is therefore accidentally coupled to policy reload.Proposed Fix
Track the currently acknowledged policy version separately from the loaded policy hash. When a polling result:
PolicySource::Sandbox;select it for acknowledgement without an OPA reload. Enqueue
PolicyStatusUpdate::loaded(version)after any required policy-runtime or middleware reconciliation succeeds, update the tracked version, and emit the normal configuration-state success event. Keep provider-environment refresh and its readiness reporting independent from policy acknowledgement.Do not apply this shortcut to local policy overrides, different hashes, equal/older revisions, or failed reconciliation.
Logs