Repository navigation
chore: synchronize main into dev - #169
Merged
Merged
Conversation
release: promote reconciled dev to main
Add exact retained attention navigation
Replace the GTK tray backend with native GPUI
fix(security): upgrade notify to 8.2
fix(core): add authoritative platform attention custody
fix(security): upgrade stacksafe dependency
The attributed review action result now carries the server actor, which pushes `PlatformActionResult` past the `large_enum_variant` threshold and fails the `-D warnings` clippy gate. Box it the way `PlatformLoadResult` already boxes the same payload. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nf2PAqdKZxRuZSYGq3NE6o
Add confirmed check-rerun custody
The confirmed-rerun custody work claims SDTEST-1822..1828 in parallel. Move this branch's activation suite to SDTEST-1829..1841 so the two land without colliding, and rename the two core test functions that carry the identifier in their name. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nf2PAqdKZxRuZSYGq3NE6o
…on-128 Activate the authoritative attention board in Workspace and Fleet
Nothing but prose said ShellDeck, the hosted cockpit, and Mobile agree about what a sequence of attention reads means. `automonique.platform/attention/v1` is `atomic_replace`, so no single snapshot decides it. Vendor the shared corpus byte-for-byte from Automonique and replay it case by case against the authoritative board. Every recorded outcome must be reached exactly: the first-read revision fence, exact-predecessor succession, an identical replay, a conflicting one, a retention gap, an authenticated baseline bridging that gap, a baseline rollback, a baseline built behind the retained revision, and an item-revision regression. Final availability and rendered item identities must match, and hiding a source must never discard its revision chain — a client that forgot where it was could only resynchronize by trusting whatever the next read claims. The board needed no change: every case already replayed to the recorded outcome, which is the result worth having from a conformance fixture. Refs #128, bext-stack/automonique#163 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nf2PAqdKZxRuZSYGq3NE6o
…y-128 Replay the shared attention succession corpus against the board
Re-audited the RustSec baseline against the committed lockfile. `cargo audit` without this repository's ignore list reports exactly the six documented IDs and nothing else, so no entry is stale and none was widened. None of the six can be cleared today, and the reason differs per group, so write each one down with its evidence rather than leave the next reader to re-derive it. The three "GPUI vendored" advisories are not reachable from the fork at all. `instant`, `async-std` and `rustls-pemfile` arrive through `adabraka_util` and `adabraka_http_client` 0.5.1, which are plain crates.io siblings of the vendored `adabraka-gpui`, not part of it. All three constraints are non-optional (`futures-lite ^1.13`, `async-tar ^0.5.1`, `zed-reqwest`), so no feature switch or lockfile move touches them; 0.5.1 is still the newest release of every `adabraka_*` crate and the upstream repository is 404, so there is not even a tracker to file against. Reaching them means a new vendor or a `[patch.crates-io]` entry, which `.agents/patches.md` puts behind explicit human sign-off. `paste` reaches the lockfile through three independent chains (`metal`, `pulp`/`exr`, `rav1e`/`ravif`) and every one of them still declares `paste ^1` at its latest release, `metal` 0.33.0 included. Dropping `image` default features in the fork would cut two chains but not the `metal` one, so the ID would keep firing while GPUI lost image formats it advertises. `ttf-parser` is the closest to clearing and the only one with a live upstream change: `fontdb` 0.24.0 removed it, and pop-os/cosmic-text#526 is the open bump. `cosmic-text` 0.19.0 still pins `fontdb ^0.23`, so nothing resolves there yet. The exact follow-up is recorded so it is a one-line fork manifest change when the release lands. `rsa` has no patched version at all: the advisory records `patched = []` and RustCrypto/RSA#626 is open. `russh` 0.63.1 only moves to rc.18, which the advisory covers identically, and turning off the default `rsa` feature would remove the RSA key path `shelldeck-ssh` deliberately implements. No advisory ID was added, removed, or reworded away from its real path, and `Cargo.lock` is untouched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nf2PAqdKZxRuZSYGq3NE6o
The Fleet review listed every reviewed file in one flat column. That column could not answer the question a reviewer actually opens it to ask — what is staged, what is not, what is untracked, and what is stuck in a conflict — even though the Platform v2 snapshot has carried `worktree` and `conflict` on every file all along. The combined lanes are a read-side projection of state the server already sends, so nothing here needs new authority. Staging deliberately stays absent. `ReviewCapabilities` advertises `rerunnable_checks` and nothing else: Platform v2 defines no staging capability, no staging confirmation digest and no staging receipt-correlation digest, and `PlatformReviewActionPreview` structurally refuses a confirmation on Stage, Unstage, Commit and ResolveConflict. A proposal's `git` authority inside the read snapshot is an observation, not a proof that a mutation will be fenced exactly once — which is the same distinction the confirmed check rerun already makes. Rather than invent that proof, the projection reports the exact missing fence and shows the server's proposals as per-file observations, so a reader can see what the server would do without the client pretending it may. Hunk-level staging is not representable at all: a proposal names files. Previews were the other half of the gap. The contract ships preview *metadata*, never a payload, so a "preview" is a decision about what may be drawn from a claim. Declared byte sizes and raster dimensions are now bounded before they become a rendering budget, and an image is described beside an aspect-preserving placeholder that cannot exceed its edge cap — no pixels are decoded or fetched. Sanitized HTML is described only; it is never interpreted as markup and never re-emitted as source, which is the one thing a diff viewer must not do. Text gets the treatment the protocol's own bound cannot give it: `char::is_control` does not cover U+202E and its neighbours, so a bidirectional override could repaint a diff line as something it is not (the trojan-source class). Those scalars are replaced, and line count and length are capped, at the last point before pixels rather than trusted upstream. The anchor identity now binds lane, file and hunk because a partially staged file legitimately appears in two lanes, and two GPUI elements sharing an id route each other's clicks. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nf2PAqdKZxRuZSYGq3NE6o
…-125 docs(security): record why the six baseline advisories cannot clear yet
feat(review): combined worktree lanes and bounded safe previews (#128)
The authoritative board has carried `observed_at_ms` since the source inventory landed, but nothing read it. Both surfaces consumed `visible_items`, whose order is the `BTreeMap` key order — source kind, source id, item id. That is deterministic but arbitrary: a "feed" whose sequence has nothing to do with when the server observed anything. The Fleet strip made that worse by flattening several workspace boards into one row, so every item of the first board stayed ahead of every item of the second no matter how old it was. Ordering now comes from the one clock the contract actually provides. `PlatformAttentionBoard::chronology` sorts on the authoritative observation, falling back to the item revision and then to the `(source, item)` key so the sequence is total and identical in every process. Poll arrival is never consulted: a board that was refreshed later is not therefore newer. Rows keep carrying only the activation token, so opening one still re-resolves workspace, session and pane against the live catalogue through the PR #156 resolver. The row gains a relative time and the exact catalogue name of the workspace it activates into, and the desktop toast body gains the same name — an actionable notification that says only why it fired and never where it goes is half a deep link. Only the workspace is named there: it is part of the activation itself, whereas the session and pane are resolved at activation time and naming them at post time would be a guess with a shelf life. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nf2PAqdKZxRuZSYGq3NE6o
PR #155 built the durable at-most-once custody lane but wired only the confirmed check rerun through it: `prepare`, `mark_dispatched`, `record_receipt` and `cancel_prepared` were all guarded on `preview.confirmation().is_some()`. Comments and approvals — the two mutations Fleet actually exposes to a reviewer — dispatched with no durable record at all. The only trace was `unresolved_review_actions`, which lives in memory, so a restart between the POST and its receipt left a comment that had certainly been posted indistinguishable from one that had never started; re-preparing produced a fresh idempotency key and a duplicate server-side comment. The receipt actor was shown once and then forgotten. The custody disk format already understood `AddComment` and `ApproveReview`; nothing called it with them. Every exposed mutation now crosses the same fence, and preparation is refused outright when the store is unavailable rather than quietly falling back to an unfenced dispatch. A custody refusal is reported with its own copy: told that the snapshot moved, a reviewer re-anchors and retries, which is the wrong response to "an effect is still pending". The second half is persistence. A reviewer's notes lived in a single input field that a refresh, a workspace switch or a restart emptied. `PlatformReviewNoteStore` keeps them under the same bounded, no-follow, cross-process-locked private boundary as custody, each note retaining the file, hunk, side, line and the snapshot revision it was written against. Binding the revision is the point: a note whose snapshot has advanced is reported stale and refuses to prepare, because silently re-anchoring a comment onto whatever now occupies that line number is how a review comment ends up attached to code nobody wrote it about. Selection is stored beside the note so a batch decision survives a restart too. What that selection cannot do yet is leave the machine. `automonique_protocol::platform_v2_transport::ReviewCapabilities` carries exactly one capability vector, `rerunnable_checks`; there is no comment or batch-send capability on the wire, and therefore no confirmation digest and no receipt-correlation digest to make an ambiguous batch outcome recoverable. Fleet states that instead of offering a control that could not honour its own at-most-once contract. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nf2PAqdKZxRuZSYGq3NE6o
Persist anchored review notes, fence every review mutation, and order attention chronologically
…tract `ReviewCapabilities` advertised only `rerunnable_checks`, which is why the batch send-to-agent and staging controls have been shipping as stated refusals rather than controls. bext-stack/automonique PR #221 lands the contract layer: `agent_deliverable_comments` plus three independently withheld pull-request slots. This commit is mechanical and grants nothing on its own. `ReviewCapabilities` grew two constructor arguments, and the response it travels in is now boxed upstream because the type is far larger than the refusal it competes with in the same enum; `PlatformReviewCapabilitiesLoad::Available` follows suit for the same reason, matching `PlatformReviewLoad::Available`. The lockfile change is limited to the two `automonique-*` source lines. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nf2PAqdKZxRuZSYGq3NE6o
`ReviewCapabilities` now advertises `agent_deliverable_comments`, so the control this issue asked for can finally be fenced. Fleet renders a send toggle only for the comments that list names, and dispatches `batch_send_comments_to_agent` with each `comment_id` and `expected_comment_revision` taken verbatim from the capability, at the capability's own `snapshot_revision`. The snapshot is consulted only to prove the two reads agree; it supplies no value that crosses the network. This is the unconfirmed lane, and that is deliberate rather than an omission. A rerun needs a digest because the client names the target and the effect fires in a system the daemon does not own. Delivery differs on every axis that motivated one: the session is registry-owned and never on the wire, the snapshot revision is fenced twice server-side, and the note set is fenced by the server's batch arm. Exactly-once falls out of the domain state machine. Minting a receipt correlation would have been worse than redundant, because the host's receipt lookup skips a retained action carrying one, so the client would have handed itself a token that makes its own receipt unfindable. What replaces the digest is the advertisement, and the rule that follows is the one this change exists to enforce: re-read it, never reuse it. Settling a delivery moves the comment out of `not_sent`/`refused` and bumps both the snapshot revision and the comment's own revision, so a re-read cannot still list it. `matches_capabilities` therefore revalidates a batch preview before it crosses the dispatch fence, and the persisted selection is retained against the advertisement rather than the snapshot, so a stale list empties itself instead of being posted. The custody fence is not weakened to fit. This lane needs no confirmation digest, but it is an exposed mutation and takes the same durable at-most-once record as every other one. That required extending the custody disk format, which knew only `AddComment`, `ApproveReview` and `RerunCheck` — so a batch delivery could not be recorded at all and would have refused at the fence. Two locale strings were corrected while passing: the staging refusal claimed Platform v2 publishes only the check rerun, which stopped being true with this contract, and the notes panel claimed batch delivery was unavailable. A note is a local draft with no server comment id, so its durable selection marks which drafts to prepare; delivery names server comments, and says so. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nf2PAqdKZxRuZSYGq3NE6o
SDUC-495 still said batch delivery was unexposed because `ReviewCapabilities` advertised only check reruns, and the staging entry repeated that claim as its reason. Both stopped being true when the contract grew `agent_deliverable_comments`, so the catalogue now describes what is actually exposed, why the lane carries no confirmation digest, and the one rule that follows from having no digest: re-read the advertisement, never reuse it. The staging reason is narrowed rather than dropped. Staging is still withheld, but for its own reasons — no staging digest, no receipt correlation, no representable hunk granularity — not because the rerun is the only capability that exists. SDTEST-1863..1866 are added at Green. SDTEST-1863 is the one worth reading: it demonstrates the stale-list case instead of asserting it, by replaying the server's own eligibility rule across a settlement. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nf2PAqdKZxRuZSYGq3NE6o
Send selected review comments to the authorized session
PR #221 shipped no staging capability on purpose: a proposal id plus a snapshot revision does not pin a worktree, so a staging confirmation digest would have had to commit to the HEAD object id and the index state, and no projection carried either. That was the single contract gap behind the last open item of #128, and both halves of the ticket reached it independently. bext-stack/automonique PR #225 earned that field set from a mutation-free preflight of the repository. `ReviewCapabilities` now carries `staging` and `conflict_resolutions`, each entry naming the commit HEAD resolved to and a digest over the whole index, plus the two digests every confirmed lane needs. The four staging actions moved into `requires_confirmation`, so their unconfirmed spelling no longer encodes on either side. This commit is the bump and the mechanical repair that keeps the tree green: `ReviewCapabilities::new` grew an eighth argument, so every test helper that mints a capability response now passes an explicitly empty `ReviewGitStagingCapabilities`. Empty is the honest value for a helper that is exercising another family — it says the server proved no staging, which is exactly what those tests assume. The lockfile diff is limited to the two `automonique-*` source lines. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nf2PAqdKZxRuZSYGq3NE6o
The combined staged/unstaged/untracked/conflicted view has shipped since PR #159. Only the mutations were missing, and for one structural reason: `ReviewCapabilities` carried no staging capability, so a stage could only have gone out unconfirmed and uncorrelated, and an ambiguous outcome would have been reconcilable by nothing but an uncorrelated key search. That is exactly what the confirmed lane exists to avoid. The capability landed, so this consumes it, following `delivery.rs` rather than inventing a second shape: the two are the same problem, one read-side projection reporting what the server proved plus which fence is missing when it proved nothing. Absence is the withholding. The three staging kinds share one capability type but not one grant: an operator installs `index_write`, `commit` and `conflict_resolution` independently. A deployment granting stage and unstage but not commit therefore advertises two entries, and the commit proposal keeps its observation badge and grows no button. A disabled button with a tooltip would claim the grant is present and merely unavailable, which is the opposite of what the list says. `conflict_resolutions` lists one entry per admissible side, because the side decides which blob lands and a digest cannot commit to a choice not yet made. A file with both stage 2 and stage 3 recorded renders two controls; a delete/modify pair renders one. Three things this had to touch beyond the obvious: `review_action`'s confirmation guard now asks `requires_confirmation()` instead of restating it as a local `matches!` on the rerun. The confirmed set grew from one member to eight with this protocol revision, and the local spelling had already gone stale for `merge_pull_request`, which was minting previews the transport could no longer encode. That constructor now takes its capability like the rerun does, so it refuses honestly instead of failing at the wire. `custody.rs` did not understand these four families. It would have returned `UnsupportedAction` at `prepare` and the dispatch would have died at the fence, which is precisely what PR #161 found for the batch delivery after PR #160 asserted the format already knew "these actions". It knew the two it named. The disk enum now spells each staging kind separately, because a recovered plan that could be re-read as another kind would let a narrower grant replay as a wider one, and a conflict resolution persists its side because the side is part of the effect's identity. Receipts are polled through `GetReviewReceipt` with the correlation digest, which `lookup_review_action` already routes for any confirmed preview: re-sending the action would be pointless anyway, since the write invalidated the confirmation it was minted with. A stale worktree withdraws the control locally rather than reaching the daemon. The server mints the confirmation over the commit HEAD resolved to, the whole index and every named path, so comparing the digest against a fresher capability document *is* the head-and-index comparison; the observation is exposed on the projection so a reader can see the fence rather than trust that one exists. Hunk granularity is not built and not faked. Proposals list file ids and `ReviewAnchor`'s hunk id serves comments only, so file-level staging is all the contract can express. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nf2PAqdKZxRuZSYGq3NE6o
Amends SDUC-495 for capability-fenced file-level staging, unstaging, committing and conflict resolution, and adds SDTEST-1867..1873 across the core and UI inventories. The use case now states the two things a reader has to know to review this surface: a control exists only where a slot exists for that exact proposal, so a withheld grant is an absent control rather than a disabled one; and `conflict_resolutions` lists one entry per side git recorded, so a file holding both renders two. SDTEST-1848 is retired rather than deleted. It pinned the reason staging had no control at all, and that reason is gone: PR #225 closed the contract gap it named. SDTEST-1867 replaces it and fails closed the other way round, demonstrating that a deployment granting stage and unstage but not commit renders no commit control while both siblings go end to end. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nf2PAqdKZxRuZSYGq3NE6o
A staging proposal names files, so its control belongs on the file card next to the observation badge, not in the footer row where the check rerun and the batch send live. Those two act on the review as a whole; these do not. Same widgets, same sizing, same disabled gate as both siblings, so the placement is the only divergence and it is recorded where the next reader will look for it. Two smaller corrections in the same pass: the control row claims its bottom margin only when it holds a control, so a card with none does not push its preview down by an empty row's spacing; and the lane-level "is there anything a control could apply to" check now walks proposals once instead of every file against every proposal on a render path. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nf2PAqdKZxRuZSYGq3NE6o
Offer a git staging control only where the server proved a slot
Nothing cleared. All six remaining IDs were re-checked against the crates.io sparse index, the resolved dependency graph and the live upstream trackers rather than against the previous write-up, and every path still resolves: - a full `cargo update --dry-run` moves nothing in any of the six chains; - `cosmic-text` still pins `fontdb ^0.23` on `main`, and pop-os/cosmic-text#526 is still open and unmerged; - the `rsa` advisory still records `patched = []`; - `adabraka_util` / `adabraka_http_client` are still 0.5.1, and the only public source snapshot carries the same `futures-lite = "1.13"` constraint. So `.cargo/audit.toml`, `deny.toml` and the workflow ignore list are unchanged: no ID was removed because no dependency path disappeared, and none was added. One recorded claim was wrong and is corrected. The note said the adabraka advisories had "no upstream tracker to file against". `Augani/adabraka-gpui` does still 404, but `Augani/adabraka-ui` is live with issues enabled and issue #10 already tracks the missing source, where a commenter states the project is superseded by `kael`. A tracker exists; the crate line is abandoned. That is a stronger reason to keep the exception than the claim it replaces. Also records why the lockfile trails `metal` and `exr` without that mattering, and warns that the `cargo update --dry-run` this file recommends will propose the `pathfinder_simd` 0.5.6 bump that breaks the macOS release build. Refs #125 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nf2PAqdKZxRuZSYGq3NE6o
…ify-2026-08-30 Re-test the six baseline advisories against live upstreams
`workspace_review.rs` models `StageHunks`/`UnstageHunks` with no adapter behind them, fenced by `MutationTargetFence::LocalReview`. That fence pins the checkout and this crate's own review revision, neither of which moves when another process running as the same uid moves HEAD, the index or the file, so wiring it to a git write would fence nothing. shelldeck#163 asked whether a hunk identity stable enough to close a write exists before anything gets built. It does not, and the doc comment now carries the three reasons at the site rather than leaving them to be re-derived: a hunk is a property of a rendering rather than of the repository, the contract's hunk id and bounded preview exist for comment anchors, and `git apply --cached` (which is what `git add -p` runs) matches context at any line offset and will write into a region nobody reviewed. Documentation only. No SDUC and no SDTEST: nothing changed behaviour, and a test here would pass by construction. The USE_CASES change log records the outcome so the decision is legible next to the file-level staging that ships. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nf2PAqdKZxRuZSYGq3NE6o
Record why hunk staging cannot be fenced, at the site that would wire it
Agent workspace cockpit
…ation fix(agents): restore remote cockpit integration
feat(marketing): publish responsive user-support video
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Résumé
devau niveau demainaprès les versions 0.9.5 et 0.9.6maindevest un ancêtre direct demain: cette synchronisation ne nécessite aucune résolution de conflit.