499 lines
25 KiB
Markdown
499 lines
25 KiB
Markdown
# Handoff — 2026-08-07
|
||
|
||
Written at `ada751c`, pushed to `origin/main`. Working tree clean, no stashes, no
|
||
unpushed commits on any branch.
|
||
|
||
**Scope.** Written from the **spec / Pass-13 / format-epoch** session. A second
|
||
session has been committing to this repository in parallel on the **editor /
|
||
T4** track, and its files were out of bounds for this one for most of the work.
|
||
**That boundary was lifted on 2026-08-07 for the purpose of this handoff**, so
|
||
§2 is now read from the sources rather than inferred — but it is still written
|
||
by someone who did not do that work, and it is not a substitute for that
|
||
session's own account of its reasoning. Every section is verified against the
|
||
tree or the documents; where a claim is second-hand, it says so.
|
||
|
||
---
|
||
|
||
## §0a. If you are an agent picking this up cold
|
||
|
||
Read **`CLAUDE.md` at the repo root first** — it carries the standing rules
|
||
(contract discipline, mutation-first, the git and `cargo fmt` constraints, the
|
||
green baseline, the one live constraint). This document is the *state*; that one
|
||
is the *method*.
|
||
|
||
Then: §4 for what to do, §1 or §2 for whichever track you are on, §3 only if the
|
||
environment is not already working.
|
||
|
||
**Two things that do not arrive via `git clone`** and that change how much you
|
||
know: the agent memory directory (§0.3 — it holds the accumulated track notes and
|
||
method lessons) and this session's conversation. If the memory directory was not
|
||
restored, treat `CLAUDE.md` and this file as the whole inheritance and say so
|
||
rather than guessing at intent.
|
||
|
||
---
|
||
|
||
## §0. Transfer manifest — what `git clone` does NOT carry
|
||
|
||
**The good news first, because it is most of the risk retired.** `spikes/` is
|
||
**tracked** (106 files), so the T4 spike moves with the repository. The
|
||
`editor-t4` worktree is **clean** — zero uncommitted, zero untracked, zero
|
||
unpushed. No stashes anywhere. Every commit on every local branch is already on
|
||
`origin`. **There is no unpushed work on this machine.**
|
||
|
||
What a fresh `git clone` will nevertheless *not* give you:
|
||
|
||
### 0.1 Gitignored files that exist locally
|
||
|
||
| File | Size | Status |
|
||
|---|---|---|
|
||
| `HANDOFF.md` (repo root) | 18 KB, last touched 2026-06-21 | **Not regenerable — carry it.** Deliberately gitignored as "a planning briefing, not committed" |
|
||
| `ALL_DECISIONS_AND_READMES.md` | 99 KB | Regenerable — it is a concatenation of the tracked per-crate `DECISIONS.md` and `README.md` |
|
||
| `out.svg` | 50 KB | Regenerable — `cargo run -p epiphany-render-svg --example render_fixture` |
|
||
| `target/`, `spec/*.aux` etc. | — | Build artifacts; let them rebuild |
|
||
|
||
Note the root `HANDOFF.md` is a *different, older* document from this one
|
||
(`spec/HANDOFF_2026-08-07.md`, which is tracked and will transfer normally).
|
||
|
||
### 0.2 Local git state that is not on the remote
|
||
|
||
- ~~The branch ref `editor-t4-packet2b` exists only locally.~~ **Resolved
|
||
2026-08-07** — pushed; `origin` now carries both refs. Recorded because it was
|
||
a real exposure: its commits were safe via the `f33673d` merge, but the pointer
|
||
was not, and a wiped machine would have lost the branch name the spike's rounds
|
||
are organised under.
|
||
- **The worktree is local by nature.** Recreate on the other machine with:
|
||
`git worktree add .claude/worktrees/editor-t4 editor-t4-packet2b`.
|
||
- `.claude/settings.local.json` is untracked — local permissions/settings.
|
||
|
||
### 0.3 Outside the repository entirely
|
||
|
||
- **Agent memory: `~/.claude/projects/-home-jeans-Repos-active-epiphany/memory/`**
|
||
— 21 files, 228 KB, including the track notes both threads have accumulated
|
||
(`format-epoch-track`, `editor-app-plan-track`, `editor-core-editing-track`,
|
||
`genesis-ops-track`, `pass12-g-pass`, `schema-major-1-track`, and the
|
||
method/lesson notes). This lives outside the repo and will **not** move with
|
||
it. Copy the directory to the same path on the other machine.
|
||
- **Session/conversation state for both threads cannot transfer at all.** That is
|
||
the irreducible loss in a machine move, and it is the reason this document and
|
||
the other thread's own handoff exist.
|
||
|
||
### 0.4 Environment (see §3 for detail)
|
||
|
||
Toolchains 1.95.0 + 1.85, a TeX Live with **`xelatex`** and `fontspec`, and the
|
||
GUI apt packages. None of it is in the repo.
|
||
|
||
---
|
||
|
||
## §1. This thread — spec, Pass 13, format epoch
|
||
|
||
### 1.1 What just landed
|
||
|
||
The container format major became **1**, and the header now carries a
|
||
provenance **epoch** rather than only a wire-layout discriminator.
|
||
|
||
| Commit | What |
|
||
|---|---|
|
||
| `79a2507` | P13-S27 contract (DRAFT, blocked) |
|
||
| `818a16f` | P13-S28 filed as the critical path |
|
||
| `8bb917d` | Format-epoch contract ratified |
|
||
| `973297e` | Amended pre-dispatch: pin 3c, touch rows 10/11, gate 8 |
|
||
| `bc06706` | **The rung**: container major 1 |
|
||
| `be244df` | Pin 3b's projection refusal made symmetric |
|
||
|
||
`FORMAT_MAJOR` 0 → 1, `FORMAT_MINOR` 1 → 0. `FixedHeader::decode` classifies
|
||
three ways through a named `FormatEpoch` (legacy / current / unsupported) carried
|
||
on the header, so major 0 is decoded **deliberately as legacy**, not rejected.
|
||
|
||
**Why the major carries it.** The header never changes after creation
|
||
(`req:format:fixed-header-integrity`), so the epoch is a property of the file's
|
||
creation that no later commit can confer. That immutability is exactly what
|
||
disqualified `FORMAT_MINOR` as a provenance field — a legacy bundle committing a
|
||
freshly validated base keeps its old minor forever — and exactly what makes the
|
||
major sound. Old readers already fail closed on an unknown major, so that half
|
||
needed no new mechanism.
|
||
|
||
Normative text: `core_spec.tex` §"The Container Epoch" +
|
||
`req:format:container-epoch`; `binary_format.tex` header table (0.17.0);
|
||
`text_projection.tex` `req:textproj:roundtrip` (0.14.0).
|
||
|
||
### 1.2 The live constraint — read this before touching bases
|
||
|
||
**Until P13-S27 lands, no bundle anywhere may carry a canonical base** — not in
|
||
production, not in tests, not in the conformance suite. Four rules compose to
|
||
that: `Bundle::create` already rejected a base-bearing manifest; matrix row 3
|
||
refuses committing one into major 0; row 6i refuses committing one into major 1;
|
||
rows 2 and 5i refuse *opening* one in either epoch.
|
||
|
||
Consequences you will hit immediately if you forget:
|
||
|
||
- A base-bearing `Bundle` is **unconstructible**. Fixtures must be hand-built
|
||
images — see `craft_image` / `craft_image_with_base` in
|
||
`crates/epiphany-bundle/src/bundle.rs`, which write header, manifest, and
|
||
superblock bytes directly through the public `encode()`s.
|
||
- Two refusal tests are unit tests over `Manifest`, not end-to-end, for exactly
|
||
this reason, and say so in their doc comments.
|
||
- Conformance criterion 4's canonical-base wiring is **suspended**, marked in
|
||
`crates/epiphany-testkit/src/roundtrip.rs` with a comment naming P13-S27. Its
|
||
serialize → load → decode → reserialize cycle still runs via a direct
|
||
`ChunkRef` read. **Do not "restore" it by re-homing the snapshot to
|
||
`acceleration_snapshots`** — nothing in `open` or `verify_canonical_chunks`
|
||
reads that field, so it would verify nothing while looking like coverage. Pin
|
||
3c forbids it explicitly.
|
||
|
||
Three errors exist, none of which may degrade to read-only:
|
||
`LegacyBundleHasCanonicalBase` and `LegacyBaseIntroductionRejected` (permanent,
|
||
both name **repack**), and `ReductionAuthorityUnavailable` (temporary, names
|
||
**P13-S27**, must **not** say repack — a major-1 container is already the right
|
||
epoch).
|
||
|
||
### 1.3 Text projection lost a capability, deliberately
|
||
|
||
Base-bearing documents no longer round-trip through text. All three sides refuse
|
||
— projection, parsing, and a dedicated `SerializeError::CanonicalBaseUnsupported`.
|
||
None of the three pre-existed; an earlier contract draft wrongly claimed
|
||
serialization already refused.
|
||
|
||
- `COMPANION_VERSION` → **0.14.0** (`crates/epiphany-textproj/src/lib.rs`).
|
||
- Corpus rebuilt: **20 vectors**, 10 accept / 10 reject, **ten** rejection
|
||
classes, `canonical_bases` reach **2 → 0**.
|
||
- The base spelling survives only as the `canonical_base_present` reject vector,
|
||
built through the crate-private `render_text_document`. **That function is the
|
||
one intentional hole in the refusal** and exists solely so a negative vector
|
||
can contain the spelling it asserts is refused. Keep it private.
|
||
|
||
### 1.4 Chain state
|
||
|
||
```
|
||
format-epoch rung (LANDED) → P13-S27 (UNBLOCKED, dispatchable) → P13-S16 (blocked on S27)
|
||
```
|
||
|
||
**P13-S27** — `spec/CONTRACT_P13S27_REDUCTION_AUTHORITY.md`, still DRAFT, now
|
||
dispatchable. Its pin 2a was **resolved from outside** by the format rung's pin
|
||
8, exactly as pin 2a's own prohibition required: *legacy bases are refused by
|
||
container epoch, never by version arithmetic.* The number collision it feared —
|
||
a pre-S27 base carrying `1` versus a rebuilt S16 base carrying `1` — never has to
|
||
be adjudicated, because the two can never meet: the former exists only in a
|
||
major-0 container, refused before any version is compared.
|
||
|
||
S27 **owes three inherited items**, written as required tests in its contract so
|
||
they cannot be discharged in prose:
|
||
|
||
1. Convert **both** interim refusals (open-side and commit-side) to real
|
||
capability validation. Converting one leaves the hole the format rung's own
|
||
review found.
|
||
2. **M8's deferred laundering demonstration** — with pin 3b's text refusal
|
||
removed, show that a base-bearing document whose raw version happens to match
|
||
the authority serializes into a major-1 container indistinguishable from a
|
||
validated one. Never observed, only reasoned about.
|
||
3. **Pin 3c's two suspended conformance assertions** — `verify_canonical_chunks`'s
|
||
base branch with its `base.hash != base.root.hash` cross-check, and the
|
||
reopened manifest carrying the base. Restoring them means **deleting the
|
||
suspension marker**; if the marker is still in the tree when S27 reports, the
|
||
restoration did not happen.
|
||
|
||
**P13-S16** — `spec/CONTRACT_P13S16_PROJECTION.md`, complete and ratifiable as a
|
||
plan, blocked purely on sequencing now rather than on an open question, for the
|
||
first time since it was filed.
|
||
|
||
### 1.5 Other open Pass-13 candidates
|
||
|
||
Ledger: `spec/PASS13_CANDIDATES.md`. Ten rows still read **open**: S4, S8, S9,
|
||
S16, S18, S19, S23, S24, S25, S26. Beyond those, **S27 is UNBLOCKED and
|
||
dispatchable** and **S28 is IMPLEMENTED** — both status openers were corrected in
|
||
this handoff commit, because each still began "open" while its resolution sat
|
||
further down the cell. Worth knowing the shape of that staleness: the ledger's
|
||
status cells are appended to rather than rewritten, so **the opener can lag the
|
||
truth by several rungs**. Scan the whole cell, not its first clause.
|
||
|
||
**S8 is the one needing a ruling, not an implementation.** It is a semantic fork:
|
||
two byte spellings are currently both accepted. Normalizing one on encode
|
||
violates `req:binfmt:decode-vectors`' injectivity rule, so the repair must either
|
||
**reject one spelling** or **explicitly retain both as distinct canonical
|
||
values**. Nothing else in the ledger is waiting on a decision like this.
|
||
|
||
### 1.6 Working agreements that must survive the move
|
||
|
||
These were established through this session and are not derivable from the code:
|
||
|
||
- **Contracts are ratified through adversarial review rounds before dispatch,
|
||
and frozen after.** A defect found during execution is **reported, not patched
|
||
in place** — that is how pin 3c came to exist rather than being absorbed
|
||
silently.
|
||
- **Subagent claims are verified independently before anything is committed.**
|
||
This session's agents were substantively accurate but got three things wrong:
|
||
one misattributed four test failures to "a concurrent session" (it was this
|
||
session's own spec edit), one missed a fifth failing suite entirely, and the
|
||
implementation left pin 3b's guard on the unreachable path. All three surfaced
|
||
only because the work was re-run rather than relayed.
|
||
- **Mutation-first.** Every regression is verified by re-introducing its bug and
|
||
*observing* the failure. Reasoning that a mutation would fail signs nothing. A
|
||
**compile error is not a test failure**.
|
||
- **Staging is explicit, never `git add -A`**, and the touch table is the staging
|
||
allowlist — which is why a file that must change but isn't listed silently
|
||
drops out of the commit.
|
||
|
||
### 1.7 The recurring defect, named so it can be watched for
|
||
|
||
**Searching one spelling and concluding about all sites.** Four instances in this
|
||
rung alone:
|
||
|
||
- grepped a **hex-encoded** corpus for plaintext, got 0, nearly reported it
|
||
unaffected;
|
||
- grepped `(0 13 0)`, missed a normative `version~0.13.0`;
|
||
- searched for `ReductionAlgorithmVersion(` **constructor** calls to prove no
|
||
writer existed — a *propagating* path never constructs;
|
||
- ran `grep … | head -14` and asserted a universal negative from truncated output.
|
||
|
||
Before believing a zero, ask **what this search would miss if the claim were
|
||
false**, and never pipe through `head` when the conclusion is a universal
|
||
negative.
|
||
|
||
**And its sibling:** a guard placed on the path the spec sentence *names* rather
|
||
than on every path a caller can reach. In `be244df` the named path
|
||
(`document_from_bundle`) was additionally the unreachable one, so the only
|
||
reachable entry point was unguarded — and the new corpus vector was being built
|
||
straight through the hole.
|
||
|
||
---
|
||
|
||
## §2. The other thread — the editor track and the T4 toolkit spike
|
||
|
||
**Boundary lifted 2026-08-07**; this section is now read from the sources, not
|
||
inferred. Primary documents: `spec/PLAN_EDITOR_APP.md` (1,024 lines — the plan
|
||
and Rulings A–E), `spec/CONTRACT_EDITOR_T4_SPIKE.md` (Revision 6, 16 design
|
||
pins), `spikes/editor-toolkit/DECISIONS.md` (the running findings log), and the
|
||
per-tranche `CONTRACT_EDITOR_T*` set.
|
||
|
||
### 2.1 Where the track is
|
||
|
||
The editor's *model* is built; its shell is a demo. `epiphany-editor-core` is
|
||
~6.7k lines with 93 tests behind conformance gate `[7c]`; the hit-test
|
||
provenance contract and the SVG renderer are golden-locked;
|
||
`epiphany-editor-gui` is 598 lines of self-described demo binary, disposable by
|
||
design. The discipline is that every capability lands headless in `editor-core`
|
||
first, proven at the IR boundary, before any GUI wiring.
|
||
|
||
Ladder: **T1a** (visual golden harness) landed; **T1b** (document layer) is
|
||
blocked; **T2** selection v2, **T3** note-entry caret, **T4** the rendering
|
||
tranche (open now, via the spike), **T4b** incremental materialization, **T5**
|
||
playback.
|
||
|
||
**Rulings:** A (direct vector canvas over `ResolvedLayoutIR`) granted;
|
||
C (golden harness) granted; D (new `epiphany-editor-app` crate created *at* T4)
|
||
granted conditionally; E (clipboard fragment format) granted;
|
||
**B (document/persistence) still not granted** — see 2.3.
|
||
|
||
All three Ruling-A prerequisites are discharged: W1 IR primitive ownership
|
||
(`dd33b34`), W2 the `epiphany-glyphs` seam (`24f8c80`), W3 the text-run
|
||
primitive ruling (`f639919`).
|
||
|
||
### 2.2 The T4 spike — exactly where it stands
|
||
|
||
An elimination experiment producing one deliverable,
|
||
`spec/RULING_EDITOR_TOOLKIT.md`, which **does not exist yet**. Candidates:
|
||
**C1** modern egui + lyon meshes, **C2** vello behind winit, **C3** iced.
|
||
|
||
| Round | Subject | State |
|
||
|---|---|---|
|
||
| 0 | Accessibility route + desk survey | **COMPLETE. C3 (iced) ELIMINATED.** |
|
||
| 1 | Compound-path fill correctness | **COMPLETE. C1 PASS, C2 PASS** (27 points × 2 adapters each) |
|
||
| 2 | Text (5 checks) | **APPARATUS ONLY.** Packet 2A (fixtures/emitter/differential) and 2B (candidatekit + check-5 oracle) landed; **no candidate results yet** — there is no `round2-evidence/` |
|
||
| 3 | Accessibility semantics | not started |
|
||
| 3b | Damage correctness (untimed) | not started |
|
||
| 4 | Staged latency (ranking) | not started |
|
||
| 5 | Foreclosure probes | not started |
|
||
|
||
**C3's elimination is worth reading before anything else** — it is the
|
||
methodological centre of the whole spike. It first reported PASS, and the PASS
|
||
was an artefact: `probe-iced` registered a hand-built static AT-SPI tree through
|
||
`accesskit_unix`, which takes no window handle and registers from *process*
|
||
identity. The tree was decoupled from iced's window, focus and event lifecycle,
|
||
and `view()` happened to label its button identically — so the transcript read
|
||
as though iced produced it. **Deleting iced from the probe would have produced
|
||
the identical readback.** Corrected to FAIL on coordinator review, with the
|
||
false positive preserved rather than rewritten. The same shape recurs in Round 1
|
||
(C1's first run drew nothing: `egui-wgpu` silently skips primitives whose
|
||
texture id is unregistered, so a blank target passed every background point) —
|
||
whence the standing rule: *every round must keep at least one assertion that can
|
||
only succeed if ink was actually deposited.*
|
||
|
||
### 2.3 What blocks what
|
||
|
||
- **T1b is blocked on Ruling B blocker (ii), versioned decode.** Blocker (i)
|
||
(graph-state persistence) was resolved 2026-07-24 by
|
||
`spec/RULING_GENESIS_PERSISTENCE.md` — the operation set absorbs genesis,
|
||
Pass-12 K8 reversed — which is the same genesis-ops track §1 has been
|
||
interleaved with. Blocker (ii) needs the migrate-on-read API in
|
||
`epiphany-ops`: `decode_envelope` is current-layout-only while the format
|
||
requires migrate-on-read, and the "written by the current writer" restriction
|
||
is **unenforceable** because minimal stamping means a current writer
|
||
legitimately emits major-0, -1 and -2 blocks.
|
||
- **T4b's trigger is measured, not guessed.** `benches/editor_pipeline.rs`
|
||
found reduce is the only depth-scaling stage and is superlinear (~n^1.4),
|
||
breaking the frame budget **between 3,000 and 5,000 edits** — the wall is
|
||
~4,500, and note entry mints one operation per note. Reopen is full replay,
|
||
so nothing resets that depth until T4b's checkpoint machinery exists.
|
||
|
||
### 2.4 Two machine-specific facts that a move puts at risk
|
||
|
||
**These are the reason this section matters for a hardware change, and neither
|
||
is recoverable from the documents alone.**
|
||
|
||
1. **The spike's measurement protocol requires two GPU adapter classes.** Round
|
||
1's harness refuses to report PASS unless it finds **one `DiscreteGpu` and
|
||
one `IntegratedGpu` Vulkan adapter**, and pin 4 fixes the deciding
|
||
configuration across candidates. This machine has a discrete Navi 31 and an
|
||
integrated Granite Ridge. **The integrated adapter's figures are the ones
|
||
that decide Round 4** — "a budget met on a Navi 31 says nothing about the
|
||
machine most users have." If the other box does not present both classes,
|
||
Round 1's completed results are not comparable to anything measured there,
|
||
and Round 4 cannot be run as specified. Check adapter enumeration *from the
|
||
spike's own process* before assuming continuity, and if the hardware differs,
|
||
treat it as a contract question rather than re-running quietly on whatever
|
||
enumerates.
|
||
2. **Accessibility rounds need two settings that are off by default.** On this
|
||
machine (sway + AT-SPI2), `Atspi.get_desktop(0)` enumerates **zero**
|
||
applications — even with a probe alive, rendering, and connected to the
|
||
AT-SPI bus — unless both of these have been set:
|
||
```
|
||
gsettings set org.gnome.desktop.interface toolkit-accessibility true
|
||
gdbus call --session --dest org.a11y.Bus --object-path /org/a11y/bus \
|
||
--method org.freedesktop.DBus.Properties.Set org.a11y.Status \
|
||
ScreenReaderEnabled "<true>"
|
||
```
|
||
Without them, Rounds 0 and 3 produce a `NOT RUN` that looks like a candidate
|
||
limitation and is not one. The spike's own log flags this for exactly this
|
||
situation: *any later round run in a fresh sandbox or session must redo both
|
||
steps before trusting a `NOT RUN` verdict on accessibility.*
|
||
|
||
Also environment-shaped: `a11y-verifier/verify.py` uses `gi.repository.Atspi`
|
||
(Python GObject introspection), so the other machine needs that binding, not
|
||
just the Rust toolchain.
|
||
|
||
### 2.5 Frozen-baseline discipline
|
||
|
||
Spike pin 12 runs every round inside a `git worktree` at a **pinned baseline
|
||
commit**, so path dependencies resolve to frozen sources rather than the live
|
||
tree — which has had §1's work moving through it continuously. Round 1 is
|
||
anchored to root baseline `0a35697d8e48e65d62cd96c19eec2431e414359c`, oracle
|
||
commit the same, candidate harness `c20bc93`, with `oracle.json` hashing to
|
||
`b3fc017b…`. **If the baseline moves, the affected round is re-run in full**;
|
||
partially re-run rounds are not reported. Any round resumed on the other machine
|
||
must either reuse that baseline or re-run whole.
|
||
|
||
### 2.6 Cross-thread collision surface — checked, and clean
|
||
|
||
The one place the threads could have collided is §1.2's constraint that no
|
||
bundle may carry a canonical base. **Verified: it cannot reach the editor
|
||
track.** The spike path-depends on `epiphany-layout-ir`, `-core`, `-glyphs`,
|
||
`-determinism` and `-ops` — **not** on `epiphany-bundle` — and none of
|
||
`epiphany-editor-core`, `-engrave`, `-layout-ir` or `-glyphs` depends on
|
||
`epiphany-bundle` either. `cargo metadata` resolves in the spike workspace
|
||
against the current tree. §1's format-epoch work therefore has no path into
|
||
T4's measurements.
|
||
|
||
The remaining shared surfaces are the ones already named: `.tex` requirement
|
||
counts in `testkit/tests/requirement_labels.rs`, and — when T1b eventually
|
||
opens — `epiphany-bundle`, which is exactly where §1's rungs live. **T1b and
|
||
P13-S27 both land in `bundle.rs` and must not fly together.**
|
||
|
||
## §3. Reproducing the environment on the other machine
|
||
|
||
### 3.1 Toolchains
|
||
|
||
`.github/workflows/ci.yml` pins **stable 1.95.0** for lint/GUI/conformance and
|
||
**1.85** as the MSRV floor. The MSRV job runs
|
||
`cargo test --workspace --exclude epiphany-editor-gui --all-targets` plus
|
||
`--doc`; excluding the GUI crate is what keeps `resvg`'s raster stack out of the
|
||
MSRV dependency closure.
|
||
|
||
### 3.2 LaTeX — the one non-obvious dependency
|
||
|
||
The spec builds with **`xelatex`, not `pdflatex`**. `pdflatex` fails immediately:
|
||
`fontspec` requires XeTeX or LuaTeX. Build with:
|
||
|
||
```
|
||
cd spec && latexmk -xelatex -interaction=nonstopmode <doc>.tex
|
||
```
|
||
|
||
`core_spec.tex` needed a **second pass** before newly added labels resolved;
|
||
check the log for `undefined references` rather than trusting the first exit
|
||
code. Six PDFs are tracked in git and must be rebuilt whenever their `.tex`
|
||
changes.
|
||
|
||
### 3.3 GUI build deps (Linux)
|
||
|
||
`libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libxkbcommon-dev
|
||
libssl-dev`.
|
||
|
||
### 3.4 The formatting trap
|
||
|
||
**Never run `cargo fmt --all`** while a parallel spike workspace is present — it
|
||
reaches the root crates through path dependencies and reformats across
|
||
workspaces. Use `cargo fmt -p <crate>` for writes. Note the asymmetry: CI runs
|
||
`cargo fmt --all -- --check`, and the **check** form is safe; it is the *writing*
|
||
form that crosses.
|
||
|
||
### 3.5 Green baseline to reproduce first
|
||
|
||
```
|
||
cargo test --workspace # 1570 passing, 0 failed
|
||
cargo clippy --workspace --all-targets -- -D warnings # clean
|
||
cargo fmt -p epiphany-bundle -p epiphany-textproj -p epiphany-testkit --check
|
||
```
|
||
|
||
If `cargo test --workspace` is not 1570 on arrival, reconcile that **before**
|
||
starting new work — this thread's whole method depends on a known-green baseline
|
||
to mutate against.
|
||
|
||
---
|
||
|
||
## §4. Order of operations for the move
|
||
|
||
### 4.1 Before wiping this machine
|
||
|
||
1. ~~Push `editor-t4-packet2b`~~ — **DONE 2026-08-07.** `origin` now carries
|
||
both `main` and `editor-t4-packet2b`.
|
||
2. Copy off the four local-only items: root `HANDOFF.md`,
|
||
`.claude/settings.local.json`, and the out-of-repo
|
||
`~/.claude/projects/-home-jeans-Repos-active-epiphany/memory/` directory
|
||
(§0.1, §0.3). `ALL_DECISIONS_AND_READMES.md` and `out.svg` regenerate.
|
||
3. Have the editor/T4 session add its own account of §2's *reasoning* — this
|
||
document reads its artefacts, not its intent. Specifically: whether Round 2's
|
||
checks are ready to run, and whether the hardware change in §2.4 changes the
|
||
spike's plan.
|
||
|
||
### 4.2 On arrival
|
||
|
||
4. `git clone`, then restore the memory directory to the same path, then
|
||
`git worktree add .claude/worktrees/editor-t4 editor-t4-packet2b` if that
|
||
thread is resuming there.
|
||
5. Install the environment in §3, including **`xelatex`** (`pdflatex` fails
|
||
outright on `fontspec`) and, for the spike, the `gi.repository.Atspi` Python
|
||
binding plus §2.4's two accessibility settings.
|
||
5b. **Enumerate GPU adapters from the spike's own process** (§2.4). If the new
|
||
machine does not present both a discrete and an integrated Vulkan adapter,
|
||
stop and raise it — Round 1's results were taken under that configuration and
|
||
Round 4's deciding figures are defined by it.
|
||
6. **Reproduce the green baseline in §3.5 before starting new work.** 1570
|
||
passing. This thread's whole method depends on a known-green baseline to
|
||
mutate against; if the number differs, reconcile that first.
|
||
|
||
### 4.3 Then, in priority order
|
||
|
||
**The two threads are independent right now** (§2.6) and can resume in
|
||
parallel. They collide only when T1b opens, since it and P13-S27 both land in
|
||
`bundle.rs`.
|
||
|
||
7. **Spec thread — dispatch P13-S27.** The only unblocked item on the critical path, its
|
||
contract is complete, and landing it discharges the three inherited
|
||
obligations *and* ends the no-canonical-base interval that currently
|
||
constrains every other piece of bundle work (§1.2).
|
||
8. **Editor thread — run Round 2's checks**, whose apparatus is built and
|
||
whose candidates are wired (§2.2); then Rounds 3, 3b, 4, 5 and the
|
||
`RULING_EDITOR_TOOLKIT.md` verdict.
|
||
9. Then **P13-S16**, dispatchable the moment S27 lands.
|
||
10. Take a ruling on **S8** (reject one spelling vs. keep both canonical) whenever
|
||
convenient — it needs a decision, not an implementation, and blocks nothing in
|
||
the meantime.
|