Deferred general lineage refresh state design
This is the weight-3 contingency design for a future second lineage mesh. It is not the current implementation plan. Review keeps its purpose-built SQLite store; the report-kind critique assay now reuses that same mesh. Full-pass closure retains gitignored initial and closing reports while they remain actionable, then deletes them; its calibration tested and retired a hand-written event surface rather than creating a second current-state mesh. Every other present case remains at artifact-local metadata, stable source handles, report contracts, workshop evidence, or commit history until it develops churning many-to-many edge state plus a real selector or audit query.
If that trigger appears, the design takes the review system's storage lesson as the starting point: keep SQLite for operational lineage state, keep Markdown files as the primary artifact API, and keep refresh execution outside the lineage subsystem. The resulting hybrid would preserve two properties:
- agents and maintainers still read and edit ordinary markdown artifacts;
- automation gets an indexed state store for dependency freshness, current baselines, auditable events, and model-aware derivations.
Until then, this file is a schema and boundary sketch to test the general vocabulary. It must not be cited as evidence that a generic lineage database has been approved or earned.
Core Boundary
The lineage system answers:
What retained artifacts, derivations, or artifact relations are stale, missing, acknowledged, retired, or current, and why?
It does not answer:
Which runner, batch shape, prompt packing, queue, model invocation, or merge procedure should perform the refresh?
That boundary matters because the same stale target may be refreshed by a live agent, a batch sweep, an external orchestrator, a one-off command, a manual merge, or a trivial acknowledgement. Lineage state should survive changes in execution strategy.
Responsibilities
In scope for the lineage layer:
- stable identities for lineage targets;
- accepted baselines for target dependencies;
- auditable lineage events when a cross-class history is required;
- current-state views;
- stale/missing/retired selectors;
- dependency resolvers that can observe current versions;
- producer provenance, including model where it matters;
- machine-readable reasons that a target needs attention.
Out of scope for the lineage layer:
- prompt rendering;
- batch packing;
- runner adapters;
- queue scheduling;
- parallelism;
- retry policy;
- report parsing beyond accepted output metadata;
- applying merge-back edits;
- deciding whether a stale target should be fixed now.
Refresh tools consume lineage targets and later report accepted outcomes back to the lineage store.
Primary API Remains Markdown
Markdown remains the authoring and inspection API:
- notes, sources, gates, type specs, instructions, reviews, connect reports, and generated analysis reports are still files;
- report types still define the readable shape of their markdown output;
- skills and commands still write or revise markdown artifacts;
- canonical notes do not become "DB records with prose payloads."
SQLite stores the operational relation that markdown files do not naturally own: which derivation was accepted, which inputs it depended on, which versions were observed, which model or producer made it, and whether those inputs still match.
Some generated markdown files should still carry self-describing frontmatter, especially one-shot derivatives that may be read outside the local DB. That frontmatter is an artifact API. It is not the freshness index.
Target Model
A lineage target is the thing whose freshness can be asked.
Examples:
| target kind | logical key | why it needs lineage |
|---|---|---|
| review pair | note_path, criterion_path, model_partition |
accepted assay freshness depends on note path, criterion path, and model partition; result_kind fixes completion protocol but is not part of the key |
| connect report | source artifact path, report contract, optional model | report depends on source artifact and current KB context |
| agent-memory-system review | review file path, external repo URL, reviewed revision, optional model | source is an external git repository, not a KB snapshot |
| generated index | index path, index contract | deterministic copy of library state should be checked or rebuilt |
| merge-back event | canonical artifact path, source report/event ids | canonical artifact was revised from previous version plus generated evidence |
| adapted-from artifact | retained packet path or id, source set, prompt/spec | retained one-off source shaping may later need promotion or refresh |
The target key should be stable enough for lookup, but not pretend every target has the same shape. Store target keys as structured data, not concatenated strings. Review's (note_path, criterion_path, model_partition) key is the first path-keyed target-kind schema, not the universal schema. criterion_path is the criterion document's repo-relative path; shorthands such as prose/source-residue are display or CLI conveniences, not the persisted identity.
Event Model
If a cross-class event surface is built, lineage history should be append-only at that event layer. This is a proposed audit model, not a description of current review storage: review acceptance is now a current-state upsert with inline pruning of superseded evidence.
Core event fields:
| field | role |
|---|---|
target_kind / target_key |
what freshness target this event updates |
event_kind |
full-refresh, ack, merge-back, manual-override, migration-import, retire |
output_ref |
file path, DB row, external revision, or null for pure ack |
operation_kind |
review, connect, source-ingest, index-build, merge-back, adapt |
producer |
command, skill, agent, migration, or human operator |
model_partition |
declared model-side partition when the target or event is model-specific |
producer_model |
optional literal observed model, when available after execution |
accepted_at |
when this event became the accepted baseline |
inputs |
accepted dependency versions used for freshness checks |
The generic current baseline would be derived from accepted events according to the target kind's ordering rule. Current review reaches a similar selector result through the acceptance current-state table and guarded current_criterion_acceptances view, not through an append-only acceptance-event log.
Input Version Model
Each event records the dependency versions that made the accepted output valid.
Input records should include:
| field | examples |
|---|---|
input_kind |
kb-file, review-gate, external-git-repo, source-snapshot, schema, prompt-contract, model-partition, db-row |
input_key |
path, repo URL, schema id, prompt contract id |
role |
source, gate, contract, context, model, previous-output, previous-canonical |
version_kind |
content hash, git blob sha, package asset hash, source hash, semantic version, DB schema version |
accepted_version |
the version observed when the event was accepted |
snapshot_ref |
optional DB snapshot id or retained source path for the accepted input |
Freshness is computed by resolving the current version for each input and comparing it with accepted_version. The lineage store records accepted versions; resolver code observes current versions.
That resolver layer is deliberately narrower than a refresh runner. A resolver can say "this gate blob changed." It should not decide how to rerun the review.
Resolvers should be typed and substrate-specific. For local review inputs, the resolver should be file-content: hash canonical bytes and store the reviewed bytes in the lineage DB. A package-asset resolver can provide package version plus asset hash. Source-oriented target kinds may still refer to external Git repositories when the external source itself is Git-backed, but local review freshness should not depend on the user's Git checkout. The lineage store should record which resolver produced the accepted version so installed projects are not forced into Commonplace's local Git commit discipline.
The general lineage layer should not own diffing. Diffs are an explainer feature for particular domains, especially reviews. A review explainer can compare current text with stored input snapshots when it wants to show what changed. The lineage selector should remain useful when it only reports that an input version differs.
Selector Contract
The lineage selector returns refresh targets, not jobs.
A target returned by the selector should contain:
target_kind;- structured
target_key; reason:missing,input-changed,output-missing,contract-changed,retired-source,manual-refresh-requested;- changed inputs with accepted and current versions;
- latest accepted event id, if any;
- output reference, if any;
- producer/model partition information needed to interpret the target;
- optional human-readable summary.
It should not contain:
- batch id;
- runner command;
- prompt path;
- concurrency settings;
- queue priority beyond a neutral severity or urgency hint;
- assumptions about whether refresh will be note-packed, gate-packed, source-packed, or manually merged.
Batch processors, review sweeps, and future orchestrators consume this selector output and choose an execution plan outside the lineage layer.
Review Mapping
The current review subsystem can be mapped into the general model without forcing an immediate rewrite:
| current review concept | general lineage concept |
|---|---|
(note_path, criterion_path, model_partition) |
lineage target of kind review-pair |
review_jobs |
review-specific invocation, packing, status, and optional execution provenance |
review_pairs |
review-specific requested pair with persisted result_kind, nullable decision, reviewed_at, and snapshot-backed evidence |
acceptance |
current baseline for review-pair targets; successful writes upsert by the full key |
current_criterion_acceptances |
guarded current baseline view, restricted to completed jobs and per-kind pair completion |
| accepted note snapshot hash | input version with role source |
| accepted criterion snapshot hash | input version with role criterion |
review_jobs.model_partition / acceptance.model_partition |
target partition; literal runner model and telemetry are producer evidence |
This is a conceptual mapping, not a migration plan. Review already separates execution concerns from freshness APIs while keeping both in one purpose-built store. Its accepted baseline and stale selector over (note_path, criterion_path, model_partition) remain the first implementation witness for the general target/input vocabulary.
Recent conformance and critique work also limits how much generic input machinery review needs. Type specs, COLLECTION.md contracts, and critique-note.md become the criterion document in separate factored (note, dependency) pairs. The default answer to another independently executable criterion is another pair with that dependency on the criterion side, not a wider N-input target. A generic lineage input set is for derivations that cannot honestly factor into independent pairs.
Batch Isolation
Batch processing is an optimization over stale targets. It should remain replaceable.
A future review flow might:
- ask lineage for stale
review-pairtargets; - group targets by gate, note, token budget, model, or external executor constraints;
- run any number of batches;
- parse outputs into review-specific result rows and markdown artifacts;
- record accepted baselines for the completed targets using that subsystem's chosen semantics.
The lineage store only needs steps 1 and 5. Everything between them can change as the system learns better packing, routing, model choice, or delegation.
This boundary may fit connect reports, source comparisons, generated indexes, and merge-back edits if any of them later earns swept freshness state. Their current forms do not.
SQLite Shape
Once a second churning mesh meets the escalation trigger, a generic layer could start with a small table set separate from the review schema:
lineage_targets
target_id
target_kind
target_key_json
target_partition_json
primary_artifact_path
status
lineage_events
event_id
target_id
event_kind
operation_kind
output_ref_json
producer
model_partition
producer_model
accepted_at
note
lineage_input_snapshots
snapshot_id
content_hash
media_type
content
created_at
lineage_event_inputs
event_id
input_kind
input_key
role
resolver
version_kind
accepted_version
snapshot_id
provenance_ref_json
policy_mode
current_lineage_baselines
view: latest accepted event per target
This is not a full implementation proposal. The design constraint is more important than the exact table names: any future generic lineage tables should represent targets, events, and accepted dependency versions; type-specific systems should own their report bodies, parsing, prompts, and execution provenance. Do not fold review into these tables merely to make the abstraction look uniform.
Markdown Integration
For generated artifacts that are retained as files, frontmatter can include a compact pointer back to lineage state:
lineage:
target_kind: review-pair
event_id: 12345
model_partition: claude-opus-4-6
For canonical authored notes, do not write "last model" frontmatter. If a note is changed by merge-back from a report, the lineage event should record:
- previous note version;
- source report or review event;
- source material/context used;
- accepting operator or producer;
- optional commit id once committed.
The note remains the canonical artifact. The derivative fact lives at the update-event layer.
Storage Policy If Escalated
If built, the SQLite lineage store would be the canonical freshness index for the target kinds explicitly registered in it. Markdown artifacts would remain the canonical human-readable outputs when the artifact itself is retained. Unregistered artifact classes would continue to use their lighter existing carriers.
Default policy:
- commit authored source and canonical library files;
- commit retained generated reports only when they are durable evidence, reviewable output, or intentionally reusable context;
- keep cheap, bulky, or transient run artifacts out of git unless their type contract says otherwise;
- keep lineage DB local operational state by default, with export/import or migration tools if a future workflow needs shared lineage state.
This keeps the experiment surface open without pre-registering every derived artifact class in a database.
Refresh Lifecycle If Escalated
The candidate generic lifecycle:
- Discover targets from file contracts, type contracts, or explicit registration.
- Resolve current input versions.
- Compare current inputs with latest accepted lineage event.
- Emit refresh targets with reasons.
- Let a runner, command, agent, or human process those targets.
- On accepted output, append lineage event and dependency versions.
- Optional: write or update retained markdown artifacts.
- Optional: export audit reports from the lineage DB.
This would make refresh automation more bitter-lesson-compatible without binding the lineage system to any particular batch processor.
Open Questions
- What concrete second churning mesh and selector would be sufficient to activate this design?
- If activated, should the generic lineage DB be separate from the purpose-built review store?
- Which target kinds need model as part of the target partition, and which only need model as event provenance?
- Which generated markdown types should carry lineage pointers in frontmatter?
- How should local lineage DB state be backed up or shared when multiple agents operate on the same repo?
- Is ordinary commit history sufficient for merge-back provenance, and what query would justify a shared append-only event surface?