Fold the Ghostlight L0 lessons into the briefs and the fork rule

The Soul template now attacks constructibility at sealed boundaries (a
derive is a public constructor, and on stable rustc a compile_fail test does
not pin its error code). It also asks for forgeries shaped like real values
and treats text scanners as tripwires with stated limits.

The Hands template now says to wait for long jobs instead of reporting a
to-do list, to restore mutations without git checkout, to measure warnings
from forced rebuilds, and to prefer semantic tools for semantic properties.

The fork rule now weighs proportion: a fork guarding only against the
project's own code gets a default and a recorded follow-up.

Evidence: Ghostlight's library extraction postmortem, recorded in the
changelog.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-09-16 12:26:08 +02:00
commit 82074a7ab5
3 changed files with 52 additions and 1 deletions

View file

@ -142,7 +142,10 @@ in the session.
Distinguish a real fork from a default. "Should I use the conventional thing" is
not a question. "3-5 are not decisions," as the operator put it, is the failure
of asking about non-decisions.
of asking about non-decisions. Weigh proportion too: a fork that guards only
against the project's own code, such as how strictly to enforce an internal
tripwire, gets a default and a recorded follow-up. Asked how much one such
question mattered, the operator said not at all.
### 3. Hands executes one cut

View file

@ -90,6 +90,15 @@ it reported was fiction.
When a cut deletes, list every rule that had a test before and has none after.
A rule that still exists in code with its only test deleted is the failure mode
of subtraction; either the rule goes too, or it gets a test in the same cut.
Long jobs: wait for them and finish. Never end the turn with a to-do list in
place of a report.
Mutations: restore with a reverse edit or run against committed code; `git
checkout` also reverts uncommitted fix code and silently invalidates the run.
Warnings: measure from a forced rebuild and compare distinct messages; cargo
replays warnings only when it actually rebuilds.
Semantic properties ("exactly one call site", "this step actually runs"):
prefer a semantic tool (a Clippy lint, the type system) over a text scanner,
or state the scanner's limits in the test itself.
Commits:
- Small and pushed.
@ -147,6 +156,17 @@ Falsify specifically:
including ones that are not plain reverts>
- <the layer where the invariant really fails: wire bytes, another runtime's
decoder, the editor, the compiler, a legacy file decoded independently>
- <for a sealed or private boundary: attack constructibility from an external
scratch crate or consumer, not path privacy. Try every public constructor the
language gives away: Deserialize and other derives, Default/From impls,
public fields, functions returning mutable references. A compile_fail test
pins a name; on stable rustc it does not even pin the error code>
- <for rejection tests: forgeries must be shaped like real values (same length,
prefix, case and alphabet), or a weakened comparison passes them all>
- <for any text scanner, grep assertion or line pin: try evasions (aliases,
function values, formatting, control flow around the pinned text such as
`if false` or `true ||`). A scanner is a tripwire with stated limits, not
proof of a semantic property>
- <leftover greps>
- rerun the builds, tests and captures yourself

View file

@ -2,6 +2,34 @@
Record each change to the skill together with the evidence that motivated it.
## 2026-09-16: sealing, forgeries, scanners and proportion, from Ghostlight L0
Evidence: Ghostlight `docs/architecture/ghostlight-library-extraction-postmortem.md`
and its cut map.
- **Soul attacks constructibility, not names.** Ruling Q1-4 said sealed
constructors must be unreachable. Ten compile_fail doc-tests passed while
every public ID type derived `Deserialize`, so an external crate built any of
them from JSON; an ID-minting `Default` impl left all ten green. It was found
only because Self added the serde route to the Soul brief by hand. On stable
rustc the compile_fail error codes are not enforced either.
- **Rejection tests need realistic forgeries.** Short fake digests passed
against kernels comparing only length, a prefix, all but the last character,
case-insensitively, or only the hex after the label. Five mutants survived
across two Soul passes.
- **Text scanners are tripwires.** Every one written in the campaign lost to a
short evasion: a single-minter count to an alias, a subdirectory, a type
alias and a function value; a deploy wiring test to a two-line deletion that
reattached the pinned line to the wrong container, and its fix to `if false`
around exact lines. Prefer a semantic tool, or state the limits.
- **Default proportionate forks.** Asked how much the single-minter enforcement
question mattered, the operator said not at all. A fork that guards only
against the project's own code is a default plus a recorded follow-up.
- **Hands brief additions:** wait for long jobs instead of reporting a to-do
list (one Hands agent did); restore mutations without `git checkout` (one
run was invalidated that way); measure warnings from forced rebuilds (a
cached build reported zero).
## 2026-09-16: subtraction rules, from the Eureka campaign's own cuts
- **A deletion can take a live rule's only test with it.** Cut 4 deleted a store