Repository navigation
Commit aab7070
feat: workspace review — withdrawn and removed requests, and a notice when someone removes yours (#1708)
* feat: workspace review — skill publish waits for the owner, review status, decision notices, your pending rules
- `skill publish`: submits the skill to the linked workspace (`POST /datamates/{id}/reviews`) and reports the server's answer: published, sent for review, already waiting, or already approved; a member is told before upload when the owner has review off; older backends fall back to the previous attach; `--json`; every failure exits non-zero
- `skill-sync`: reads skill detail and files with `datamate_id`, so a contributed skill arrives at its approved version (or, for its author, the waiting one); detects changes by `revision`, falling back to `updated_at`
- `altimate-code workspace review status [--json]`: your submissions, their state and the reviewer's reason; reads only, starts nothing
- Decision notices for your skill and knowledge submissions: recorded per account and workspace outside the project, kept (the 50 most recent) and replayed by the TUI like rule notices, so one is never lost when no client is listening
- Your own pending rules (`my_pending` from the rules pull) reach your sessions under "Your rules pending review"; a pending edit shows its proposed wording to you in place of the approved rule; same scope, credential and kill-switch checks as team rules
- Server text passes through `printable` before reaching the terminal
- Docs: skills, CLI usage, learn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: workspace review — skill sync downloads one version, publish finds rejected skills, CLI source
- `skill-sync`: the detail and every file read carry the listed `revision`; a mismatch (including a 409 `revision_changed`) discards that skill's whole download and the next sync retries, so a project never holds files from two versions
- A previous copy is kept over a failed download only while it is the version the workspace still serves (or was synced without a revision, from an older server); a copy of a version no longer served — a rejected or replaced one — is removed, even when every skill failed, and on an abandoned run
- `skill publish --replace` finds your existing skill through your own skills (`GET /skills?mine=true`), so a skill whose first submission was rejected is found; it still refuses a same-name skill attached only to another workspace
- Submissions from `skill publish` are recorded as from the CLI (`source: "cli"`)
- Docs: CLI usage, learn, skills
Note: workspace knowledge search is scoped by the engine that calls the knowledge query, outside this repository; it already receives the workspace id at start.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: workspace review — skill sync withdraws what the server says is no longer served, serialised across processes
From a second three-model review of the whole feature:
- A copy is withdrawn when the server has said its version is not served: the successful list names another revision, a read is refused with 409 `revision_changed` naming another one, or the list no longer names a skill synced from a review-aware server (it recorded a revision). This holds even when every other download fails and on an abandoned run; a plain failure (network, 401/403, 5xx) still keeps a copy the server has not contradicted
- The snapshot swap and the withdrawal on an abandoned run take the same cross-process `Flock` lock, and a withdrawal removes only a copy still identical to the one this run judged obsolete, so a newer copy another process published is kept
- A detail that answers for another revision raises the same coded `revision_changed` as the server's 409
- Docs: CLI usage
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: workspace review — one credential per publish, sync never undoes a newer snapshot, notices scoped to their project
Publish
- The whole publish (identity, review summary, upload, submission, attach, ownership checks) uses one captured
credential; review client calls require it.
- A member whose server turns out to have no review keeps the upload and is told the submission failed, instead of
falling back to an owner-only attach that takes the upload back.
- A skill detail without a readable `attached_datamate_ids` fails rather than replacing the attachment set.
- `skill publish --json` reports failures before the publish (opening the project, reading skills) as JSON, once.
Skill sync
- Every removal of the live snapshot takes the cross-process snapshot lock.
- A swap or an empty-list removal goes ahead only while the live manifest is still the one the run read; a superseded
run keeps the newer snapshot and still withdraws what its own read said is no longer served.
- A copy recorded with a revision is kept on a failed download when the list names no revision.
Review notices
- A list with unreadable rows, a page short of its total, or paging without counts never lets a pending request go;
a server that ignores `page` stops after the repeat.
- Replay never waits on the network: an unknown account is looked up in the background; a link read under another
credential returns nothing.
- The TUI handles rules events of its own project only; an unknown decision status still shows a notice.
- `workspace review status` resolves the link like `workspace status` (server revalidation, unlink, rebind).
Rules
- A pending edit keeps the pin of the rule it replaces; a pending proposal whose paths change rebuilds the session.
- Pending proposals left out of a pull (unreadable or failing the lint) are reported in the sync status.
- The learning-setting response and `learn status` read review notices for the session directory.
Docs state which decisions are noticed, the first-replay exception, and what the sync and status command guarantee.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: workspace review — pending rules stay pending in plugin sessions, an abandoned sync withdraws replaced copies, notices reach every linked project
Plugin host sessions (after merging main, which added them)
- Session start gives what sync vouches for, as an altimate-code session does: the person's own pending proposals
carry `review: "pending"` in `Start.rules` and are listed under their own heading, never under "approved by the
workspace owner"; a pending edit no longer shows as approved wording. The no-session fallback uses the same set.
Skill sync
- A copy whose listed revision moved on is withdrawn when the run is abandoned or superseded before its swap, even
when its replacement downloaded fine.
- The liveness check also compares the "workspace has no skills" record, so a run that started with no snapshot
cannot bring skills back after another run removed them as empty.
- A previous workspace's or account's manifest is never used to withdraw; withdrawals report the sync as changed.
Review notices
- A server or tenant without review is asked again only after 6 hours, and its 404 is not reported as an API error.
- A pending request past the page cap is looked up by id (up to 10 per poll), so its decision is still noticed.
- Stored notices follow the IDE's pin for the tree, from what is on hand; every kept decision is replayed.
Commands
- `skill publish` captures the credential before resolving the link and stops if the sign-in changed; signed out is
said as such. Error text is made printable; a failure after a written result still exits non-zero.
- `workspace review status` lists with the credential the link was resolved for.
- The TUI's fallback notice status is made printable.
Docs: a notice is shown once in each project linked to the workspace; the poll's cost is stated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: workspace review — notice lookups let go of removed requests and rotate, an accepted submission never fails on an unknown row shape
- Past the list cap, a pending request the server answers 404 for is let go, and one whose lookup fails moves behind
the others, so a few failures never take every lookup.
- `skill publish` keeps an accepted submission when the server's row has a status or change this version does not
know.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat: workspace roles — admins approve and publish like the owner, members send for review
The server now sends the caller's `role` (`owner`, `admin` or `member`) next to `is_owner` on the review summary,
the rules summary and rules `/sync`. `WorkspaceRole.roleOf` reads it, falling back to `is_owner` for an older server
or a role this version does not know; `manages` is owner or admin.
- Rule cards: an admin is offered "approve" like the owner; a member "send". The role from the last pull is kept in
the rules state, and the remember tool says "you (a workspace admin)".
- `skill publish`: review off refuses members only; an admin's skill is attached directly by the server; an admin
whose server turns out to have no review falls back to attaching. A server without review still needs ownership.
- Wording that named only the owner as reviewer now says "the owner or an admin" (plugin host sessions, the pending
heading, the review-off error, `learn propose --send`), and the docs say admins review too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: workspace roles — review wording names the owner or an admin everywhere
- `learn reply --approve` help: "(workspace owner or an admin)"; `--send-for-review` help and the bootstrap /
import-reviews epilogs and prompts say the owner or an admin decides.
- Rule replies, queued sends and history-staged sends say "Sent for review in <workspace>: <owner> or an admin
decides" instead of naming the owner's queue.
- TUI card hint: an admin's approve says "You are an admin of <workspace>", not "You own".
- The training tool's description: a rule goes for review by the workspace owner or an admin.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat: workspace review — withdrawn and removed requests, and a notice when someone removes yours
- `review-api.ts`: `withdrawn` and `retired` are read as statuses (never skipped, so a list
stays complete and pending ids are let go), plus `decided_by_me` and `author_has_access`.
- Notices: a withdrawn request is let go silently. Approved requests are tracked (bounded,
`MAX_APPROVED`), and when an owner or admin removes one (`retired`, not by you) the TUI
shows it once with who and why. Your own removal, and removals of requests this client
never saw, show nothing. State files without the new field still load.
- TUI toast and `workspace review status` wording for withdrawn and removed requests.
- Docs: withdrawing and removing happen in the web app; the new notice.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix: workspace review — removal notices track approved requests stably and reach ones past the list cap
- The approved requests a client tracks keep their order: a newer approval
waits for room instead of evicting one, so past 200 the tracked set and the
state file no longer change from poll to poll.
- An approved request the capped `view=mine` list does not reach is looked up
by id with the pending ones (same rotation, a 404 lets it go), so its
removal is still noticed.
- Docs say removal notices cover requests this client has seen approved or
waiting, within the 200 it tracks, and not your own removal.
- `decided`'s docstring covers removals; `author_has_access` is no longer
parsed (nothing read it).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>1 parent ebaaefe commit aab7070
7 files changed
Lines changed: 154 additions & 21 deletions
File tree
- docs/docs
- configure
- usage
- packages/opencode
- src
- altimate/workspace
- cli/cmd
- plugin/tui/altimate
- test/altimate/workspace
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
209 | 209 | | |
210 | 210 | | |
211 | 211 | | |
212 | | - | |
| 212 | + | |
213 | 213 | | |
214 | 214 | | |
215 | 215 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
70 | | - | |
| 70 | + | |
71 | 71 | | |
72 | 72 | | |
73 | 73 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
43 | | - | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
44 | 47 | | |
45 | 48 | | |
46 | 49 | | |
| |||
53 | 56 | | |
54 | 57 | | |
55 | 58 | | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
56 | 62 | | |
57 | 63 | | |
58 | 64 | | |
| |||
0 commit comments