← Corpus / augment-it / spec
Entity-Card Edit & Remove Affordances — every visible property gets a micro-button pair
The org card views and edits in place, but only additively — a misclicked ➕ today required a direct database write to undo. Every entry and identity property the card shows grows ✎ and × micro-buttons.
- Path
- specs/Entity-Card-Edit-And-Remove-Affordances.md
- Authors
- Michael Staton
- Augmented with
- Claude Code on Claude Fable 5
- Tags
- Spec · Augment-It · Org-Workbench · Workspace · Canonical-Layer
Entity-Card Edit & Remove Affordances
Why Care?
The operator ruling that shaped the org card — “no two loops, two apps;
one screen that views AND edits in place” — was only half-honored. The
card edits in one direction: additive. Today (2026-07-24) the operator
accidentally ➕‘d alpha.school as Princeton University’s identity URL,
and the only undo was an agent session doing a raw SurrealDB UPDATE.
The additive discipline that protects canonical data from agents also
locks the human out of corrections — exactly backwards for the
human-in-the-drivers-seat model: agents propose, the operator disposes,
and disposal includes removing what’s wrong.
The rule this spec sets: anything the card renders, the operator can edit; anything the operator (or an accepted candidate) put on a list, the operator can remove. Micro-buttons, in place, no other surface.
Scope
- List entries — org card’s three
AdditiveLists (identity/social links, pulse streams, corpus items) and the person-card lists that reuse the component. Each row gets:- ✎ edit — patch
kind(all lists),name(streams — already shipped viaorganization.streams.update), andurlitself. - × remove — delete the entry, inline confirm (“remove alpha.school from Identity & social links?”), no modal.
- ✎ edit — patch
- Identity block — the
<dl>properties: complete/conventional name (rides the existingresolver.update_org, which the workbench never exposed), aliases (add ✕-chip removal), domains (same chip pattern). - Affiliation edges (same-day extension — the Marla Blow case:
accepted against the wrong org, no way to detach) — the expanded
person card shows its affiliation (“role at OrgName”) with × (
person.unaffiliate: edge delete +affiliation_removedobservation; person, org, and history all stay) and a ”+ other org” door that reuses the bio-promotion gate with no seeding entry. - Out of scope — affiliation rating flows, and merge/dedupe (gh #30, its own surface).
Decisions
- D1 — Removal is a first-class capability, not a UI trick. New
verbs, mirroring the add pair shapes, all match-by-URL (the de-facto
entry key everywhere — dedupe, scan, streams.update precedent):
organization.links.update/organization.links.remove,organization.streams.remove,organization.corpus.update/organization.corpus.remove, and the person twins (person.links.remove,person.corpus.remove). Served by record-surrealdb-resolver beside their add siblings; 30s Cloud round-trip budget. - D2 — Updates are flat-shaped, swap-in-place.
*.update {org_slug, url, new_url?, kind?, client}(streams keepname?too) — the same flat shapeorganization.streams.updateestablished, which just gainsnew_url. The handler patches the entry in place soadded_atprovenance survives a typo fix; a corpus URL edit re-resolves the entry’scontent_idso the ledger bond stays true. - D3 — Corpus removes detach the entry, never delete content.
organization.corpus.removepulls the entry offorg_corpus; fetched markdown in the per-client corpus filesystem andcontent_itemsrows stay (other records/clients may reference them; storage is subscale — the redundancy ethos). A later sweep can garbage-collect orphans if it ever matters. - D4 — Removal leaves a trail. Every remove writes one observation
(
predicate: 'entry_removed', object = the URL,clienttag, actor attribution) so canonical history keeps what-was-there-and-when without keeping the wrong data live. Accumulate observations, not overwrites. - D5 — Micro-buttons are hover-revealed, confirm inline. Row rest
state stays as today; hover (or row focus) reveals
✎ ×at the row’s right edge, sized to the existing.ow-plusclass. × flips to an inline “remove? yes / keep” pair — the Search-Results-Queue dismiss confirm pattern, no dialogs. The streams ✎ generalizes to all lists. - D6 — Wire discipline unchanged. Slugs/uuids only,
clienton every call,augment-it:entity-updatedbroadcast after every mutation so the card, roster counts, and any open search-rail cards refetch.
Implementation sketch
- Capabilities — handlers in record-surrealdb-resolver (links.ts /
streams / corpus modules beside the adds), capability map + timeout
entries in
services/workspace/src/capabilities.ts. - AdditiveList —
oneditgeneralizes from streams-only to all lists (kind editing everywhere, name wherenameable); newonremoveprop with the inline confirm; hover-reveal CSS. - OrgCard / PersonCard — wire the new verbs; identity block gains
name-edit (via
resolver.update_org) and alias/domain chip removal. - Proof — extend
prove-augment-from-db-capabilities.mjswith the remove/update round-trips against the Aspen safe target; browser drive: add a wrong link, edit its kind, remove it, watch the card and roster counts refetch.
Resolved questions
- × on a stream that fed corpus items warns. Operator confirmed 2026-07-24 (“Yah warn if it fed a corpus”). Implemented as a domain-match approximation — corpus entries don’t record their source stream, so the confirm notes “this stream’s domain fed N corpus items — they stay”. Exact stream→item lineage is a later refinement if scan provenance ever lands on corpus entries.
- Alias/domain removal rides
resolver.update_org— it already owns the identity block;aliases/domainstravel as full-array replacements the chip editors compute client-side.
Related
- [[Augment-From-DB-Flow]] — the card this corrects; its D-series set the additive discipline this spec now balances.
- [[../plans/Workbench-Usability-Sweep-Corpus-Visibility-Stream-Editing-Affiliation-Promotion]] —
the
streams.updatematch-by-URL precedent (#26). - [[Search-Results-Queue-Remote]] — the inline-confirm pattern D5 copies.