Provenance authored:* marks are dropped — sidebar renders human-owned content as AI
Summary
The core "every character knows its author" promise is breaking in practice. In a shared doc, authored:* marks disappear from /state.marks under two different conditions, and the editor's gutter/sidebar falls through to rendering the affected spans as AI (purple) when the text was actually human-owned.
Two separate failure modes observed in the same session:
- Live human typing does not produce an
authored:human:* mark. Typing directly into the browser editor leaves the new span with no provenance mark at all.
POST /ops with type: "suggestion.accept" appears to wipe pre-existing authored:* marks on spans other than the accepted suggestion's own span.
Severity
User-visible. Breaks the feature most prominently advertised in the onboarding doc ("Every character knows its author"). Not a data-loss bug — the document text is intact — but the provenance UI is actively misleading.
Environment
- Site:
https://www.proofeditor.ai
- Doc slug used to repro:
bzbxikyp (happy to share tokens and raw /state dumps privately)
- Agent: Cursor / Claude Opus 4.7 driving the HTTP API as
cursor-composer-kmiller
- User: typing directly in Chrome on macOS
- Date: 2026-04-22
Repro
Starting from a fresh share with some seeded content:
- Agent edit (works correctly). Agent calls
POST /api/agent/<slug>/edit/v2 with insert_after on an existing block. GET /state shows a new authored:ai:<agent-id>:<range> mark covering the inserted span. Gutter shows purple on that block, as expected.
- Human edit (bug A). User types a paragraph directly in the browser editor. No
authored:human:* mark appears in /state.marks for the new span. In the editor UI, the user-reported observation is that the entire doc's gutter flipped to purple at this moment — not just the new paragraph.
- Agent
suggestion.accept (bug B). Agent calls POST /ops with type: "suggestion.add" for a kind: "replace", then POST /ops with type: "suggestion.accept" on that markId. The accepted suggestion applies correctly to the document body, and a new authored:ai:<agent-id>:<range> mark appears on the accepted span. However, the previously-correct authored:ai:<agent-id>:<range> mark from step 1 is now missing from /state.marks.
After step 3, /state.marks contains exactly one authored:* mark across the full 17-block doc — the span written by the accept operation. Every other piece of text (both human-owned original content and the agent's earlier blockquote) has no provenance attribution.
Quick verification command:
jq '.marks | to_entries | map(select(.value.kind == "authored")) | map({markId: .key, by: .value.by, startRel: .value.startRel, endRel: .value.endRel})' state.json
Expected behavior
- Live human edits in the browser should produce
authored:human:<name>:<range> marks on the newly-authored span, same contract as agent edits produce authored:ai:* marks.
suggestion.accept should touch authorship only for the span it writes. Pre-existing authored:* marks on unrelated spans should be preserved across accept, reject, comment, and reply operations.
Hypothesis
- Bug A (live typing): the Yjs-side provenance emitter that runs for agent edits may not be wired up for local browser edits, or the user identity / mark-kind resolver isn't producing
authored:human on the editor path.
- Bug B (accept wipes marks):
suggestion.accept may be recomputing the set of authored:* marks from scratch using only its own write intent, rather than delta-patching. This would explain why only the accept's own span survives.
Both behaviors may share a common cause if they funnel through the same provenance-mark reducer.
Evidence
Marks after step 3 (raw /state.marks snippet)
{
"a5dbf6c9-0aab-4644-ab60-2aafa1697db8": {
"kind": "comment",
"by": "ai:cursor-composer-kmiller",
"startRel": "char:355",
"endRel": "char:388",
"quote": "Every character knows its author."
},
"authored:ai:cursor-composer-kmiller:311-360": {
"kind": "authored",
"by": "ai:cursor-composer-kmiller",
"startRel": "char:305",
"endRel": "char:354",
"quote": "Green = human authorship. Purple = AI authorship."
}
}
Doc also contains:
- A blockquote ("Hello from Cursor — I am kmillers coding agent...") that was inserted by the agent in step 1 and had an
authored:ai:cursor-composer-kmiller:123-230 mark immediately after insertion. That mark is no longer present.
- A user-typed paragraph ("Hi, this is Kyle. How do human comments work?") that has never had an
authored:* mark in any /state snapshot taken during the session.
Earlier /state.marks (after step 1, before step 3)
Contained an authored:ai:cursor-composer-kmiller:123-230 mark on the agent's blockquote. Can reconstruct exact bytes on request — I have the full /state payloads from four points in the session.
Related hosted-side context
contract.mutationStage: A
contract.preconditionMode: token-only
readSource: yjs
readAuthority: authoritative_live
Questions for the team
- Is the provenance-mark computation in
EveryInc/proof-sdk (packages/doc-core?) or in hosted-only code? I'm about to self-host proof-sdk for a personal tool and want to know whether to expect this bug in my deployment too.
- If it's in OSS code, I'm happy to take a first pass at a fix / open a PR — just point me at the right module.
Related
Filed companion issue re: /bridge/report_bug returning 502 REPORT_BUG_CREATE_FAILED, which is why this is coming in as a GitHub issue rather than via the bridge. If that weren't broken, this evidence would have landed on your side under requestId: 9e57521d-6a21-4a6a-a201-f56432676581 (evidence was captured locally per that response).
Provenance
authored:*marks are dropped — sidebar renders human-owned content as AISummary
The core "every character knows its author" promise is breaking in practice. In a shared doc,
authored:*marks disappear from/state.marksunder two different conditions, and the editor's gutter/sidebar falls through to rendering the affected spans as AI (purple) when the text was actually human-owned.Two separate failure modes observed in the same session:
authored:human:*mark. Typing directly into the browser editor leaves the new span with no provenance mark at all.POST /opswithtype: "suggestion.accept"appears to wipe pre-existingauthored:*marks on spans other than the accepted suggestion's own span.Severity
User-visible. Breaks the feature most prominently advertised in the onboarding doc ("Every character knows its author"). Not a data-loss bug — the document text is intact — but the provenance UI is actively misleading.
Environment
https://www.proofeditor.aibzbxikyp(happy to share tokens and raw/statedumps privately)cursor-composer-kmillerRepro
Starting from a fresh share with some seeded content:
POST /api/agent/<slug>/edit/v2withinsert_afteron an existing block.GET /stateshows a newauthored:ai:<agent-id>:<range>mark covering the inserted span. Gutter shows purple on that block, as expected.authored:human:*mark appears in/state.marksfor the new span. In the editor UI, the user-reported observation is that the entire doc's gutter flipped to purple at this moment — not just the new paragraph.suggestion.accept(bug B). Agent callsPOST /opswithtype: "suggestion.add"for akind: "replace", thenPOST /opswithtype: "suggestion.accept"on thatmarkId. The accepted suggestion applies correctly to the document body, and a newauthored:ai:<agent-id>:<range>mark appears on the accepted span. However, the previously-correctauthored:ai:<agent-id>:<range>mark from step 1 is now missing from/state.marks.After step 3,
/state.markscontains exactly oneauthored:*mark across the full 17-block doc — the span written by the accept operation. Every other piece of text (both human-owned original content and the agent's earlier blockquote) has no provenance attribution.Quick verification command:
jq '.marks | to_entries | map(select(.value.kind == "authored")) | map({markId: .key, by: .value.by, startRel: .value.startRel, endRel: .value.endRel})' state.jsonExpected behavior
authored:human:<name>:<range>marks on the newly-authored span, same contract as agent edits produceauthored:ai:*marks.suggestion.acceptshould touch authorship only for the span it writes. Pre-existingauthored:*marks on unrelated spans should be preserved across accept, reject, comment, and reply operations.Hypothesis
authored:humanon the editor path.suggestion.acceptmay be recomputing the set ofauthored:*marks from scratch using only its own write intent, rather than delta-patching. This would explain why only the accept's own span survives.Both behaviors may share a common cause if they funnel through the same provenance-mark reducer.
Evidence
Marks after step 3 (raw
/state.markssnippet){ "a5dbf6c9-0aab-4644-ab60-2aafa1697db8": { "kind": "comment", "by": "ai:cursor-composer-kmiller", "startRel": "char:355", "endRel": "char:388", "quote": "Every character knows its author." }, "authored:ai:cursor-composer-kmiller:311-360": { "kind": "authored", "by": "ai:cursor-composer-kmiller", "startRel": "char:305", "endRel": "char:354", "quote": "Green = human authorship. Purple = AI authorship." } }Doc also contains:
authored:ai:cursor-composer-kmiller:123-230mark immediately after insertion. That mark is no longer present.authored:*mark in any/statesnapshot taken during the session.Earlier
/state.marks(after step 1, before step 3)Contained an
authored:ai:cursor-composer-kmiller:123-230mark on the agent's blockquote. Can reconstruct exact bytes on request — I have the full/statepayloads from four points in the session.Related hosted-side context
contract.mutationStage:Acontract.preconditionMode:token-onlyreadSource:yjsreadAuthority:authoritative_liveQuestions for the team
EveryInc/proof-sdk(packages/doc-core?) or in hosted-only code? I'm about to self-hostproof-sdkfor a personal tool and want to know whether to expect this bug in my deployment too.Related
Filed companion issue re:
/bridge/report_bugreturning502 REPORT_BUG_CREATE_FAILED, which is why this is coming in as a GitHub issue rather than via the bridge. If that weren't broken, this evidence would have landed on your side underrequestId: 9e57521d-6a21-4a6a-a201-f56432676581(evidence was captured locally per that response).