Skip to content

chore: synchronize main into dev - #169

Merged
pedrokarim merged 58 commits into
devfrom
fix/sync-main-into-dev
Sep 7, 2026
Merged

pedrokarim merged 58 commits into
devfrom
fix/sync-main-into-dev

Conversation

@pedrokarim

Copy link
Copy Markdown
Collaborator

Résumé

  • remet dev au niveau de main après les versions 0.9.5 et 0.9.6
  • récupère les intégrations et correctifs déjà publiés sur main
  • inclut la vidéo marketing Utilisateur/Support et le centrage des icônes de la landing

dev est un ancêtre direct de main : cette synchronisation ne nécessite aucune résolution de conflit.

pedrokarim and others added 30 commits August 28, 2026 16:56
release: promote reconciled dev to main
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
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
benfavre and others added 28 commits August 29, 2026 17:43
…-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
…ation

fix(agents): restore remote cockpit integration
feat(marketing): publish responsive user-support video
@pedrokarim
pedrokarim merged commit 9046fee into dev Sep 7, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants