39ac61c4116cfa721d452178119d36680aff7e3e
7
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
cba0fe4337 |
docs(tdd): fix ten defects the GREEN run found in the language references
The pressure test that #18 and #20 were waiting on. All six original gaps came back ANSWERED with the lines quoted — and the run then found ten problems in what I had written. The worst two are mine, not inherited. **The Python exemplar was the evaluation task.** references/python.md demonstrated `split_vat` — the exact function the test scenario asks for, negative-amount case included. The run said so: "as a teaching example that's over-fitted; as an evaluation it's a leak... this task can't answer it — the reference handed over the finished artifact." So the run could not measure whether the guidance transfers, only whether copying works. The exemplar is now `parse_retry_after`, deliberately unrelated to anything in this estate, and it states its own contract rather than requiring the reader to divide 12500 by 1.25 to discover it. **mypy at RED pointed at the stub the same file forbids.** python.md taught that a pytest ImportError is a legitimate red, then presented `mypy --strict` as a matched pair without saying that mypy reports the same missing module — so following both literally, the way to get mypy green at RED is to create the module. Now stated: that error is the expected red; what must be fixed immediately is a --strict violation inside the test file you just wrote. The rest, each quoted in the run: - The checklist contradicted itself two lines apart — "strike it deliberately" above, "Can't check all boxes? You skipped TDD" below. A struck box is by definition unchecked, so the Python path routed straight into "start over". - `match=` was overclaimed as "free". It is `re.search`, so a message containing parens quietly matches almost anything; and it couples every error test to wording. The Go comparison was a strawman against `assert.Error` when `assert.ErrorIs` exists — the honest Python analogue is a custom exception type, with `match=` as the fallback. - `pytest.approx` was listed as the soft-assert analogue. It solves float tolerance and has nothing to do with collecting failures; that is pytest-subtests or pytest-check, neither of which ships with pytest. - The whole-shape assertion silently required value equality — on a plain class it compares identity and can never pass. - "When Stuck" is a language-neutral table that prescribed `t.Helper()`. - `__tracebackhide__` must be a local inside the helper body; at module level it does nothing, silently. Refs #18, #20 Bump-Type: patch |
||
|
|
1d368d4b5d |
docs(skills): drop the Mode 2 routing notes, fix the contributing steps
Seven skills carried a `## Mode 2 Routing Note` citing a routing pod ("Plan 6")
that does not exist. Several admitted in their own text that nothing about the
skill changes between modes — so it was roughly ten lines of context on every
load for zero behavioural effect. The content is not worthless, just not
per-skill: it now lives as one table in README.md, with the caveat that nothing
depends on it.
The related line inside the session_log sections stays, because that one does
motivate behaviour — but it no longer cites a component that has never shipped.
It now says what is true: pass-rate is what a future routing decision would be
based on, and a skill that never logs contributes no evidence either way.
While in README: the contributing steps were stale enough to fail CI for anyone
who followed them. They said to add a row to SKILLS_INDEX.md by hand — the table
is generated now, and `task check` fails on a hand-edited diff — and listed none
of the four frontmatter keys the gates require. Step 4 now names the
pressure-test bar from #19 rather than leaving it to be discovered.
Closes #36
Bump-Type: patch
|
||
|
|
b616c51a2c |
fix(skills): document a session_log call the tool would actually accept
Nine skills documented the payload. None named `session_id`, which is the tool's only required field. So every documented call was one the tool rejects — an agent following any of them either failed the call or invented an id, and invented ids do not group, which means the pass-rate the /pass-rate endpoint computes was being assembled from entries that cannot be joined. Found by the #19 pressure test against `debug`, which invented `debug-signed-artifact-missing-2026-08-29` and said so: "my three entries are only groupable by luck of naming". The grep afterwards showed it was fleet-wide, not a `debug` bug. Also removed: `duration_ms: <wall-clock>` in eight of them. An agent does not observe a clock. The same run omitted it "rather than fabricate", which is the good outcome; the bad outcome is the run that fabricates, and a made-up number in a metrics stream is worse than a missing one. It is an optional field and is now simply absent. bin/check-session-log gates both, with tests. This is exactly the case #19 has in mind for a small tool over prose: the rule is a grep, so it should be a gate, not a note asking people to remember. Closes part of #36 Bump-Type: patch |
||
|
|
8da7c9c45f |
docs(tdd): make the spine language-neutral, add four language references
The discipline in tdd was already language-agnostic; the checklist under it was not. A Python user inherited a mandatory `go test -race` box they can never tick and never got told that `mypy --strict` belongs in the red gate. Per #18's own comment and writing-skills' Multi-Language Dilution warning, the main SKILL.md keeps ONE canonical inline example (Go, the default stack) and the other four languages live in reference files: python, typescript, rust, java. The RED run drove every change. A subagent given a Python task with the Go-only skill reported, in its own words: - "Everything from L169 to L244 is Go-only, and the verification checklist at L326 silently inherits that Go-ness — which is why a Python user ends up with a mandatory box (-race) they can never tick and a required gate (mypy --strict) that isn't listed at all." - "For a brand-new function, the first RED is always a collection-time ImportError... The only clean resolutions are a stub that raises NotImplementedError (production code before a red test?) or accepting ImportError as a legitimate red. The skill picks neither, and this is the single biggest gap." It now picks: that red is legitimate, and writing a stub to satisfy the runner is the Iron Law with extra steps. - The Go table-driven exemplar branches on a `wantErr` column inside the loop. Translated literally that is a conditional assertion folding two behaviours into one test — which this skill's own quality table forbids. The agent caught itself mid-translation; both SKILL.md and python.md now say not to port it. Also: the checklist names the static-analysis gate per language instead of assuming `go vet`, and says to strike the concurrency box deliberately where no equivalent exists — a box that cannot be ticked teaches people to skip checklists. Refs #18 Bump-Type: minor |
||
|
|
c6787e04d7 |
feat(index): generate the skills table from frontmatter
Second half of #29. The index was hand-maintained and had already drifted once: dream and experiment-spec shipped with no row, their rows lost to a squash-merge after a directory reorg. bin/check-index caught that after the fact; generating removes the class. The curated summary and trigger move into each SKILL.md as `summary:` and `use_when:`, carried over verbatim from the existing table rather than derived from `description:` — description is a paragraph written for model selection, and truncating it would have produced a worse table than the one it replaced. Knowledge now lives once, next to the skill it describes, which is the argument that made a hand-maintained index the wrong shape to begin with. The table is written between markers, so the wiring docs, the relationships tree and the trigger table below it are untouched — those are prose, not data. Rows are alphabetical now; the conceptual grouping the old order carried lives in the relationships tree, which is the better place for it. A fourth column shows each skill's surfaces, which is what makes #29's field visible rather than merely enforced. bin/check-index and its test are deleted: a generated table cannot drift in either direction, so `generate-index --check` subsumes both of its assertions. Verified by mutation — deleting the tdd row turns `task check` red with "SKILLS_INDEX.md is out of date". Closes #29 Bump-Type: minor |
||
|
|
90a58f0b9e |
feat(skills): declare which surfaces each skill ships to
The repo distributes three ways — the Claude Code plugin, the symlinked library for Crush/Pi/OpenCode, and claude.ai, which has no fetch path at all — and treated every skill as belonging to all of them. claude.ai is not a fourth host to mirror: gitea-ci, playwright and web-shot have no shell and no cluster there, so a flat mirror installs skills that can never fire and degrades selection for the ones that can. Every SKILL.md now carries `surfaces:`, defaulting to [claude-code, library]; dream, own-the-task and grill-me add `chat`, matching what is actually installed on claude.ai today. Claude Code accepts the extra key — `claude plugin validate` passes and the skills still load. bin/check-surfaces validates values, not just presence, because the failure mode here is silent: a wrong surface removes a skill from a harness rather than erroring. install.sh links only skills whose surfaces include `library`, and a source that declares nothing at all is treated as foreign and linked as-is — Anthropic's official set has no reason to know this convention. doctor's missing-link check skips non-library skills for the same reason. Refs #29 Bump-Type: minor |
||
|
|
56a947b2a0 |
refactor(plugin)!: ship as a Claude Code plugin, one dir link per harness
Skills move to skills/<name>/SKILL.md and the repo gains both manifests, so it is now a marketplace hosting exactly one plugin whose root is the repo root (source: "."). Claude Code installs it from git; no symlinks involved. Why: install.sh wired the library into every consuming repo as an ABSOLUTE symlink to $CHECKOUT_DIR. The checkout moved three times, most recently when local-dev@1966d5a dropped the embedded .skills/ copy, and nothing migrated the links — 243 dangling links across 12 repos, hidden from git by the **/.claude/skills/ ignore rule. Worse, ~/dev spans two path roots (/Users/mathias on the iCloud-shared Macs, /home/mathias on koala), so an absolute link stored there is broken on one side by construction. Re-running the installer cannot fix that; only removing the mechanism can. install.sh keeps the harnesses with no plugin system and drops from 42 links per harness to one directory link, via the convergent ~/.agents/skills convention that Pi and OpenCode both read: ~/.agents/skills -> $CHECKOUT_DIR/skills ~/.config/crush/skills -> ~/.agents/skills ~/.config/opencode/skills -> ~/.agents/skills wire_claude_repo is deleted outright rather than gated behind a flag — on a mixed-root fleet it cannot be made correct. Antigravity and Vibe targets go too; both unused. CHECKOUT_DIR keeps its host-local default deliberately: pointing it into ~/dev would put a git working tree inside iCloud with two concurrent writers. Taskfile drops five near-identical wiring loops (they had already drifted) and delegates to install.sh. `task check` gains frontmatter validation, a stray-root-entry gate, and manifest/tag version parity — the loose secret-hygiene.md sat unloadable for months because nothing checked layout. Verified: claude plugin validate . passes clean; a probe skill loaded as skills:zzprobe through --plugin-dir; task check green at 42 skills. Refs: #23 Bump-Type: minor Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BeAp5LTscnz2W7Ubt4eJ6m |