ADR-018: substrate provenance register + cherry-pick procedure (OQ-11 resolved — Phase 1 question set closed)
This commit is contained in:
1 parent
eba77909a7
commit
c49befd195
7 files changed
+382
-45
No files matched your search
@@ -240,7 +240,10 @@ owned, tested, contract-ahead fork on maintenance, not on novelty.
|
||||
- OQ-06 (`docs/architecture/open-questions.md`) — the resolved
|
||||
assessment this ADR follow-throughs; OQ-11 — the scaffold-time
|
||||
residue this ADR leaves (workspace wiring, register format,
|
||||
cherry-pick procedure).
|
||||
cherry-pick procedure) — since resolved:
|
||||
[ADR-013](013-fold-substrate-into-sqlite.md) (item 1, dissolved)
|
||||
and [ADR-018](018-provenance-register-and-cherry-picks.md) (items
|
||||
2–3, the register and the procedure).
|
||||
|
||||
[ADR-001]: 001-crate-split.md
|
||||
[ADR-003]: 003-sqlite-driver.md
|
||||
|
||||
@@ -153,6 +153,10 @@ in-tree beside the substrate subtree (its location settles with the
|
||||
fold; its format/granularity remains OQ-11 item (2)). Items (2)
|
||||
(register format and delta-list granularity) and (3) (cherry-pick
|
||||
procedure in practice) remain, now scoped to the in-tree register.
|
||||
*(Resolved 2026-10-06 by
|
||||
[ADR-018](018-provenance-register-and-cherry-picks.md): the register
|
||||
is `src/substrate/PROVENANCE.md`; per-delta, category-tagged entries;
|
||||
the five-step cherry-pick procedure.)*
|
||||
|
||||
## Consequences
|
||||
|
||||
|
||||
@@ -139,6 +139,7 @@ duty — that is what makes them non-events).
|
||||
clean. Core bumps its major (pre-1.0: its `0.y`).
|
||||
4. **Non-events** — engine-internal changes (engine opts, derived
|
||||
names, substrate cherry-picks per OQ-11's procedure —
|
||||
[ADR-018](018-provenance-register-and-cherry-picks.md), resolved:
|
||||
contract-blind by ADR-012 §2, so they cannot be contract events
|
||||
by construction); and doc clarifications *only* where a correct
|
||||
implementation could not have behaved differently before them
|
||||
@@ -333,6 +334,7 @@ number *must* encode the contract version (its manifest pin does,
|
||||
rejection that narrowed this discipline's scope (no descriptor to
|
||||
version); its three-carriers pattern (§4).
|
||||
- OQ-11 — the fork-scaffold residue whose cherry-pick procedure
|
||||
governs the substrate-side non-events (class 4).
|
||||
governs the substrate-side non-events (class 4) — resolved by
|
||||
[ADR-018](018-provenance-register-and-cherry-picks.md) (2026-10-06).
|
||||
- `docs/research/consumer-inventory.md` — the row-first gate on
|
||||
extensions (class 2/§2's closing rule).
|
||||
@@ -0,0 +1,298 @@
|
||||
# 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
|
||||
Reference in new issue
Block a user