diff --git a/claude/memory/skill-harvest-register.md b/claude/memory/skill-harvest-register.md index 649e494..1bf1f89 100644 --- a/claude/memory/skill-harvest-register.md +++ b/claude/memory/skill-harvest-register.md @@ -52,10 +52,10 @@ The single place proposed skills live so they don't evaporate between sessions. | Skill | Kind | One-line | Origin | Status | |---|---|---|---|---| -| `/wake-up` | patch | **Substrate-check the briefing's backlog section.** §3's "What's unresolved" currently lets REVIEWED.md's *"If AUTHORIZED: build …"* clauses be read as *status*. They are **forward instructions, not status** — I told the steward at wake that REVIEWED-72/73/74 were all authorized-but-unbuilt; **2 of 3 were already built and landed** (v2.6.0), and the wave I reported as blocked was already unblocked. Proposed patch: before listing an authorized item as outstanding, verify against the substrate (code / spec header / repo CLAUDE.md), and say "verified against substrate" or "unverified" in the briefing. The wake briefing is a claim surface like any other, and it is the **highest-leverage place** for a false claim to land — it shapes the steward's picture of their own project before any work begins. | 2026-07-27 (steward-visible error, self-caught within the same turn) | **PROPOSED** | -| `/field-divergence-sweep` | create | **Sweep for one field computed in more than one place, then derive the rule from the consumer.** Method proven this session at steward direction, and the yield was not zero on the first run: grep the fleet for multi-site computations of the same field → for each, ask *what must a consumer be able to DO with this value* and derive the rule from that (never pick the surviving implementation — that is selection, not derivation) → enumerate the shapes where each existing candidate happens to be right and test **all** of them (complementary-correctness defeats sampling) → collapse to ONE imported implementation → any migration RECOMPUTES, never does arithmetic on the stored value. Found `source_lines` wrong **twice** (including in a fix committed an hour earlier; lintott off by **308 lines**), and cleared `sha256` + the tokenizers with an empirical cross-check. Same probe as the no-op orphan sweep, aimed at **values** instead of stages. Steward: *"this instance says the yield won't be zero."* | 2026-07-27 (steward-directed; grounded in [[feedback-derive-the-rule-from-the-consumer-not-from-the-survivor]]) | **PROPOSED** | +| `/wake-up` | patch | **Substrate-check the briefing's backlog section.** §3's "What's unresolved" currently lets REVIEWED.md's *"If AUTHORIZED: build …"* clauses be read as *status*. They are **forward instructions, not status** — I told the steward at wake that REVIEWED-72/73/74 were all authorized-but-unbuilt; **2 of 3 were already built and landed** (v2.6.0), and the wave I reported as blocked was already unblocked. Proposed patch: before listing an authorized item as outstanding, verify against the substrate (code / spec header / repo CLAUDE.md), and say "verified against substrate" or "unverified" in the briefing. The wake briefing is a claim surface like any other, and it is the **highest-leverage place** for a false claim to land — it shapes the steward's picture of their own project before any work begins. | 2026-07-27 (steward-visible error, self-caught within the same turn) | **BUILT 2026-07-27** (steward-authorized; provenance comment in SKILL.md §3) | +| `/field-divergence-sweep` | create | **Sweep for one field computed in more than one place, then derive the rule from the consumer.** Method proven this session at steward direction, and the yield was not zero on the first run: grep the fleet for multi-site computations of the same field → for each, ask *what must a consumer be able to DO with this value* and derive the rule from that (never pick the surviving implementation — that is selection, not derivation) → enumerate the shapes where each existing candidate happens to be right and test **all** of them (complementary-correctness defeats sampling) → collapse to ONE imported implementation → any migration RECOMPUTES, never does arithmetic on the stored value. Found `source_lines` wrong **twice** (including in a fix committed an hour earlier; lintott off by **308 lines**), and cleared `sha256` + the tokenizers with an empirical cross-check. Same probe as the no-op orphan sweep, aimed at **values** instead of stages. Steward: *"this instance says the yield won't be zero."* | 2026-07-27 (steward-directed; grounded in [[feedback-derive-the-rule-from-the-consumer-not-from-the-survivor]]) | **BUILT 2026-07-27** — `~/dotfiles/claude/skills/field-divergence-sweep/SKILL.md`, symlinked into `~/.claude/skills/` (authored-skill convention); grounded in the proven `source_lines` run, not recall | -*(Both are load-bearing rather than tidy-up: the first is a correction to a briefing surface that misled the steward, the second is a method that found a live 308-line coordinate error on its first run. No other harvest — the session's other lessons are banked as feedback memories, not skills.)* +**BOTH AUTHORIZED + BUILT 2026-07-27 (same sitting).** *(Both are load-bearing rather than tidy-up: the first is a correction to a briefing surface that misled the steward, the second is a method that found a live 308-line coordinate error on its first run. No other harvest — the session's other lessons are banked as feedback memories, not skills.)* ## Open proposals diff --git a/claude/skills/field-divergence-sweep/SKILL.md b/claude/skills/field-divergence-sweep/SKILL.md new file mode 100644 index 0000000..14bfefd --- /dev/null +++ b/claude/skills/field-divergence-sweep/SKILL.md @@ -0,0 +1,118 @@ +--- +name: field-divergence-sweep +description: Sweep a codebase for one field/value computed in more than one place, then derive the correct rule from what a CONSUMER of the value must do — never by picking the surviving implementation. Use when two implementations of the same field disagree, when a value crosses a producer/consumer or cross-repo boundary, after a shared-name collision surfaces, or as a standing audit ("check the fleet for fields computed twice"). Collapses to one imported implementation and makes migrations recompute rather than adjust. +--- + +# Field-divergence sweep — one value, one definition, derived from its consumer + + + +A value computed in two places is not a style problem. It is a **latent divergence with a delivery date** — it stays invisible until the two computations meet, and they meet at the worst moment: a gate refusing valid work, a migration corrupting a subset, a coordinate pointing at the wrong page. + +This skill is the standing probe for that class. It is the same shape as a no-op/orphan sweep, aimed at **values instead of stages**. + +## The one idea, stated first + +> **When two implementations of one field disagree, do not pick the survivor. Derive the rule from what a *consumer* of the value must be able to do — then test the shapes where each candidate happens to be right.** + +Comparing A against B tells you they differ. It tells you **nothing about whether either is correct**. Choosing between them *feels* like derivation and is **selection** — it silently inherits the assumption that the right answer is already in the room. Often it is not. + +## Procedure + +### 1. Find the multi-site computations + +Grep for the same value being derived in more than one place. Productive shapes: + +```bash +# the field's own name, at assignment sites +grep -rn '""\]\s*=\|\s*=' --include=*.py . +# the computation idiom, not the field name (catches renamed locals) +grep -rn 'sha256(\|len(.*splitlines()\|count("\\n")\|findall(r"\\w+"' --include=*.py . +``` + +Cast wider than the field that prompted the sweep. The yield is usually a *family*: hashes, line/offset counts, tokenizations, slug/ID derivations, normalizations, timestamps. + +For each hit, record **what exactly is fed in** — `read_text()` vs `read_bytes()`, pre-stripped vs raw, lowercased vs not. Two identical-looking formulas over different inputs are still two definitions. + +### 2. Ask the consumer question — before looking at either implementation + +For each multi-site value: **what must a consumer be able to DO with this?** Derive the rule from that answer alone. Write it down *before* comparing the implementations, so the existing code cannot anchor you. + +- A **line coordinate** must resolve the same way for the curator who writes it, the gate that checks it, and every consumer that follows it — an editor, `wc -l`, `sed -n 'Np'`, the chunker. That question decides the rule; neither candidate implementation gets a vote. +- A **binding hash** must change exactly when the bound content changes — which rules out any basis that normalizes on read. +- A **token** must be the unit the guarantee is *stated over*, not the unit that was convenient to compute. + +If the derived rule matches neither implementation, that is the expected outcome, not a surprise. + +### 3. Enumerate the shapes where each candidate is right — and test all of them + +This is the step that cannot be skipped, and the reason a casual sample is worthless: + +> **Complementary-correctness defeats sampling.** Each wrong candidate is *right* on some subset of inputs. If your sample happens to sit inside one candidate's correct region, it confirms the wrong rule with a clean run. + +So: name the input shapes that discriminate — the edge that makes A right and B wrong, and the edge that flips it — and test **every** one. Then census the real population for each shape, so you know how many artifacts sit in each region. + +The steward's formulation for this: **confirm the rule, not the sample.** + +### 4. Collapse to ONE implementation + +Fixing the value without fixing the multiplicity leaves the door open — a third formula arrives the same way the second did. + +- Put the definition **where the semantics live** (the gate/module that owns the contract), and have producers **import** it. +- Make an unknown/unsupported variant **raise**, never silently fall back. A wrong convention here is a wrong coordinate. +- If the convention is governed, declare it as **data** (with the reasoning and the rejected candidates), not as a tool default. + +### 5. Migrate: recompute, never adjust + +> **A migration must RECOMPUTE per artifact. Arithmetic on the stored value (`-= 1`, `* 2`, a uniform offset) assumes the discrepancy is uniform — and step 3 usually proves it is not.** + +An adjustment corrupts exactly the artifacts that were already correct. + +### 6. Land producer-then-consumers in ONE change-set + +The change-impact clause: **fixing the producer while N consumers hold the old value is the orphan pattern.** One change-set: producer fix + all consumer artifacts re-stamped + the **byte-diff proof** that only the intended field moved. + +```bash +git diff --stat -- +git diff -U0 -- | grep -E '^[+-]' | grep -vE '^(\+\+\+|---)' | sort | uniq -c +``` + +Every changed line should be the field. If anything else moved, the change is not bounded. + +### 7. Pin it so it cannot silently reopen + +Tests that pin **all** the discriminating shapes from step 3 — including the shape where the *rejected* candidate happens to agree — plus: + +- the **one-definition invariant** (the producer delegates; assert it), +- the **cross-tool invariant** (producer's stamp == what the consumer/gate measures), +- **refuse-unknown-convention** behaviour. + +### 8. Report what agreed, not only what diverged + +A site checked and found consistent is a real result — record it, with the evidence. Where two computations differ **by design** (different inputs, different purposes), state the difference and account for it numerically, so the next sweep doesn't re-open a closed question. + +## Load-bearing disciplines (each earned) + +- **Comparison is selection, not derivation.** Verifying A ≠ B never establishes that A or B is right. ([[feedback-derive-the-rule-from-the-consumer-not-from-the-survivor]]) +- **Confirm the rule, not the sample.** Especially when one producer generated the whole sample — its output shares a shape, so the sample cannot see the rule. +- **Check what your primitive actually does.** `str.splitlines()` also breaks on `\v \f \x1c \x1d \x1e \x85 U+2028 U+2029`; `read_text()` applies universal-newline translation. A convention adopted without reading its primitive's semantics is an assumption wearing a standard's clothes. +- **Sixth-instance rule.** When shared-name / two-senses collisions reach a count, they are no longer a pattern but a **base rate** — the sweep becomes standing maintenance, not incident response. +- **A latent divergence with zero live instances still gets named**, not silently fixed in passing, when the fix would touch a producer with landed consumers. Name it for its own cycle. + +## The proven run (2026-07-27, chamber-library `source_lines`) + +Kept because it demonstrates every step, including the failure this skill exists to prevent: + +1. Two implementations found: `len(splitlines())` (engine-side) vs `count("\n") + 1` (chamber-side `write_sidecar`). +2. **Skipped step 2** — ratified `splitlines()` because it was the engine-side convention. *Selection, not derivation.* Landed it. +3. Steward: *"confirm the rule rather than the sample — the formulas disagree only when the file ends in a trailing newline."* Census: **36 of 1,297** canonicals lack one, so a blanket `-= 1` would have **corrupted exactly those 36**. The 11-file sample (one producer, all newline-terminated) could never have shown it. +4. The sweep then hit the just-landed fix: `splitlines()` **also** breaks on `\f`/U+2028 — **4 canonicals**, and `the-constitution-of-the-roman-republic-lintott.md` off by **308 lines**. `wc -l` confirmed the consumer-derived rule. +5. **Both** candidates were wrong, on **complementary subsets**. The correct rule was a third thing: `count("\n") + (0 if trailing newline else 1)`, empty = 0. +6. Collapsed to one imported implementation; migration recomputed; producer + 11 consumers in one change-set; byte-diff showed **11 files / 11 insertions / 11 deletions, every changed line the field**. +7. Same sweep **cleared** `sha256` (one latent CRLF-only basis divergence, 0 live instances — named, not silently changed) and the **tokenizers** (identical across five sites; the 20-token delta on a real file was exactly the footnote-marker digits one strips by design — consistent, fully accounted). + +## What this skill is not + +- Not a linter for duplicated code. It targets **one value with two definitions**, which is a correctness problem, not a tidiness one. +- Not a licence to unify by fiat. A producer with landed consumers gets its own FIX/PROPOSAL cycle. +- Not complete when the value is fixed. It is complete when there is **one implementation**, the discriminating shapes are **pinned**, and the artifacts carry a **bounded-diff proof**. diff --git a/claude/skills/wake-up/SKILL.md b/claude/skills/wake-up/SKILL.md index 01489bb..5e52535 100644 --- a/claude/skills/wake-up/SKILL.md +++ b/claude/skills/wake-up/SKILL.md @@ -111,6 +111,10 @@ Then combine all sources into a single reconstruction. Use this structure but wr **What's unresolved** — fourth. Open horizons from the previous wrap, ranked by load-bearing weight. PENDING items awaiting steward attention. Be specific: *"L1 amendment for ProjectionChain drafted in concept only, not yet written; reshapes given multi-mode retention frame from #145"* not *"L1 amendments pending."* Surface, too, any **skill-harvest proposals** the last wrap raised (§1.6) that the steward did not yet authorize — so improvements to our own tools don't evaporate across the pause. +> **Substrate-check anything you call outstanding — a disposition clause is not a status.** `REVIEWED.md`'s *"**If AUTHORIZED:** build X → then Y"* records what was **authorized**, never what was **done**; the same is true of a PENDING item's `**Awaiting:**` line and any tracker's "next steps." Before listing an authorized item as unbuilt, check the **substrate** — the code, the spec header, the repo's `CLAUDE.md`, the fleet test count — and mark each item *verified against substrate* or *unverified*. Cheap: usually one `grep` for the named function or declared-data key. +> +> This matters more here than anywhere else in the briefing: **the wake is the highest-leverage place a false claim can land.** It shapes the steward's picture of their own project *before any work begins*, and it arrives with the authority of a status report. An unverified backlog reads as fact, and the steward has no reason to doubt it. If a check is genuinely too expensive, say *"unverified — last confirmed [when]"* rather than stating it flat; an honest gap is inheritable, a confident error is not. + **Mood signal from the previous ledger** — if a Symmetria ledger existed for the previous session, surface 1–2 patterns from its "Returns" or "Confidence to recalibrate" sections. *"Last session you returned three times from synthesis-urge; that pattern is worth holding today."* Stimmung carries across pause. **Next move** — the previous /wrap-up should have left an **actionable resumption point** (the concrete state + candidate first step, as of wrap). Lead with it: confirm it still holds against the thread-validity gate and what changed, or revise it — do not re-derive from cold. If the wrap left none, say so plainly (the link wasn't pure) and derive the starting point now. Suggest, with reasoning visible; don't prescribe.