Skip to content

feat(gateway): persist operator approvals#103579

Merged
steipete merged 13 commits into
mainfrom
codex/durable-approval-registry
Jul 11, 2026
Merged

feat(gateway): persist operator approvals#103579
steipete merged 13 commits into
mainfrom
codex/durable-approval-registry

Conversation

@steipete

Copy link
Copy Markdown
Contributor

Related: #103505

What Problem This Solves

Operator approvals currently depend on process-local waiter state. Authorized surfaces cannot reliably reopen the same pending request, race to one canonical decision, or recover the recorded winner after reconnects and Gateway restarts.

Why This Change Was Made

This first increment establishes the Gateway-owned approval lifecycle: sanitized reviewer presentations in the shared SQLite state database, atomic first-answer-wins resolution, retained terminal records, generic approval.get and approval.resolve methods, and a persisted source/ancestor audience snapshot. Raw exec/plugin requests and executable bindings remain process-local and are never rehydrated from SQLite.

The accompanying design note maps the current Gateway, agent, channel, Control UI, Telegram, native, and plugin-SDK paths and defines the stacked UI/actions and ancestor-event follow-ups.

User Impact

This is the durable foundation; it does not yet add the standalone Control UI page or change channel rendering. Existing exec/plugin approval request flows keep their current compatibility behavior while gaining one canonical durable lifecycle behind them.

Evidence

  • Blacksmith Testbox lease tbx_01kx5exst4xv8cdjg8nhzthykn (violet-barnacle): full changed gate passed, including core/test typechecks, core lint, app lane, macOS app CI test shards, generated-state checks, import-cycle checks, and sidecar/storage policy checks.
  • Final focused durable-store and manager proof: 8 files, 176 assertions passed, including real child-process SQLite write contention and exact-boundary fail-closed redemption.
  • Final Gateway handler/protocol/presentation proof: 7 files, 344 assertions passed.
  • Real Gateway E2E: two distinct authorized devices submitted conflicting decisions concurrently; exactly one applied, both received the same canonical winner, and terminal reload returned the recorded result (2/2 tests passed).
  • Fresh core and test tsgo typechecks plus targeted oxlint --deny-warnings passed.
  • Protocol/Swift and shared-state/Kysely generated outputs were regenerated and verified.
  • Fresh staged autoreview: no actionable findings; patch judged correct at 0.82 confidence.
  • Linux Swift compilation reached an unrelated pre-existing CoreFoundation failure in AnyCodable.swift; generated approval models compiled before that point. Authoritative macOS CI remains the platform gate.

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation app: web-ui App: web-ui gateway Gateway runtime agents Agent runtime and tooling size: XL maintainer Maintainer-authored PR labels Jul 10, 2026
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. labels Jul 10, 2026
@clawsweeper

clawsweeper Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Codex review: found issues before merge. Reviewed July 11, 2026, 7:46 PM ET / 23:46 UTC.

Summary
The PR adds a durable SQLite-backed Gateway operator-approval lifecycle with unified lookup and resolution APIs, authorization, protocol models, documentation, and regression coverage.

PR surface: Source +3523, Tests +3406, Docs +431, Generated +147, Other +502. Total +8009 across 39 files.

Reproducibility: yes. for the patch defect: the exact-head implementation and included regression directly conflict on the return value of a successful persisted timeout.

Review metrics: 2 noteworthy metrics.

  • Gateway API surface: 2 methods added. The new lookup and resolution RPCs become compatibility-sensitive dependencies for stacked clients.
  • Persistent state surface: 1 SQLite table added. Approval lifecycle, restart cleanup, retention, and upgrade behavior become durable product contracts.

Stored data model
Persistent data-model change detected: database schema: packages/gateway-protocol/src/schema/approvals.ts, database schema: src/state/openclaw-state-schema.generated.ts, database schema: src/state/openclaw-state-schema.sql, serialized state: src/infra/approval-presentation.test.ts, serialized state: src/state/openclaw-state-db.generated.d.ts, unknown-data-model-change: packages/gateway-protocol/src/schema/approvals.ts, and 4 more. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #103505
Summary: This PR is the first implementation candidate for the canonical durable-approvals issue; the channel and native PRs are dependent increments rather than replacements.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦐 gold shrimp
Proof: 🦞 diamond lobster
Patch quality: 🦐 gold shrimp
Result: needs maintainer review before merge.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P2] Fix successful persisted timeout reporting and verify both timeout and no-route results.
  • [P1] Obtain explicit approval-path owner confirmation for authorization, fail-closed, restart, and retention semantics.

