Skip to content

skill: make the spool the way lessons are added, and guard it - #3323

Closed
gHashTag wants to merge 4 commits into
masterfrom
w118b-spool-is-the-way
Closed

skill: make the spool the way lessons are added, and guard it#3323
gHashTag wants to merge 4 commits into
masterfrom
w118b-spool-is-the-way

Conversation

@gHashTag

@gHashTag gHashTag commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Refs #3236

Pass 117 shipped tri skill add / tri skill fold so two branches cannot choose
the same section number. It shipped as a tool and a habit. A habit is what failed
here in the first place: the next pass reads what is convenient and reaches for
cat >> SKILL.md.

The rule now lives at the top of SKILL.md, where a pass looking for how to add
a lesson reads it before reaching for the shell.

And it is checked. The collision is invisible on a branch — tri skill check
passes on both sides and fails only on the merge result — but the practice that
causes it is not. tri skill fold deletes one spool file for every section it
appends; a direct append deletes nothing. tri skill spooled --gate compares
section TITLES on base against titles now and allows as many new ones as there
are spool files this branch deleted.

  • By title, not numbertri skill renumber rewrites every number and keeps
    every title, so a number comparison would report the whole file as new and fire
    hardest on the command whose job is avoiding collisions.
  • By parsed section, not diff line — a +## N. line cannot be told from a
    heading quoted inside a fence. 3 of the 518 such lines on master are
    quotations, and miscounting one has already destroyed a real section here.

A branch that runs add and fold together still picks its number against
its own base, so it collides exactly like a direct append — and it fails this
guard, because the spool file it deleted was never on base. The flow left open is
add on the branch, fold after the merge.

Two things found while building it

  • The gate could not have run in CI. The checkout is shallow, so
    origin/master does not resolve; every file would read absent-on-base, the
    population would empty, and a gate that never ran would print a pass. The step
    fetches the ref, and the command now exits 2 (COULD NOT RUN) rather than 0.
  • skill_files() read 3 of 5 tracked skill files. Two are spelled
    skill.md; on a case-insensitive filesystem the old code found them under a
    name git does not have. Both carry zero numbered headings, so the missing
    population is empty and no past check was wrong — the next numbered heading
    added to one of them would have been.

Verification

6 unit tests. Three mutants of the decision line killed (5, 3 and 3 failing
tests). Five controls:

control expected got
branch adds no section 0 0
## 999. appended by hand 1 1
spool file on base, folded now 0 0
same two commits, base before the spool file 1 1
--base origin/no-such-branch 2 2

skill check 0 · skill refs 0 · census pin --gate 0 · 795 tests, 0 failed.
Census shell run: steps 235 → 236, blessed in the same commit.

lab added 3 commits September 6, 2026 01:32
Refs #3236

Pass 117 added `tri skill add` / `fold` so two branches cannot choose the
same section number. It shipped as a tool and a habit, and a habit is what
already failed here -- the next pass reads what is convenient and reaches
for `cat >> SKILL.md`.

The collision itself is invisible on a branch: `tri skill check` passes on
both sides and fails only on the merge result. The PRACTICE that causes it
is not invisible. `tri skill fold` deletes one spool file for every section
it appends; a direct append deletes nothing. That difference is in the diff.

`tri skill spooled --gate` compares the section TITLES on base against the
titles now, and allows as many new ones as there are spool files this branch
deleted. By title rather than by number, because `tri skill renumber`
rewrites every number and keeps every title -- a number comparison would
report the whole file as new and fire hardest on the command whose job is
avoiding collisions. By parsed section rather than by diff line, because a
`+## N. ` line cannot be told from a heading QUOTED inside a fence, and 3 of
the 518 such lines on master are quotations; miscounting one of those has
already destroyed a real section here.

A branch that runs `add` AND `fold` together still chooses its number
against its own base, so it collides exactly like a direct append -- and it
fails this guard, correctly, because the spool file it deleted was never on
base. The flow the guard leaves open is: `add` on the branch, `fold` after
the merge.

Also writes the rule at the top of SKILL.md, where a pass looking for how to
add a lesson will read it before reaching for the shell.

6 tests. Three mutants of the decision line killed (5, 3 and 3 failures).
Refs #3236

Three things, all in service of the guard actually running.

1. The gate itself, in cli-tri.yml beside `tri skill check`. That check finds
   a duplicate number; it cannot find the practice that makes one, because the
   collision is in neither branch. This asks the question a diff can answer.

2. `tri skill spooled` exits 2, not 0, when no skill file can be read on the
   base. This checkout is shallow, so `origin/master` does not resolve, every
   file reads as absent-on-base, the population empties, and a gate that never
   ran prints a pass. The step fetches the ref; the exit code is there for when
   something else stops it resolving. Control: `--base origin/no-such-branch`
   exits 2.

