Co-work Content Provenance¶
Frozen-target, append-only attestations that keep content source, authorship, human review, and the attester distinct.
Details¶
Co-work content provenance¶
Co-work records four related facts without collapsing them:
- Source says how the content entered Co-work, such as a file import, paste, direct entry, or accepted proposal.
- Authorship is human, AI, mixed, or unknown. Human or mixed authorship can name human contributors.
- Human review is reviewed, not reviewed, not applicable, or unknown. Reviewed content can name its human reviewers.
- Attester and basis say who supplied the information and whether it came from a user attestation, automatic short-text attribution, automatic direct-entry attribution, proposal acceptance, migration, or legacy data.
An authorship and human-review attestation is a report, not a verification result. Saying that a person reviewed AI-written text does not mean the text was approved, fact-checked, accepted as correct, or adopted as the person's own writing. Accepted-proposal provenance remains a separate stronger chain: Co-work knows the producing agent run, the exact proposed wording, and the human acceptance gesture.
Frozen targets¶
Every attestation is bound to content that cannot silently change underneath it:
- From file targets the immutable document version created by the import and records that version's structured-head hash.
- Pasted or locally typed text creates an exact quote-anchored document span and binds the attestation to that span and one expected structured-head digest. The client first persists the inserted edit, then freezes that digest into the request; the server records the attestation only if its locked current head still matches.
Before sending or replaying a span-provenance request, the client requires the complete
exact, prefix, and suffix quote anchor to resolve to exactly one passage in
the currently hydrated editor. An absent or ambiguous passage becomes a stale
target instead of being silently attached elsewhere. The server also binds an
idempotency key to the exact selector, attestation, and structured head, so an
ambiguous response can replay only the same immutable logical request.
The append-only record carries a canonical digest and idempotency key.
Corrections append a replacement that names the prior attestation through
supersedes_id; they do not update or delete history.
Provenance surface¶
The Co-work rail tabs are Review | Provenance | Truth | Chat:
- Review owns document-change and evaluation decisions.
- Provenance answers where current document text came from, who is said to have written it, and what human review is recorded.
- Truth owns claims, expressions, evidence, and their lifecycle. It can still show the acquisition and decision provenance of those Truth records, but it does not own document-authorship treatment in the editor.
- Chat remains the conversational surface.
The persistent editor lenses are review, provenance, truth, and
neutral, respectively. A lens switch replaces view-only ProseMirror
decorations; it never changes document content, Yjs state, Markdown, selection,
scroll, or undo history. Temporary Chat, Working-on, and one-shot passage
highlights remain independent.
The Provenance lens uses independent visual channels. Authorship receives a subtle tint or pattern; human-review state receives a distinct underline. Source, attester, and basis remain first-class textual details rather than competing per-character colors. Red wavy treatment is reserved for unresolved, ambiguous, or conflicting targets, not ordinary AI authorship or an explicit not-reviewed state. Every meaning is repeated as text in the hover explanation and stable panel so color is never the only channel.
Hover is explanatory and passive. While the editor has an expanded text selection, the passive hover card is dismissed and suppressed so it cannot cover the passage's coverage-aware selection action; collapsing the selection restores ordinary hover behavior. The stable Provenance panel owns summary, filters, document-order items, frozen target and history details, and mutation controls. Missing data is visible as No provenance recorded, never inferred as human. Browser-local direct entry awaiting a ledger receipt is instead visible as Recording provenance… over only the pending passage; it is neither loading nor evidence of an unrecorded passage. Loading and failed refresh are separate from an empty record set. List-row activation opens detail and may apply compatible focus, but it does not scroll the editor. A uniquely resolved span has a separate Show in document action for one present-user reveal. The panel also exposes Complete provenance history, so old or malformed records without safe current geometry remain inspectable without receiving a guessed range.
The generic Give feedback selection bubble belongs to the other lenses and is suppressed in Provenance. A selected passage instead gets exactly one coverage-aware action: Record provenance when uncovered, Mark as reviewed when the selection fully contains at least one current AI/mixed target which the current enrolled user has not reviewed, View provenance for one healthy record, or Inspect provenance for stale, ambiguous, or conflicting coverage. A selection can review several fully contained span targets together; a partially selected target is never promoted into a claim that its whole passage was reviewed. A document-version fallback is eligible from the selection action only when all document text is selected. Review by another person does not suppress the current user's action.
The floating action routes review to a stable confirmation card rather than mutating immediately. If a selected target disappears, conflicts, or becomes ineligible before confirmation, that card stays visible, disables the write, and receives focus with a reselect-and-inspect explanation. Recording pre-existing text uses an explicit determination and keeps its source labeled Untracked / legacy.
Resolving the current human actor is required for Record provenance and Mark as reviewed, but never for non-mutating View provenance or Inspect provenance. If the dashboard's local identity session is missing or expires, the Provenance selection affordance remains available for inspection; the editor shows a reconnect action, and the stable panel keeps review controls visible but disabled with the same reconnect reason. If identity becomes unavailable while a routed review is focused, focus moves to that review's status card. The generic Give feedback action is not substituted because it also records a human-authority mutation.
Provenance has a dedicated typed provider and panel projection. It can share the authoritative open-document snapshot source with other rails, but it does not enlarge Review's domain payload into a general provenance transport. Hover and the editor lens consume the same projection; hover never owns an action.
For the current overlay, one unsuperseded record is the effective leaf of its lineage. A document-version attestation covers the current whole document only while its target structured head equals the current head; later text is not silently attributed. A span record at the current frozen head is current. After an unrelated document change, it can be reanchored for display only when its complete exact, prefix, and suffix quote selector resolves uniquely in the hydrated editor. Missing or duplicate matches are stale. A uniquely reanchored changed-head span is paintable and inspectable, but this first mutation slice does not let browser placement authorize a durable Mark reviewed assertion; review remains exact-head-only. Independently effective overlapping peer span records which disagree produce a conflict rather than last-write-wins. A current document-level attestation is fallback coverage, and a current exact span overrides it in its range; that specific-over-fallback precedence is not a peer conflict. Different attesters or bases do not create a conflict when source, authorship, and review agree. A stale document-level record is not fallback coverage. Conflicted coverage is recorded-but-disputed; unrecorded means there is no current safely resolved record for that text.
An unsynchronized local-human edit invalidates the pulled provenance head at once. The overlay withholds document-wide fallback and treats exact spans as requiring re-anchor, so newly typed text cannot inherit stale authorship. A unique span may stay paintable for inspection; review stays unavailable until persistence settles and a matching fresh authoritative projection arrives.
Mark as reviewed is a constrained, per-user append-only action for one or
more effective, exact-current-head AI- or mixed-authored document-version or
span targets. Each derived successor preserves its target, source, authorship,
and contributors, changes human review to reviewed, retains every distinct
prior reviewer, and adds the enrolled acting user as reviewer and attester. A
review already recorded by someone else therefore remains eligible for the
current user; a duplicate review by that same current user is rejected. Every
new record has a user_attestation basis referencing its predecessor, while
the old record keeps its own automatic, proposal, migration, or legacy basis in
history. The transition remains “AI-authored, human-reviewed,” not
“human-authored.” Reviewed is not approval, factual confirmation, or
acceptance.
The editor owns the review mutation barrier. It disables editing, retries and flushes pending Yjs persistence, verifies canonical state, and compacts to one durable structured head. While that lock remains held, the dedicated provider forces a fresh document pull and the panel rechecks the same effective leaf, head, eligibility, unique exact-span resolution, and incompatible peer overlap. Only then does it post one atomic batch and repull authoritative state. The signed command is bound to the frozen reviewer, ordered predecessor IDs, and exact structured head; an identity change, changed target set, reordered replay, partial prior batch, or head drift fails before any target is appended. Any drift fails closed; the editor is re-enabled only if the mounted document is still writable.
Accepted agent proposals¶
When the user confirms an agent-run edit proposal and the sitting applies it,
Co-work records provenance for the text contributed by that proposal in the
same locked database transaction as the document materialization and sitting
commit. The resulting exact-span attestation records AI authorship and
human_review=not_reviewed; accepting an edit is a document-change decision,
not a claim that the user reviewed the resulting prose. A later Mark
reviewed action remains a separate append-only transition.
The record uses source=proposal_acceptance and
basis=proposal_acceptance. Its source detail binds the immutable proposal and
canonical digest, the accepted replacement digest, the consumed human
acceptance gesture, and the validated producing agent-run reference and
producer metadata. The human actor who confirmed the proposal is the attester,
while the producing run remains the attributed authoring activity. These roles
are intentionally not collapsed.
The target covers only text mechanically attributable to the accepted replacement. A replacement which does not preserve the original quote produces one exact AI-authored span. For insertion-style proposals whose replacement contains the original quote exactly once, Co-work excludes that preserved text and records the non-whitespace text inserted before and/or after it as separate exact spans. Deletions create no text span. If the original is repeated, the derived selector is invalid, or any inserted segment does not resolve uniquely in the exact committed projection, the entire sitting fails closed. The document change, acceptance gesture, proposal status, and provenance rows therefore cannot commit independently.
Direct entry and manual repair¶
Ordinary local typing is captured at the editor ingress rather than inferred later from an opaque Yjs update. Each evolving contiguous same-block burst is synchronously staged before asynchronous IndexedDB work, updated through backspace and correction, and closed at a quiescent persistence or interaction boundary. Paste/drop, undo/redo, remote/applied Yjs, seed/system work, formatting-only changes, and disjoint edits do not inherit the assertion. A fully deleted burst produces no provenance record.
After the Yjs edit is durable, the client freezes one exact selector and
structured head. The server records source=direct_entry, human authorship by
the capture-time enrolled local actor, review not_applicable, and
basis=automatic_direct_entry_attribution. The capture-time actor is never
replaced by whichever identity happens to exist after a crash or reload. A
changed or unavailable actor requires an explicit honest determination.
Between synchronous capture and the authoritative server receipt, the Provenance lens projects the uniquely resolved exact local capture range as Recording provenance…. This pending decoration is delivery state only. It does not provisionally assert authorship, review, contributor, reviewer, or attester facts, even when the capture already carries a frozen actor binding. The stable panel exposes the same passage-scoped pending state and does not announce that the passage has no provenance. Pending typing never replaces or disables the selection menu for unrelated text. Manual recording is blocked only when its selected range overlaps an unresolved local capture, preventing a duplicate attestation while leaving every other provenance action available.
As soon as authoritative recorded coverage is present, that ledger projection wins for the overlapping range even if local outbox cleanup has not completed; removing the pending row later cannot make a server receipt disappear. The client retains the frozen outbox row and pending treatment until a fresh history entry matches the server receipt's attestation ID, document-span ID, and structured head. A missing, stale, misbound, or failed refresh therefore remains visibly pending and safely retryable. Publication of a later matching snapshot automatically replays and reconciles the frozen request, so receipt visibility does not depend on another user gesture.
Typing observed without a capture-time actor, or whose actor changes before
the automatic request can be frozen, is not discarded. Its exact selector
stays durable in the document outbox as source=legacy,
basis=user_attestation, and status=awaiting_determination, with no actor
attached. After a trusted identity session is available, Co-work surfaces
Recent typing needs attribution and requires the user to choose authorship
and review explicitly. Keep for later closes the prompt without deleting or
duplicating the durable row, and Review pending attribution reopens it.
Reloading must rediscover the same recovery row even after an in-progress form
edit. Selecting that same exact passage through the manual action also reuses
the row rather than creating an overlapping claim. A later actor is never
retroactively claimed as the author merely because identity recovered; that
actor supplies the explicit attestation. Conversely, when a capture already
has an immutable actor and only the current browser session is temporarily
unavailable, the actor-bound capture remains pending for trusted session
recovery rather than being downgraded or dropped.
The synchronous recovery journal retains the newest coalesced burst over an
older unfrozen capturing row. It never overwrites a ready or frozen request.
Closing the page leaves an unfinished capture recoverable rather than trying to
resolve it after the editor has disappeared. Once frozen, retry is the same
immutable logical request. A visible storage retry rehydrates and explicitly
finalizes an open mounted-page capture, including one queued behind an already
running finalizer. If an open row still cannot resolve or finalize, the retry
warning remains visible while independent ready rows continue delivery.
Text that predates this path cannot be safely attributed retroactively. In the
Provenance lens the user can select that text and choose Record provenance;
the shared determination creates an exact span with source=legacy and
basis=user_attestation. Product copy calls that source Untracked / legacy
instead of pretending the selection proves how the text entered Co-work.
From file¶
From file is format-neutral at the picker and importer-registry boundary.
The only importer currently registered is markdown/v1 for .md and
.markdown files with the text/markdown media type. A later Word importer can
join the registry without changing the outer workflow or provenance model. An
importer owns its accepted paths, media type, title derivation, source-size
limit, and conversion into the structured Co-work representation; the current
Markdown limit is 16 MiB.
The server registry is authoritative for admission and returns a validated,
versioned importer descriptor. The browser selects a bundled converter only by
that exact importer ID and uses the descriptor's suffixes only for presentation,
such as title derivation. If the server admits an importer version the browser
does not implement, the import stops with
importer_version_unavailable before document commit; the browser never guesses
a converter from the filename or media-type claim.
Later observation of a detached source also uses the document's persisted
importer descriptor and its source-size limit. Co-work opens only a regular file
without following links or reparse points, hashes it within that bound, and
rejects a source whose identity changes during the read. Routine catalog,
document, and drift views reduce an unsafe, unavailable, changed, or oversized
observation to an unknown digest (null) without making the managed document
unusable. An explicit current-source read instead returns a typed failure such
as source_too_large or source_unavailable. Historical pre-registry Markdown
imports may use the same bounded markdown/v1 rules; Co-work does not guess a
different importer.
The Markdown importer performs supported import normalization into the structured editor model. The exact source artifact hash and the managed projection hash are recorded separately, because normalized formatting can make their bytes differ. A current import also retains the exact selected bytes as a content-addressed source blob: when source and projection match they share that blob, and when they differ the source is retained independently. Portable Truth export includes those exact bytes when captured. Historical imports upgraded from before source-byte retention may remain hash-only; the missing source blob is an integrity warning rather than a reason to make the document unusable.
Imported source metadata carries writeback_policy=never. The original file is
never rewritten by editing, proposal acceptance, Save, retirement, recovery, or
portable import; Co-work advances its own structured state and managed
projection. Before a detached import is retired, the live editor retries pending
persistence, flushes its outbox, verifies the canonical head, and compacts any
Yjs update tail into a durable snapshot. This is an internal lifecycle
settlement, not a file materialization, and it leaves the source bytes unchanged.
Selecting a path already registered as a detached import opens its existing managed Co-work copy automatically only when the newly observed source hash matches the recorded import hash. If the source changed, or a historical record lacks enough identity to make that comparison, Co-work warns and offers Open existing Co-work copy. That action neither refreshes the managed copy from the selected file nor changes the file. Re-selection never silently converts an external file change into replacement document content.
Retirement permanently reserves the document's original path identity so its history cannot later be confused with a new document. Selecting that exact source path again returns a typed retired-path conflict and offers Choose another file, not an impossible action for opening the retired document. Copying or renaming the source creates a distinct path that can receive a new document identity. The conflict is decided from registered identity before the source is read or written, whether or not the source bytes changed after the original import.
Before the import commits, the shared provenance form asks who wrote the content and, for AI or mixed content, whether a person reviewed it. The same form is used when a paste is large or structured enough that direct human authorship should not be assumed. A short ordinary paste may be attributed to the current user automatically, with that automatic basis recorded explicitly.
Pasted text¶
This first paste-provenance slice covers text-bearing editor paste transactions. It anchors the text that the editor actually inserted after ProseMirror normalization, including the text in supported rich clipboard content. It does not attest image-only or attachment-only clipboard content, preserve the original clipboard HTML, or infer where the clipboard content originated.
A paste asks for the shared provenance determination when it has more than one top-level block, contains a list, task list, code block, blockquote, or table, or contains at least 600 Unicode characters in one ordinary block. The text is inserted immediately; the modal determines authorship and, for AI or mixed authorship, whether and by whom it was reviewed. Choosing Decide later records unknown authorship rather than inventing an author.
A single paste is bounded to 1,000,000 Unicode characters so its exact quote anchor remains admissible to the provenance ledger. A larger paste is rejected before it enters Yjs, the recovery journal, or the outbox, and the editor asks the user to paste it in smaller sections. This prevents an edit from becoming durable while its required provenance record is permanently undeliverable.
A text-bearing paste below that threshold, with one ordinary block and no
listed complex structure, is automatically attributed to the current local
human actor with review marked not applicable. This is a user-requested
low-friction heuristic based on paste shape, not proof that the user wrote the
clipboard content; its record carries
basis=automatic_short_text_attribution so downstream readers can distinguish
it from an explicit user determination.
The browser keeps pending paste and direct-entry records in a document-scoped IndexedDB FIFO outbox. Before the asynchronous outbox write, it synchronously stages the capture in a small local-storage recovery journal; hydration reconciles staged captures into the outbox and deduplicates them by idempotency key. Once a determination is ready, Co-work flushes the Yjs edit, freezes the complete request against the resulting structured head, revalidates the unique quote anchor, and retains that same request until the server confirms receipt. Retryable, terminal, and stale failures remain explicit and recoverable.
The Yjs edit, local recovery journal, IndexedDB outbox, and Truth attestation do not form one atomic transaction. The synchronous journal is a recovery barrier for that cross-store gap, not a claim of atomicity. If browser storage itself fails, Co-work keeps the capture in the mounted page, warns the user to keep the page open, and offers a storage retry. Malformed stored records are quarantined individually while valid records remain usable; a transient IndexedDB startup failure can be retried without remounting the page.
Person identity¶
Me first obtains the enrolled local principal binding from the server and freezes its actor ref and identity status into the determination. Dashboard mutations additionally require the revocable browser session and CSRF boundary plus a one-time gesture bound to the exact action, subject, and request context. The server derives the Truth actor from that authority; it does not accept a client-supplied human actor.
The server revalidates the frozen binding when an import, paste, direct-entry, manual-selection, or review attestation is recorded. If the acting identity changed, the determination is rejected instead of being reassigned. A queued paste can be reset to unknown authorship for a fresh explicit determination. A direct-entry capture instead retains its capture-time determination and is never rewritten to whichever actor happens to be current after a crash or reload. Nothing is resent under a changed actor without a fresh honest user decision.
The enrolled local actor ref is durable within this installation and stronger
than an arbitrary request header, but it is not a verified remote multi-user
account. It remains identity_status=local_actor_ref; product copy must not
describe it as an authenticated external identity or account_ref.
Someone else stores the typed display name with
identity_status=claimed_name. It is useful attribution supplied by the
attester, not proof of identity. The Truth schema reserves
identity_status=account_ref for a future authenticated participant or account
reference. The current dashboard does not mint that status. Future
collaboration can supply it from a participant directory while retaining the
same authorship, reviewer, attester, and frozen-target fields.
Storage and portability¶
Truth schema v10 stores these facts in the append-only
document_provenance_attestations table. Truth export format v10 includes the
records, validates their target links and canonical hashes on import, and
preserves supersession history. It also includes exact retained import-source
blobs when available while accepting that historical imports can carry only a
source hash. Existing detached imports from before provenance attestations
receive a deterministic migration-backfill attestation with unknown authorship,
unknown human-review status, and a system attester; migration does not invent a
human or AI author. The managed Markdown projection, browser input-provenance outbox, and
editor decorations remain supporting projections or delivery state; the
append-only Truth record is the provenance authority after receipt.