Risk before merge

  • [P2] A normal persisted timeout can settle the durable row and local waiter correctly while returning false, causing callers to interpret a completed expiry as a lost race.
  • [P1] Merging establishes two public Gateway RPCs and a persistent approval schema that dependent web, channel, and native clients will treat as a compatibility contract.
  • [P1] Malformed, kind-mismatched, disallowed, restart, timeout, and no-route outcomes intentionally fail closed; changing these semantics later could alter authorization and client recovery behavior.

Maintainer options:

  1. Fix timeout reporting, then confirm contract (recommended)
    Correct expire() to treat a successful persisted expiry as success and obtain owner acceptance for the durable API and security semantics.
  2. Revise the durable semantics
    If approval owners reject a fail-closed or authorization choice, revise the protocol, manager/store transitions, compatibility coverage, and live proof before merge.
  3. Pause the dependent stack
    Pause this PR and dependent approval-surface PRs if the foundational contract is not ready to stabilize.

Next step before merge

  • [P2] The PR has a protected maintainer label and a security-boundary decision; the author should make the narrow timeout repair, followed by explicit owner review rather than automated work-lane dispatch.

Maintainer decision needed

  • Question: Should the durable approval contract intentionally make malformed, kind-mismatched, disallowed, timeout, no-route, and restart outcomes terminal fail-closed states with the submitted authorization and retention rules?
  • Rationale: This PR establishes a security-sensitive public contract used by dependent clients; automated review can verify internal consistency but cannot choose permanent approval and recovery policy.
  • Likely owner: steipete — Recent merged approval-security work and the feature history make this the strongest available routing candidate for the contract decision.
  • Options:
    • Accept after timeout fix (recommended): Repair the boolean result, then accept the submitted authorization, fail-closed, restart, retention, and legacy-adapter semantics.
    • Revise contract semantics: Update the protocol, storage transitions, compatibility tests, and live multi-device proof for any rejected policy choice.
    • Pause the approval stack: Keep this foundation and dependent approval PRs unmerged until the durable contract is agreed.

Security
Needs attention: The implementation separates reviewer state from executable capability, but the permanent resolver authorization and fail-closed contract needs explicit owner approval.

Review findings

  • [P2] Return success for persisted timeouts — src/gateway/exec-approval-manager.ts:915-924
Review details

Best possible solution:

Fix persisted timeout success reporting without changing its terminal state, then land the durable Gateway contract only after approval-path owners accept its authorization, restart, malformed-verdict, retention, and legacy-adapter semantics.

Do we have a high-confidence way to reproduce the issue?

Yes for the patch defect: the exact-head implementation and included regression directly conflict on the return value of a successful persisted timeout.

Is this the best way to solve the issue?

The Gateway-owned SQLite compare-and-set lifecycle with process-local executable bindings is the correct ownership boundary. The patch is not merge-ready until timeout success reporting is fixed and the permanent security contract is owner-approved.

Full review comments:

  • [P2] Return success for persisted timeouts — src/gateway/exec-approval-manager.ts:915-924
    A normal persisted timeout calls forceDenyDetailed with terminal status expired, but this return expression accepts only denied. The exact-head regression expects expire() to return true after the durable row and waiter settle, so this path currently misreports a completed expiry as a lost race. Accept expired for the normal timeout path while preserving denied for no-route handling.
    Confidence: 0.99

Overall correctness: patch is incorrect
Overall confidence: 0.97

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 2adaf8b3b5d0.

Label changes

Label changes:

  • add rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦞 diamond lobster and patch quality is 🦐 gold shrimp. Replaced prior rating: 🐚 platinum hermit.
  • remove rating: 🐚 platinum hermit: Current PR rating is rating: 🦐 gold shrimp, so this older rating label is no longer current.

Label justifications:

  • P1: This foundational approval and security change is used by multiple dependent stacks and currently contradicts its persisted-timeout regression.
  • merge-risk: 🚨 compatibility: The PR adds public Gateway methods and a persistent schema while adapting shipped exec and plugin approval flows.
  • merge-risk: 🚨 security-boundary: The PR changes who may inspect or resolve approvals and how malformed, concurrent, timeout, and restart outcomes fail closed.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦞 diamond lobster and patch quality is 🦐 gold shrimp. Replaced prior rating: 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR provides a real Gateway two-device concurrent-resolution and terminal-reload run, supplemented by focused SQLite contention and exact-head handler validation.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR provides a real Gateway two-device concurrent-resolution and terminal-reload run, supplemented by focused SQLite contention and exact-head handler validation.
Evidence reviewed

PR surface:

Source +3523, Tests +3406, Docs +431, Generated +147, Other +502. Total +8009 across 39 files.

View PR surface stats
Area Files Added Removed Net
Source 20 3726 203 +3523
Tests 13 3425 19 +3406
Docs 3 432 1 +431
Config 0 0 0 0
Generated 2 147 0 +147
Other 1 502 0 +502
Total 39 8232 223 +8009

Security concerns:

  • [medium] Confirm the durable approval security contract — src/gateway/server-methods/approval.ts:512
    The new public resolver and persisted terminal model intentionally consume malformed or mismatched verdicts fail-closed and cancel pending records on restart; owners must confirm these permanent authorization and recovery semantics before dependent clients rely on them.
    Confidence: 0.96

What I checked:

Likely related people:

  • steipete: Recent merged work on exec approval revocation, durable authorization, and manager semantics dominates this area, and this person merged that security-hardening change. (role: recent approval-security contributor and merger; confidence: high; commits: 9b1c36d23c3f; files: src/gateway/exec-approval-manager.ts, src/gateway/server-methods/approval-shared.ts, src/infra/exec-approvals.ts)
  • vincentkoc: Current-main blame attributes the existing process-local exec approval manager implementation to this person's commit. (role: introduced current manager behavior; confidence: high; commits: 1b0a34c9a939; files: src/gateway/exec-approval-manager.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (6 earlier review cycles)
  • reviewed 2026-07-10T11:53:48.939Z sha 3ab2685 :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-10T19:46:03.006Z sha ff3afc4 :: needs real behavior proof before merge. :: [P1] Carry reviewer bindings through the real request path
  • reviewed 2026-07-11T14:49:23.909Z sha 0770f80 :: needs real behavior proof before merge. :: [P1] Require and validate the approval kind before resolving
  • reviewed 2026-07-11T22:50:07.335Z sha a27420d :: needs real behavior proof before merge. :: [P1] Include the required kind in the real resolve race
  • reviewed 2026-07-11T23:12:35.392Z sha 1e802b8 :: needs changes before merge. :: [P2] Stop hard-coding the obsolete core-method tail
  • reviewed 2026-07-11T23:28:15.870Z sha f36dbd8 :: needs maintainer review before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jul 10, 2026
@steipete
steipete force-pushed the codex/durable-approval-registry branch from ff3afc4 to 8a86227 Compare July 11, 2026 14:24
@steipete

Copy link
Copy Markdown
Contributor Author

Land-ready update: rebased onto current main with the #103515 exec-revocation hardening deliberately reconciled, review findings fixed, and revalidated end to end.

#103515 reconciliation (this PR's key delta): resolutionSource and one-shot consumeAskFallback survive as process-local record facts on the durable-bridge manager; trusted auto-review resolves through the durable CAS as a runtime resolver; a lost CAS race settles with the winner's operator source; ask-fallback re-admission stays in-memory one-shot (the durable row remains expired), matching the deferred strict-exec plan in docs/refactor/operator-approvals.md. Main's #103515 test suites (exec-approval-manager, node-invoke-system-run-approval, exec-host-gateway) pass against the durable bridge.

Review fixes since the last head: reviewer-binding E2E repaired (pre-rebase), audience walker cap now derived from the store cap, a resolve losing the CAS race reports APPROVAL_ALREADY_RESOLVED instead of not-found, approval.get/approval.resolve documented in docs/gateway/protocol.md, and the test-only local manager mode carries a named removal plan comment.