3. `skill_files()` reads the directory entry instead of joining "SKILL.md".
   5 skill files are tracked and 2 are spelled `skill.md`, so the old form read
   3 of 5 -- and on a case-insensitive filesystem it read the other two under a
   name git does not have, so `git show origin/master:<path>` failed and they
   looked NEW. Neither lowercase file carries a numbered heading, so the missing
   population is empty and no past check was wrong; the next numbered heading
   added to one of them would have been. `tri skill check` now reports 5 files
   and still exits 0.

Census: `shell` run: steps 235 -> 236, the one step added above. Blessed here.

Controls, all four run:
  - branch adding no section          -> exit 0
  - `## 999.` appended by hand        -> UNSPOOLED, exit 1
  - spool file on base, folded now    -> exit 0
  - the SAME two commits, base moved
    back before the spool file        -> exit 1
The last is the sharpest: identical trees, opposite verdicts, which is the
add-and-fold-in-one-branch case being refused. A branch that does both still
picks its number against its own base and collides exactly like a direct
append.
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

📓 NotebookLM Notebook linked to this PR

This notebook contains session context, decisions, and artifacts for this work.

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-09-05 18:37:59 UTC

Summary

Status Count
Total Open PRs 13
PRs with Failing Checks 10
PRs with All Checks Green 3
READY 2
FAILING 10
PENDING 0

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=ffccfa1a71cf != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

Refs #3236

The PR body described `skill_files()` reading the directory entry instead of
joining "SKILL.md". The code was written, verified, and then destroyed before it
was committed -- by a control in this same branch.

The control needed two commits to test a fold against a base. It built them with
`git add -A`, which swept in the uncommitted `skill_files` change, and cleaned up
with `git reset --hard $BASE~1`, which threw that commit away. The controls all
passed and the fix was gone. Only `git cat-file` on the pushed head found it: the
description said one thing and the tree said another.

The change itself, again: 5 skill files are tracked and 2 are spelled
`skill.md`, so joining the uppercase name reads 3 of 5 -- and on a
case-insensitive filesystem `join("SKILL.md").is_file()` is TRUE for a file
actually named `skill.md`, so the path pushed is one git has never heard of,
`git show origin/master:<path>` fails, and a tracked file reads as NEW. That is
the quiet direction to be wrong in.

Neither lowercase file carries a numbered heading, so the population that was
missing is empty and no past check gave a wrong answer. That is luck, not
design.

Controls re-run on the restored code: all 5 paths the guard names now resolve in
git (previously 2 did not), `skill check` 0, `skill refs` 0, `skill spooled
--gate` 0, 795 tests 0 failed.
@gHashTag

gHashTag commented Sep 5, 2026

Copy link
Copy Markdown
Owner Author

Correction, pushed as a fourth commit.

The body above described the skill_files() change and the branch did not carry it. The code was written and verified, then destroyed before being committed — by a control in this same branch. The control built two commits with git add -A (which swept in the uncommitted change) and cleaned up with git reset --hard $BASE~1 (which threw that commit away). Every control passed; the fix was gone.

It surfaced only from git cat-file on the pushed head — eq_ignore_ascii_case: 0 against a description that claimed it. A passing control says nothing about whether the thing it exercised is still in the tree.

Restored, controls re-run: all 5 paths the guard names now resolve in git, where previously 2 did not.

gHashTag pushed a commit that referenced this pull request Sep 5, 2026
Refs #3236

While building the guard in #3323, a control built two commits with `git add -A`
and cleaned up with `git reset --hard $BASE~1`. That swept an uncommitted fix
into the discarded commit. Every control passed, the PR body described the fix,
and the branch did not carry it -- visible only from `git cat-file` on the
pushed head.

Second instance this session of a git command chosen for safety destroying work,
after `git checkout HEAD@{1} -- <files>`. Both were cleanup steps, both exited
zero, both were invisible until the tree was read on purpose.
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

📓 NotebookLM Notebook linked to this PR

This notebook contains session context, decisions, and artifacts for this work.

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-09-05 18:58:37 UTC

Summary

Status Count
Total Open PRs 15
PRs with Failing Checks 10
PRs with All Checks Green 5
READY 3
FAILING 10
PENDING 0

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=ffccfa1a71cf != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

auto-merge was automatically disabled September 5, 2026 19:33

Pull request was closed

gHashTag added a commit that referenced this pull request Sep 5, 2026
… answers (#3334)

* fix(rust): int, uint, float and double, which every neighbour already answers (Refs #3333)

* chore(seals): re-seal the 5 specs whose Rust output changed (Refs #3323)

---------

Co-authored-by: lab <lab@example.com>
gHashTag pushed a commit that referenced this pull request Sep 6, 2026
The branch was green with auto-merge armed and BEHIND by nine commits, and
`allow_update_branch` is false, so nothing but a session could move it. The
claim mechanism it carries is the one both concurrent sessions need: this pass
alone duplicated an issue already open (#3323 against #3333) and nearly retook a
task a neighbour had finished.

Two censuses moved and are re-blessed in this same commit, as the gate demands:
`quiet` 127 -> 128 (one more path named but not quiet) and `shell`
`run: steps` 234 -> 235, both from the nine commits being merged in, not from
this branch's own work.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant