Skip to content

fix: gate encrypted agent starts by signed device and user turn - #1992

Merged
zxch3n merged 8 commits into
mainfrom
e2ee-agent-execution-claim
Oct 28, 2026
Merged

zxch3n merged 8 commits into
mainfrom
e2ee-agent-execution-claim

Conversation

@zxch3n

@zxch3n zxch3n commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Related issue

Problem / pressure

Encrypted Meta/history dispatch and realtime offers need one durable execution decision per user turn. Admission must also verify the original signing device, current ledger authority and ownership of the target machine, including after snapshot recovery or a confirmed credential revocation.

Summary

  • Route actual start/continue execution through the existing SQLite journal using agent-start:<userTurnId>. Preserve original receipts, clock floors, explicit reset, and completed/uncertain evidence across restart. Uncertain execution is never automatically resubmitted.
  • Retain original encrypted update frames and operation ranges in workspace-local SQLite. Reverify the signature, reconstruct the exact original turn and bind its prompt/configuration, session and original expiry before authorization. UI account IDs remain display-only.
  • Default production construction to host.authorizeExecution(workspaceId, requesterDevice). The verified signing device must be active, have a current non-Guest member role, and belong to the same ledger membership as the target machine device. Another device of that member can execute; cross-member execution fails with e2ee_machine_not_owned and “加密工作区暂不支持使用其他成员的机器”. Ordinary workspace visibility/project-sharing checks remain unchanged.
  • Recover snapshot-only pending turns by fetching and verifying original signed updates from Streams. Missing originals and ordinary network failures remain retryable within the original execution window; the snapshot author never substitutes for the original signer.
  • Confirmed member removal or machine-device revocation synchronously closes workspace execution admission and clears native authorization grants before the existing owner drain. Late refresh/authorization results and late originals cannot create a journal start. Only identity-verified member removal erases member data; device revocation retains local originals. These failures stay scoped to their workspace.

Execution boundary

verified original update -> exact turn + signing device + original expiry
                                           |
Meta/history or offer -> SessionExecutionService
                         current device/role + same-member machine policy
                         SQLite claim(userTurnId)
                         agent create/restore/prompt -> settlement

The optional LodyOptions.authorizeEncryptedExecution override keeps the native host signature:

type AuthorizeEncryptedExecution = (
  workspaceId: string,
  requesterDevice: string // verified signing public key, lowercase hex
) => Effect.Effect<ExecutionAuthorization, unknown>;

ExecutionAuthorization is Authorized or Denied with reason invalid-request, not-authorized, e2ee_machine_not_owned, unavailable or closed. The durable signed turn's original 15-minute execution window is independent of the host's ledger-read cache. Future encrypted realtime ingress must provide equally verified origin evidence through this boundary; this PR does not implement that transport.

Validation

  • Deterministic RED → GREEN reproductions cover cross-member prompt submission, cached authorization surviving a confirmed backfill revocation, and late authorization creating a SQLite start after workspace closure.
  • Real production Lody.create regressions use native custody, signed ledger/content and SQLite, with synthetic cloud I/O and an ACP harness; no authorization callback/mock host is injected. They cover same-member devices, other Members, Guest/revoked/removed signers, real UI account IDs, snapshot backfill, missing originals, confirmed member/device revocation and ordinary network recovery.
  • Journal tests cover overlapping durable/realtime claims, duplicate delivery, restart, uncertain settlement, original evidence preservation and workspace isolation. Watcher tests retain ordinary not_visible and project_not_shared denials.
  • 9 affected CLI suites / 612 tests passed, no expected failures. CLI typecheck, affected type-aware Oxlint (0 errors), Effect lint, changed-file Oxfmt, docs check and public/platform/process/presence boundary guards passed.
  • Only affected local checks ran. No hosted-CI wait, deployment, encrypted-network acceptance or latency-threshold claim.

@zxch3n zxch3n changed the title fix: deduplicate encrypted agent starts by user turn fix: gate encrypted agent starts by signed device and user turn Oct 28, 2026
Keep missing originals retryable without consuming the turn. Record the unresolved UI account-ID binding regression explicitly.

Model: gpt-6.1-sol
Treat account IDs as display metadata and defer encrypted dispatch admission to the native device gate. Preserve earlier journal evidence and cover real UI accounts, revoked devices, Guest and removed members.

Model: gpt-6.1-sol
Resolve E2EE scope documentation mechanically, retaining minimal plaintext presence and execution authorization rules. Normalize the automatically merged API documentation tables.

Model: gpt-6.1-sol
@zxch3n
zxch3n marked this pull request as ready for review October 28, 2026 06:15
@zxch3n
zxch3n merged commit 66c9d01 into main Oct 28, 2026
16 checks passed
zxch3n pushed a commit that referenced this pull request Oct 28, 2026
CI checks out the PR merge commit but passed pull_request.base.sha as
the docs base. That SHA can predate main commits merged since, so the
new "new note needs an owner link" gate attributed notes added by other
PRs (#2003, #1992) to this one. Pass the merge commit's first parent,
read from the shallow commit object, and fetch only that commit.

Model: claude-opus-5-5

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lodyai Bot pushed a commit that referenced this pull request Oct 28, 2026
* docs: keep Agent Notes as maintained decision memory

Narrow note creation to durable rationale, require a supersession check
that archives replaced notes, keep implemented notes current with the
code they cite, and replace the hard 8192-byte AGENTS.md gate with
word ceilings that can be raised with a recorded reason.

`pnpm run docs` now fails on ceiling breaches, unarchived Supersedes
targets and proposal headings in changed implemented notes, warns on
run-log phrases, and lists active notes citing missing paths. Adds the
archive-agent-notes skill and archives the superseded trigger note.

Model: claude-opus-5-5

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: link notes from current-state owners and maintain them on read

Make Agent Notes retrievable through the documents agents already read:
every new note must be linked from a README, .agents/docs page,
AGENTS.md or Spec, and `docs status` lists the 589 active notes that
are not (`unlinkedNotes`). A task that relies on a stale, unlinked or
mis-staged note fixes it in the same PR, and the PR implementing a
proposal moves it to implemented/.

Root guidance now starts reading from owner docs and follows their note
links; notes rules gain Linking and Maintenance-on-read sections and a
recorded 1400-word ceiling.

Model: claude-opus-5-5

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: compare docs checks against the merged base commit

CI checks out the PR merge commit but passed pull_request.base.sha as
the docs base. That SHA can predate main commits merged since, so the
new "new note needs an owner link" gate attributed notes added by other
PRs (#2003, #1992) to this one. Pass the merge commit's first parent,
read from the shallow commit object, and fetch only that commit.

Model: claude-opus-5-5

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: LodyAI <agent@lody.ai>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant