F3 — Live human/Claude attribution in the buffer, git-native provenance #6

Closed
opened 2026-06-10 14:45:23 +00:00 by benstull · 0 comments
Owner

Summary

Live human/Claude attribution in the buffer: as a document is coauthored, the
editor shows — live, in the buffer — which spans were written by the human
and which by Claude, with the attribution record persisted git-natively in
the same sidecar (the spec's reserved attributions[] extension point, reusing
the shared anchors primitive established by F2).

Problem / pain

Coauthoring with an AI in the editor has no attribution/provenance: once a
machine edit lands in the buffer it is indistinguishable from human typing. The
human can't see, while writing, which spans they authored vs. which the machine
did — so there is no basis for trust ("did I write this claim or did it?"), no
provenance to carry up the ladder to review surfaces, and no substrate for F4's
propose/accept to render against. F2 gave regions durable discussion; nothing
yet records who wrote what.

Who feels it

A writer/engineer coauthoring prose or specs with Claude inside VS Code — one
human + one machine — who needs to know at a glance, while the document is being
written, which spans are theirs and which are the machine's, and to keep that
record when the file is committed and reopened.

Desired outcome / value

The buffer becomes an honest record of authorship: human and Claude spans are
visibly distinguished as edits happen, the attribution
survives further editing (the same hybrid re-anchoring F2 shipped), and it
persists git-natively in the shared sidecar — no server. This delivers the
epic's second acceptance pillar ("see, live in the buffer, which spans are human
vs. Claude"), populates the attributions[]/provenance model F2 reserved, and
gives F4's propose/accept flow the attribution substrate its accepted diffs
render into.

Acceptance — "done right"

  • As the human types, their new/changed spans are recorded and rendered as
    human-attributed; when a machine edit is applied to the buffer, its spans
    are recorded and rendered as Claude-attributed (visibly distinct in the
    buffer, with the provenance primitive — kind: human | agent — as the
    record).
  • Attribution is live: the visible attribution updates as edits happen,
    without a save/reload cycle.
  • Attributed spans survive edits: text moving above/around an attributed span
    keeps the attribution on the same logical span (anchor re-resolution); spans
    that can't be confidently re-resolved are orphaned, never silently moved
    (F2's INV-1 applies to attributions too).
  • Attribution persists git-natively and reloads: closing and reopening the
    workspace restores attributed spans from the sidecar's attributions[]
    (schemaVersion honored, no format break — spec INV-4).
  • Mixed editing works: a human edit inside a Claude-attributed span splits or
    re-attributes it sensibly (the exact granularity/merge rules are design-time
    decisions, documented in the slice).
  • Unit tests cover the attribution-tracking logic and the persistence
    round-trip; host E2E covers type → attribute → machine-edit → attribute →
    reload, per the F2 test pattern.

Scope / non-goals

In scope: live in-buffer rendering of human/Claude span attribution;
capturing human keystrokes vs. applied machine edits as attributed, anchored
spans; the attributions[] shape on the shared anchors/provenance primitives;
attribution survival across edits (re-anchor / orphan); git-native persistence +
reload in the existing sidecar; whatever minimal machine-edit ingress the
design settles on so there is something real to attribute (see the open question
below).

Out of scope (deferred): the propose/accept diff flow itself (F4 — keep /
reject UX, inline diff); the final cross-rung persistence format + Gitea
round-trip (F5 / #46); attribution of edits made outside the session (external
editors, git merges) beyond the orphan rule; per-character blame depth (span-level
is the unit); multi-file orchestration; any server.

Assumptions · constraints · dependencies

  • Parent: #1 (the coauthoring Epic). Blocked by: #4 (F2 — shipped; PR #5).
    Blocks / feeds: F4 (propose/accept renders into this attribution substrate);
    relates to F5 (cross-rung format).
  • Builds on the graduated spec (specs/coauthoring-inner-loop.md): the
    sidecar's reserved attributions: [] extension point, the shared anchors
    primitive (INV-4), the provenance primitive (kind: human | agent), and the
    Anchorer's resolve/orphan ladder (INV-1/INV-3) are the established base — F3
    fills the extension point, it does not re-litigate the format.
  • Open design question (the fork): the epic words F3 as tracking
    "applied-proposal edits vs. human keystrokes", but proposals are F4. What
    counts as a machine edit in F3 before F4 exists is a genuine design
    decision: (a) a minimal live @cline/sdk turn that applies edits directly
    (the spec defers "where Claude runs + provider/auth" to exactly this moment —
    "the first live @cline/sdk turn, F3/F4"), (b) a programmatic apply-edit
    ingress (an internal API/command F4 later drives), or (c) both. Also open: the
    exact attributions[] shape and the split/merge granularity rules for mixed
    edits. Epic #1 routes these to a follow-on brainstorming session — this
    Feature consumes that reviewed Solution Design (or makes a provisional call
    inline and flags it, per the F2 precedent). Resolve which before planning.
  • If the design picks a live SDK turn, credentials/provider setup arrives with
    it — F2's no-credentials invariant (spec INV-5) ends at F3's door by design.
  • Native primitive exists: the Decorations API
    (vscode.window.createTextEditorDecorationType) renders span styling without
    bespoke UI.

Source / signal

Epic #1 (coauthoring-plugin-on-cline) decomposition item F3; the graduated
Solution Design vscode-cowriting-plugin-content/specs/coauthoring-inner-loop.md
(§6.3 attributions[]/provenance, §9 "OPEN → F3/F4"); architecture lineage
ben.stull/rfc-app#48. Builds on F2 shipped in #4 (PR #5, session
vscode-cowriting-plugin-0004). Captured in session
vscode-cowriting-plugin-0005.

Priority (WSJF)

Provisional: Value high (the epic's second acceptance pillar; the
trust/provenance capability that differentiates the coauthoring surface) ·
Time-criticality medium · Opportunity-enablement high (F4 renders its
accepted diffs into this substrate; F5 carries the provenance up the ladder) ÷
Size medium → P1.

Decomposition (Feature → slice checklist)

  • Resolve the design fork (machine-edit ingress: SDK turn vs. programmatic
    apply vs. both; attributions[] shape; mixed-edit split/merge rules) — consume
    the follow-on Solution Design, or make a provisional call and document it.
  • attributions[] data model on the shared anchors/provenance primitives
    (schema extension, vscode-free, round-trip tests — per the F2 SLICE-1 pattern).
  • Human-edit tracking: document-change events → human-attributed anchored
    spans, with the split/merge rules from the design.
  • Machine-edit ingress + tracking: the settled ingress applies an edit →
    Claude-attributed spans (provenance carries the agent identity).
  • Live in-buffer rendering of attributed spans (visibly distinct
    human/Claude styles), updating as edits happen.
  • Persistence + reload: attributions survive save/reopen and external change
    via the existing Store/Anchorer (re-anchor or orphan, never guess).
  • Unit tests (tracking logic, split/merge, round-trip) + host E2E
    (type → attribute → machine-edit → attribute → reload).

Solution notes (optional — NOT a design)

Native primitives map cleanly: the Decorations API
(createTextEditorDecorationType) is the obvious renderer for attributed spans —
the epic's F3 line names it — and onDidChangeTextDocument (which F2's Anchorer
already consumes for live shift) carries the edit deltas attribution tracking
needs. The Anchorer's fingerprint/resolve/orphan ladder and the sidecar's
reserved attributions[] are the intended reuse points (spec INV-4) — F3 fills
them rather than inventing parallel machinery. If the design picks a live
@cline/sdk turn as the machine-edit ingress, the POC's vscode-free cline.ts
driver (F1/#2) is the starting point. All non-binding — the fork above is the
design session's to resolve.

<!-- Set the type/* label: type/feature --> ## Summary **Live human/Claude attribution in the buffer**: as a document is coauthored, the editor shows — live, in the buffer — which spans were written by the **human** and which by **Claude**, with the attribution record persisted git-natively in the same sidecar (the spec's reserved `attributions[]` extension point, reusing the shared `anchors` primitive established by F2). ## Problem / pain Coauthoring with an AI in the editor has **no attribution/provenance**: once a machine edit lands in the buffer it is indistinguishable from human typing. The human can't see, while writing, which spans they authored vs. which the machine did — so there is no basis for trust ("did I write this claim or did it?"), no provenance to carry up the ladder to review surfaces, and no substrate for F4's propose/accept to render against. F2 gave regions durable *discussion*; nothing yet records who *wrote* what. ## Who feels it A writer/engineer **coauthoring prose or specs with Claude inside VS Code** — one human + one machine — who needs to know at a glance, while the document is being written, which spans are theirs and which are the machine's, and to keep that record when the file is committed and reopened. ## Desired outcome / value The buffer becomes an **honest record of authorship**: human and Claude spans are visibly distinguished as edits happen, the attribution **survives further editing** (the same hybrid re-anchoring F2 shipped), and it **persists git-natively** in the shared sidecar — no server. This delivers the epic's second acceptance pillar ("see, live in the buffer, which spans are human vs. Claude"), populates the `attributions[]`/`provenance` model F2 reserved, and gives F4's propose/accept flow the attribution substrate its accepted diffs render into. ## Acceptance — "done right" - As the human types, their new/changed spans are recorded and rendered as **human-attributed**; when a machine edit is applied to the buffer, its spans are recorded and rendered as **Claude-attributed** (visibly distinct in the buffer, with the `provenance` primitive — `kind: human | agent` — as the record). - Attribution is **live**: the visible attribution updates as edits happen, without a save/reload cycle. - Attributed spans **survive edits**: text moving above/around an attributed span keeps the attribution on the same logical span (anchor re-resolution); spans that can't be confidently re-resolved are **orphaned, never silently moved** (F2's INV-1 applies to attributions too). - Attribution **persists git-natively and reloads**: closing and reopening the workspace restores attributed spans from the sidecar's `attributions[]` (`schemaVersion` honored, no format break — spec INV-4). - Mixed editing works: a human edit **inside** a Claude-attributed span splits or re-attributes it sensibly (the exact granularity/merge rules are design-time decisions, documented in the slice). - **Unit tests** cover the attribution-tracking logic and the persistence round-trip; **host E2E** covers type → attribute → machine-edit → attribute → reload, per the F2 test pattern. ## Scope / non-goals **In scope:** live in-buffer rendering of human/Claude span attribution; capturing human keystrokes vs. applied machine edits as attributed, anchored spans; the `attributions[]` shape on the shared `anchors`/`provenance` primitives; attribution survival across edits (re-anchor / orphan); git-native persistence + reload in the existing sidecar; whatever **minimal machine-edit ingress** the design settles on so there is something real to attribute (see the open question below). **Out of scope (deferred):** the **propose/accept** diff flow itself (F4 — keep / reject UX, inline diff); the final cross-rung persistence format + Gitea round-trip (F5 / #46); attribution of edits made **outside the session** (external editors, git merges) beyond the orphan rule; per-character blame depth (span-level is the unit); multi-file orchestration; any server. ## Assumptions · constraints · dependencies - **Parent:** #1 (the coauthoring Epic). **Blocked by:** #4 (F2 — shipped; PR #5). **Blocks / feeds:** F4 (propose/accept renders into this attribution substrate); **relates to** F5 (cross-rung format). - **Builds on the graduated spec** (`specs/coauthoring-inner-loop.md`): the sidecar's reserved `attributions: []` extension point, the shared `anchors` primitive (INV-4), the `provenance` primitive (`kind: human | agent`), and the Anchorer's resolve/orphan ladder (INV-1/INV-3) are the established base — F3 fills the extension point, it does not re-litigate the format. - **Open design question (the fork):** the epic words F3 as tracking *"applied-proposal edits vs. human keystrokes"*, but proposals are **F4**. What counts as a **machine edit** in F3 before F4 exists is a genuine design decision: (a) a minimal live `@cline/sdk` turn that applies edits directly (the spec defers "where Claude runs + provider/auth" to exactly this moment — "the first live `@cline/sdk` turn, F3/F4"), (b) a programmatic apply-edit ingress (an internal API/command F4 later drives), or (c) both. Also open: the exact `attributions[]` shape and the split/merge granularity rules for mixed edits. Epic #1 routes these to a **follow-on brainstorming session** — this Feature consumes that reviewed Solution Design (or makes a provisional call inline and flags it, per the F2 precedent). Resolve which before planning. - If the design picks a live SDK turn, **credentials/provider setup** arrives with it — F2's no-credentials invariant (spec INV-5) ends at F3's door by design. - Native primitive exists: the **Decorations API** (`vscode.window.createTextEditorDecorationType`) renders span styling without bespoke UI. ## Source / signal Epic #1 (`coauthoring-plugin-on-cline`) decomposition item **F3**; the graduated Solution Design `vscode-cowriting-plugin-content/specs/coauthoring-inner-loop.md` (§6.3 `attributions[]`/`provenance`, §9 "OPEN → F3/F4"); architecture lineage `ben.stull/rfc-app#48`. Builds on F2 shipped in #4 (PR #5, session `vscode-cowriting-plugin-0004`). Captured in session `vscode-cowriting-plugin-0005`. ## Priority (WSJF) Provisional: **Value** high (the epic's second acceptance pillar; the trust/provenance capability that differentiates the coauthoring surface) · **Time-criticality** medium · **Opportunity-enablement** high (F4 renders its accepted diffs into this substrate; F5 carries the provenance up the ladder) ÷ **Size** medium → **P1**. ## Decomposition (Feature → slice checklist) - [ ] Resolve the design fork (machine-edit ingress: SDK turn vs. programmatic apply vs. both; `attributions[]` shape; mixed-edit split/merge rules) — consume the follow-on Solution Design, or make a provisional call and document it. - [ ] `attributions[]` data model on the shared `anchors`/`provenance` primitives (schema extension, vscode-free, round-trip tests — per the F2 SLICE-1 pattern). - [ ] Human-edit tracking: document-change events → human-attributed anchored spans, with the split/merge rules from the design. - [ ] Machine-edit ingress + tracking: the settled ingress applies an edit → Claude-attributed spans (provenance carries the agent identity). - [ ] Live in-buffer rendering of attributed spans (visibly distinct human/Claude styles), updating as edits happen. - [ ] Persistence + reload: attributions survive save/reopen and external change via the existing Store/Anchorer (re-anchor or orphan, never guess). - [ ] Unit tests (tracking logic, split/merge, round-trip) + host E2E (type → attribute → machine-edit → attribute → reload). ## Solution notes (optional — NOT a design) Native primitives map cleanly: the **Decorations API** (`createTextEditorDecorationType`) is the obvious renderer for attributed spans — the epic's F3 line names it — and `onDidChangeTextDocument` (which F2's Anchorer already consumes for live shift) carries the edit deltas attribution tracking needs. The Anchorer's fingerprint/resolve/orphan ladder and the sidecar's reserved `attributions[]` are the intended reuse points (spec INV-4) — F3 fills them rather than inventing parallel machinery. If the design picks a live `@cline/sdk` turn as the machine-edit ingress, the POC's vscode-free `cline.ts` driver (F1/#2) is the starting point. All non-binding — the fork above is the design session's to resolve.
benstull added the type/featurepriority/P1 labels 2026-06-10 14:45:23 +00:00
Sign in to join this conversation.