Validation (fresh, on this head's stack):

  • Blacksmith Testbox (through Crabbox): focused durable-store/manager/handler matrix green across multiple runs (final leases tbx_01kx8pb669psgdcmhzxdpchma5 typechecks incl. tsgo:extensions + import cycles, tbx_01kx8r0r4g46agd58kdt2rqbfg and tbx_01kx8pke4db6thssf4bxnhr5ah focused suites, exit 0).
  • Fresh structured Codex review of the reconciliation commit: clean, no actionable findings.
  • Full per-slice/stack review ledger and remaining known gaps are summarized on the stack PRs.

Known gap: the two-device live E2E from the original evidence was not re-run on this exact head; the same suites run in CI.

@steipete
steipete marked this pull request as ready for review July 11, 2026 14:37
@steipete
steipete requested a review from a team as a code owner July 11, 2026 14:37
@clawsweeper clawsweeper Bot removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 11, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0770f80328

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/gateway/protocol.md

<Accordion title="Approval families">
- `exec.approval.request`, `exec.approval.get`, `exec.approval.list`, and `exec.approval.resolve` cover one-shot exec approval requests plus pending approval lookup/replay.
- `approval.get` and `approval.resolve` are the kind-agnostic durable approval methods (scope `operator.approvals`). `approval.get` returns a sanitized pending or retained terminal projection with a stable `urlPath`; `approval.resolve` accepts the canonical approval id, an explicit `kind`, and a decision, applies first-answer-wins resolution, and always returns the recorded canonical result.

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.

P2 Badge Remove the nonexistent kind field from approval.resolve docs

For clients implementing the new durable approval API from this docs entry, including the documented kind field will make the request fail schema validation because ApprovalResolveParamsSchema only permits id and decision with additionalProperties: false (packages/gateway-protocol/src/schema/approvals.ts:211). The handler has already loaded the pending approval by then and treats invalid params as a malformed verdict (src/gateway/server-methods/approval.ts:503), so a docs-following client can accidentally deny the approval instead of resolving it. Please either document the actual two-field payload or add kind to the schema/handler contract.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. labels Jul 11, 2026
steipete added 13 commits July 11, 2026 16:34
Map #103515 semantics onto the durable lifecycle: resolutionSource and
one-shot consumeAskFallback stay process-local record facts, trusted
auto-review resolves through the durable CAS as a runtime resolver, and
lost races settle with the winner's operator source. Also: derive the
audience walker cap from the store cap, report APPROVAL_ALREADY_RESOLVED
for a resolve that loses the CAS race, document approval.get/resolve in
the protocol docs, and regenerate Swift models on the new base.
@steipete
steipete force-pushed the codex/durable-approval-registry branch from f36dbd8 to b53f59b Compare July 11, 2026 23:34

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b53f59be41

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

| Method | Contract |
| ----------------------------------- | ------------------------------------------------------------------------------------------- |
| `approval.get { id }` | Returns a visible pending or retained terminal projection. |
| `approval.resolve { id, decision }` | Runs authorization, allowed-decision validation, deadline reconciliation, and terminal CAS. |

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.

P2 Badge Document the required approval kind

For clients using this public /refactor/operator-approvals page, the documented payload omits kind, but ApprovalResolveParamsSchema requires { id, kind, decision } (packages/gateway-protocol/src/schema/approvals.ts:212) and the handler treats invalid params for a known pending approval as forceMalformedDeny (src/gateway/server-methods/approval.ts:514). A docs-following approval.resolve call with only { id, decision } will consume the first-answer slot as a malformed-verdict denial instead of applying the intended decision, so include kind in this contract table.

Useful? React with 👍 / 👎.

@steipete
steipete merged commit 02dc25a into main Jul 11, 2026
163 of 165 checks passed
@steipete
steipete deleted the codex/durable-approval-registry branch July 11, 2026 23:53
@steipete

Copy link
Copy Markdown
Contributor Author

Merged via squash.

steipete added a commit that referenced this pull request Jul 12, 2026
…-ups

Follow-up delta to the merged #103579 head, rebased onto current main:
- gateway-protocol wire types derive from owner-module schema consts
  (types.ts tombstone) and ProtocolSchemas leaves the package index so the
  public plugin-sdk d.ts graph tree-shakes the registry declaration
- approval access authority follows the operator.approvals scope tier with
  reviewerDeviceIds as the opt-in restriction (cross-surface
  first-answer-wins; requester identity gates only legacy adapters)
- plugin node.invoke approvals register directly so unrenderable
  presentations fail closed before request routing
- exec-approval manager reconciliation with #103515 revocation hardening
  (resolution source attribution, one-shot ask-fallback consumption)
- surface-report pins and plugin-sdk API baseline refreshed; Swift models
  regenerated
steipete added a commit that referenced this pull request Jul 12, 2026
…-ups

Follow-up delta to the merged #103579 head, rebased onto current main:
- gateway-protocol wire types derive from owner-module schema consts
  (types.ts tombstone) and ProtocolSchemas leaves the package index so the
  public plugin-sdk d.ts graph tree-shakes the registry declaration
- approval access authority follows the operator.approvals scope tier with
  reviewerDeviceIds as the opt-in restriction (cross-surface
  first-answer-wins; requester identity gates only legacy adapters)
- plugin node.invoke approvals register directly so unrenderable
  presentations fail closed before request routing
- exec-approval manager reconciliation with #103515 revocation hardening
  (resolution source attribution, one-shot ask-fallback consumption)
- surface-report pins and plugin-sdk API baseline refreshed; Swift models
  regenerated
steipete added a commit that referenced this pull request Jul 12, 2026
…-ups

Follow-up delta to the merged #103579 head, rebased onto current main:
- gateway-protocol wire types derive from owner-module schema consts
  (types.ts tombstone) and ProtocolSchemas leaves the package index so the
  public plugin-sdk d.ts graph tree-shakes the registry declaration
- approval access authority follows the operator.approvals scope tier with
  reviewerDeviceIds as the opt-in restriction (cross-surface
  first-answer-wins; requester identity gates only legacy adapters)
- plugin node.invoke approvals register directly so unrenderable
  presentations fail closed before request routing
- exec-approval manager reconciliation with #103515 revocation hardening
  (resolution source attribution, one-shot ask-fallback consumption)
- surface-report pins and plugin-sdk API baseline refreshed; Swift models
  regenerated
steipete added a commit that referenced this pull request Jul 12, 2026
* fix(gateway): approval registry hardening and protocol-surface follow-ups

Follow-up delta to the merged #103579 head, rebased onto current main:
- gateway-protocol wire types derive from owner-module schema consts
  (types.ts tombstone) and ProtocolSchemas leaves the package index so the
  public plugin-sdk d.ts graph tree-shakes the registry declaration
- approval access authority follows the operator.approvals scope tier with
  reviewerDeviceIds as the opt-in restriction (cross-surface
  first-answer-wins; requester identity gates only legacy adapters)
- plugin node.invoke approvals register directly so unrenderable
  presentations fail closed before request routing
- exec-approval manager reconciliation with #103515 revocation hardening
  (resolution source attribution, one-shot ask-fallback consumption)
- surface-report pins and plugin-sdk API baseline refreshed; Swift models
  regenerated

* feat(channels): add typed operator approval actions

Squash-rebased #103679 segment onto the durable-approval-registry tip on
current main. Typed approval/command/select presentation actions replace
raw-string inference across slack/telegram/discord/matrix/imessage/whatsapp,
approval.resolve carries an explicit kind, and channel adapters map native
callback envelopes through the typed action registry.

Drift reconciliation: deprecated buildExecApprovalInteractiveReply assertions
dropped (#104650 removed the shims); worker_environments bootstrap-column
migration kept alongside the approval resolution_ref backfill; plugin-sdk API
baseline regenerated.

(cherry picked from commit 68765a5d39d2118c88a7a54d00387337912d4494)
(cherry picked from commit 8642ac12af142e4b751f4f30d4b114615e7e5f66)
(cherry picked from commit 036c4bc39499925fc03de16ec9302e346769350a)
(cherry picked from commit 19dc350d6bc34e29a5169c6bc80971b0ad12adde)
(cherry picked from commit fc978b0bad86aef421c79f6a211b25cc1b743c01)
(cherry picked from commit 10de4d1ed5071f9be6ad1ee5d1e32c0fa8c9d11c)
(cherry picked from commit 9a664ced1b1fa740172b258f355f1a82925ae41c)
(cherry picked from commit c5ff69abbf444139e9e007bfa45beb0f00ffea54)
(cherry picked from commit d466a80)
(cherry picked from commit f5b4fe40dd5c961322f8553cc80b2fdfb3f6503e)
(cherry picked from commit 7340b4749a4cc4c72f7a41cce1bc9cb550cae038)
(cherry picked from commit a151f41808f23ae60b10305ccd2bc959b9169a86)

* fix(approvals): preserve typed transport ownership

* test(imessage): narrow chunked approval text

* refactor(protocol): remove retired type tombstone

* fix(plugin-sdk): align surface budgets after rebase

* docs(changelog): note typed operator approvals

* docs(changelog): defer typed approval release note
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 12, 2026
* feat(gateway): persist operator approvals

* fix(gateway): preserve approval ids exactly

* fix(gateway): enforce approval reviewer bindings

* fix(gateway): reconcile durable approvals with exec revocation hardening

Map openclaw#103515 semantics onto the durable lifecycle: resolutionSource and
one-shot consumeAskFallback stay process-local record facts, trusted
auto-review resolves through the durable CAS as a runtime resolver, and
lost races settle with the winner's operator source. Also: derive the
audience walker cap from the store cap, report APPROVAL_ALREADY_RESOLVED
for a resolve that loses the CAS race, document approval.get/resolve in
the protocol docs, and regenerate Swift models on the new base.

* fix(approvals): validate resolver kind

* docs(approvals): explain malformed verdict denial

* fix(protocol): regenerate approval models after rebase

* chore: leave changelog entry to release generation

* fix(gateway): preserve approval registration boundaries

* test(gateway): prove multi-device approval races

* test(gateway): keep approval order assertion stable

* docs: index operator approval architecture

* fix(protocol): bound approval declaration exports
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 12, 2026
…3679)

* fix(gateway): approval registry hardening and protocol-surface follow-ups

Follow-up delta to the merged openclaw#103579 head, rebased onto current main:
- gateway-protocol wire types derive from owner-module schema consts
  (types.ts tombstone) and ProtocolSchemas leaves the package index so the
  public plugin-sdk d.ts graph tree-shakes the registry declaration
- approval access authority follows the operator.approvals scope tier with
  reviewerDeviceIds as the opt-in restriction (cross-surface
  first-answer-wins; requester identity gates only legacy adapters)
- plugin node.invoke approvals register directly so unrenderable
  presentations fail closed before request routing
- exec-approval manager reconciliation with openclaw#103515 revocation hardening
  (resolution source attribution, one-shot ask-fallback consumption)
- surface-report pins and plugin-sdk API baseline refreshed; Swift models
  regenerated

* feat(channels): add typed operator approval actions

Squash-rebased openclaw#103679 segment onto the durable-approval-registry tip on
current main. Typed approval/command/select presentation actions replace
raw-string inference across slack/telegram/discord/matrix/imessage/whatsapp,
approval.resolve carries an explicit kind, and channel adapters map native
callback envelopes through the typed action registry.

Drift reconciliation: deprecated buildExecApprovalInteractiveReply assertions
dropped (openclaw#104650 removed the shims); worker_environments bootstrap-column
migration kept alongside the approval resolution_ref backfill; plugin-sdk API
baseline regenerated.

(cherry picked from commit 68765a5d39d2118c88a7a54d00387337912d4494)
(cherry picked from commit 8642ac12af142e4b751f4f30d4b114615e7e5f66)
(cherry picked from commit 036c4bc39499925fc03de16ec9302e346769350a)
(cherry picked from commit 19dc350d6bc34e29a5169c6bc80971b0ad12adde)
(cherry picked from commit fc978b0bad86aef421c79f6a211b25cc1b743c01)
(cherry picked from commit 10de4d1ed5071f9be6ad1ee5d1e32c0fa8c9d11c)
(cherry picked from commit 9a664ced1b1fa740172b258f355f1a82925ae41c)
(cherry picked from commit c5ff69abbf444139e9e007bfa45beb0f00ffea54)
(cherry picked from commit d466a80)
(cherry picked from commit f5b4fe40dd5c961322f8553cc80b2fdfb3f6503e)
(cherry picked from commit 7340b4749a4cc4c72f7a41cce1bc9cb550cae038)
(cherry picked from commit a151f41808f23ae60b10305ccd2bc959b9169a86)

* fix(approvals): preserve typed transport ownership

* test(imessage): narrow chunked approval text

* refactor(protocol): remove retired type tombstone

* fix(plugin-sdk): align surface budgets after rebase

* docs(changelog): note typed operator approvals

* docs(changelog): defer typed approval release note
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling app: web-ui App: web-ui docs Improvements or additions to documentation feature: ✨ showcase ClawSweeper spotlight: unusually compelling feature idea for maintainer attention. gateway Gateway runtime maintainer Maintainer-authored PR merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. P1 High-priority user-facing bug, regression, or broken workflow. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: XL status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant