# Entity Reference Block Schema — Composable Reference Primitive # KNO Schema Version: 0.1.0 # # Defines the composable building block for deliberate entity references # ("@-mentions" in user-facing copy) inside content-bearing entities. # # HOME RULING (M84.P1 DC-2 gate, operator-ratified — see # content/decisions/m84-mention-record-home-dc2-gate.kno): this definition # lives in ONE schema under its own version line; content-bearing hosts # embed it by reference. Three-gate 3/3; five-test 2/5 -> sibling, not # extension. The rejected alternative (per-host field duplication) is the # portability failure the council's own conditional anticipated. # # COMPOSITION MECHANISM (S1 AC4 — no novel mechanism; the Layer-1 # precedent): hosts declare an UNVERSIONED `composes:` edge to this schema # (`kno://specs/entity-reference-block-schema`), exactly as they already do # for identity-schema / history-schema / quality-schema. Unversioned means # there are no per-host pins that can drift — which is the DC-2 rationale # enforced mechanically rather than by convention. Hosts declare the # `entity_references` field and point at this schema for its item shape; # they never inline a copy of it. # # WIRE NAME IS LOAD-BEARING: the host field is `entity_references`, matching # the inbound-projection index expression frozen by the M84.P2 spike # (`USING gin ((content->'entity_references') jsonb_path_ops)` on # kno_objects). Renaming the field without the same-commit migration change # silently degrades every inbound query to a sequential scan — nothing # fails, it just gets slow. See docs/planning/entity-graph-mention/ # spike-gin-inbound-projection.md § 5. # # GENUS NAMING (content/decisions/m84-entity-mention-naming.kno): the wire # vocabulary is genus-named ("reference"); "@mention" is the species and # stays in UI copy. Future non-mention reference kinds (backlinks, embeds) # reuse this block rather than minting siblings. # ============================================================================= # SCHEMA DECLARATION (RFC-007) # ============================================================================= $schema: kno@0.0.9 # ============================================================================= # IDENTITY # ============================================================================= id: 01M0A7QP3XKC5F8ZVBWD2NRHTJ slug: entity-reference-block-schema type: spec version: 0.1.0 # ============================================================================= # STANDARD TIER # ============================================================================= title: "Entity Reference Block Schema" purpose: "Define the composable building block for deliberate entity references inside content-bearing entities" description: | An entity reference is an occurrence record: a structured statement that one entity was deliberately referenced inside another entity's content. The record stores the target's Identity XRI — never meaning-bearing display text — so that display resolves live at render time and a principal who has masked or deleted their identity is never re-exposed by stale stored copy. The block is host-lifecycle-bound: records live inside the host entity, are tombstoned when the host is deleted, and are restored with revision state when the host is reverted. A reference grants nothing. Ever. # ============================================================================= # RICH TIER — Relationships (Edge Maximization) # ============================================================================= relationships: depends_on: - xri: "kno://specs/kno-spec" reason: "Conforms to the KNO format specification" related_to: - xri: "kno://specs/relationship-vocabulary-schema" reason: "refers_to / referred_to_by predicates project from these records" - xri: "kno://specs/identity-schema" reason: "target_xri and author_xri are Identity XRIs" enables: - xri: "kno://specs/document-schema" reason: "Content-bearing host: composes this block" - xri: "kno://specs/guide-schema" reason: "Content-bearing host: composes this block" - xri: "kno://specs/knowledge-base-schema" reason: "Content-bearing host: composes this block" provenance: origin: id: 01M0A7QP3XKC5F8ZVBWD2NRHTJ timestamp: "2026-08-18T06:10:00Z" publisher_possibility_xri: pspace://possibility/pos_01KPCQR2Y8ZT7GW1QK7Q348Q0K # ============================================================================= # SPEC # ============================================================================= spec: status: Draft description: | Entity references are a **composable primitive** — a building block that gives any content-bearing .kno entity a set of deliberate outbound references. **P10 (Derivable Structure):** the inbound direction ("references of me") is NEVER stored. It is derived at query time from these records under the caller's authorization, so a reference cannot be used to learn that unreadable content exists. ## What the record stores, and why so little | Field | Immutable | Why | |-------|-----------|-----| | `entry_id` | yes | Stable handle for a single occurrence; survives host revision | | `target_xri` | yes | Identity XRI only. A slug is a mutable label; a reference must survive renames | | `author_xri` | yes | Who made the reference. Authorship is not reassignable | | `created_at` | yes | When. Notification and audit both need it | | `display_snapshot` | yes | Authoring-time label, **audit/history only** — never rendered as current | | `notify` | no | Whether this occurrence should produce a notification event | | `selector` | no | Optional, rot-tolerant anchor into host content | | `source_revision` | yes | Host revision the record was authored against | ## The four rules that shape the block 1. **Identity XRIs only.** Named-XRI and bare-slug targets are rejected at the write path. A reference outlives a rename. 2. **Display resolves live.** `display_snapshot` exists for audit and diff, and MUST NOT be rendered as a current label — a target who masked or deleted their identity would otherwise leak (**TM-7**). 3. **Grants nothing.** No authority-bearing field may appear in a record. Referencing a principal conveys no access, no membership, no role (**TM-5**, m84-edge-taxonomy-m49-boundary). 4. **Target is immutable.** Retargeting is remove + create, so notification semantics stay single-fire (**TM-12**). ## Actor kind is not a target type Valid `target_xri` types are `user`, `persona`, and `helper` — the tenant-scoped people-shaped node types the entity-graph provider registry resolves. "Agent" is an **actor kind** (a human, an agent, or a service with API access may be the actor behind any of these), an axis orthogonal to role and owned by the frame-oriented permissioning work. `pspace://agent/` XRIs are actor identifiers and are NOT valid reference targets in v1 (operator ruling 2026-08-18). schema: type: object required: - entry_id - target_xri - author_xri - created_at additionalProperties: false properties: entry_id: type: string pattern: "^ref_[0-9A-HJKMNP-TV-Z]{26}$" description: | Stable identifier for this occurrence. Convention: ref_{ULID}. Survives host revisions; a retarget mints a new entry_id. examples: - "ref_01M0A7QP3XKC5F8ZVBWD2NRHTJ" # pragma: allowlist secret target_xri: type: string pattern: "^pspace://(user|persona|helper)/[A-Za-z0-9_-]+$" description: | Identity XRI of the referenced entity. IMMUTABLE. Identity form only — named XRIs and bare slugs are rejected at the write path, because a reference must survive a rename. `pspace://agent/` is an actor identifier, not a target type (see § "Actor kind is not a target type"). examples: - "pspace://user/usr_01KH862FTH030S64JRDS1VP4YK" - "pspace://persona/per_01KGXYZ123ABC456DEF789GH" - "pspace://helper/hlp_01KGXYZ123ABC456DEF789GH" author_xri: type: string pattern: "^pspace://(user|persona|helper)/[A-Za-z0-9_-]+$" description: "Identity XRI of the principal who authored the reference. IMMUTABLE." examples: - "pspace://user/usr_01KH862FTH030S64JRDS1VP4YK" created_at: type: string format: date-time description: "When the reference was authored (RFC 3339). IMMUTABLE." examples: - "2026-08-18T06:10:00Z" display_snapshot: type: string maxLength: 200 description: | The target's display label AT AUTHORING TIME. AUDIT AND DIFF ONLY. Never rendered as the target's current label — display is re-resolved live through the four-state fallback matrix (resolved / masked / deleted / unavailable). Rendering a snapshot as current re-exposes principals who have since masked or deleted their identity (**TM-7**). examples: - "Ada Lovelace" notify: type: boolean default: true description: | Whether this occurrence should emit a notification event. Display-only edits to the host MUST NOT re-set this to produce a second notification (**TM-12**). selector: type: object additionalProperties: false description: | Optional anchor into host content. Rot-tolerant BY DESIGN: a selector that no longer locates its span does not invalidate the record (**TM-9**). Consumers degrade to "referenced somewhere in this content" rather than dropping the reference. properties: type: type: string enum: - text_quote - text_position description: "Selector strategy" exact: type: string maxLength: 500 description: "For text_quote: the quoted span" prefix: type: string maxLength: 100 description: "For text_quote: leading context that disambiguates the quote" suffix: type: string maxLength: 100 description: "For text_quote: trailing context that disambiguates the quote" start: type: integer minimum: 0 description: "For text_position: start offset" end: type: integer minimum: 0 description: "For text_position: end offset" source_revision: type: string description: | Host revision the record was authored against. Reverting a host restores the reference set of the target revision (**TM-8**) and MUST NOT re-notify (**TM-12**). examples: - "3" # ============================================================================= # EXAMPLES # ============================================================================= examples: - name: "Minimal reference" description: "A user referenced in a document, no anchor" value: entry_id: "ref_01M0A7QP3XKC5F8ZVBWD2NRHTJ" target_xri: "pspace://user/usr_01KH862FTH030S64JRDS1VP4YK" author_xri: "pspace://user/usr_01KM20Z0SW5TW4GN26FE9RCWQS" created_at: "2026-08-18T06:10:00Z" - name: "Anchored reference with audit snapshot" description: "A persona referenced at a quoted span, snapshot retained for audit" value: entry_id: "ref_01M0A8ZK9WTB4C7YVAQE1MSGRK" target_xri: "pspace://persona/per_01KGXYZ123ABC456DEF789GH" author_xri: "pspace://user/usr_01KH862FTH030S64JRDS1VP4YK" created_at: "2026-08-18T06:12:00Z" display_snapshot: "Writer" notify: true source_revision: "3" selector: type: text_quote exact: "handed to the Writer for review" prefix: "the draft was " suffix: " before publication" - name: "Notification-suppressed reference" description: "A helper referenced without emitting a notification event" value: entry_id: "ref_01M0A9F2QRXD6E5NVCPH3KTJWB" target_xri: "pspace://helper/hlp_01KGXYZ123ABC456DEF789GH" author_xri: "pspace://user/usr_01KH862FTH030S64JRDS1VP4YK" created_at: "2026-08-18T06:15:00Z" notify: false # ============================================================================= # HISTORY (P9 Temporal) # ============================================================================= _history: version: 1 created: "2026-08-18T06:10:00Z" created_by: "claude" modified: "2026-08-18T06:10:00Z" modified_by: "claude" snapshots: - version: 1 date: "2026-08-18T06:10:00Z" summary: >- Initial schema authored at M84.P3 S1 (#3710) per the DC-2 gate's domain-schema-block ruling (content/decisions/ m84-mention-record-home-dc2-gate.kno; three-gate 3/3, five-test 2/5 -> sibling). Field name `entity_references` is bound to the M84.P2 spike's GIN index expression. Target types are user|persona|helper per the 2026-08-18 actor-kind ruling. author: "claude" fields_changed: ["*"]