--- title: Origin and authorization description: How transaction provenance differs from document locks and integration permissions. section: Development group: Development order: 22 --- Inkfinite records the source of each transaction separately from the rules that decide whether an operation is valid or authorized. Keeping those concerns separate prevents caller-supplied history metadata from becoming a permission credential. ## Transaction origin `Origin` is defined in `crates/inkfinite-core/src/lib.rs` and serialized as one of four values: - `human` for edits made through the editor - `agent` for edits submitted through agent-oriented CLI and IPC paths - `sync` for changes received from a peer - `system` for deterministic repair and other internal changes Origin is provenance metadata. Code can retain it in transaction history, diagnostics, and attribution UI, but must not use it to grant or deny access. In particular, changing a transaction from `origin: agent` to `origin: human` must never give the caller more capability. ## Validation and authorization The transaction engine applies document correctness rules to every origin. These include schema validation, causal-head and record-version checks, atomic commit, document validation, and ordinary shape and layer locks. Authorization belongs at an interface that can identify the caller and its granted permissions. The general CLI is a capability interface: people, scripts, and agents can invoke it or construct a raw transaction draft. A permissioned integration such as MCP can enforce read, create, modify, delete, and layout permissions before passing a valid transaction to the engine. `agent_editable` remains document metadata for permissioned integrations. It is not a document invariant, and the core engine should not infer a caller's authority from transaction provenance. ## Relevant code The current implementation spans these paths: | Path | Responsibility | | ------------------------------------------------------ | ------------------------------------------------------------------------ | | `crates/inkfinite-core/src/lib.rs` | Defines `Origin`, provenance, and document metadata | | `crates/inkfinite-core/src/engine/policy.rs` | Applies transaction schema checks and ordinary document locks | | `crates/inkfinite-core/src/engine/query.rs` | Queries records independently of layer visibility and transaction origin | | `crates/inkfinite-core/src/session.rs` | Validates live proposals and applies | | `crates/inkfinite-core/src/ipc` | Carries live transactions between CLI and desktop sessions | | `crates/inkfinite-cli/src/cli` | Constructs agent-originated shape, mutation, and SVG import transactions | | `packages/core/src/persistence/canonical.ts` | Maps `agent_editable` between native records and editor state | | `packages/ui/src/lib/editor/components/Toolbar.svelte` | Lets people set `agent_editable` on selected shapes | Generated document, transaction, and protocol schemas also expose `Origin` and `agent_editable`. Regenerate them after changing either serialized type. ## Current behavior The transaction engine does not branch on `Origin`. Direct CLI transactions can query and mutate records in invisible layers and records whose `agent_editable` value is false. Shape and layer locks still reject edits for every origin, including edits reached through a locked ancestor or a layer delete. `session.rs` requires agent origin at live proposal and apply entry points as a protocol-shape check, not as authorization. Proposal size, description length, stale-head handling, transaction validation, and atomic commit do not depend on origin. Live applies do not require a desktop access mode. The local `inkfinite-mcp` server is the policy-aware integration. It defaults to read-only access, selects rules by document path or desktop session ID, applies `read`, `create`, `modify`, `delete`, and `layout` scopes, filters hidden layers, and requires `agent_editable` for existing shape changes. It reports policy failures as `authorization_denied`. Ordinary document locks remain core errors and are never bypassed. MCP can submit an authorized proposal to a live session; desktop review accepts or rejects it, and MCP can poll the resulting proposal state. Committed transactions retain their origin. Causal heads, record versions, schema validation, document validation, and atomic commit apply to every caller. Permissioned integrations must check caller permissions before passing a transaction to the engine rather than trusting provenance in the transaction body.