Map Cut 6d: resolution history and stewardship by sequence
Two key shapes gain a writer-set sequence so a subject's resolutions and a repo's stewardships keep their history under one prefix, with the in-force record derived as the latest not withdrawn. A hand-off stays a transfer with no lease field. Two schema files regenerate, no epoch moves, and the Huginn follow-up commit is named for when the pin moves. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
542dc1848c
commit
b693f9f3b3
1 changed files with 582 additions and 8 deletions
|
|
@ -45,14 +45,23 @@ schema-ownership phase inside Epiphany, not because the campaign stops.
|
|||
`b6f6e802`, `80db5db6`, `3ee78e05`, second fix batch at `9b68d83c`,
|
||||
`4cccb45c`, `4a654351`. `epiphany-pipeline` is a leaf library Huginn can
|
||||
depend on without `epiphany-core`.
|
||||
- **Cut 6b landed** at `602ffd9f` (deletes), `1bddd2ac` (grammar), `95ee551a`
|
||||
(mutation suite); fix batch in Hands. The second fix batch's Soul pass had
|
||||
found the same invariant open one level up for the third time, so the key
|
||||
grammar was redesigned rather than patched a fourth time. Soul's first pass
|
||||
on the grammar found no collision in 212,450 adversarial keys and four
|
||||
unpinned checks.
|
||||
- **Cut 6c landed** at `4d6af409`, `13570e84`, `dddf9ede`, after the third
|
||||
6b fix batch at `9d57a460`, `7cd1a38b`. Soul in flight on both.
|
||||
- **Cut 6b landed and closed** at `602ffd9f` (deletes), `1bddd2ac`
|
||||
(grammar), `95ee551a` (mutation suite), with three fix batches at
|
||||
`4b85dd2d`, `d03a32df`, `9370aa0f`, `f00062db`, `9d57a460`, `7cd1a38b`.
|
||||
The second fix batch's Soul pass on Cut 6 had found the same invariant
|
||||
open one level up for the third time, so the key grammar was redesigned
|
||||
rather than patched a fourth time; Soul found no collision in 212,450
|
||||
adversarial keys. The shared mutation harness came out of its fix
|
||||
batches.
|
||||
- **Cut 6c landed and closed** at `4d6af409`, `13570e84`, `dddf9ede`, fix
|
||||
batch `fcfbda3f`, `3f7d58d1`, harness repairs `b3bd4a82`, `aef0e1bf`.
|
||||
- **Cut 6d in Hands** against `b4b17fc`: the key sequences Q17, Q19 and Q20
|
||||
ruled, in the leaf. Its Huginn follow-up commit lands after Soul closes it
|
||||
and the pin moves. **Must land before Cut 9.**
|
||||
- **Cut 8 landed**: the Epiphany half at `a65c6420` (Soul-closed) with the
|
||||
Cut 10 prerequisite at `b4b17fc`; the Huginn half on `eureka/memory-organ`
|
||||
at `946758f`, `a4c5b79`, `0bd7133`, `ca30d3e`, fix batch `1cfa81d`,
|
||||
`acd32f3`, `30daff8`. Soul in flight on the fix batch.
|
||||
- **Cut 7 landed and closed** on Huginn `eureka/memory-organ` at `1320fc4`,
|
||||
`f63c0f2`, `e20c786`, fix `4094e68`; Eve `main` `e777e4c`, fix `167a2d3`;
|
||||
EveConformance `main` `048ea2f`. Started in parallel on the operator's
|
||||
|
|
@ -2045,6 +2054,571 @@ moves to this commit.
|
|||
cost of one shared `CARGO_TARGET_DIR` across sessions, already accepted
|
||||
(correction 22); not a dependency, and not Hands' explanation either.
|
||||
|
||||
## Cut 6d. Resolution history and stewardship by sequence
|
||||
|
||||
Imagination, 2026-09-16, revised the same day for Q19 A and Q20 A.
|
||||
Implements Q17 B, Q18 A as corrected, Q19 A and Q20 A: **a hand-off is a
|
||||
transfer of stewardship, symmetric and final as a record; a lease is two
|
||||
transfers and nothing more** (no lease, expiry, return or intent field
|
||||
anywhere); **a withdrawal cannot be withdrawn**; and **stewardship is keyed by
|
||||
a per-(instance, repo) sequence, not by date**, exactly as resolutions are
|
||||
keyed by a per-subject sequence.
|
||||
|
||||
- **Repo/branch:** Epiphany `codex/eureka-pipeline-state`. Anchors are
|
||||
`file:line` against `epiphany-pipeline/src/lib.rs` at **`b4b17fc`** (2,099
|
||||
lines, 28 tests), byte-identical at HEAD `542dc184` (`git diff --stat
|
||||
b4b17fc HEAD -- epiphany-pipeline/ schemas/cultnet/ tools/` empty, probed
|
||||
twice). HEAD moved three times during this pass, the map only; re-anchor by
|
||||
content as every cut since 6b has.
|
||||
- **Depends on:** nothing unlanded. **Blocks:** Cut 9 (in-force derivation),
|
||||
Cut 12 (hand-off), and a Cut 8 follow-up commit in Huginn that this cut
|
||||
implies (below). Lands before any of them.
|
||||
- **Cost:** two kinds' keys move (`resolution`, `stewardship`); two fields are
|
||||
added (`resolution.sequence`, `stewardship.sequence`); two schema files
|
||||
regenerate; no epoch moves; no kind widens. Keys are free to move today: no mind exists on Yggdrasil.
|
||||
Huginn pins `a65c6420` (`crates/huginn-mind/Cargo.toml:15`) and its fixtures
|
||||
spell both old shapes, so the pin move is a named follow-up, not a surprise.
|
||||
|
||||
### What the cut does
|
||||
|
||||
**Q17 B.** A resolution is the record of how a subject was closed and by
|
||||
what. Its key gains a per-subject sequence as the **last** local part:
|
||||
`<subject root>:resolution:<subject kind>.<subject local>.n<N>`. Withdrawn
|
||||
resolutions stay under their subject as records; the subject can be resolved
|
||||
again at `n<N+1>`; the history is the key prefix
|
||||
`<root>:resolution:<kind>.<local>.n`.
|
||||
|
||||
**Q18 A + Q20 A.** A stewardship is keyed by repo and a per-(instance, repo)
|
||||
sequence: `<instance>:stewardship:<repo escaped>.n<N>`. A repo transferred
|
||||
away and later transferred back to the same mind is two records under one
|
||||
prefix, `<instance>:stewardship:<repo escaped>.n`, and the in-force one is
|
||||
the latest not withdrawn. `assigned_on` stays a field, validated as a `Date`
|
||||
by the derived `Bounded` impl, and no longer enters the key.
|
||||
|
||||
Both are key-shape changes in the leaf plus one field each. Everything semantic
|
||||
(what "in force" means, what `AlreadyResolved` refuses, how a transfer derives
|
||||
its writes) is admission's and is specified here for the Huginn follow-up, not
|
||||
built here. The leaf gains no cross-field rule (authority map, Cut 6b/6c).
|
||||
|
||||
### Decisions, with the reasons
|
||||
|
||||
#### D1. The sequence is a field the writer sets; admission checks it
|
||||
|
||||
This decision is made once and applied to both kinds: `resolution.sequence`
|
||||
is per subject, `stewardship.sequence` is per `(instance, repo)`. The leaf
|
||||
holds no image (`pipeline_key`'s inputs are "the document's own
|
||||
fields. No clock, store, registry or counter", map Cut 6b authority map), so
|
||||
the only way the sequence reaches the key is a field. Admission cannot set it
|
||||
either: `admit_prepared` takes envelopes "prepared by anyone" and the receipt
|
||||
digests the exact payload bytes (`receipt.rs`, map Cut 8 A9/A11), so a field
|
||||
rewritten by admission would make Cut 12's import and exact replay
|
||||
impossible. Precedent already in the leaf: `revision: u32` on `target` and
|
||||
`cut_spec` is writer-set and keyed `r<N>`, and Huginn's `revision_rule`
|
||||
(`admission.rs:605-622` at `1cfa81d`) checks it against the image. The
|
||||
sequence follows the same pattern exactly.
|
||||
|
||||
- **Fields:** `sequence: u32` on `PipelineResolution` after `subject`, and
|
||||
`sequence: u32` on `PipelineStewardship` after `repo`.
|
||||
- **Bound:** none in the leaf beyond `u32` and `LOCAL_MAX`; `n4294967295` is
|
||||
an 11-byte label. The leaf refuses neither `0` nor a gap, as it refuses
|
||||
neither `revision: 0` nor `revision: 7` without a predecessor; those are
|
||||
admission's (`revision_rule` refuses 0). Stated in both fields' doc comments
|
||||
and pinned as a stated limit in the new tests.
|
||||
- **Admission's rule (follow-up), the same for both:** `sequence ==
|
||||
latest + 1`, where `latest` is the greatest `sequence` among the records of
|
||||
the same scope (resolutions of that subject; stewardships of that
|
||||
`(mind, repo)`) in image ∪ batch other than this document; and no record of
|
||||
that scope is in force other than this document. Refusals below.
|
||||
- **Derived writes** (a ruling's `Answered` resolution; on a transfer, the
|
||||
source mind's `Withdrawn` resolution of its stewardship and the receiving
|
||||
mind's new stewardship) get their `sequence` from `derive()` the same way,
|
||||
since `derive` already reads `docs` (`admission.rs:417-458` at `30daff8`).
|
||||
|
||||
#### D2. Spelling: `n<N>`, the last part
|
||||
|
||||
Every numeric key part the leaf has carries a one-letter marker (`r2`, `h1`,
|
||||
`s2`, `:724,:731,:739,:748`), and `parent_cut` reads the marker to tell a
|
||||
spec's tail from a report's. The sequence takes `n` ("the nth resolution").
|
||||
Nothing parses it back: admission reads `sequence` from the document, never
|
||||
from the key, and the reader `pipeline_id` stays one shape with no `match
|
||||
kind` (R1, R2 hold; `:579-599` unchanged). The marker buys legibility and the
|
||||
house convention for one byte per nesting; the alternative, bare digits, was
|
||||
considered and rejected because a key a human reads in a Studio row should
|
||||
say what its tail is.
|
||||
|
||||
The sequence is the **last** part so that the subject's resolutions, and only
|
||||
they, share the prefix `<root>:resolution:<kind>.<local>.n`. Under R2 no part
|
||||
carries a dot, so `question.Q1.n` cannot match `question.Q10.n1`, and the
|
||||
withdrawal of `Q1`'s first resolution keys under `resolution.question.Q1.n1.n1`,
|
||||
outside the prefix. The same spelling and position serve stewardship: the
|
||||
history of a repo on a mind is the prefix `<instance>:stewardship:<repo
|
||||
escaped>.n`, and `key_segment` escapes `.` to `_d`, so an escaped repo can
|
||||
never end in `.n`. Both prefix properties are pinned by leaf tests (below) and
|
||||
are what Cut 9's history queries ride on.
|
||||
|
||||
#### D3. Nesting arithmetic changes
|
||||
|
||||
A depth-one local is `<kind>.<subject local>.n<s>`. Each nesting prepends
|
||||
`resolution.` (11 bytes) and appends `.n<s>` (3 bytes for one digit), so a
|
||||
chain `d` deep composes `14 * (d - 1) + L1` bytes, `L1` the depth-one local.
|
||||
At `LOCAL_MAX = 64`: `ruling.A.n1` (11 bytes) and `question.Q1.n1` (14 bytes)
|
||||
both key **four** deep and refuse at five (53 and 56 fit; 67 and 70 do not).
|
||||
The bound stays the local's alone (`local`, `:673-682`); no guard is added
|
||||
(Q11 A). The depth test derives its expectation from `LOCAL_MAX` and the two
|
||||
literal widths, so the numbers are not restated.
|
||||
|
||||
A stewardship local is `<repo escaped>.n<N>`, so the escaped repo has
|
||||
`LOCAL_MAX - 3` bytes for a one-digit sequence (61), not 64. It does not
|
||||
nest. The resolution of a stewardship is `<instance>:resolution:stewardship.<repo
|
||||
escaped>.n<N>.n<M>`, two sequence parts, the inner one the stewardship's; a
|
||||
withdrawal of that is one more `resolution.` and `.n1`, and Q19 A stops the
|
||||
chain there.
|
||||
|
||||
#### D4. What "withdrawn" means, and what `AlreadyResolved` becomes
|
||||
|
||||
Documents are immutable and status is derived (Cut 9: "status is derived at
|
||||
read time, never stored"), so the only way a resolution stops counting is
|
||||
another document naming it: **a resolution of the resolution with outcome
|
||||
`Withdrawn`**, the matrix row Cut 8 first specified ("resolution: `Withdrawn`
|
||||
only: withdrawing a resolution reopens its subject", map `:2376`) and Soul
|
||||
found unimplementable under the outcome-invariant key. The sequence makes it
|
||||
implementable. Huginn's landed fix batch already restored that row
|
||||
(`acd32f3`, `admission.rs:673` at `30daff8`: `(K::Resolution, O::Withdrawn {
|
||||
.. }) => true`) and its doc comment says the sequence "is mapped separately";
|
||||
this is that map.
|
||||
|
||||
In-force, one derivation for every kind, recursive and well-founded:
|
||||
|
||||
> `in_force(kind, id)` holds when no resolution `R` with `R.subject == (kind,
|
||||
> id)` exists in image ∪ batch such that `in_force(Resolution, key(R))`.
|
||||
|
||||
`key(R)` is strictly longer than `id`, so the recursion descends a bounded
|
||||
chain (D3) and terminates. Today's `in_force` (`admission.rs:255-267`) is the
|
||||
non-recursive special case that counts a withdrawn resolution as if it still
|
||||
stood; that is the exact defect Soul named.
|
||||
|
||||
The in-force resolution of a subject is then "the latest not withdrawn". The
|
||||
two readings of that phrase ("the latest, if not withdrawn" and "the latest
|
||||
among the not-withdrawn") coincide **only if a withdrawal cannot itself be
|
||||
withdrawn**: otherwise `n1` withdrawn, `n2` admitted, then `n1`'s withdrawal
|
||||
withdrawn leaves two resolutions standing. **Q19, ruled A:** the chain is capped at admission (a resolution
|
||||
of a resolution is admissible only when that resolution's own subject is not
|
||||
a resolution), so reinstating a withdrawn closure is done by resolving the
|
||||
subject again at `n<N+1>`, which is what "keep a log, attached to the
|
||||
subject" asks for. Under A the two readings coincide and "the latest not
|
||||
withdrawn" is exact.
|
||||
|
||||
`AlreadyResolved { subject }` moves from A10 to A8:
|
||||
|
||||
- **A8, resolution row:** the subject has an in-force resolution other than
|
||||
this document → `AlreadyResolved { subject }`. "Other than this document"
|
||||
is content identity (the same `subject`, `sequence`, `outcome`, `rationale`,
|
||||
`resolved_on`), so an exact replay passes A8 and reaches A9's
|
||||
`AlreadyAdmitted`, as the ruling row's `own` closure already arranges
|
||||
(`admission.rs:496-501`). A wrong sequence → `ResolutionOutOfSequence {
|
||||
subject, expected, actual }` (new `MindRefusal` variant, Huginn's enum, not
|
||||
the leaf's).
|
||||
- **A10:** the `Resolution` arm of `refuse_collisions` (`admission.rs:727-729`
|
||||
at `30daff8`) is deleted. A resolution key is no longer one-per-subject, so a collision on
|
||||
it means what it means for every other kind: that identity is taken.
|
||||
`IdentityCollision` names it. The map's A10 sentence "a subject resolves at
|
||||
most once because its resolution key is outcome-invariant" is retired.
|
||||
- **The ruling row** keeps `AlreadyResolved` (a ruling answering a question
|
||||
whose resolution is in force); the derived `Answered` resolution's sequence
|
||||
is `latest + 1`, so a question withdrawn-and-reopened can be answered again.
|
||||
|
||||
#### D5. Stewardship: keyed by sequence, in force = the latest not withdrawn
|
||||
|
||||
- **Key:** `local(&key_field, &[&key_segment(&value.repo.0), &sequence])`
|
||||
with `let sequence = format!("n{}", value.sequence);`, after the existing
|
||||
`org_repo_text("stewardship.repo", …)?`. `assigned_on` does not enter the
|
||||
key, so the arm validates nothing about it; the field is validated where
|
||||
every field is, by the `Bounded` impl `value_types!` emits (`:248-253`),
|
||||
and `validate_pipeline_write_envelope` runs that before the key check.
|
||||
Q20's first draft put the date in the key and a `validate` call in the arm;
|
||||
both are gone, and no test may assert a date-shaped refusal from
|
||||
`pipeline_key`.
|
||||
- **Date-invariance:** two stewardships of one repo with one sequence and
|
||||
different `assigned_on` key once, exactly as two resolutions of one subject
|
||||
with one sequence and different outcomes key once. Pinned in the new test.
|
||||
- **Escaped repo bound:** the local is `<repo escaped>.n<N>`, so the escaped
|
||||
repo has 61 bytes for a one-digit sequence. `a_composed_local_is_bounded_whole`'s
|
||||
stewardship boundary moves with it (below).
|
||||
- **In force (follow-up), mirroring the resolution row exactly:** `sequence
|
||||
== latest(mind, repo) + 1` → else `StewardshipOutOfSequence { repo,
|
||||
expected, actual }`; and no in-force stewardship of `(mind, repo)` other
|
||||
than this document → else `AlreadyStewarded { repo }`. Both are new
|
||||
`MindRefusal` variants; the first is the sequence rule the coordinator
|
||||
named, the second is the in-force half `AlreadyResolved` plays for
|
||||
resolutions, and it is the one Cut 12's transfer-back depends on (a repo
|
||||
cannot be assigned twice while one assignment stands). Today the row is
|
||||
the key collision (`:2362`), which a sequenced key no longer provides.
|
||||
With both, at most one stewardship of a repo is in force on a mind, so
|
||||
"the latest not withdrawn" is "the one not withdrawn" and `stewardship_of`
|
||||
(`admission.rs:271-284` at `30daff8`) keeps returning `find_map` of the
|
||||
in-force one with no tie-break.
|
||||
- **Same-day limit, retired.** With the date out of the key, a repo
|
||||
transferred away and back to the same mind on one day is `n1` withdrawn and
|
||||
`n2` standing; nothing collides. The hand-off key itself still carries
|
||||
`handed_on` (`:721`), so two hand-offs in one direction for one repo on one
|
||||
day still share a key; that is the pre-existing hand-off shape, which this
|
||||
cut does not touch, recorded under Findings.
|
||||
|
||||
#### D6. A hand-off is a transfer; the derivations are symmetric already
|
||||
|
||||
Operator, 2026-09-16: "We might start with, say, Odin as steward over a whole
|
||||
swarm of infra tools, and spin off a new steward only when the workload
|
||||
justifies it. Odin wouldn't be getting it back in that case."
|
||||
|
||||
`derive` at `admission.rs:433-452` (`30daff8`) reads only `from_instance ==
|
||||
mind` (withdraw the in-force stewardship) and `to_instance == mind` (assign a
|
||||
new one, `assigned_on: handed_on`). A transfer back is a hand-off with the
|
||||
instances swapped; the source side withdraws the transferee's stewardship
|
||||
(a resolution at that stewardship's next sequence), the receiving side
|
||||
derives a new stewardship at `latest(mind, repo) + 1`, which no longer
|
||||
collides with the withdrawn original. **No field names a return, and none is
|
||||
added.** `hand_off` is unchanged in shape and key; `PipelineHandOff`
|
||||
(`:374-377`) does not move and `hand_off.v1.schema.json` does not regenerate.
|
||||
|
||||
What changes for Cut 8's per-kind rules: the hand-off row's two derivations
|
||||
each set a `sequence` (`derive` computes both from `docs`), and the derived
|
||||
stewardship's key is `<mind>:stewardship:<repo escaped>.n<N>`. What changes for Cut 12's
|
||||
spec: the sentence "with the superseding `stewardship` on the source side"
|
||||
(map `:2707-2709`) is wrong at HEAD and was before this cut — Cut 8 derives a
|
||||
`Withdrawn` resolution on the source side, not a supersession — and one test
|
||||
is added, `a_repo_transferred_back_is_stewarded_again` (transfer A→B, then
|
||||
B→A; A's in-force stewardship is `n2`; `n1` is still readable by key; the
|
||||
prefix `A:stewardship:<repo escaped>.n` yields both). Cut 12 models no return
|
||||
specially.
|
||||
|
||||
### Deletes first
|
||||
|
||||
| Path | Lines | What dies |
|
||||
|---|---:|---|
|
||||
| `epiphany-pipeline/src/lib.rs` | 0 | Nothing. The cut adds one field and two key parts; the resolution and stewardship arms are already one exit each through `local`, and the cut changes what they compose, not how. |
|
||||
| Huginn `crates/huginn-mind/src/admission.rs:727-729` at `30daff8` (follow-up, not this commit) | 3 | `refuse_collisions`'s `Resolution` arm. Goes before any new rule is added in that commit. (The matrix's Q17 A paragraph already died at `acd32f3`.) |
|
||||
|
||||
An honest zero in the leaf, not an omission.
|
||||
|
||||
### Keeps and moves
|
||||
|
||||
- **Keeps:** thirteen kinds, `PipelineKind`, every type id, the epoch
|
||||
constant (`:667`), `pipeline_id` (`:579-599`) untouched, `local`,
|
||||
`key_segment`, `ROOT_LOCAL`, `LOCAL_MAX`, `parent_local`, `parent_cut`,
|
||||
`PipelineRef`, `ResolutionOutcome` and its `Bounded` impl, the hand-off arm
|
||||
(`:714-723`) and key, `PipelineHandOff` and `PipelineStewardship.assigned_on`
|
||||
as fields, the outcome-invariance assertion (`:1102-1109`: the sequence is
|
||||
the same across outcomes, so the assertion stays true as written), every
|
||||
`value_types!` and `pipeline_kinds!` entry,
|
||||
`validate_pipeline_write_envelope`, all twenty-eight test names.
|
||||
- **Moves:** the resolution sample key (`:941`), the stewardship sample key
|
||||
(`:951`), and every literal resolution or stewardship key in the tests
|
||||
(listed per line below). The nested-depth arithmetic in
|
||||
`a_resolution_of_a_resolution_reads_back` and the stewardship boundary in
|
||||
`a_composed_local_is_bounded_whole` are key-shape assertions and move with
|
||||
the shape; both are named below with the exact new expression.
|
||||
- **Re-anchor, not move:** `tools/eureka-cut6b-mutations.psd1` M2 pins the
|
||||
exact `let parts = …` line of the resolution arm; that line changes, so M2's
|
||||
`Old` and `New` are re-anchored (below). Precedent: N7/N8 re-anchored Cut
|
||||
6's M12/M13 in the same file.
|
||||
|
||||
### Adds
|
||||
|
||||
| Add | Owner | Live consumer | Protected invariant | Why an existing owner cannot serve |
|
||||
|---|---|---|---|---|
|
||||
| `PipelineResolution.sequence: u32` | the leaf (shape and key) | `pipeline_key`'s resolution arm now; `huginn-mind`'s resolution row and `derive` in the follow-up | A subject's resolutions are distinct records with a total order the key carries, so a withdrawn one is kept and the next one is nameable (Q17 B) | The key must come from fields (D1); no existing field distinguishes two resolutions of one subject. |
|
||||
| `n<N>` as the last part of a resolution local | `pipeline_key` | the same | History is one key prefix per subject (D2) | The composer has no other path to a key. |
|
||||
| `PipelineStewardship.sequence: u32` | the leaf | `pipeline_key`'s stewardship arm now; `huginn-mind`'s stewardship row and `derive` in the follow-up | A repo's stewardships on a mind are distinct records with a total order the key carries, so a transferred-away repo can come back as a new record (Q18 A, Q20 A) | No existing field distinguishes two assignments of one repo to one mind; the date was rejected (Q20) because same-day records would collide and a date orders nothing the sequence does not. |
|
||||
| `n<N>` as the last part of a stewardship local | `pipeline_key` | the same | History is one key prefix per `(instance, repo)` | The composer has no other path to a key. |
|
||||
| Three tests and `tools/eureka-cut6d-mutations.psd1` (M23-M27) | the leaf's suite | the shared harness | Each rule above has a runtime mutation | — |
|
||||
|
||||
No kind, module, dependency, target, format or epoch. No type outside
|
||||
`value_types!`.
|
||||
|
||||
### Per-file changes, `epiphany-pipeline/src/lib.rs` at `b4b17fc`
|
||||
|
||||
| Line | Change |
|
||||
|---|---|
|
||||
| `:16-20` | Module doc gains one sentence: "A resolution's local ends in its per-subject sequence, `n<N>`, and a stewardship's in its per-repo sequence, so a subject's resolutions and a repo's assignments each share a prefix." |
|
||||
| `:363` | `pub struct PipelineResolution { subject: PipelineRef, sequence: u32, outcome: ResolutionOutcome, rationale: Para, resolved_on: Date }`, with a doc comment: the record of how a subject was closed and by what; `sequence` is per subject and set by the writer, `1` for the first; whether it is the previous plus one, and whether an earlier one still stands, are admission's. |
|
||||
| `:369-371` | `pub struct PipelineStewardship { instance: Slug, repo: OrgRepo, sequence: u32, assigned_on: Date, note: Line }`; doc: "an assignment of a repo to a mind; `sequence` is per `(instance, repo)`, set by the writer, `1` for the first, so a repo transferred away and back is two records under one prefix. `assigned_on` is a field, not a key part." |
|
||||
| `:695-701` | Rewrite the arithmetic comment: each nesting prepends `resolution.` and appends `.n<s>`, `14 * (n - 1) + L1` bytes against `LOCAL_MAX`. |
|
||||
| `:702-707` | Resolution arm: `let sequence = format!("n{}", value.sequence);` before `let parts = …`; the parts line becomes `let parts = std::iter::once(value.subject.kind.name()).chain(subject_local.split('.')).chain(std::iter::once(sequence.as_str())).collect::<Vec<_>>();`. The tuple line `(field, subject_root, local(&key_field, &parts)?)` is **byte-identical** (M3 anchors it). |
|
||||
| `:710-713` | Stewardship arm: `org_repo_text("stewardship.repo", &value.repo.0)?; let sequence = format!("n{}", value.sequence);` then `local(&key_field, &[&key_segment(&value.repo.0), &sequence])`. No validation of `assigned_on` here. |
|
||||
| `:937-941` | Resolution sample gains `sequence: 1`; expected key `format!("{CAMPAIGN}:resolution:question.Q1.n1")`. |
|
||||
| `:948-951` | Stewardship sample gains `sequence: 1`; expected key `format!("{INSTANCE}:stewardship:GameCult_-Epiphany.n1")`. |
|
||||
| `:1251` | `ruling.R8` → `ruling.R8.n1`. |
|
||||
| `:1270` | `question.Q1` → `question.Q1.n1`. `:1272` (`{CAMPAIGN}:resolution:R8` validates as well-formed grammar) unchanged; `:1274-1284` refused list unchanged. |
|
||||
| `:1296` | `campaign.self` → `campaign.self.n1`. |
|
||||
| `:1413`, `:1428`, `:1432` | Stewardship keys gain `.n1`. `:1436-1441` (no org) and `:1443-1452` (60-byte name still refused, now at 73 bytes) unchanged. |
|
||||
| `:1530` | The nested probe's subject id: `question.Q1` → `question.Q1.n1` (a real resolution key; the key composed is `resolution.question.Q1.n1.n1`). |
|
||||
| `:1616-1620` | `campaign.self` → `campaign.self.n1` in both the key and the read-back tuple. |
|
||||
| `:1824-1831` | Doc comment: the new arithmetic and depths (four for both fixtures at 64). |
|
||||
| `:1840` | Expected `resolution.question.Q1.n1.n1`. |
|
||||
| `:1841-1843` | Recovery: `let (subject_kind, rest) = local.split_once('.')`; `let (subject_local, _sequence) = rest.rsplit_once('.')`; assert `format!("{root}:{subject_kind}:{subject_local}") == inner`. |
|
||||
| `:1846` | `let nesting = "resolution.".len() + ".n1".len();` The loop and its two assertions are otherwise unchanged; `deepest` is still derived from `LOCAL_MAX`. |
|
||||
| `:1886-1912` | The stewardship boundary: `let stewardship_rest = "GameCult_-".len() + ".n1".len();` and `stewarded(64 - stewardship_rest)`, `stewarded(65 - stewardship_rest)`. Comment says the local is `<repo escaped>.n<N>`. The hand-off half is untouched. |
|
||||
| tests, after `:1938` | Three new tests, under Verification. No sample is added, so every `samples().remove(N)` index is unchanged. |
|
||||
|
||||
`tools/eureka-cut6b-mutations.psd1:38-39` (M2): `Old` becomes the new parts
|
||||
line above; `New` becomes `let parts = subject_local.split('.').chain(std::iter::once(sequence.as_str())).collect::<Vec<_>>();`
|
||||
(the kind dropped, the sequence kept, so the mutant still compiles and still
|
||||
keys `question.Q1` and `ruling.Q1` to one key, which
|
||||
`a_resolution_names_its_subjects_kind` kills as before). No other 6b, 6c, 8e
|
||||
or D entry anchors a line this cut touches (read: M1, M3-M6, S2, S4, S5, N3,
|
||||
N6-N10, X1, X11 anchor `local`, `key_segment`, `pipeline_id` and the campaign
|
||||
arm; 6c anchors `ResolutionOutcome`'s impl, `MutationRecord`, `VerdictClaim`
|
||||
and the estimate literal).
|
||||
|
||||
`schemas/cultnet/`: **exactly two files regenerate.**
|
||||
`epiphany.pipeline.resolution.v1.schema.json`: `properties` gains
|
||||
`"sequence": { "format": "uint32", "minimum": 0, "type": "integer" }` (the
|
||||
shape `revision` already has in `epiphany.pipeline.target.v1.schema.json:101-105`)
|
||||
and `required` (`:219-224`) gains `"sequence"` after `"subject"`.
|
||||
`epiphany.pipeline.stewardship.v1.schema.json`: the same property, and
|
||||
`required` (`:37-42`) gains `"sequence"` after `"repo"`. Derived, never
|
||||
hand-written: `pipeline_published_schemas_match_derivation` writes the
|
||||
derivation to a per-run temp directory and names it; copy from there.
|
||||
`epiphany.pipeline.hand_off.v1.schema.json` is **byte-identical**: no field
|
||||
moves on `PipelineHandOff`, and keys are not in schemas. The other ten and
|
||||
`index.json` (no hashes) are byte-identical. **No epoch moves.** Honesty
|
||||
about "additive": the epoch constant's doc comment (`:660-666`) says additive
|
||||
means "a new named field with a serde default", and neither `sequence` has
|
||||
one — a default of `0` would key a document to `n0`, which admission refuses,
|
||||
so the default would be a lie.
|
||||
This lands without a bump on the same ground Cut 6c's four required fields
|
||||
did: no store is written at this epoch and no reader is pinned to the file
|
||||
(Huginn pins the crate rev, not the schema). Recorded under Findings as the
|
||||
rule the campaign will owe an epoch to once a mind exists.
|
||||
|
||||
`git diff --stat b4b17fc -- schemas/cultnet/` names exactly the two files.
|
||||
|
||||
### Authority map
|
||||
|
||||
- **Owner:** `pipeline_key` (`:687`), through `local`, for both keys. Unchanged
|
||||
owner; changed inputs.
|
||||
- **Inputs:** the document's own fields, now including `resolution.sequence`
|
||||
and `stewardship.sequence`. `stewardship.assigned_on` is **not** a key
|
||||
input. No clock, store, registry or counter. A sequence is a field the
|
||||
writer sets, never derived here.
|
||||
- **Outputs:** one `String` or a `PipelineRefusal` naming the field
|
||||
(`resolution.key`, `stewardship.key`, `stewardship.repo`).
|
||||
- **Derived state:** the key, never stored. The history of a subject is a
|
||||
key prefix, not a list anything maintains. In-force status, the sequence
|
||||
rule, the withdrawal chain and the single-in-force-stewardship rule are
|
||||
admission's, computed at rule time, never stored (Cut 8/9), and are **not
|
||||
in this crate**.
|
||||
- **Forbidden writers:** the leaf may not check either `sequence` against
|
||||
anything (not `> 0`, not a gap), may not refuse a nested resolution, may
|
||||
not decide which stewardship is in force, may not put `assigned_on` (or any
|
||||
date) into the stewardship key, and may not parse a sequence back out of a
|
||||
key. `pipeline_id` gains no arm. Nothing may put a sequence anywhere but
|
||||
last. Admission (Huginn) may not set or rewrite `sequence` on a submitted
|
||||
document; it computes it only for the writes it derives.
|
||||
- **Shared paths:** the four grammar paths of 6b, unchanged:
|
||||
`pipeline_key`, `pipeline_id`, `PipelineRef::validate`,
|
||||
`validate_pipeline_write_envelope`. Huginn's `admit` and `admit_prepared`
|
||||
converge before A1 and see the new keys through A3 with no new code.
|
||||
- **Deletion line:** none in the leaf. In the follow-up: `refuse_collisions`'s
|
||||
`Resolution` arm and the matrix's Q17 A default go before any new rule is
|
||||
added.
|
||||
|
||||
### Verification
|
||||
|
||||
**Builds.** `CARGO_TARGET_DIR=C:\Users\Meta\.cargo-target-codex`, path-list
|
||||
baseline before and after. `cargo check -p epiphany-pipeline --lib --tests`;
|
||||
`cargo test -p epiphany-pipeline --lib` (28 existing + 3 = **31 tests**, 0
|
||||
warnings); `cargo check -p epiphany-core --lib --tests` (untouched; `cargo
|
||||
tree --workspace -i epiphany-pipeline -e normal,build,dev` lists the leaf
|
||||
alone, map correction 41, so no recompile is legitimate). Host = target =
|
||||
workstation; the leaf has no platform code.
|
||||
|
||||
Baseline probed this pass in a detached worktree at `b4b17fc` under the
|
||||
scratchpad: 28 passed, 0 failed, 15 s wall with warm rlibs; worktree removed.
|
||||
|
||||
**Tests.** Existing twenty-eight unchanged in name; assertions unchanged
|
||||
except the key-shape moves named per line above.
|
||||
|
||||
| Test | Rule it pins |
|
||||
|---|---|
|
||||
| `a_subject_keeps_every_resolution_it_had` | Q17 B in the key: two resolutions of `question:Q1` with `sequence` 1 and 2 key to `…question.Q1.n1` and `…n2`, `assert_ne`; each reads back through `pipeline_id` with the local's last part `n<sequence>`; the same document with `sequence` 1 under `Answered` and `Withdrawn` keys once (outcome-invariance holds per sequence). Stated limits: `sequence: 0` composes `n0` and `u32::MAX` composes `n4294967295` (21-byte local under `ruling.A`); the leaf refuses neither, admission does. |
|
||||
| `a_subjects_resolutions_share_a_prefix_no_other_key_has` | D2: over the keys of `Q1` n1..n3, `Q10` n1, `ruling:Q1` n1, the campaign-root resolution n1, and the withdrawal of `Q1.n1` (`resolution.question.Q1.n1.n1`), `starts_with("{CAMPAIGN}:resolution:question.Q1.n")` selects exactly the three. Pinned as a string property, which is what a prefix query is. |
|
||||
| `a_repo_keeps_every_stewardship_it_had` | Q18 A + Q20 A in the key: one repo with `sequence` 1 and 2 keys to `…GameCult_-Epiphany.n1` and `…n2`, `assert_ne`; each reads back through `pipeline_id` with the last part `n<sequence>`; the same document with `sequence` 1 on `2026-09-15` and on `2026-09-16` keys **once** (date-invariance: `assigned_on` is a field, not a key part); over the keys of `GameCult/Epiphany` n1..n2, `GameCult/Epiphany_thing` n1 and `GameCult/Huginn` n1, `starts_with("{INSTANCE}:stewardship:GameCult_-Epiphany.n")` selects exactly the two. Stated limit: `sequence: 0` composes `n0`; the leaf refuses nothing on the value. |
|
||||
|
||||
**Negative greps over `epiphany-pipeline/src`:** `rg -n "sequence"` shows the
|
||||
two fields, the two arms, docs and tests and **no** `if`, `match`, `==`, `>`
|
||||
or `+ 1` on either outside `tests`; `rg -n "assigned_on" -- src/lib.rs`
|
||||
shows the field, the samples, the derived stewardship nowhere (the leaf
|
||||
derives nothing) and **no** occurrence inside `pipeline_key`; `rg -n "match kind|declared_kind|KeyParts"` empty;
|
||||
`rg -n "fn pipeline_id" -A 20` shows no change (`git diff b4b17fc --
|
||||
epiphany-pipeline/src/lib.rs` has no hunk in `:572-599`); `git diff --stat
|
||||
b4b17fc -- schemas/cultnet/` names exactly two files; `rg -n '"sequence"'
|
||||
schemas/cultnet/epiphany.pipeline.{resolution,stewardship}.v1.schema.json`
|
||||
matches twice in each (property and required) and `rg -n '"sequence"'
|
||||
schemas/cultnet/epiphany.pipeline.hand_off.v1.schema.json` is empty;
|
||||
`rg -n "lease|expiry|returns_to|intent"` empty.
|
||||
|
||||
**Suites that must still kill every entry:** `eureka-cut6b-mutations.psd1`
|
||||
(seventeen entries, M2 re-anchored), `eureka-cut6c-mutations.psd1` (M16-M22),
|
||||
`eureka-cut8-epiphany-mutations.psd1` (E1-E3, D1-D2), `eureka-cut5-`, `eureka-cut6-`
|
||||
if still run per the harness header, and the new `eureka-cut6d-mutations.psd1`.
|
||||
All through `tools/eureka-mutations.ps1` with M0 green.
|
||||
|
||||
#### Mutations, `tools/eureka-cut6d-mutations.psd1`
|
||||
|
||||
Each restores the old permissiveness of the shape it pins. Anchors are
|
||||
content Hands lands, matched exactly once.
|
||||
|
||||
| # | Rule | Mutation, exactly | Killed by |
|
||||
|---|---|---|---|
|
||||
| M23 | A subject's resolutions are distinct records | Resolution arm: `.chain(std::iter::once(sequence.as_str()))` → removed (the old one-per-subject key) | `a_subject_keeps_every_resolution_it_had` (n1 and n2 key equal); collaterally every moved sample key |
|
||||
| M24 | A repo's stewardships on a mind are distinct records | Stewardship arm: `&[&key_segment(&value.repo.0), &sequence]` → `&[&key_segment(&value.repo.0)]` (the old one-per-repo key) | `a_repo_keeps_every_stewardship_it_had` (n1 and n2 key equal); collaterally every moved stewardship key |
|
||||
| M25 | The stewardship sequence is the last part | Stewardship arm: `&[&key_segment(&value.repo.0), &sequence]` → `&[&sequence, &key_segment(&value.repo.0)]` | the same test's prefix assertion (`n1.GameCult_-Epiphany` leaves the prefix) |
|
||||
| M26 | The sequence is the last part | Resolution arm: sequence chained **before** the subject local (`once(kind).chain(once(sequence)).chain(local parts)`) | `a_subjects_resolutions_share_a_prefix_no_other_key_has` (`question.n1.Q1` leaves the prefix) |
|
||||
| M27 | The nested subject is recovered whole, sequence stripped | In the resolution arm, `subject_local.split('.')` → `subject_local.rsplit_once('.').map_or(subject_local, \|(head, _)\| head).split('.')` (drop the subject's own sequence when nesting) | `a_resolution_of_a_resolution_reads_back` (the recovered subject is `question.Q1`, not the inner key) and `every_key_has_exactly_three_segments`'s nested probe |
|
||||
|
||||
Stated limits: the `n` marker is pinned only by the sample-key equalities in
|
||||
`keys_are_derived_and_mismatch_refuses` and the two prefix literals, a
|
||||
fixture pin like 6c's M21; a marker change is a spelling change and no
|
||||
mutation restores a permissiveness by it. The `u32` type has no runtime
|
||||
mutation. Date-invariance has no mutation of its own: putting `assigned_on`
|
||||
into the key is not a permissiveness the old code had, and M24 already pins
|
||||
that the second part is the sequence and nothing else (a mutant that appends
|
||||
the date as a third part dies on M24's test's `assert_eq` of the local's
|
||||
part count, which Hands asserts as `2`).
|
||||
|
||||
**Operator checks before landing:** none. Q19 and Q20 are ruled.
|
||||
|
||||
### The Cut 8 follow-up commit this cut implies
|
||||
|
||||
Huginn `eureka/memory-organ`, one commit after **`30daff8`** (the fix batch
|
||||
landed as `acd32f3`, which restored the `resolution → Withdrawn` matrix row
|
||||
and flipped the nested assertions, and `30daff8`, entries H21-H39; anchors
|
||||
below are `file:line` at `30daff8`). Pinned rev moves from `a65c6420` to this
|
||||
cut's landing commit, which also carries `b4b17fc`'s derives: the
|
||||
`#[serde(remote)]` mirror of `PipelineRefusal` in `refusal.rs` can come out
|
||||
then, but that is Cut 10's stated work and not this commit's.
|
||||
|
||||
| File | Change |
|
||||
|---|---|
|
||||
| `crates/huginn-mind/Cargo.toml:15` | `rev` → the 6d landing commit. |
|
||||
| `Cargo.lock` | the `epiphany-pipeline` source line. |
|
||||
| `src/refusal.rs` | `ResolutionOutOfSequence { subject: String, expected: u32, actual: u32 }`, `StewardshipOutOfSequence { repo: String, expected: u32, actual: u32 }`, `AlreadyStewarded { repo: String }`. `AlreadyResolved { subject }` kept. The two `OutOfSequence` variants are the sequence rule for each kind; `AlreadyResolved`/`AlreadyStewarded` are the in-force half. |
|
||||
| `src/admission.rs:23-26` | Module doc: "in force" is recursive: no resolution names the document that is itself in force. |
|
||||
| `:248-267` | `resolutions()` yields `(key, &PipelineResolution)`; `in_force_unless` becomes the recursion of D4, with `own` taking the whole `&PipelineResolution` (content identity) rather than the outcome. Add `latest_resolution(subject) -> u32` and `latest_stewardship(mind, repo) -> u32` over image ∪ batch (0 when none). |
|
||||
| `:271-284` | `stewardship_of` unchanged in shape; its result is now unique by the `AlreadyStewarded` rule. |
|
||||
| `:417-458` | `derive`: the ruling's `Answered` resolution and the source side's `Withdrawn` resolution each get `sequence: latest_resolution(subject) + 1`; the receiving side's stewardship gets `sequence: latest_stewardship(mind, repo) + 1` with `assigned_on: handed_on` as before. Keys follow from the leaf, no other code. |
|
||||
| `:591`, new `resolution_rule` steps | Before the matrix: `sequence` rule (`ResolutionOutOfSequence`), then in-force (`AlreadyResolved`). After the matrix, Q19 A: a subject of kind `Resolution` whose own subject is a `Resolution` → `IncompatibleResolution`. |
|
||||
| `:598` | Stewardship row, mirroring the resolution row: `sequence == latest_stewardship + 1` else `StewardshipOutOfSequence`; then no in-force stewardship of `(mind, repo)` other than this document, else `AlreadyStewarded`. |
|
||||
| `:654-680` | `matrix`: already restored at `acd32f3`; unchanged. |
|
||||
| `:724-733` | `refuse_collisions`: delete the `Resolution` arm (`:727-729`); one refusal, `IdentityCollision`. |
|
||||
| `src/fixtures.rs:100-107`, `:263-270` | `stewardship(instance, repo)` sets `sequence: 1`; add `stewardship_n(instance, repo, sequence)`; `resolution(subject, outcome)` sets `sequence: 1`; add `resolution_n(subject, sequence, outcome)`. |
|
||||
| Tests moving | `two_minds_in_one_state_root_stay_separate:800`, `the_resolution_matrix_is_admissions:1024,:1042`, `a_ruling_answering_a_question…:1132,:1135`, `a_hand_off_derives_this_minds_side_only:1427,:1448`, `id_of:1474-1477` (appends `.n1`): every `…:stewardship:GameCult_-Epiphany` gains `.n1` and every `…:resolution:question.Q1` gains `.n1`. Fixtures in `:52-116` of the landed batch (H21-H39's tests) that spell either literal move the same way; grep `stewardship:GameCult\|resolution\", \"question.Q1\"` after `30daff8` and re-anchor. |
|
||||
| `subject_resolves_at_most_once:977` | Renamed `a_subject_with_a_resolution_in_force_refuses_another`: second resolution of `Q1` at `sequence: 2` → `AlreadyResolved`; at `sequence: 1` → `ResolutionOutOfSequence { expected: 2, actual: 1 }`; the answering ruling → `AlreadyResolved` (unchanged). |
|
||||
| new `a_withdrawn_resolution_reopens_its_subject_and_stays_readable` | `Q1` resolved n1; withdrawal of `…question.Q1.n1` (`Withdrawn`) lands; `Q1` resolved n2 lands; `get` of n1 still returns it; a withdrawal of the withdrawal → `IncompatibleResolution` (Q19 A); a third resolution at n3 while n2 stands → `AlreadyResolved`; a second answering ruling after the withdrawal derives `…question.Q1.n2`. |
|
||||
| new `a_repo_is_stewarded_once_at_a_time_and_again_after_a_transfer` | second stewardship of `REPO` at `sequence: 2` while n1 stands → `AlreadyStewarded`; at `sequence: 1` → `StewardshipOutOfSequence { expected: 2, actual: 1 }`; after a hand-off away, a hand-off back (swapped instances) lands and derives `<mind>:stewardship:GameCult_-Epiphany.n2` with `assigned_on` the second `handed_on`; `envelope` of n1 still present; the source mind's derived withdrawal is `…:resolution:stewardship.GameCult_-Epiphany.n1.n1`. |
|
||||
| `tools/eureka-cut8-mutations.psd1` | H14's expectation stands (`IdentityCollision` on a ruling). Any H21-H39 entry anchoring `stewardship_of`, `derive` or `refuse_collisions` lines re-anchored. New: H40 resolution sequence rule → `true`; H41 in-force non-recursive (a withdrawn resolution still counts) → the reopen test; H42 stewardship sequence rule → `true` → the stewardship test's `expected: 2, actual: 1` case; H43 `AlreadyStewarded` dropped → the same test; H44 Q19 cap dropped → the reopen test's withdrawal-of-withdrawal; H45 `derive` uses `sequence: 1` for every derived write → the reopen test's second ruling and the transfer test's `n2`. |
|
||||
| `README.md`, `AGENTS.md` | unchanged; Cut 12's map section corrected by Self ("superseding" → "withdrawal"). |
|
||||
|
||||
Estimate: +about 260 lines in Huginn (rules 50, refusals 9, fixtures 16,
|
||||
tests 150, entries 48), −about 3 (the A10 arm). One build, `cargo test -p
|
||||
huginn-mind --lib`, plus the cut-8 suite through the harness with `-Repo`.
|
||||
|
||||
### Subtraction estimate
|
||||
|
||||
Epiphany, this cut: source outside tests +about 12 (two fields, two
|
||||
`format!("n{}")` lines, two chained parts, four doc lines), −0; tests +about
|
||||
100 (three tests) and about 25 lines of moved literals; two schema files
|
||||
+5/−0 each; one 6b entry re-anchored. Kinds, dependencies, targets, formats,
|
||||
epoch, `index.json`: zero. Liability retired: the one key that could not
|
||||
name the second closure of a subject, and the one key that could not name
|
||||
the second stewardship of a repo — both of which Soul found as medium
|
||||
defects against Cut 8, and both of which would have cost a stored-document
|
||||
re-key the moment Yggdrasil's mind held a resolution. Also retired before it
|
||||
ever shipped: the date-keyed stewardship's same-day collision.
|
||||
|
||||
Huginn, the follow-up: +260/−3 as above. Net across both: about +380, all
|
||||
tests and rules for a capability the operator asked for by name.
|
||||
|
||||
### Build budget
|
||||
|
||||
Epiphany: `epiphany-pipeline` lib + tests only; `epiphany-core` check, no
|
||||
rebuild expected. Debug, workstation host = target, no features, no
|
||||
codegen. Footprint delta: within the noise of a warm leaf rebuild (the probe
|
||||
this pass rebuilt the leaf's test binary in 15 s); expected +0 to +40 paths.
|
||||
Huginn follow-up: `huginn-mind` lib + tests; the leaf rlib rebuilds at the
|
||||
new rev (+about 30 paths). Retention: the shared target dir is the operator's;
|
||||
nothing deleted.
|
||||
|
||||
### Operator questions
|
||||
|
||||
None open. Two were raised by this spec and ruled the same day:
|
||||
|
||||
- **Q19. Can a withdrawal be withdrawn? Ruled A, 2026-09-16.** A resolution
|
||||
is admissible with `Withdrawn` only when its subject's own subject is not a
|
||||
resolution (chain depth two at admission). To reinstate a withdrawn
|
||||
closure, resolve the subject again at `n<N+1>`. History stays append-only,
|
||||
"the latest not withdrawn" has one reading, and the in-force recursion
|
||||
never re-raises an earlier record over a later one. The rejected B (any
|
||||
depth; in-force is "the latest among the not-withdrawn") could express a
|
||||
standing record that is not in force. H44's mutant is exactly B.
|
||||
- **Q20. Stewardship keyed by date or by sequence? Ruled A (sequence),
|
||||
2026-09-16.** `<instance>:stewardship:<repo escaped>.n<N>`, writer-set
|
||||
`sequence: u32` checked by admission as previous plus one, exactly as
|
||||
resolutions; `assigned_on` stays a field. The first draft's date key was
|
||||
rejected for the same-day collision and because a date orders nothing the
|
||||
sequence does not.
|
||||
|
||||
The Q18 correction (transfer, not lease) raised nothing new: the derivations
|
||||
were already symmetric in the source.
|
||||
|
||||
### Findings not assignable to this cut
|
||||
|
||||
- **"Additive" has two definitions in the repo.** The epoch constant's doc
|
||||
(`lib.rs:660-666`) says a new field is additive with a serde default; the
|
||||
campaign's practice (6c's four required fields, this cut's `sequence`) is
|
||||
"additive while no store is written at the epoch". Both are right today and
|
||||
will disagree the day Yggdrasil holds a mind. Owner: the map's ruling 8
|
||||
text and the constant's doc; not this cut's.
|
||||
- **Cut 12's spec says "the superseding `stewardship` on the source side"**
|
||||
(map `:2707-2709`); Cut 8 landed a `Withdrawn` resolution there
|
||||
(`admission.rs:437-442`). Stale before this cut; Self's to correct.
|
||||
- **Cut 8's map text at A10** ("a subject resolves at most once because its
|
||||
resolution key is outcome-invariant", `:2344`) and the stewardship row
|
||||
("the key collides, A10", `:2362`) both describe the shape this cut retires.
|
||||
Self's, at the follow-up's landing.
|
||||
- **Cut 9's `open_items_and_rulings_in_force_follow_resolutions`** needs the
|
||||
recursive derivation and a reopened-subject fixture, or it will pin the
|
||||
non-recursive defect as correct. Cut 9's spec should say so before Hands
|
||||
reads it.
|
||||
- **Same-day granularity survives only in the hand-off key** (`:721`,
|
||||
`<from>:hand_off:<to>.<repo>.<handed_on>`): two hand-offs in one direction
|
||||
for one repo on one day share a key. The stewardship half of this limit is
|
||||
retired by Q20 A. If the Odin-swarm workflow ever transfers a repo twice
|
||||
in a day in one direction, the hand-off key wants the same treatment; not
|
||||
asked, not this cut's, recorded.
|
||||
- **`Date` derives `Ord` on its string** (`:212`), correct for `YYYY-MM-DD`
|
||||
only because `Bounded::validate` enforces the shape. Nothing orders dates
|
||||
after Q20; the sequence orders.
|
||||
|
||||
### Pinned HEADs
|
||||
|
||||
- Epiphany `codex/eureka-pipeline-state` at `542dc184` (map only since
|
||||
`87d3420c`: `993600fd`, `76167f0a`, `542dc184`); `epiphany-pipeline/src/lib.rs`,
|
||||
`schemas/cultnet/` and `tools/` byte-identical to `b4b17fc`. Tree clean.
|
||||
- Huginn `eureka/memory-organ` at `30daff8`, tree clean. The fix batch
|
||||
landed as `acd32f3` (matrix row `resolution → Withdrawn` restored, nested
|
||||
assertions flipped) and `30daff8` (nineteen rules pinned, entries
|
||||
H21-H39). Follow-up anchors above are against `30daff8`. Pin in
|
||||
`crates/huginn-mind/Cargo.toml:15` is still `a65c6420`.
|
||||
- CultLib untouched and unread this pass (Soul is in that tree).
|
||||
- Probe artifacts: a detached worktree `scratchpad/cut6d-wt` at `b4b17fc` ran
|
||||
`cargo test -p epiphany-pipeline --lib` once (28 passed) under the shared
|
||||
target dir and was removed; Huginn's sources at `1cfa81d` were copied to
|
||||
`scratchpad/huginn-*-1cfa81d.rs` by `git show` and read there while the
|
||||
batch was in flight, then the landed `30daff8` was grepped for every site
|
||||
the follow-up anchors.
|
||||
|
||||
## Cut 7. Retire Huginn's TypeScript body
|
||||
|
||||
- **Repo/branch:** Huginn `main` at `91b7fcf`, on a new branch
|
||||
|
|
|
|||
Reference in a new issue