298 lines
16 KiB
Markdown
298 lines
16 KiB
Markdown
# ADR-018: Substrate provenance register and cherry-pick procedure
|
||
|
||
## Status
|
||
|
||
Accepted (2026-10-06, Phase 1 — OQ-11's resolution, items (2) and (3);
|
||
item (1) dissolved by [ADR-013](013-fold-substrate-into-sqlite.md) §4.
|
||
Fills in the register's format and the cherry-pick procedure the prior
|
||
records point at: [ADR-012](012-forked-substrate-design.md) §1/§6,
|
||
[ADR-013](013-fold-substrate-into-sqlite.md) §3/§4,
|
||
[ADR-017](017-contract-versioning.md) §2 class 4)
|
||
|
||
## Context
|
||
|
||
[ADR-011] fired the fork; [ADR-012] designed it (fidelity posture,
|
||
contract-blind boundary, port deltas, upstream-tracking stance);
|
||
[ADR-013] folded it into `alkstore-sqlite` as the `src/substrate/`
|
||
module subtree. Every one of those records pinned the *existence* of a
|
||
provenance register — its location (in-tree, beside the subtree), its
|
||
timing (fork-scaffold), and its initial contents (upstream identity +
|
||
the delta list) — and deferred two questions to OQ-11:
|
||
|
||
- **(2) The register's format and delta-list granularity.** ADR-012 §1
|
||
named a delta list but not its shape: are port deltas recorded
|
||
per-commit or per-delta-class? Does each future cherry-pick get its
|
||
own entry, and does that entry land at adoption time or in a
|
||
deferred sweep?
|
||
- **(3) The cherry-pick procedure in practice.** ADR-012 §6 said
|
||
adoption is deliberate and recorded; ADR-017 §2 class 4 said
|
||
cherry-picks are non-events because ADR-012 §2's contract-blind
|
||
boundary makes them structurally un-contract-side. Neither says
|
||
*how* a candidate is evaluated, applied, or recorded so the
|
||
deliberate-work posture stays auditable — and ADR-013's fold moved
|
||
the boundary's enforcement from the crate graph to review
|
||
discipline (its accepted negative consequence), which makes the
|
||
audit trail the record that review works from rather than an
|
||
optional artifact.
|
||
|
||
Much of the shape is already fixed by the retained records, and this
|
||
ADR composes with it rather than re-deciding it:
|
||
|
||
- **The register is a second ledger — for the substrate, not the
|
||
contract.** ADR-017 §1 rejected a parallel contract-version ledger
|
||
under the one-normative-owner rule; the substrate is the
|
||
complementary case: it is *not* a contract artifact, its changes are
|
||
class-4 non-events ([ADR-017] §2.4), and its semver carrier (the
|
||
engine crate's changelog) has no *versioning* reason to mention
|
||
them — the semver does not move for them. Upstream lineage is a
|
||
fact the contract machinery cannot carry — the register is its
|
||
single normative home.
|
||
- **The alksocks precedent supplies the in-tree shape.** alksocks'
|
||
ADR-013 there (the targeted fork) folded the forked core into
|
||
`src/rfc1928/` with a bundled module-level `LICENSE` notice, module
|
||
docs carrying the fork-point statement, and git history as the
|
||
fork-point record — and that shape shipped on crates.io without
|
||
provenance problems ([ADR-013]'s context cites it twice). The
|
||
distinction this ADR must add: alksocks' fold *retired* the vendor
|
||
framing — upstream is quiet, and a future fix "arrives as a
|
||
hand-port" with no register apparatus. The honker fork is the other
|
||
case: its fix stream is *alive* (the #80/#133 train is what fired
|
||
the fork), and ADR-012 §6 commits to deliberate cherry-picks.
|
||
Recurrent adoption needs a durable ledger; a one-shot extraction
|
||
does not. Both are the same posture — the record apparatus scales
|
||
with the upstream's activity.
|
||
- **The known defect class is named in the evidence base already.**
|
||
`quality-read-honker-core.md` §3 (D-1..D-7) is the re-derivation
|
||
work's rationale-of-record — its entries feed the re-derivation
|
||
delta entries' Why fields; the fix train the fork point *inherits*
|
||
(`4881f27`, `3ab43aa`, `claimed_at` et al. at `f4e53c6`) is
|
||
upstream lineage, recorded under upstream identity, not a delta of
|
||
ours. The scaffold work is formatting, not gathering.
|
||
|
||
## Decision
|
||
|
||
### 1. The provenance register: `alkstore-sqlite/src/substrate/PROVENANCE.md`
|
||
|
||
The provenance register is a **single Markdown file inside the
|
||
substrate subtree** — `alkstore-sqlite/src/substrate/PROVENANCE.md` —
|
||
per the ADR-017 §1 altitude: it is substrate lineage, so it lives with
|
||
the substrate; the fold's "in-tree, beside the substrate subtree"
|
||
placement ([ADR-013] §3) names the directory, this ADR names the
|
||
file. (ADR-012 §1's `provenance.md`-at-the-crate-root named the
|
||
pre-fold crate-root location; superseded with that §1. The uppercase
|
||
filename follows the family precedent for standing-in-tree notices —
|
||
the alksocks bundled `LICENSE` inside its forked module.)
|
||
|
||
The register **carries two sections**:
|
||
|
||
1. **Upstream identity** (ADR-012 §1's initial contents): the fork
|
||
source — upstream project, `/workspace/honker` reference checkout @
|
||
`f4e53c6` (package `node-v0.5.1-10-gf4e53c6`), published-release
|
||
lineage (0.5.0, 2026-08-23), license **MIT OR Apache-2.0** — and
|
||
the fork-point statement: the scaffold commits are the provenance
|
||
line in git history, exactly alksocks' extraction-commit-window
|
||
shape. This section is also where inherited lineage facts live
|
||
(the fix train the fork point carries — `4881f27`, `3ab43aa`,
|
||
`claimed_at` et al. — is upstream code we inherited, not a delta
|
||
of ours).
|
||
2. **The delta register** — §2's format; every divergence from
|
||
lineage lands here *including cherry-picks* (their category is
|
||
`cherry-pick`; §3's procedure writes to this section — there is
|
||
no separate cherry-pick ledger). The scaffold's port deltas
|
||
([ADR-012] §4, ADR-011's scope register) are its initial entries;
|
||
cherry-picks are empty at scaffold, append-only forever.
|
||
|
||
The register is **not** itself a guard — the contract-blind
|
||
boundary's guards remain the diff fence, review, and the contract
|
||
suite ([ADR-013] §2's re-sited enforcement); the register is the
|
||
audit trail review works from. It records: what lineage this is,
|
||
what we have already changed, and how each change arrived. Its duty
|
||
is completeness, not authority — the ADRs remain the decisions of
|
||
record.
|
||
|
||
### 2. Delta register format: one entry per delta, tagged by category — never per commit
|
||
|
||
**Per-delta, category-tagged** — one entry per distinct delta, each
|
||
carrying its category tag — never one per commit. Granularity the
|
||
evidence dictates: the fork's divergence arrives in bursts (the
|
||
scaffold adds the port deltas at once; a future upstream fix train
|
||
lands as several commits, one category), and a
|
||
per-commit register would grow into a duplicate of the git log — a
|
||
second ledger for the same fact, the drift ADR-017 §1 rejects. The
|
||
git history of this repository *is* the per-commit record; the
|
||
register is the semantic index over it.
|
||
|
||
Each entry pins **five fields**:
|
||
|
||
- **Category** — one of the standing classes (kept-half port delta /
|
||
re-derivation / drop / hygiene / cherry-pick), so the entry says at
|
||
a glance which slice of the scope register the change touches.
|
||
- **What** — the delta in one or two sentences (the read's W-numbers
|
||
and D-numbers are admissible identifiers — e.g. "W-1 reconnect
|
||
backoff applied").
|
||
- **Where** — the module path(s) in the subtree the delta touches.
|
||
- **Why** — the deciding record (ADR + section, quality-read finding,
|
||
or the cherry-picked upstream issue/commit hash pair — see §3).
|
||
- **Lineage** — for cherry-picks: the upstream commit hash(es) the
|
||
delta carries (the `4881f27`/`3ab43aa` pattern the evidence uses);
|
||
for born deltas (port deltas, re-derivations): "ours" — no upstream
|
||
counterpart exists.
|
||
|
||
The **initial entries at scaffold** are fixed by the retained
|
||
records, not re-litigated: the ADR-011 scope register's keep /
|
||
re-derive / drop tripartition as three class entries, the three
|
||
watcher deltas of ADR-012 §4 (W-1, W-2, the dead-man's-switch
|
||
re-death; W-3's not-actionable and W-4's keep-RW recorded where the
|
||
read put them), the `__alkstore_*` rename, and the port discipline
|
||
deltas (sync substrate, no-panics/no-unwrap hygiene). Nothing here
|
||
makes new decisions — the register's section 2 simply carries what
|
||
ADR-011 §3 and ADR-012 §3–§5 already decided, in the format this ADR
|
||
pins, and the scaffold task inherits the list as its checklist.
|
||
|
||
Subsequent entries append only. Amending an existing entry is
|
||
permitted solely to *correct the record* (a wrong path, a mis-cited
|
||
hash) — never to change the register's story; a superseded delta is a
|
||
new entry that cites the one it supersedes.
|
||
|
||
### 3. The cherry-pick procedure: five steps, one record
|
||
|
||
When upstream (honker-core proper — the reference checkout's lineage)
|
||
ships a fix relevant to the kept half, adoption runs this procedure,
|
||
whose steps make the ADR-012 §6 deliberate-work posture auditable —
|
||
each step leaves a checkable artifact:
|
||
|
||
1. **Candidate identification (notice duty).** Since no ambient
|
||
tracking exists ([ADR-012] §6), a candidate arrives by deliberate
|
||
review of the reference checkout / upstream history when a reason
|
||
exists (a defect observed in our fork — first stop, upstream's fix
|
||
train; a fresh upstream release announcement; a routine periodic
|
||
sweep at whatever cadence future maintenance wants, or none).
|
||
The procedure does *not* create a sweep duty — it says that if a
|
||
candidate arrives by any route, the following steps apply.
|
||
2. **Evaluation against the port-cost logic** ([ADR-012] §6): does
|
||
the upstream fix touch kept-half machinery that still tracks its
|
||
lineage? Does it beat our owned, tested, contract-ahead fork on
|
||
maintenance rather than novelty (quality-read §7's re-adoption
|
||
bar's spirit, applied per-fix)? A fix for a defect class in the
|
||
re-derived machinery (the queue ops — D-1–D-3, D-5–D-7's fix
|
||
classes; D-4's `lock_acquire` sits in the *kept* half and stays
|
||
cherry-pick-eligible) is *not adoptable* — it
|
||
evaluates against machinery that no longer tracks upstream, and
|
||
the correct response to an observed defect in re-derived code is
|
||
an owned fix under the fork's own test discipline.
|
||
3. **Application** — hand-application of the upstream change against
|
||
the kept half, preserving ADR-012 §3's fidelity posture (module
|
||
structure and internal names survive the application where the
|
||
surrounding code does; mechanical token renames stay banned), plus
|
||
the family deltas the substrate always carries (no panics, no
|
||
`unwrap()` outside tests — the port applies exactly this
|
||
discipline to the inherited fixes). The application is verified
|
||
against the inherited suites and the contract suite's substrate
|
||
rows — the fork's version of alksocks' differential-suite guard,
|
||
which is what makes "the cherry-pick preserved the inherited
|
||
semantics" a testable claim rather than an assertion.
|
||
4. **Record** — one delta-register entry (fields §2 pins;
|
||
category `cherry-pick`, lineage = the upstream commit hashes,
|
||
why = the evaluation's reasoning and outcome) **plus one line in
|
||
the engine crate's changelog** — not a versioning event
|
||
([ADR-017] §2 class 4: the engine's semver does not move for it),
|
||
but a *changelog-visible* entry citing the register, so a reader
|
||
auditing the crate's history between versions finds the substrate
|
||
change without needing to know the register exists. This is the
|
||
fold's answer to the crate-graph signal the standalone
|
||
`alkstore-substrate` crate's version bumps would have carried.
|
||
5. **Commit** — the cherry-pick commit message names the upstream
|
||
commit hash(es); the register entry cites the commit. Git history
|
||
and the register cross-link, and the fork point stays linear: every
|
||
lineage-relative change from scaffold onward is
|
||
register-entry-addressable by commit.
|
||
|
||
**Recording timing: at adoption, not swept.** The register entry and
|
||
changelog line land in the same commit as the applied change; there
|
||
is no deferred-registration window in which the delta exists but the
|
||
record does not. Keeping it that way is what makes the audit trail
|
||
trustworthy without enforcement tooling.
|
||
|
||
**When a cherry-pick would touch the re-derived half or cross the
|
||
contract boundary**: it is *not* a cherry-pick, it is a fork change —
|
||
an owned edit, evaluated by the engine's own review discipline, and
|
||
(if it moves contract-visible semantics) classified under ADR-017's
|
||
taxonomy like any engine change. The register records it as a born
|
||
delta / maintenance entry, never as lineage adoption. The boundary
|
||
between the two record types *is* ADR-012 §2's contract-blind
|
||
boundary showing up in the maintenance posture.
|
||
|
||
### 4. What this does not decide
|
||
|
||
- **Sweep cadence** — deliberately unset; ADR-012 §6's no-ambient
|
||
posture governs (adoption is triggered, never scheduled).
|
||
- **Re-adoption of upstream as a dependency** — quality-read §7's
|
||
bar, unchanged and untouched here.
|
||
- **The scaffold task itself** — the register's initial contents and
|
||
the scaffold work items are the fork-scaffold task's body, now
|
||
without open questions; per the OQ's own scoping, this resolution
|
||
gates nothing and precedes no task.
|
||
|
||
## Consequences
|
||
|
||
**Positive**
|
||
|
||
- OQ-11's residue resolves without new machinery: the register is one
|
||
Markdown file whose two sections mirror the decided facts (identity,
|
||
deltas — cherry-picks riding the delta register as tagged entries),
|
||
the procedure is five steps of
|
||
discipline already implied by retained records, and the class-4
|
||
non-event status of substrate changes now has a paper trail.
|
||
- The audit posture scales: scaffold-time deltas and future
|
||
cherry-picks land in the same section in the same format, so a
|
||
reader of the subtree in
|
||
year three finds one register answering "what is this code, what
|
||
differs from its lineage, and why."
|
||
- The engine crate's changelog gains substrate visibility without
|
||
gaining versioning noise — the one-line entries carry no semver
|
||
movement and cannot be mistaken for contract events.
|
||
|
||
**Negative (accepted)**
|
||
|
||
- The register is maintained by discipline, not tooling — nothing
|
||
enforces that a substrate edit added a register entry beyond the
|
||
diff fence and review (the same accepted-enforcement weakness
|
||
ADR-013 §2 stated for contract-blindness; its answer here is the
|
||
same: low-risk because the boundary is structural and the file is
|
||
adjacent).
|
||
- The changelog-line duty adds one small standing obligation to every
|
||
cherry-pick; skipping it is a process defect, not a caught one.
|
||
|
||
## References
|
||
|
||
- OQ-11 (`docs/architecture/open-questions.md`) — this ADR's
|
||
resolution; items (2)/§2 and (3)/§3, item (1) dissolved by
|
||
[ADR-013] §4.
|
||
- [ADR-011](011-sqlite-substrate-fork.md) — the fork decision and its
|
||
scope register (the initial delta entries' content).
|
||
- [ADR-012](012-forked-substrate-design.md) — §1/§6 (the register's
|
||
naming and the upstream-tracking stance), §2 (the boundary that
|
||
splits cherry-picks from fork changes), §3 (the fidelity posture
|
||
the application step preserves), §4 (the port deltas).
|
||
- [ADR-013](013-fold-substrate-into-sqlite.md) — the fold (§3's
|
||
in-tree placement; §4's reshaping of this OQ); its re-sited
|
||
enforcement is the audit gap this register fills.
|
||
- [ADR-017](017-contract-versioning.md) — §1 (the one-normative-
|
||
owner rule this register's scope respects), §2 class 4 (substrate
|
||
cherry-picks as non-events — the classification this procedure
|
||
gives a paper trail), §4.2 (the version-stamped suite the
|
||
application step verifies against).
|
||
- `docs/research/quality-read-honker-core.md` — the fork calculus,
|
||
the defect register (D-1..D-7), the W-1..W-4 notes, §7's
|
||
re-adoption bar; the hash-citation pattern (`4881f27`, `3ab43aa`)
|
||
§2's lineage field adopts.
|
||
- alksocks `docs/architecture/decisions/011-inline-vendor.md` and
|
||
`013-targeted-fork.md` (@ `/workspace/@alkdev/alksocks`) — the
|
||
in-tree LICENSE/module-docs/git-history provenance shape, and the
|
||
quiet-upstream contrast (no register apparatus needed there) that
|
||
scopes why this ADR adds one.
|
||
|
||
[ADR-011]: 011-sqlite-substrate-fork.md
|
||
[ADR-012]: 012-forked-substrate-design.md
|
||
[ADR-013]: 013-fold-substrate-into-sqlite.md
|
||
[ADR-017]: 017-contract-versioning.md |