Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions spec/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,14 +209,14 @@ changes; pure schema bumps.

The KP:1 manifest root remains closed; the `extensions` lane (added in v0.7.4)
is the sanctioned compatibility surface for producer-defined metadata. This
release catalogues the producer-defined extension blocks that the Nova
ecosystem uses today and retires the never-fully-realized `entities.md`
release catalogues the producer-defined extension blocks that the
reference implementation uses today and retires the never-fully-realized `entities.md`
companion file in favour of the typed `extensions.entities` block.

### Added
- **EXTENSIONS.md** (NEW companion document) — informative catalogue of
producer-defined extension blocks under `extensions.*` in active use across
the Nova ecosystem. Documents `extensions.ai_brief` (the v0.7.4 example),
the reference implementation. Documents `extensions.ai_brief` (the v0.7.4 example),
`extensions.entities` (typed entity graph), `extensions.relations` (typed
edges between entities, mirroring the relation_types vocabulary in
DEFINITIONS.md §3), `extensions.intent` + `extensions.intent_schema_version`
Expand Down Expand Up @@ -244,7 +244,7 @@ companion file in favour of the typed `extensions.entities` block.
- **`entities.md`** — used in only five packs out of ~770 and never landed as
a practical primitive. Producers MUST NOT emit `entities.md` in new packs.
Equivalent and richer information now lives under `extensions.entities`
(typed entity records with stable Nova IDs and external-ID vocabulary)
(typed entity records with stable canonical entity IDs and external-ID vocabulary)
and `extensions.relations` (typed edges with optional temporal and
attribute data per DEFINITIONS.md §3). A one-shot migration script
(`scripts/migrate-entities-md-to-extensions.mjs`, shipped with kp-forge)
Expand Down
2 changes: 1 addition & 1 deletion spec/DEFINITIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ Edge attributes are particularly important for:
### Consumer Pattern — `extensions.relations` in PACK.yaml

The `relation_types` schema above defines the *vocabulary*. Producers in
the Nova ecosystem write *instances* of relations under
the reference implementation write *instances* of relations under
[`extensions.relations`](EXTENSIONS.md#23-extensionsrelations--typed-edges)
in PACK.yaml, where each instance references entities declared under
[`extensions.entities`](EXTENSIONS.md#22-extensionsentities--typed-entity-graph):
Expand Down
107 changes: 105 additions & 2 deletions spec/EXTENSIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ the optional `extensions` object instead of appearing as new top-level keys
[SPEC.md §3.2](SPEC.md)).

This document is the catalogue of **producer-defined** extension blocks in
active use across the reference implementation (the public `kp-forge`,
`kp-packs`, and `kp-viewer` repositories). It is informative — KP:1 does
active use across the reference implementation. It is informative — KP:1 does
not require any extension to exist, and consumers MUST ignore extension
content they do not understand. New extensions are listed here so producers and
consumers can converge on shared shapes without forcing schema breaks or
Expand Down Expand Up @@ -277,6 +276,110 @@ it. The English claim remains valid and complete on its own; the
translations block adds audit trail without creating a parallel canonical
surface.

### 2.9 `extensions.collection` — pack-bundle membership

**Owner:** kp-forge intake pipeline + kp-viewer library organization.
**Status:** active (introduced 2026-05-24).

Declares that a pack belongs to a user-facing **collection** — a bundle of
related packs sharing a real-world origin (a private art collection, a watch
collection, a wine cellar, a portfolio of holdings). Collections are an
**orthogonal organizational axis** alongside `tier:` (claim-clustering hubs,
≤20 sub_packs) and the viewer-derived `category` (first segment of `domain:`).
A collection MAY span multiple categories — e.g., the Joukowsky Collection
contains both antiquities and fine art under the `art/*` root.

```yaml
extensions:
collection:
name: "Joukowsky Collection" # required — display name, grouping key
id: joukowsky-collection # optional — stable identifier (see compat)
role: member # optional — hub | member | standalone (default: member)
item_kind: object # optional — see "Inventory taxonomy" below
item_role: artist # optional — finer classification within item_kind
```

**Field semantics.**

- `name` — required. The display name shown in the viewer's scope chip and
used today as the grouping key. Two packs with the same `name` are treated
as belonging to the same collection.
- `id` — optional. A stable, opaque identifier (e.g., kebab-case slug).
Reserved for future use when collections become a top-level spec field with
rename-safe references. Today, consumers MAY ignore `id` and group by `name`.
- `role` — optional enum (`hub` | `member` | `standalone`), defaults to
`member`. `hub` marks a spine pack that describes the collection itself
(typically `domain: art/private-collection` or similar) — viewer renders it
as the collection cover when present. `member` is a regular pack in the
collection. `standalone` is reserved for packs that historically carried the
block but stand alone in the viewer; treat as "no collection" for grouping.
- `item_kind` — optional controlled-vocabulary enum identifying what kind of
thing this pack represents *within the collection's inventory*. Drives the
viewer's inventory-dashboard layout when the user scopes to a collection.
Generalizable across art, watches, wine, real estate, and auction inventory.
See the table below.
- `item_role` — optional free-form string narrowing the `item_kind`. e.g. a
pack with `item_kind: person` might carry `item_role: artist | scholar |
dealer | family | owner | auctioneer`; a `place` might carry `item_role:
room | gallery | auction_house | residence | region`; an `event` might carry
`item_role: exhibition | auction | sale | acquisition | appraisal`. Consumers
MAY surface these as filter pills within the kind's section. Unknown values
are ignored gracefully.

### Inventory taxonomy (`item_kind`)

| Value | Meaning | Joukowsky example | Christie's analogue |
|---|---|---|---|
| `spine` | Collection's overview/hub pack (typically one per collection) | `joukowsky-collection` | The auction-house catalog pack |
| `subcollection` | Category hub that groups objects (a sub-bucket within the collection) | `category-antiquities` | Department (Impressionist, Contemporary) |
| `object` | Individual inventory item | `category-antiquities-001-jade-figure-of-a-bixie` | Lot |
| `person` | Any human entity | Artists, scholars, family members, owners | Consigners, buyers, specialists |
| `place` | Physical location or organization-with-location | Rooms, residences, galleries, auction houses | Sale rooms, regions |
| `period` | Temporal classification (era, dynasty, vintage) | Tang Dynasty, Hellenistic period | Era, vintage year |
| `event` | Exhibition, auction, sale, acquisition, appraisal | 1985 Brown Exhibition | Auctions, sales |
| `document` | Records (appraisals, catalogs, certificates, invoices) | Gurr Johns 2022 appraisal | Sale catalogs, condition reports |
| `narrative` | Story content (voice briefings, monographs, voice scripts) | `narration-joukowsky-parents` | Sale-room essays |

**Item kinds are display-axes, not access-control or routing axes.** A pack's
`item_kind` controls how it appears in the collection inventory dashboard
(which section, which filter pill). It does not affect search, embeddings,
sealing, or any other system. Producers MAY omit `item_kind` entirely; the
viewer falls back to name-prefix inference for legacy packs and otherwise
shows the pack as a generic "other" entry.

**One spine per collection (convention, not enforced).** A collection should
have at most one pack with `item_kind: spine` — the cover/overview pack. If
multiple are present, the viewer picks one deterministically (typically the
oldest-sealed or alphabetically first). This is a convention, not a hard
constraint; the parser does not error.

**Distinction from `tier: hub`.** `tier: hub` (spec) is for small claim
clusters (≤20 sub_packs) that declare their children explicitly via
`sub_packs:`. `extensions.collection` is for large user-facing bundles
(hundreds of items possible) where members share a `name` rather than being
pre-declared. Both MAY coexist on the same pack; they describe different
concerns.

**Distinction from `category`.** `category` is derived at scan time from the
first segment of `domain:` and is not authored. A collection MAY span
multiple categories. Producers MUST NOT use `extensions.collection` to
override or canonicalize category derivation.

**Compatibility.** Consumers that do not understand the block MUST ignore
it. Producers MAY omit the block entirely; packs without it appear in the
viewer's "Uncollected" section (or the category section, depending on
grouping mode). The kp-viewer reference consumer treats `name` as
authoritative for grouping today; if/when `collection:` is promoted to a
top-level spec field with `id` semantics, this catalogue entry will be
updated and an alias-and-migrate path documented.

**Authoring expectations.** When an intake pipeline detects sibling structure
(shared origin, similar domains, shared creator/location/period metadata) it
SHOULD propose a collection name to the user rather than emit individual
standalone packs. The user accepts, edits, or rejects the proposal; on
acceptance, every pack in the batch receives the same `name` and `role:
member` (or `role: hub` for the spine pack if one exists).

---

