Skip to content

Neutron N6 — Desktop Mutation Host Flow (Security + Architecture Brief) ​

Status ​

D1 — READ-ONLY AUTHORITATIVE MUTATION REVIEW TRANSPORT: IMPLEMENTED AND MERGED

DESKTOP MUTATION D2 IMPLEMENTED AND MERGED

D3 IMPLEMENTED AND MERGED (PR #522)

DL IMPLEMENTED AND MERGED (PR #525)

DESKTOP MUTATION DURABLE HOST STATE PREREQUISITE IMPLEMENTED AND MERGED (PR #528)

DESKTOP MUTATION D4 IMPLEMENTED AND MERGED (PR #534)

D5 SLICE 1 — AUTHORITATIVE STATUS RECOVERY: IMPLEMENTED AND MERGED (PR #537)

D5 SLICE 2 — DESKTOP RECONNECT AND AUTHORITATIVE STATUS RECOVERY UX: IMPLEMENTED AND MERGED (PR #540)

DESKTOP MUTATION D5 COMPLETE

Verification retry is a separate post-D5 capability, intentloom.neutron.mutation.verification.retry.v1. It re-runs Slice 4 verification for an already applied transaction and does not Apply, approve, or Undo. Undo and rollback execution remain unauthorized.

This document is the canonical threat-reviewed design for the first safe Desktop mutation flow. D1 (read-only review payload transport) is implemented (PR #516, merge ca87a2532d1e4965655f97d39efb21fc8ad36437; implementation head 25d0f6391ebc3079a755c2cbe0f492ef868a6578). D2 (Desktop exact mutation review UI) is implemented (PR #519, merge 2d3dfed9296ee998a458379db81ac5c0e1fa9e67; implementation head 74acec00d07afcf8c5a69e8ba667d091fcedbfa7). D3 (host approval-intent protocol + security tests) is implemented (PR #522, merge f629c2ef8b4c8cb962bf502eec07c1bad20dfc3a; implementation head e36a74b8bc09698b70621da31e37f7c09f6b6917). D3 adds in-process host approval issuance only; it does not authorize D4–D5, production mutation UI, mutating mutation RPC, Approve/Apply buttons, an N4 mutation tool, Undo, or any change to mutationAllowed. DL (legacy fake Approved Apply removal) is implemented and merged (PR #525). Desktop durableStateDirectory wiring is implemented and merged (PR #528, merge be1f0201e968846765f7efa731560886a8b50032; implementation head a3eb8c96b5012283107eb361c14fecd69025e22e). That prerequisite is not itself Approve & Apply. D4 (combined host Approve & Apply) is implemented and merged (PR #534, merge 0da5612e45d99454eb765cb370a058187ef47f94; implementation branch feat/neutron-desktop-approve-and-apply; starting main 67c0a58d850d9d566177fd920bc8b3fd8da654c4; implementation head 42d8810308326bb69e29ac499962626fe42ea393, which is not the merge SHA). D5 Slice 1 (read-only intentloom.neutron.mutation.status.get.v1) is implemented and merged (PR #537, merge 866c96ab6fd1a1265dfc46a8840117baaaebd0b6; branch feat/neutron-desktop-mutation-status-recovery; starting main d62b10a67051fc0f5f1ccb4d8a863c69bca0b1c8; initial head 0793cdc1624049dd477be07bc85d9fb6c5039816; final audited head c366d9f7d8d27f2a6f92b328ee775e1ceab53381, which is not the merge SHA). It D5 is complete. Slice 2 reconnect UX is merged (PR #540, merge bb9255a79229d9a64d611ce644c0f75caaec74bf; final audited head a0c029f62c30008dde416f5f93847fca45279e0d). Post-D5 verification retry is a separate operation and does not change the D5 security model. Undo remains unauthorized.

Evidence baseline: origin/main @ be1f0201e968846765f7efa731560886a8b50032 (2026-09-28; PR #528 merged). Tracked tree clean at handoff start.

Authoritative implementation and tests remain truth. Related:


0. Maintainer recommendation (not an implementation grant) ​

DecisionVerdict
Current mutation sliceD4 merged (PR #534). D5 complete (Slice 1 PR #537, Slice 2 PR #540). Post-D5 verification retry is a separate verification-only operation. Undo is not authorized.
Approval issuerTrusted daemon/application host only. Desktop submits a typed human intent. Host re-fetches the review bundle and issues NeutronMutationApproval itself.
Public RPC shapeB — one host approveAndApply action (merged) plus read-only review.get, read-only status.get, and post-D5 verification.retry (durable verification metadata only; zero project-write authority). No separate public Approve RPC.
Desktop button copyApprove & Apply is implemented on the exact mutation review and is enabled only for an eligible/current review.
approvalTokenHost-only. Public result validation rejects approvalToken and other authority/content-bearing fields. Diagnostics are redacted.
Durable authorityReuse Slice 3.1 store and project lock. Do not add a Desktop approval database.
Apply engineReuse applyApprovedNeutronGraphMutation → applyApprovedNeutronMutation → declared-path Approved Apply → Slice 4 verification.
N4 / mutationAllowedUnchanged. Seven read-only tools. Literal false.
UndoOut of first Desktop mutation scope.
Legacy fake Approved ApplyDL implemented and merged (PR #525). Fabricated applied: true and synthetic rollback evidence are removed from production Desktop. Neutron must never reuse a fake Apply path.
This documentD1–D5 are merged. Verification retry is the separate post-D5 slice in this implementation. Undo remains unauthorized.

1. Baseline ​

ItemEvidence
Expected main after PR #511Merged Slice 5.1 handoff
Actual origin/main1a8abac9dce73cbdddb12d035416691b6360cde6
Latest mergePR #511 docs(neutron): handoff for Mutation Slice 5.1
Prior correctionPR #510 Slice 5.1 implementation b36d836c05591599f2526f0d3f5302e7edce8f5b
Tracked tree at brief startClean main fast-forwarded to origin/main
Unrelated scratchNone present; nothing preserved or deleted

If this brief is read against a tree where #511 is not merged, stop: DESKTOP MUTATION HOST FLOW BRIEF BLOCKED: SLICE 5.1 HANDOFF NOT MERGED.


2. Current mutation foundation (Slices 1–5.1) ​

Implementation and tests are authoritative.

SliceWhat existsAuthority
1NeutronMutationProposal, host-shaped NeutronMutationApproval, preflight envelopesTypes only
2preflightNeutronMutation semantic authorizationEligible/rejected; zero writes
2.5Content-bound NeutronMutationReviewArtifact, canonical planDigest, declared-path syncReview artifact is not approval
3Host-only applyApprovedNeutronMutationOne claimed transaction; declared-path Apply
3.1Durable approval/transaction store + exclusive project lockProduction requires store or durableStateDirectory
4Independent post-Apply verification; sanitized rollback projectionapplied ≠ verified; no Apply retry
5N5 candidate → host materialization → payload store; applyApprovedNeutronGraphMutationHost composition after separately issued approval
5.1Stale materialization fail-closed; production capability clampCandidate A cannot rebind onto project B

Invariants that this Desktop design must not weaken:

  • NeutronRuntimeSession.mutationAllowed is typed false.
  • N4 catalog is seven read-only tools. assertReadOnlyTool denies writes.
  • Proposal validators reject approved, grantedApprovals, approvalToken, and related authority keys.
  • Approval source is local-interactive. Token format is approved:<proposalDigest> (binding string, not a high-entropy secret).
  • Model grantedApprovals cannot authorize Neutron mutation. The inner Approved Apply string "atomic-commit-approval" is attached only by the trusted Apply adapter (NEUTRON_MUTATION_INNER_APPLY_APPROVAL).
  • Hidden .aif/manifest.lock.json and .aif/source-map.json must not appear unless declared (NEUTRON_HIDDEN_GENERATED_METADATA_PATHS).
  • Graph-linked Apply calls detectNeutronGraphStaleness before applyApprovedNeutronMutation.
  • There is no production issueNeutronMutationApproval helper today. Tests construct the approval record. Desktop must not become that issuer.

3. Current Desktop foundation (N6 Slices 1–5) ​

SliceWhat existsMutation?
1Named Neutron session RPCs + Desktop Neutron viewNo
2Bounded N3 context + N4 tool activity on the completed turn snapshotNo
3Graph get / one-wave execute / cancelNo
4Authoritative result/evidence/provenance UXNo
5Read-only NeutronMutationProposal panelPaths + digests only

Current Desktop review is intentionally insufficient for real approval:

  • Session viewmodel carries a single mutationProposal or null.
  • selectSessionMutationProposal uses array-first (length === 1) or ambiguous → null. That is acceptable while Apply is impossible.
  • NeutronMutationProposalPanel shows ids, class, plan/baseline/proposal digests, and paths only via DiffViewer.
  • Copy is Mutation not authorized / No Approve control / No Apply control.
  • NeutronGraphSnapshot does not project mutationProposals[].
  • Review artifact bytes and GeneratedFile[] stay in the host payload store.
  • desktopClient.neutronRequest(request: object) plus invoke_neutron_request forwards one of seven allowlisted read-only methods. That hole must not grow to mutation.

Daemon Neutron capabilities are classified read-only. Spawn (packages/daemon/src/bin.ts) creates createNeutronSessionRuntime with an Ollama adapter. Desktop-owned and SEA production launches now inject a host-controlled durableStateDirectory through --neutron-mutation-state-dir. The flag remains optional for non-Desktop read-only daemon launches. Payload store is still in-process memory (createMemoryNeutronGraphMutationPayloadStore). This is not Apply.


4. Critical principle ​

Desktop is presentation and user-intent capture.

Desktop must not:

  • fabricate approval or Apply success;
  • generate approvalToken, approvalDigest, or approvalId;
  • recompute security-sensitive digests as authority;
  • hold mutation authority independently;
  • write project files directly;
  • call a provider/model to approve;
  • call generic shell;
  • regenerate reviewed content;
  • silently retry Apply.

Actual authority stays in trusted host/application boundaries:

text
Neutron task graph
  → host-materialized authoritative proposal + review artifact + payload
  → Desktop displays exact review information (read-only transport)
  → human explicitly selects proposalId and clicks Approve & Apply
  → Desktop sends typed intent (identities + reviewed artifact digest)
  → authenticated daemon / application host
       1. re-fetches host-held bundle
       2. revalidates session/graph/project currentness
       3. issues bound NeutronMutationApproval (token stays host-side)
       4. durable Slice 3.1 claim + project lock
       5. applyApprovedNeutronGraphMutation
       6. applyApprovedNeutronMutation
       7. declared-path Approved Apply engine
       8. Slice 4 verification
       9. persist structured result
  → Desktop displays authoritative result/evidence from host state

Do not invent a parallel Desktop mutation engine, a second approval store, or an N4 applyApprovedTransaction tool.


5. Existing authority chain (reuse, do not fork) ​

Verified chain for a later implementation:

text
Desktop UI
  → typed desktopClient operation (narrow; not generic request: object)
  → dedicated Tauri command allowlist
  → authenticated local daemon (session token, no wildcard methods)
  → versioned JSON-RPC
  → application host operation
  → host-issued NeutronMutationApproval
  → applyApprovedNeutronGraphMutation
       (payload-store lookup, authoritative source only,
        detectNeutronGraphStaleness)
  → applyApprovedNeutronMutation
       (parse envelope, canonical realpath, durable store,
        exclusive claim, lock, pre-write validate)
  → executeTrustedDeclaredPathApply
       → evaluateApprovedApplyPlan + executeApprovedApplyPlan
       → synchronizeGeneratedFiles (declared-paths-only)
  → Slice 4 independent verification
  → durable transaction record (ids, digests, statuses; no token/bodies)

Forbidden substitutes:

  • intentloom.project.approvedApply.v1 as the Neutron Desktop path
  • App.tsx fabricated applied: true
  • model output, expectedOutput, or preview proposal as Apply bytes
  • renderer-supplied approval record
  • Desktop filesystem or shell commands
  • N4 mutation tool
  • adoption Apply (applyProjectAdoption) or workspace approvedBy

Adoption Approve/Apply is a pattern analogue (host-issued bound approval, explicit human click, daemon mutating classification), not the Neutron writer.


6. Threat model ​

6.1 Approval spoofing ​

ThreatRequired control
Model says approved: trueKeep proposal/candidate rejection of the key. Host ignores it.
UI sends approved: trueRequest schema forbids authority flags. Host issues approval itself.
Malicious renderer JSTreat renderer as untrusted. Intent only. Host recomputes facts.
Replayed old approvalSlice 3.1 one-use claim. Combined approveAndApply so unused approvals are not exported.
Forged approvalIdHost allocates ids. Client-supplied approval ids are rejected.
Copied proposal digestDigest is review-visible by design. Unforgeability is architectural (host-held record), not a MAC.
Old Desktop sessionBind sessionId/projectId/root; daemon root equality; cancelled session fails closed.
Modified RPC payloadSchema validation; host re-fetches bundle; extra paths rejected; exact path-set equality.

approvalToken is approved:<proposalDigest>. It is not a secret. The control is “never accept a client/model approval record,” not token secrecy. Desktop still must not receive the token, because presence in viewmodels/logs trains a fake-authority path.

6.2 TOCTOU ​

Windows between proposal display, click, daemon receipt, durable claim, and first write:

ChangeControl
Project files changeReview-time fingerprint + write-time project-stale / graph stale
Symlink / root changeCanonical realpath containment; root equality
Profile / checkpoint changedetectNeutronGraphStaleness before graph-linked Apply
Graph becomes staleSlice 5.1 currentness + Slice 5 graph stale reject
Approval expiresHost rechecks approvalValidUntil / plan expiresAt before issue and before write
Session cancelledExisting cancellation mapping; cancelled-before-write

Desktop click is never a capability. Both review-time currentness and write-time currentness are mandatory.

6.3 Replay ​

Double-click, network retry, daemon reconnect, Desktop refresh, app restart, duplicate RPC, and restored-tree replay of an old approval are handled by:

  • single host approveAndApply;
  • Slice 3.1 exclusive claim (wx + fsync);
  • applied replay returns the prior terminal result without a second write;
  • client idempotency keys are optional UX, not authority.

An old approval after the tree is restored must not write again. Slice 3.1 already treats consumed/applied records as non-reusable.

6.4 Multiple Desktop windows/processes ​

Desktop/Tauri locks are not authoritative. Two windows on the same project must serialize through the Slice 3.1 durable project lock (durableStateDirectory lock file keyed by canonical realpath). Lock conflict returns a structured lock-conflict / claim conflict, not a second write.

6.5 Crash ​

MomentRequired durable outcome
After intent, before host approvalNo approval, no write
After approval, before claimCombined operation: approval is not exported; crash looks like unused. Do not persist a free-floating approval in D4.
After claim, before writeclaimed / failed-before-write / in-flight → fail closed; no second writer
During writeExisting Apply rollback / failed-needs-reconciliation
After write, before verificationapplied + verification pending/incomplete; resume verification only
After verification, before Desktop responseDurable record is truth; status.get recovers it

6.6 Stale proposal (Slice 5.1) ​

Materialization already requires accepted stale report and attempt fingerprint == current project fingerprint. Desktop Apply must keep that gate. Candidate bytes generated against project A cannot be approved onto project B.

Preview expectedOutput remains non-authoritative. source !== "authoritative" is preview-not-authoritative.

6.7 Secret leakage ​

Desktop viewmodels, review RPC, status RPC, Apply result, logs, and evidence must not contain:

  • approvalToken
  • raw previous file bodies / previousContent
  • hidden context, prompts, or model reasoning
  • secret-like path excerpts beyond existing N6 redaction

Review content may include proposed bytes and current on-disk bytes for the declared path set only, through the explicit review endpoint, bounded by Slice 2.5 limits (256 files, 1 MiB/file, 8 MiB aggregate).


7. Approval creation ​

Decision: a real NeutronMutationApproval is created only inside the trusted application host during approveAndApply.

It must not be created in:

  • model output or N5 scheduler;
  • Desktop renderer;
  • N4 tool router;
  • generic RPC payload from an arbitrary caller;
  • a client-supplied approval JSON blob.

Preferred sequence:

  1. Desktop submits typed human approval intent (identity fields only; see §8 / NeutronMutationApprovalIntent).
  2. Host loads the authoritative bundle from the session payload store by proposalId.
  3. Host revalidates currentness, binding, expiry, cancellation, and artifact digest.
  4. Host constructs the approval (ids, digests, approvalSource: "local-interactive", approvingActor host-assigned, token approved:<proposalDigest>, reviewArtifactDigest required).
  5. Host immediately claims and Applies. Token never appears on the wire.

D3 (merged): the internal host issuer (issueNeutronMutationApprovalFromIntent, NeutronSessionRuntime.issueMutationApproval) constructs NeutronMutationApproval in-process from authoritative review state. Tests exercise the factory. D3 itself adds no public Approve-only RPC and no production Desktop mutating control. D4 (implemented and merged, PR #534) is the production caller that combines approval with Apply inside one trusted-host operation. There is still no public Approve-only RPC.

approvingActor is assigned by the host (for example desktop-local-interactive) from the authenticated daemon session. The renderer does not supply actor identity as authority.


8. Desktop approval request ​

Narrow typed intent (NeutronMutationApprovalIntent). D3 merged fields:

FieldRole
schemaVersionIntent schema URN
protocolVersionExisting protocol compatibility
actionLiteral request-host-approval (not approval)
rootBound to daemon canonical root
sessionIdCurrent Neutron session
projectIdCurrent project
graphIdCurrent graph identity
proposalIdExplicit authoritative proposal selection

Optional later hardening (not required for D1): host-issued reviewViewNonce from review.get, short TTL, single-use with approveAndApply. Security still depends on host re-fetch + revalidation, not the nonce.

Rejected client fields (strict validation): approvalToken, approvalDigest, approvalId, proposalDigest, reviewArtifactDigest, projectStateDigest, planDigest, grantedApprovals, approved, authorized, mutationAllowed, files, content, paths, changedPaths, proposedContent, currentContent, previousContent, expiresAt, expiry, approvalValidUntil, approvedAt, mutationClass, approvingActor, approvalSource, filesToApply, taskId, and any other unexpected key.

Host resolves authoritative proposal, artifact, files, digests, root, expiry, and mutation class from the payload store.


9. Human review boundary ​

Paths-only N6 Slice 5 was acceptable because Apply was impossible. Real approval requires the human to understand the bytes that will be written.

Desktop must show, before enabling Approve & Apply:

  • selected project / canonical root;
  • proposal identity (proposalId, session/project/graph/task);
  • mutation class approved-transaction-apply;
  • exact changed paths;
  • create / update / no-op classification (delete is not in the current writer);
  • exact content diff or other safe rendering of reviewed bytes;
  • proposalDigest, planDigest, reviewArtifactDigest;
  • baseline projectStateDigest / fingerprint;
  • stale / current status and warnings;
  • expiry;
  • test/evidence state if already present (usually empty before Apply).

A filename list is insufficient. Preview/model prose cannot substitute for the host payload.

If multiple authoritative proposals exist, Desktop lists them and requires an explicit proposalId selection. No array-first Apply.


10. Exact reviewed bytes ​

Do not reconstruct bytes from model output, expectedOutput, or a second model call.

Source of truth: host-held NeutronGraphMutationReviewBundle (proposal + artifact + GeneratedFile[]) in the session payload store populated by materializeNeutronGraphMutationReview.

D1 adds a read-only review RPC that copies declared-path proposed bytes from that store. No mutation authority in the review method.

If the bundle is missing (daemon restart, cancelled session, never materialized), return structured proposal-not-found. Do not rematerialize from the model.

Do not persist raw review bodies into the Slice 3.1 durable approval store. That store is ids/digests/statuses. File bodies stay in process memory for the review window. Restart before Apply fail-closes; the user re-runs the graph to obtain a new current proposal.


11. Diff architecture ​

Reuse DiffViewer (apps/desktop/src/design/components/code/DiffViewer.tsx). Today Neutron feeds it path names with kind: "add". Future review UI must feed real hunks.

Per path, host review payload supplies:

FieldSource
exact pathartifact changedPaths / file binding
proposed bytespayload-store GeneratedFile.content
proposed digestartifact fileBindings[].contentDigest
current bytesread-only disk read at review time, or absent
classificationmissing → create; equal → no-op; different → update

Diff display is not the Apply byte source. Apply continues to use the host payload store. Desktop-edited buffers, if any, are ignored.

Delete is unsupported in NeutronMutationProposalCandidateFile (path + content only) and in executeTrustedDeclaredPathApply (create/update/no-op). A later delete capability needs its own security review.


12. Approval binding ​

Host-issued approval must bind existing canonical facts:

  • proposalId, proposalDigest
  • reviewArtifactDigest (required for Apply; not optional in this flow)
  • planDigest, projectStateDigest
  • root, projectId, sessionId
  • graphId / taskId when the proposal carries them
  • exact changedPaths
  • mutationClass: approved-transaction-apply
  • approvalSource: local-interactive
  • approvedAt, approvalValidUntil

Do not weaken Slice 1–5.1 invariants. Do not omit reviewArtifactDigest. Do not accept approvals without content-bound artifacts.


13. Desktop must never see approvalToken ​

Decision: raw approvalToken remains inside the trusted host.

Safe Desktop fields after a later Apply:

  • approvalId
  • status / failureCode
  • expiry (if still relevant)
  • proposal / artifact / transaction identities and digests

Existing Apply/verification validators already reject approvalToken on public results. Keep that rule on every new RPC and viewmodel.


14. New protocol methods ​

Naming follows current Neutron RPC style (intentloom.neutron.<area>.<verb>.v1 in packages/protocol/src/jsonrpc.ts).

Conceptual methodClassificationAuthority
intentloom.neutron.mutation.review.get.v1read-onlyDisplay exact reviewed bytes
intentloom.neutron.mutation.approveAndApply.v1mutatingHost issues approval, claims, Applies, verifies
intentloom.neutron.mutation.status.get.v1read-onlyDurable/authoritative recovery
intentloom.neutron.mutation.verification.retry.v1read-onlyRe-run Slice 4 verification for an applied transaction. Not Apply.

Names are design targets. Implementation may keep these exact strings.

14.1 Option A — separate Approve then Apply ​

Mirrors existing-project adoption (adoption.approve.v1 + adoption.apply.v1).

ProsCons
Matches adoption UXCreates a free-floating Neutron approval
Can test issuance alone via public RPCWider TOCTOU; replay of unused approval
User could delay ApplySlice 3.1 store tracks claimed transactions, not unused approvals; A would add a new unused-approval persistence surface

One authenticated host action performs:

  1. resolve authoritative review bundle;
  2. revalidate project/session/graph;
  3. issue approval (token host-local);
  4. durable claim + project lock;
  5. existing graph/current Apply;
  6. persist result;
  7. Slice 4 verification.
ProsCons
No exported unused approvalCannot “approve now, apply later”
Smaller TOCTOU and replay windowCombined failure taxonomy must stay structured
Matches the intended buttonD4 merged the combined RPC and Desktop control (PR #534)
Fits current applyApprovedNeutronGraphMutation input shapeCancellation during the combined call needs the existing before-claim / after-claim split

Recommendation: B. Safer and simpler for the first Desktop mutation slice. D3 merged tests the internal issuer without publishing Approve-only RPC.

Do not automatically retry on stale, lock-conflict, or verification failure.


Single explicit user action: Approve & Apply.

That label is the confirmation of mutation for ordinary declared-path generated-file transactions. Do not use Continue / Accept / Done.

Host atomicity is authority-level (one operation, claim-then-write), not a promise that the OS cannot crash mid-write. Crash semantics stay on Slice 3.1 / Slice 4.


16. Staleness before approval ​

Before issuing approval the host revalidates:

  • project fingerprint vs proposal projectStateDigest;
  • Slice 5.1 currentness (attempt fingerprint == current);
  • graph stale kinds: project / checkpoint / profile;
  • session binding and cancellation;
  • proposal identity and reviewArtifactDigest;
  • payload source === "authoritative";
  • expiry.

If stale: structured stale result. No approval. No write. No automatic regenerate/rebase/rerun.


17. Staleness after approval ​

Desktop approval does not replace Slice 3 pre-write checks.

applyApprovedNeutronMutation already revalidates immediately before the first write (digest, expiry, cancellation, containment, path set, live project-state, optional graph stale). Keep both layers:

text
review-time currentness  →  may issue approval
write-time currentness   →  may enter executeTrustedDeclaredPathApply

18. Durable approval state ​

Reuse Slice 3.1. Do not design a second Desktop approval database.

Production Apply already fails closed without an injected NeutronMutationApprovalStore or host durableStateDirectory. Memory store is test-only.

D4 prerequisite: Desktop-spawned daemon must own a host-controlled directory (application-private neutron-mutation-state beside the existing runtime token/socket — not project source, not .aif generated adapters). Lifecycle: created with the Desktop app-data tree, not deleted when the daemon endpoint is reclaimed, not world-writable on Unix (0700). Wiring is implemented and merged (PR #528). It is not itself D4. No second approval database and no second lock. Merged D4 reuses Slice 3.1. Production Desktop composition does not fall back to a memory store. Missing durable host state fails closed.

Durable records store ids, digests, states, and sanitized results. No token, no file bodies, no prompts.


19. Project lock ​

Reuse the Slice 3.1 durable exclusive project lock when durableStateDirectory is set. Canonical realpath key. Fail-fast conflict.

withCanonicalProjectRootLock is in-process and insufficient across two Desktop windows / two daemon processes.

N5 leases serialize task attempts, not project files.


20. Apply result ​

Desktop must render structured host status. Never collapse to Success/Failed.

Minimum distinguishable outcomes:

OutcomeMeaning
approval-rejected / invalid intentHost refused to issue approval
stale / graph-stale / project-staleCurrentness failed; no write
preview-not-authoritativePreview/expectedOutput is not Apply
proposal-not-foundNo host bundle
claim-conflict / lock-conflict / approval-consumedAnother actor or replay
cancelled-before-writeCancelled before first write
transaction-failedWriter failed; see rollback flags
applied + verification pendingBytes written; verify not finished
verifiedApplied and independent verification matched
verification-failedApplied, verification mismatched
reconciliation-requiredUnknown/incomplete crash or rollback

Use existing NeutronMutationApplyStatus / NeutronMutationApplyFailureCode / NeutronMutationVerificationStatus plus graph-linked failure codes. Do not invent a second enum that collapses them.


21. Applied vs verified ​

Preserve Slice 4. If bytes were written and verification fails, Desktop shows Applied + Verification failed, not Apply failed, and does not offer automatic Apply retry.

Optional later control: Retry verification (read-only retryNeutronMutationVerification). Never label it Retry Apply. This brief designs the label only; it does not authorize the control.


22. Crash / reconnect UX ​

After Desktop reconnect, status comes from host durable state (and, while the same daemon process lives, in-memory review bundles). Desktop must not infer status from whether an RPC response arrived.

Host stateDesktop
Bundle present, no claimReview required / unused
claimed / executingIn flight; do not offer a second Apply
applied + pending verificationApplied; verification pending
applied + verifiedVerified
failed-before-writeFailed before write; consumed
failed-needs-reconciliationReconciliation required
Bundle missing after restart, no durable recordProposal not found; re-run graph

23. Verification recovery ​

Slice 4 already allows read-only verification resume. If Desktop later exposes it, the control is Retry verification. Out of this authorization.


24. Reconciliation UX ​

Read-only recovery information for incomplete rollback, unknown crash, or verification mismatch:

  • affected paths;
  • safe digests;
  • state / reconciliationRequired;
  • rollback summary (attempted / completed / verified, not raw bodies);
  • guidance to a human/operator.

No automatic repair. Host rollback execution / Undo remains separately unauthorized.


25. Undo ​

Keep out of the first Desktop mutation slice. Do not map rollback evidence to a clickable Undo. Rollback write execution needs its own authority/security review.


26. Legacy fake Approved Apply path ​

DL implemented and merged (PR #525).

The former apps/desktop/src/App.tsx onApprovePlan path opened ApprovedApplyModal, injected ["atomic-commit-approval"], did not call intentloom.project.approvedApply.v1, and after 600 ms fabricated applied: true plus previousContent: "// previous snapshot content".

That production composition is removed. ApprovedApplyModal.tsx no longer exists. WorkspaceContent no longer mounts it. App.tsx no longer holds Apply-plan state, grant injection, timeout-delayed success, or synthetic rollback bodies. Neutron sources still must not import the removed modal.

The daemon method intentloom.project.approvedApply.v1 is unchanged and remains unwired from Desktop spawn. DL does not activate it and does not add approveAndApply.

DL does not perform Neutron mutation. The later, separately authorized D4 path is the merged host operation. The legacy daemon method stays unwired. Fail closed outside that dedicated path.


27. Tauri security ​

Current Neutron bridge: invoke_neutron_request + is_neutron_method exact match of seven session/graph methods. No wildcards. Capabilities: core:default + dialog:allow-open. No FS/shell/HTTP plugins. CSP default-src 'self'. Commands run on main.

Do not add mutation methods to invoke_neutron_request. Do not add a generic invoke proxy or arbitrary daemon method string.

Recommended dedicated commands:

Tauri commandRPCState
get_neutron_mutation_reviewreview.get.v1Implemented with D1
approve_and_apply_neutron_mutationapproveAndApply.v1Implemented with D4; not on invoke_neutron_request
get_neutron_mutation_statusstatus.get.v1D5 merged. Read-only. Not on invoke_neutron_request
retry_neutron_mutation_verificationverification.retry.v1Post-D5. Verification only. Not on invoke_neutron_request

desktopClient grows typed methods that construct params internally. The renderer does not pass a free-form request: object for mutation.

No arbitrary filesystem command. Folder dialog remains the existing select_project_root.

Origin/window: keep commands on the default main window capability. Do not expose mutation commands to untrusted additional windows if any are added later.


28. Daemon security ​

Keep the authenticated local daemon as the host boundary.

Existing controls to reuse:

  • session token (≥32 chars) on every envelope (packages/daemon/src/index.ts);
  • protocol parse + schema validation;
  • root/session/project binding on Neutron methods;
  • canonical root enforcement where other mutating handlers already use it;
  • mutating vs read-only capability classification (see adoption Apply).

Prerequisites before D4 (identify, do not implement here):

  1. Wire durableStateDirectory in Desktop daemon spawn (implemented and merged, PR #528).
  2. Classify approveAndApply as mutating; review/status as read-only.
  3. Reject externally supplied approval records.
  4. Redact tokens from results, logs, and errors (existing redactApprovalToken helpers).
  5. Bind mutation calls to the same canonical root as the session.
  6. Keep payload-store lookup inside the daemon process that materialized the graph; missing bundle fails closed.

Current daemon security is sufficient for D1 read-only review if the new method is authenticated, root-bound, schema-validated, and classified read-only. It is not sufficient for Apply until (1)–(5) exist.


29. Desktop process trust ​

Assume the renderer is easier to compromise than the application host.

Renderer requests are intent, not mutation authority. Host always re-fetches the bundle and recomputes/revalidates authoritative facts. Desktop-computed diffs, shortened digests, and disabled buttons are UX only.


30. Multiple proposals ​

selectSessionMutationProposal array-first / ambiguous is not an Apply selector.

D1/D2 must list host-held authoritative proposals for the session/graph (proposalId + safe evidence). The human selects proposalId. Approve without an explicit selection is invalid.

Preview proposals remain non-authoritative and cannot be approved.


31. Proposal expiry ​

Display expiresAt / currentness. If expired, disable Approve & Apply. Host still rechecks. UI disabling is never security.


32. Cancellation ​

Reuse existing session/graph cancellation and Apply AbortSignal mapping.

PhaseBehavior
Before clickNo host mutation
During approval request, before claimcancelled-before-write; no approval export
After claim, before writeExisting Slice 3.1 before-write failure
During transactionExisting writer/rollback semantics
During verificationCancel does not un-apply
After appliedRenderer cancel must not erase the mutation

Client Promise abort is not success (same as N6 graph cancel).


33. Button semantics ​

Final wording for the first mutating control: Approve & Apply.

Not Continue, Accept, Done, Apply (alone), or Approve (alone). The combined host action and the label must match.

Disabled reasons (expired, stale, no selection, in-flight, already applied) must be explicit status text, not color-only (React a11y: glyph + word).


34. Confirmation design ​

Decision: do not add universal second-confirmation friction.

The explicit Approve & Apply click is the human approval for ordinary declared-path generated-file transactions inside existing bounds (max 256 files, 1 MiB/file, 8 MiB aggregate, realpath containment).

Risk-based extra confirmation is justified only when existing governance already treats the case as higher risk. For this mutation class:

  • delete is unsupported → reject, do not confirm;
  • undeclared hidden metadata → fail closed (Slice 2.5/4);
  • extra / escaped paths → fail closed, no override checkbox;
  • many files within the existing hard cap → show the full review, not a second modal by default.

If a later capability adds deletes, symlink retargeting, or writes outside generated-file declared paths, that is a new security review — not a generic “type APPLY” checkbox invented here.

Foundation scaffold’s applyConfirmed checkbox is a different domain (scaffold apply) and is not copied onto Neutron by default.


35. Sensitive paths ​

Reuse existing path/profile mechanisms; do not invent uncontrolled exceptions.

MechanismRole
Session/profile allowedPaths + proposal capability clamp (Slice 5.1)Who may propose
Canonical path + realpath containmentWhere writes may land
Exact path-set equalityNo extra path at Apply
Hidden metadata denylist unless declaredNo silent .aif widening
N4 trustedRoot string equalityInsufficient alone; Apply already uses realpath

If a proposal includes high-risk paths that fail those controls: reject. If it passes: existing host-issued approval is sufficient. Do not add a parallel “allow sensitive path” exception flag.


36. Network ​

After a review artifact exists, approval and Apply are host-local.

No provider/model call between human approval and Apply. That prevents the model from changing the reviewed transaction.

N2/Ollama remains available for new graph turns, which produce new proposal identities, not mutations of the reviewed bundle.


37. Evidence ​

Desktop-visible safe evidence (status and result surfaces):

  • transactionId, proposalId
  • approvalId (not token)
  • reviewArtifactDigest, planDigest, proposalDigest
  • changed / created / updated / unchanged paths
  • applied, verification status, verificationEvidenceDigest
  • reconciliationRequired, rollback status summary
  • graph/task/attempt identities from existing graph apply evidence

No bodies except on the explicit review content endpoint. No previousContent. No approvalToken. Byte-check records may include expected/actual digests only.


38. Audit / logging ​

Log identities, statuses, and digests. No tokens, prompts, raw secret bodies, or reasoning traces. Reuse existing redaction helpers on error messages.

Conceptual future metrics (docs only; do not add production instrumentation from this brief): approveAndApply counts by structured status, stale rejects, lock conflicts, verification mismatches. No payload bodies.


39. No N4 mutation tool ​

First Desktop mutation flow calls a host application RPC.

Keep N4’s seven read-only tools: inspect, doctor, memorySearch, timeline, conformance, securityAudit, projectDiff.

Do not design applyApprovedTransaction as model-callable. mutationAttempted stays false on proposal nodes.


40. mutationAllowed ​

Keep model-facing mutationAllowed: false on NeutronRuntimeSession.

Desktop human host mutation is outside model session permission. Do not change the N1 contract merely to enable Desktop Apply.


41. Implementation slices ​

D1, D2, D3, DL, the durable-state prerequisite, D4, and D5 Slice 1 are implemented and merged. D5 Slice 2 is implemented on branch awaiting maintainer review. D5 as a whole is not complete. Adjustments after audit: add DL as a D4 prerequisite; keep D3 as host issuer tests without public Approve-only RPC; D1 remains first.

DL — Legacy fake Approved Apply isolation/removal ​

Implemented and merged — PR #525 (fix/desktop-legacy-approved-apply-isolation); starting main ea03f6e3e5cf441eeb25e87f673d6c1e2dc45256; final head d66bb641ec62b1d6ec5eb57d0258f58b2166abc7; merge 21c7bbfb4daa389382fafd191b470b64cfed2b20. Production Desktop no longer fabricates Apply success or synthetic rollback evidence. Neutron remains unable to reach the removed path. D4 is not authorized by this slice.

D1 — Read-only review payload protocol + daemon endpoint ​

Implemented and merged — PR #516 (feat/neutron-desktop-mutation-review-transport); starting main d8d312f2c9e2dac9f7375a2f79ab572d4e75bb7d; final head 25d0f6391ebc3079a755c2cbe0f492ef868a6578; merge ca87a2532d1e4965655f97d39efb21fc8ad36437.

Transport exact reviewed bytes from the host payload store to Desktop via intentloom.neutron.mutation.review.list.v1 and intentloom.neutron.mutation.review.get.v1 (read-only). Tauri: list_neutron_mutation_reviews, get_neutron_mutation_review. Desktop client: listNeutronMutationReviews, getNeutronMutationReview. Generic Neutron invoke does not gain arbitrary mutation-review dispatch. Proposed bytes only from NeutronGraphMutationPayloadStore / authoritative NeutronGraphMutationReviewBundle — never reconstructed from preview, model output, or Desktop bodies. In-memory payload store: daemon restart without payload fails closed (persistence not implemented). Compatibility correction: resolveDaemonProjectRoot honors enforceCanonicalRoots === false for Neutron session/review dispatch; production daemon remains enforceCanonicalRoots: true; Slice 5.1 attemptFingerprint === currentFingerprint unchanged.

No approval. No Apply.

D2 — Desktop exact mutation review UI ​

Implemented and merged — PR #519 (feat/neutron-desktop-mutation-review-ui); starting main 4ce587259080d8dee8e0ebe843fc7a02899d52cc; final head 74acec00d07afcf8c5a69e8ba667d091fcedbfa7; merge 2d3dfed9296ee998a458379db81ac5c0e1fa9e67. Do not record the first branch head 759d910dab9261066283b3fd53923f0e0917cdac as the final D2 head.

Render diffs/classification/digests/expiry/currentness over the D1 viewmodel. Still no approval or Apply. Explicit multi-proposal selection UX without enabling mutation: if multiple authoritative proposals exist, none is silently selected; get uses explicit proposalId. If one proposal exists, Desktop may present it directly while preserving explicit proposal identity. Host currentness (current / stale / expired / cancelled) is rendered as-is; Desktop does not rebase, regenerate, convert stale to current, or rerun a model. Exact review distinguishes "alpha" from "alpha\n", "alpha\n" from "alpha\n\n", and "" from "\n" via presentation marker No newline at end of file without mutating authoritative D1 strings (EOF correction 5ccd169dec03deba294f9ed907c7266db1823d1e). A later test-helper CodeQL correction (74acec00d07afcf8c5a69e8ba667d091fcedbfa7) did not change production review semantics. Renderer review state clears when root, session, project, or graph scope changes. Secret-like paths expose safe status only.

D2 did not add Approve, Apply, transaction mutation, D4 approveAndApply, D5 reconnect/status flow, DL cleanup, N4 mutation tool, or mutationAllowed change.

D3 — Host approval-intent protocol + security tests ​

Implemented and merged (PR #522, merge f629c2ef8b4c8cb962bf502eec07c1bad20dfc3a; implementation head e36a74b8bc09698b70621da31e37f7c09f6b6917). Typed NeutronMutationApprovalIntent, strict validation, internal issuer issueNeutronMutationApprovalFromIntent, production composition NeutronSessionRuntime.issueMutationApproval, adversarial tests in tests/neutron-mutation-approval-intent.test.ts, and isolated canonical Apply tests via applyApprovedNeutronGraphMutation. Approval is derived only from host-held NeutronGraphMutationPayloadStore / NeutronGraphMutationReviewBundle (D1 binding, Slice 2.5 artifact, Slice 5/5.1 currentness). Host assigns approvalSource: local-interactive, approvingActor: desktop-local-interactive. Token format remains approved:<proposalDigest> (binding string, not a high-entropy secret); raw token never appears in publicNeutronMutationApprovalIssueFacts. Lifetime: 30 minutes maximum, capped by plan expiresAt when earlier. Duplicate intent may reuse stable approval identity; Slice 3.1 one-use claim governs Apply replay. Issuance is deterministic host logic with no model/provider call. No production Desktop button. No intentloom.neutron.mutation.approve.v1. No approveAndApply. Those limits describe D3. Merged D4 is recorded below and does not add a public Approve-only RPC.

D4 — Approve & Apply host operation ​

Implemented and merged — PR #534 (feat/neutron-desktop-approve-and-apply); starting main 67c0a58d850d9d566177fd920bc8b3fd8da654c4; final implementation head 42d8810308326bb69e29ac499962626fe42ea393; merge 0da5612e45d99454eb765cb370a058187ef47f94 (2026-10-01). The implementation head is not the merge SHA.

Public operation: intentloom.neutron.mutation.approveAndApply.v1, classified mutating. Trusted flow:

text
Desktop exact review
→ explicit human Approve & Apply
→ dedicated Desktop/Tauri command approve_and_apply_neutron_mutation
→ authenticated daemon
→ trusted Neutron application host
→ resolve authoritative D1 review bundle
→ construct D3 approval in-process
→ canonical graph Apply
→ Slice 3 / 3.1 transaction, durable claim, replay protection, project lock
→ Slice 4 verification
→ sanitized public result

The renderer sends only root, sessionId, projectId, graphId, and proposalId. It does not create a NeutronMutationApproval and does not supply proposed bytes, changed paths, review artifact digest, plan digest, approval fields, grant flags, or transaction authority. Exact Apply bytes come from the host-held proposal payload store and content-bound review artifact. An explicit proposalId is required.

There is no public intentloom.neutron.mutation.approve.v1 and no Apply-by-token RPC. The raw approvalToken stays host-only. Public result validation rejects it and other authority/content-bearing fields. Diagnostics are redacted. The method is not added to invoke_neutron_request.

Staleness checks run before approval and again immediately before the first write. A stale project fails closed. D4 consumes the existing host durableStateDirectory and Slice 3.1 claim, replay, transaction, and project lock. Missing durable state fails closed. Merged tests show a duplicate request does not write twice, concurrent callers cannot both mutate, and an existing project lock blocks another Apply.

applied stays distinct from verified. Verification failure after a write remains applied and does not reopen approval or retry Apply. The D4 path does not call a model after the human action. mutationAllowed remains literal false. N4 remains the seven read-only tools.

Desktop shows Approve & Apply only for an eligible/current review and keeps applied + verified, applied + verification failed, applied + reconciliation required or incomplete verification, and rejected before write distinct.

D5 — Authoritative result / verification / reconnect UX ​

D5 complete. Slice 1 merged (PR #537, merge 866c96ab6fd1a1265dfc46a8840117baaaebd0b6; final audited head c366d9f7d8d27f2a6f92b328ee775e1ceab53381). Slice 2 merged (PR #540, merge bb9255a79229d9a64d611ce644c0f75caaec74bf; final audited head a0c029f62c30008dde416f5f93847fca45279e0d). Verification retry is not part of D5. Undo remains unauthorized.

Slice 1 adds read-only intentloom.neutron.mutation.status.get.v1 on a dedicated Desktop/Tauri command (get_neutron_mutation_status). Daemon classification is read-only. The generic Neutron request surface was not widened. Lookup identity is root, sessionId, projectId, graphId, and proposalId. Optional transactionId only narrows the lookup. The renderer does not send approvalToken.

The canonical path is D4 Apply, durable transaction result persisted, Desktop response lost or host restarted, fresh runtime with the same durableStateDirectory, status.get, authoritative durable truth, and zero second Apply. Existing Slice 3.1 transaction records stay authoritative. The metadata-only proposal-index in that directory points at approvalId and transactionId. It is not a second transaction database and stores no raw approval token, file bodies, proposed content, previous content, or model prompt/reasoning.

The final head rejects a pointer unless its embedded identity exactly matches the requested identity. A self-integrity SHA digest is not host authentication. A validly encoded pointer under another identity path, or a pointer whose approvalId / transactionId does not match the loaded canonical record, fails closed as durable-status-corrupt.

Lookup outcomes are unknown, recorded, root-mismatch, project-mismatch, session-mismatch, graph-mismatch, transaction-mismatch, and durable-state-unavailable. Recorded facts use the canonical transactionState, Apply status, and verificationStatus values already defined for mutation transactions. applied stays independent of verification. A later external edit does not rewrite a historical applied/verified durable record.

Status recovery does not issue or claim approval, create a token, call Apply, write project source, retry Apply, take the mutation write lock, or invoke a provider. mutationAllowed remains literal false. N4 remains the seven read-only tools. No mutation or status tool was added to N4.

D5 Slice 2 is merged (PR #540). A lost Approve & Apply response stays an uncertain presentation state. After the existing daemon connection is authenticated again for the same root, session, project, and graph, Desktop calls read-only status.get once and renders that host result. Explicit Refresh status uses the same read. There is no polling loop, no second Apply, no new approval, and no model call. A scope change drops the unresolved identity.

Post-D5 verification recovery is intentloom.neutron.mutation.verification.retry.v1 on retry_neutron_mutation_verification. The trusted host reloads the same proposal-index and Slice 3.1 record, and only when applied is true and verification is verification-failed or verification-incomplete it runs the existing Slice 4 verifier and replaces verification metadata. Historical applied: true stays true. reconciliation-required is not retryable. The capability class is read-only because the taxonomy has no third class and this operation has zero project-write authority; the operation name is distinct from Apply. Persistence re-reads the Slice 3.1 record under the approval-record gate and compare-and-sets its digest, so a stale cross-process retry cannot replace a newer verified result. A process-local queue is not that safety boundary. Still unauthorized: Undo, rollback execution, a mutation history browser, an N4 mutation or verification tool, and Apply retry.


42. Security gates per slice ​

D1 ​

GateRule
AllowedRead host-held review bundle; return declared-path proposed bytes + current disk bytes for diff; list authoritative proposalIds
ForbiddenApproval issuance, claim, Apply, token, Desktop writes
Inputssession/project/root/graph + optional proposalId
OutputsSafe review viewmodel; stale / proposal-not-found / ambiguous listing
TestsBinding, root equality, no token/previousContent, extra-path ignore, preview not authoritative, missing store, size bounds
ExitDesktop can display exact reviewed bytes; fingerprint unchanged; Apply still impossible
Next grantExplicit maintainer authorization for D2 (or combined D1+D2 docs/UI)

D2 ​

GateRule
AllowedReview UI over D1 payload; disable expired/stale; explicit selection
ForbiddenApprove & Apply button that calls a mutating RPC; reuse of ApprovedApplyModal
InputsD1 viewmodel
OutputsHuman-readable diff + statuses
TestsPaths-only is insufficient; multi-proposal requires click-to-select; Neutron still does not import legacy modal
ExitReview UX ready; mutation still unauthorized
Next grantD3

D3 ​

GateRule
AllowedHost factory for NeutronMutationApproval from intent; reject spoofed fields; tests may call existing Apply
ForbiddenProduction Desktop mutating control; public Approve-only RPC; token in responses
InputsTyped intent fixture
OutputsHost approval object in-process; public results still token-free
TestsSection 43 adversarial cases that do not require Desktop chrome
ExitComplete (D3 merged). Issuer rejects spoofed model/renderer fields; tests cover section 43 items that do not require Desktop chrome
Next grantExplicit maintainer authorization for D4. DL and Desktop durableStateDirectory wiring are merged. D4 is not authorized by this brief

D4 ​

GateRule
AllowedapproveAndApply → host approval → Slice 3.1 claim/lock → graph Apply → Slice 4
ForbiddenN4 tool, mutationAllowed: true, Undo, silent retry, client approval records, extending invoke_neutron_request
InputsTyped intent
OutputsStructured Apply/verification result
TestsMerged D4 coverage: exact bytes, spoof rejection, staleness, duplicate, concurrent, lock, no model call, applied vs verified. Reconnect remains D5
ExitComplete (D4 merged, PR #534). One human action mutates only through the canonical chain; token stays host-only
Next candidateD5, only after a new explicit maintainer authorization. This row does not authorize D5

D5 ​

GateRule
AllowedResult/evidence/status recovery UX; optional design of Retry verification
ForbiddenRetry Apply, Undo, collapsing statuses
InputsD4 result + status.get
OutputsApplied vs verified vs reconciliation copy
TestsResponse-lost-after-Apply, verification mismatch labeling
ExitComplete. Slice 1 (PR #537) recovers durable truth. Slice 2 (PR #540) recovers it after reconnect. Verification retry is a separate post-D5 operation. Undo is not authorized
Next candidateUndo / rollback execution, only under a new explicit grant

DL ​

GateRule
AllowedRemove fabricated Approved Apply success from production Desktop
ForbiddenWiring Neutron to a stub; adding real Apply; leaving fake success reachable
ExitNo Desktop path fabricates applied: true without an authoritative host
StatusImplemented and merged (PR #525)
Next grantComplete for DL. D4 later merged (PR #534). D5 Slice 1 later merged (PR #537). Slice 2 is implemented on branch awaiting maintainer review

43. Adversarial tests ​

D3 merged (tests/neutron-mutation-approval-intent.test.ts) covers at least: spoofed authority fields; fake token/digests/bodies; approved: true, authorized, mutationAllowed; wrong proposalId; preview proposal; stale/expired/cancelled proposal; wrong root/project/session/graph; payload tampering; graph staleness; multiple authoritative proposals (exact proposalId, no first-wins); missing payload after restart; duplicate intent; one-use Apply replay via Slice 3.1; no model call; no public Approve RPC; no approveAndApply RPC; N4 still seven read-only tools.

D4 merged (tests/neutron-mutation-approve-and-apply.test.ts, tests/desktop-neutron-approve-apply-ui.test.ts) covers at least: exact reviewed bytes; renderer bytes ignored; spoofed authority rejected before write; stale project fail-closed; pre-write project-state revalidation; duplicate request does not write twice; concurrent callers cannot both mutate; an existing project lock blocks Apply; missing durable state fails closed; no model call on the Approve & Apply path; verification failure stays applied and is not retried; no public Approve RPC; no status.get; the method is absent from the generic Neutron command; N4 remains seven read-only tools; Approve & Apply is enabled only for a current review.

D5 Slice 1 merged (tests/neutron-mutation-status-recovery.test.ts, PR #537) covers response-lost recovery, applied versus verification, identity-bound index rejection, canonical pointer mismatch, and historical status after a later external edit.

D5 Slice 2 merged (PR #540, tests/desktop-neutron-mutation-recovery.test.ts) covers reconnect UX: uncertain transport presentation, one status.get after authenticated reconnect, and explicit Refresh status. Post-D5 verification retry is covered by tests/neutron-mutation-verification-retry.test.ts. Remain unauthorized: Undo, rollback execution UI, a mutation history browser, and two-window Desktop chrome walkthroughs beyond the focused UI tests.

DL tests (tests/desktop-legacy-approved-apply-isolation.test.ts, merged with PR #525) cover: no fabricated applied: true; no timeout mutation success; no synthetic previousContent; Neutron cannot reach ApprovedApplyModal; modal removed; no real Apply call; no mutating daemon RPC; no approveAndApply; mutationAllowed === false; N4 remains seven read-only tools.


44. Production metrics ​

Docs only. Do not touch production files in the brief PR. Future slices may count structured statuses without logging bodies or tokens.


45. Canonical document ​

This file: docs/roadmap/NEUTRON_N6_DESKTOP_MUTATION_HOST_BRIEF.md


Update pointers in DUTY_WATCH.md, PROJECT_STATE.md, NEUTRON_RUNTIME_ROADMAP.md, NEUTRON_N6_DESKTOP_READONLY_BRIEF.md, and NEUTRON_MUTATION_ROUTING_BRIEF.md. Mark D1, D2, D3, DL, and the Desktop durable-state prerequisite, D4 (PR #534), and D5 (Slice 1 PR #537, Slice 2 PR #540) complete and merged. Undo remains unauthorized. Verification retry is the separate post-D5 operation.


47. Status wording (normative) ​

Implementation and handoff PRs that cite this brief must repeat:

D1 IMPLEMENTED AND MERGED (PR #516)

DESKTOP MUTATION D2 IMPLEMENTED AND MERGED (PR #519)

D3 IMPLEMENTED AND MERGED (PR #522)

DL IMPLEMENTED AND MERGED (PR #525)

DESKTOP MUTATION DURABLE HOST STATE PREREQUISITE IMPLEMENTED AND MERGED (PR #528)

DESKTOP MUTATION D4 IMPLEMENTED AND MERGED (PR #534)

DESKTOP MUTATION D5 COMPLETE (Slice 1 PR #537, Slice 2 PR #540)

mutationAllowed remains literal false. N4 remains seven read-only tools.


48. Architecture decision ​

D1 (implemented): read-only authoritative mutation review payload transport from the authenticated daemon to Desktop (PR #516).

D2 (implemented): Desktop exact mutation review UI over D1 (PR #519). Read-only. No Approve/Apply.

D3 (implemented, PR #522): host approval-intent protocol and security tests. In-process issuer only. No production Approve/Apply.

DL (implemented, PR #525): legacy fake Approved Apply path removed from production Desktop. Does not add real Apply or wire intentloom.project.approvedApply.v1.

Desktop durable-state prerequisite (implemented and merged, PR #528): trusted Desktop-owned --neutron-mutation-state-dir / durableStateDirectory wiring for future Slice 3.1 host Apply. The native host derives <app_data>/neutron-mutation-state (Unix 0700; no Windows ACL claim beyond the code). The daemon validates the path and passes it into createNeutronSessionRuntime. The directory is not public. Not D4. No second store or lock.

D4 (implemented and merged, PR #534): one trusted-host Approve & Apply operation. Prerequisites merged before this slice: D1, D2, D3, DL, and Desktop durableStateDirectory wiring. D5 is complete (Slice 1 PR #537, Slice 2 PR #540). This document does not authorize Undo.

Rationale for sequencing (unchanged):

  • Exact reviewed bytes live in the host payload store; D1 exposes them and D2 presents them without widening mutation authority.
  • D3 proves the host issuer cannot be spoofed through intent fields; combined approveAndApply is the later authority slice, now merged as D4.
  • Undo and any N4 mutation tool remain future grants. Slice 1 status recovery and Slice 2 reconnect UX are merged. Verification retry is the separate post-D5 operation.

Slice 1 is the merged read-only status recovery. Slice 2 is the merged Desktop reconnect presentation (PR #540). The durable-state prerequisite is merged and is not itself Approve & Apply. D4 is the merged host operation.


49. Out of scope (repeat) ​

D4 (merged, PR #534) delivered the bounded host Approve & Apply operation described above. Still out of scope, and not authorized by this document:

  • verification retry UI
  • Undo / host rollback execution
  • N4 mutation tool
  • mutationAllowed change
  • automatic Apply retry
  • persisting unused approvals
  • rematerializing payloads from the model after daemon restart
  • a public Approve-only RPC or an Apply-by-token RPC