087-Source and report types are global library types
Type: reference/types/adr.md · Status: accepted
Status: accepted
Amended by: ADR 088 — type values become paths such as types/snapshot.md, and captures get one more recorded type-line rewrite
Date: 2026-09-25
Amends: ADR 086 (projects read the library from the installed package) and ADR 072 (ingests own source authority; snapshots are local and immutable)
Context
ADR 086 stopped copying the library into projects, but init still copies the
type specs of two collections: kb/sources/types/ (ingest report, snapshot,
source review) and kb/reports/types/ (connect report, full-pass report,
agent-memory analysis report, agentic-system analysis run state). Init
installs them as project-owned, and projects name them by path.
The copies are project-owned in name only. Commonplace code and procedures depend on their exact paths and shapes:
- the snapshot commands write
type: kb/sources/types/snapshot.md; - validation keys its type rules to
kb/sources/types/snapshot.mdandkb/reports/types/agent-memory-analysis-report.md; - the full-pass and agentic-analysis code writes its report types by path;
- the ingest, connect, full-pass, and agentic-analysis procedures produce exactly these shapes.
A project that edits its copy therefore gets code and skills that still assume the original. A release that changes a spec leaves every existing project on its old copy with no signal. This is the divergence ADR 086 removed for the rest of the library, left in place for seven types. Init also installs Commonplace-internal report types that a project never authors by hand.
These types are not tied to their collections by necessity. The sources and reports collections are where Commonplace's procedures put these artifacts by default. A user may reasonably keep ingested sources, or reports, somewhere else (operator, 2026-09-25). The global agentic-system analysis result type is a precedent: a procedure-produced type that already lives in the library.
Snapshots add a constraint. A tracked ingest pins the exact bytes of its local
snapshot, frontmatter included, with snapshot_sha256; a derived ingest also
pins its precursor capture with original_snapshot_sha256. ADR 072 makes
snapshots immutable after capture and forbids changing an existing ingest's
checksum. Validation of kb/sources warns on a mismatch, and grounding
(cp-skill-ground and the grounding-alignment gate), ingest, and re-ingest
stop on one. About 480 local captures in this checkout carry the path-valued
snapshot type, and every project that has captured sources holds its own.
Snapshots are local and ignored, so each clone on each machine holds its own
copy of the same bytes.
Decision
The seven types become global library types. Their specs and schemas move
into the library's types/ and are named by bare name: ingest-report,
snapshot, source-review, connect-report, full-pass-report,
agent-memory-analysis-report, and agentic-system-analysis-run-state. They
resolve, validate, and ship like every other global type under ADR 086. No
retired path resolves; ADR 086's rule that the form selects the resolver, with
no fallback, stands.
No new scoping rule. Like any global type, these types are eligible in every collection. No collection is closed to other types, and no type declares a home collection. The sources and reports collection contracts, and the procedures that write there, keep describing their default contents; they do not restrict them.
Snapshots are rewritten once, and their checksums re-pinned. A single
migration replaces a capture's frontmatter line naming a retired snapshot type
path (kb/sources/types/snapshot.md or ./types/snapshot.md) with
type: snapshot and changes nothing else. The transformation is
byte-deterministic, so identical old bytes on any machine become identical new
bytes. The migration retypes every such capture. An ingest beside it that pins
the capture's old bytes, through snapshot_sha256 or
original_snapshot_sha256, gets the new checksum. An ingest that already pins
the new bytes, because another clone migrated it, needs nothing more. A capture
that no ingest pins is retyped too: no checksum names its bytes, so nothing can
break. An ingest that pins neither form stays mismatched, as validation already
reports.
The migration is idempotent. It amends ADR 072 in exactly one place: this
recorded migration is the only permitted change to a capture's bytes and to an
existing ingest's checksum. New captures write type: snapshot. Installed
projects run it through init; clones of the source checkout, which never run
init, run it through a one-off script.
Init stops copying and migrates. Init no longer installs
kb/sources/types/ or kb/reports/types/. On a rerun it treats an old copy of
these specs like the old kb/types/ copy: a file matching the library is
removed, and a differing one is kept and listed. It then rewrites the
project's frontmatter pointers to removed copies as bare names, as ADR 086's
migration already does for global types, and runs the snapshot migration
instead of skipping .snapshots/. Local schemas that referred to a copied
schema move to commonplace:types/....
Projects keep local types. A project may still author its own type specs
under kb/sources/types/ or kb/reports/types/, named by path, like any
collection-local type.
Considered alternatives
Keep project copies (status quo). Loses on divergence, the reason ADR 086 exists. The copies cannot be truly project-owned while code writes and checks their paths.
Library-owned collection-local types. Keep the specs under the library's
sources/types/ and reports/types/, with a new reference form such as
type: sources/ingest-report that resolves in the library and stays eligible
only in the matching project collection. Lost: it adds a second library
resolution form next to bare names, and it keeps a scope restriction that the
operator does not want.
Global types with a home collection, or closed collections. Each spec
declares collection: sources, and the validator rejects the type elsewhere
or rejects foreign types in a closed collection. Rejected by the operator
(2026-09-25): users may want ingested sources in other places, and no failure
has shown that the restriction is needed.
A permanent resolver alias for the old snapshot path. Leave captures
untouched and resolve exactly kb/sources/types/snapshot.md as the global
snapshot type. It keeps ADR 072's immutability without exception, but it
keeps a retired path alive indefinitely as the one fallback in ADR 086's
resolver. Lost to the operator's choice (2026-09-25) to rewrite: the checksum
guards against unrecorded change, and a deterministic, recorded rewrite that
re-pins the checksum preserves that guarantee without a lasting exception.
Retype only pinned captures. The draft of this decision left unpinned captures alone and reported them. Lost in implementation: an unpinned capture's bytes are named by no checksum, so retyping it cannot break a pairing, and leaving it would keep the retired path alive in captures awaiting ingest.
A general fallback from old paths to global names. Would make every
retired kb/.../types/X.md path resolve. Lost to ADR 086's no-fallback rule;
every other pointer can be rewritten directly.
Resolved in implementation: clones of the source checkout run the migration through a one-off script rather than a package command, because the source checkout is the only consumer that never runs init.
Left open: whether the Commonplace-internal report types (full-pass, agentic-analysis run state, agent-memory analysis report) should later move out of the shipped library if their procedures stop being promoted. Today their procedures ship, so their types ship with them.
Consequences
Easier. Every type that Commonplace code or procedures produce now comes from one installed copy and follows upgrades. Init copies nothing that code depends on, so the remaining scaffold (starter collection contracts, landings, ignore files, control-plane templates) is project-owned in fact as well as in name. The residual subject of copy-provenance tracking disappears, and no retired type path survives in any resolver.
Harder or riskier.
- About 490 tracked ingest reports change their
type:line, and those whose snapshots are present locally also change their checksum. Review pairs on those files register a content change, and review baselines built on them need acknowledgement or refresh. - Until a clone runs the migration, its snapshots mismatch the pulled ingests. Validation warns, and grounding, ingest, and re-ingest stop on those pairs, until the migration rewrites them. A clone whose capture had already drifted keeps its mismatch, which validation reports.
- An ingest whose snapshot is absent on the machine that runs the migration keeps its old checksum. It is re-pinned only by a later run on a machine that holds the capture, which then commits the new checksum.
- Local, ignored report state (full-pass and agentic-analysis reports) also carries path-valued types. Init's migration rewrites the ones it can see; a file it misses fails validation with a missing type until rewritten.
- A project that customised a copied spec keeps its fork only if it still uses the path form. After migration that fork is an ordinary local type and no longer receives framework changes, which is the intended ownership.
Operativity path. The type resolver consumes the decision when it resolves
the bare names. Validation's type rules, the snapshot commands, and the
full-pass and agentic-analysis code consume it in code through bare names. The
snapshot migration consumes the ADR 072 amendment when it rewrites captures and
re-pins checksums; commonplace-init runs it in installed projects, together
with removing old copies and rewriting pointers. Agents consume the decision
through the sources and reports collection contracts, their installed
templates, and the procedures that name these types, which change to bare
names with the force of the collection contract and the invoked skill.
Where the decision stops applying. It covers only the seven types named
above. It does not change the starter COLLECTION.md files or other
scaffold, which stay project-owned and unsynchronised by design. It does not
decide where a project should keep ingested sources, and it does not govern
project-authored local types. The ADR 072 exception covers only the one
frontmatter line this migration replaces; any other change to capture bytes or
ingest checksums remains forbidden.