## 3. Cross-cutting concerns
Expand Down
61 changes: 59 additions & 2 deletions spec/PLAYBACK.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ The relationship: PLAYBACK sits one layer above VOICE. A renderer consults the p
audience_profile:
familiarity: fresh # fresh | some_context | expert
duration_tier: medium # short | medium | long
purpose: orientation # orientation | decision | risk_review | press | research | demo
domain_lens: buyer # buyer | consigner | compliance | journalist | collector | general
purpose: orientation # see "purpose" enum below
domain_lens: buyer # see "domain_lens" enum below
register: curatorial # plain | curatorial | technical | investor (per VOICE.md §4.1)
inferred: false # true if the profile was derived from defaults rather than dialogue
```
Expand All @@ -57,6 +57,63 @@ audience_profile:
| `register` | No | enum | Voice register from [VOICE.md §4.1](VOICE.md). Defaults to `curatorial` for art/heritage packs, `plain` otherwise. |
| `inferred` | Yes | boolean | `true` when the profile defaulted; `false` when explicitly captured via discovery dialogue. |

### 3.1 `purpose` enum

The `purpose` field names why the listener is here. The original six values
(`orientation`, `decision`, `risk_review`, `press`, `research`, `demo`) are
joined by six use-case-named values added 2026-05-19:

| Value | Listener context |
|---|---|
| `orientation` | New to the subject; wants the lay of the land. |
| `decision` | Has to decide something concrete (buy / consign / approve / reject). |
| `risk_review` | Reviewing for risk specifically — adverse media, sanctions, exposure. |
| `press` | Journalist or writer assembling a story. |
| `research` | Academic or analytic study; deeper than orientation, lighter than decision. |
| `demo` | Showing the system off; not a real research session. |
| `pre_meeting` | Brief before a meeting with the subject. Wants interests and obvious risks, fast. |
| `hiring` | HR vetting context. Wants credentials verified, achievements substantiated, adverse media checked. |
| `partnership` | Evaluating a potential partner or counterpart. Wants culture fit, track record, integrity surface. |
| `competitive_intel` | Studying a competitor. Wants activity, traction, relationships, market position. |
| `sales_prep` | Preparing a sales engagement. Wants decision-maker map, interests, hooks. |
| `appreciation` | Admiring or tracking the subject. Wants achievements, cultural resonance, integrity surface light. |

### 3.2 `domain_lens` enum

The `domain_lens` field names the listener's role-frame. Original five
values (`buyer`, `consigner`, `compliance`, `journalist`, `collector`,
`general`) are joined by six use-case-named values added 2026-05-19:
Comment on lines +83 to +85

| Value | Role-frame |
|---|---|
| `buyer` | Listening as a potential buyer / acquirer. |
| `consigner` | Listening as a potential consigner / seller. |
| `compliance` | Listening as a compliance officer / auditor. |
| `journalist` | Listening as press / journalist / fact-checker. |
| `collector` | Listening as a private collector with no immediate transaction. |
| `general` | No specific role; orienting. |
| `hr_reviewer` | Listening as a hiring manager / HR / reference-check. |
| `partner_evaluator` | Listening as a potential business partner. |
| `competitor_analyst` | Listening as an analyst studying this subject as a competitor. |
| `admirer` | Listening to admire or learn about the subject for its own sake. |
| `meeting_host` | Listening shortly before a meeting with the subject. |
| `salesperson` | Listening to prepare a sales engagement. |

### 3.3 Extensibility

Both enums are **extensible** — KP:1 v0.9 may add further values as new
use cases emerge in production. Renderers MUST handle unknown enum
values gracefully:

- Unknown `purpose` → treat as `orientation`.
- Unknown `domain_lens` → treat as `general`.

This prevents an older renderer from crashing on a newer pack's profile,
and it lets new values ship via spec updates without renderer
re-releases. Producers SHOULD use the registered values from the tables
above whenever possible; SHOULD NOT invent ad-hoc values when an
existing one fits.

`AudienceProfile.register` composes with — but does not replace — VOICE's producer-side `register`. Producer-side `register` controls how voice views are *written*; `AudienceProfile.register` is the listener-side selection for the *current session*. Where they conflict, the session selection wins for that session's narration; the underlying voice view file is unchanged.

---
Expand Down
2 changes: 1 addition & 1 deletion spec/SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -864,7 +864,7 @@ by Fraunhofer ISE CalLab. Commercial module target: 2028.
> **Deprecated as of v0.7.6 (2026-04-28).** New packs MUST NOT emit
> `entities.md`. Use [`extensions.entities`](EXTENSIONS.md#22-extensionsentities--typed-entity-graph)
> for the typed entity graph and [`extensions.relations`](EXTENSIONS.md#23-extensionsrelations--typed-edges)
> for typed edges. The successor surfaces carry stable Nova IDs, an external-ID
> for typed edges. The successor surfaces carry stable canonical entity IDs, an external-ID
> vocabulary suitable for cross-pack resolution, per-claim `entity_refs`, and
> the `relation_types` schema from [DEFINITIONS.md §3](DEFINITIONS.md). A
> one-shot migration script in kp-forge rewrites legacy packs into the new
Expand Down