Skip to content

id: design: chat ↔ talk-page unification (from #5682) #5872

Open

Description

@dezren39

Summary

Follow-on design ticket from #5682 — its decomposition sketch names this as a separate design, and the parent's acceptance requires these tickets to be filed and linked. Filed in the 2026-11-04 gap pass (WS-F) so the design work exists and can be prioritised on its own merits; implementation timing is a separate decision, possibly months out.

What this design must settle

Protocol extensions on #2036/#2051 unifying chat and talk pages, including retroactive anchoring of v1 chats.

Context from the parent

The parent design fixes chat's growth from v1 (#2051) — conversation↔object linking, talk pages, and terminal participation — on the #2036 protocol. The parent issue carries the surrounding decisions this ticket must not re-decide; where this ticket's answer would change a parent decision, record that explicitly rather than silently forking it.

Decision record expected

Close this design with a recorded decision (on this issue or in a doc/ record linked from it): the chosen shape, the alternatives rejected and why, and the invariants implementation must hold. If the design splits further, file the splits and link them here rather than growing this issue.

Relations

Parent: #5682. Programme: epic #2056. Filed by WS-F (2026-11-04 ID design gap & expansion pass).

Activity

  1. added
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    on Nov 5, 2026
  2. developing-today commented on Nov 5, 2026

    @developing-today
    Contributor
  3. added
    queue/queuedHas a queued task in the Supabase agent queue
    task/triageQueue packet kind: verify, reproduce, and route this item
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 5, 2026
  4. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done (triage)

    Triage findings (verified fresh 2026-11-05):

    1. Well-formed, self-contained design ticket. Issue id: design: chat ↔ talk-page unification (from #5682) #5872 (from issue id: design: Chat next steps — conversation↔object linking, talk pages, terminal participation #5682's decomposition, WS-F gap pass 2026-11-04) states its acceptance plainly: close with a recorded decision on the protocol extensions unifying chat and talk pages, including retroactive anchoring of v1 chats — chosen shape, alternatives rejected, invariants. Nothing missing, no defect to verify.
    2. Context verified live: parent issue id: design: Chat next steps — conversation↔object linking, talk pages, terminal participation #5682 is OPEN; programme epic issue epic: ID platform expansion — apps, comms, currency, hosting, boards (2026-10-28 directive, LIST 6–15) #2056 is OPEN (verified this shift). The parent fixes chat's growth from v1 (issue id: design: ID chat v1 #2051) on the issue id: design: ID messaging/relay protocol v1 #2036 protocol; those are fixed context this ticket must not re-decide silently.
    3. No blocker, no Drew decision needed to start. Implementation timing being a separate, possibly-months-out decision gates implementation, not this design. The only remaining work is the design itself, so the follow-up enqueued in this pass is the decision-record task for this same issue (standard triage dedupe key, enqueued after this triage completes).

    Disposition: triaged; design work proceeds as the follow-up task named in the addendum. Issue #5872 stays open for it.

  5. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · addendum to task 10274 triage

  6. added
    queue/queuedHas a queued task in the Supabase agent queue
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 5, 2026
  7. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    Decision record — chat ↔ talk-page unification (task 10499)

    This closes the design question on this issue. Chosen shape, alternatives, and invariants below; implementation is a separate, gated track (#6222).

    Context fixed by the parents (not re-decided here)

    Decision: unification by additive binding events on the one conversation log

    1. One abstraction. A conversation is a channel group, exactly as in v1. There is no talk-page entity, store, or protocol. A talk page is a conversation whose log contains a talk_for binding (below). Chat clients and object-embedded views are two projections of the same event log.
    2. New event kind chat.anchor.v1 (chained permanent, in the conversation's group): binds, unbinds, or re-locates a conversation↔object anchor. Payload: target object (ID + author key), link type (vocabulary owned by id: design: chat anchor data model (from #5682) #5870: about, anchored-to-part, derived-from, resolved-into), and for part anchors a by-reference selector (object ID + part identifier per id: design: chat anchor data model (from #5682) #5870's grammar) — never embedded object content, never a capability.
    3. Conversation-level talk_for binding: a chat.anchor.v1 event with link type talk-for designates the conversation as the object's talk page. Exactly one canonical binding per object: the first valid binding in causal order wins; a later conflicting binding folds to a visible disputed state on all replicas, never a silent fork. Binding authority (who may bind — object owner / members) is enforced at admission under the object's policy, with the detailed permission rules owned by id: design: talk-page semantics (from #5682) #5871.
    4. ChatLink gains a third kind, object: an addressable ID object named by ID + author, alongside v1's blob/event. This is the in-message anchor and the paste-a-link upgrade path. Recorded explicitly, per this issue's instructions: this extends the implemented v1 in chat.rs ("only blob and event are v1 link kinds") — it is an additive extension decided here, not a silent fork of id: design: ID chat v1 #2051; pre-extension clients treat it under invariant 7 below.
    5. What stays application-layer (per id: design: Chat next steps — conversation↔object linking, talk pages, terminal participation #5682 §4): anchor indexes ("conversations about this object"), search, presence, and notification fan-out are projections/indexes over the log, not protocol state. The protocol carries only anchor records, the talk_for binding, and thread-object bindings as they fall out of (2)–(3).

    Decision: retroactive anchoring of v1 chats — additive only, confirmed by a member

    • No history is rewritten, ever. Anchoring a v1 conversation or message is a new signed event appended now, referencing existing messages by event ID. V1 events are immutable (chained permanent); any design requiring re-signing or migrating them is disqualified on its face.
    • Designation: an existing v1 conversation becomes an object's talk page by a talk_for binding event (subject to the one-canonical rule and binding authority above). It keeps its history, membership, and identity.
    • Recognition proposes, members dispose: clients may scan existing message text for object URLs/IDs and propose anchors, but a proposal has no protocol effect. An anchor exists only when a conversation member confirms it with a signed chat.anchor.v1 event. No scanner silently rewrites a conversation's meaning after the fact.
    • Anchor absence is a state, not an error: unanchored v1 conversations remain fully valid, indefinitely. There is no migration deadline and no orphaned-conversation state introduced by this model (satisfies id: design: Chat next steps — conversation↔object linking, talk pages, terminal participation #5682 §4 migration/compat directly).

    Alternatives rejected

    • A. Separate talk-page system (wiki-style per-object comment store): forks moderation, search, presence, and the terminal client, and contradicts the parent identity decision. Rejected.
    • B. Migrate v1 history into a new anchored v2 format: breaks event signatures and causal history, orphans v1-only clients, and buys nothing the additive events don't. Rejected.
    • C. Anchors as client-local metadata only: never syncs, replicas diverge, the object-side anchor index is impossible, and terminal clients can't participate on equal terms. Rejected.
    • D. Talk page embedded in the object (object owns a comment list): couples discussion storage to object versioning/tombstoning, makes cross-object threads inexpressible, and breaks conversation-first clients. Rejected.

    Invariants an implementation must hold (testable)

    1. Single log: talk view and chat view are projections of one event log; no message exists in one and not the other.
    2. Additivity: every extension is a new event kind or a new link kind; a log with no anchor events projects identically to v1.
    3. No history mutation: retroactive anchoring never edits, re-signs, or reorders existing events.
    4. Determinism: anchor and talk_for state is a pure fold over the log under the existing causal order + event-ID tie-break; all replicas converge, including on disputed bindings.
    5. One canonical talk page per object, with conflicts visible, never silently forked.
    6. No capability leakage: anchors and bindings name objects by ID + author only; a binding never grants read access to the object or the conversation (visibility intersection rules are id: design: talk-page semantics (from #5682) #5871/id: design: chat anchor data model (from #5682) #5870 territory, unchanged by this record).
    7. Unknown-kind tolerance: clients that predate the extension skip chat.anchor.v1 events and object links without failing projection.
    8. Orphan safety: tombstoning an anchored object leaves the conversation intact with a tombstoned anchor (drift/re-location mechanics are id: design: chat anchor data model (from #5682) #5870's).

    Boundaries — what this record deliberately does not decide

    Follow-on

    Implementation filed as #6222, gated on (a) the separate implementation-timing decision and (b) #5870 and #5871 landing their decisions. No queue task was spawned for it — starting it now would be premature on both gates. No further design splits: the remaining #5682 decomposition items already exist as #5870/#5871/#5873/#5874/#5875.

    Queue: task 10499 completes with this record as its outcome (triaged outcome class; the design work named in the packet is this record).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/idPackage/app: id (pkgs/ or apps/ in this repo)task/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions