platypeeps

sd-typed-holes

Use when starting a Rust feature, module, or rewrite skeleton-first — design the types and signatures, land a compiling skeleton whose bodies are todo!() as its own commit, then fill the holes in a separate later pass; never mix the two.

platypeeps 0 Updated 2w ago
GitHub

Install

npx skillscat add platypeeps/sd-ai-command-pack/sd-typed-holes

Install via the SkillsCat registry.

SKILL.md

sd-typed-holes

Split Rust work into two passes that never mix. First lay the complete type
surface — real signatures, real types, todo!() bodies — and prove it
composes under check and lint before any behavior exists. Then fill the
holes one at a time against that fixed surface. The compiler reviews the
design in the first pass; the second pass cannot silently change it.

When to use

Use when starting a Rust feature, module, or rewrite where the type surface
deserves review before behavior exists, when splitting Rust work into
independently deliverable units, or when delegating implementation to
executors that must not redesign the surface they fill.

Do not use for one-line fixes or edits inside an existing surface, and do
not use it to model the types themselves — sd-rust-design owns the
modeling rules the skeleton must satisfy.

Arguments

None.

This skill takes no key=value arguments.
Unknown argument names are an error — stop and report them before starting.

Workflow

  1. Design the type surface with sd-rust-design: states as enums,
    transitions as consuming methods, constrained constructors returning
    Result with their error enums fully written. Record, per public
    type, the one business rule it enforces and the illegal state it
    forbids.
  2. Lay the skeleton — the full surface and nothing else:
    • real signatures, derives, conversion impls, and leaf types; no
      placeholder String standing in for a type not yet written;
    • todo!() only in bodies with real behavior — parsing, rendering,
      assembly, anything with a decision in it;
    • trivial accessors implemented, not held open: a field read left as
      todo!() hides surface from the compiler instead of exposing it.
  3. Mark the holes so they ask to be removed:
    • each todo!() function with parameters carries
      #[expect(unused_variables, reason = "hole; filled by <unit>")] —
      once the lint stops firing the marker warns; leave a hole unmarked
      wherever the lint could not fire in the first place and the
      expectation would go unfulfilled the moment it was written — a
      zero-parameter hole, a receiver-only one (unused_variables never
      fires on self), and one whose parameters are all
      underscore-prefixed, which is the same suppression by another name;
    • the module enters with #![allow(dead_code)], removed slice by
      slice as the surface goes live;
    • both markers get explicit removal steps in the fill plan — a filled
      body that still ignores a parameter keeps its marker silent, so
      each fill sweeps by hand.
  4. Gate the skeleton alone: workspace check and clippy with warnings
    denied, plus a format check, all green with every behavioral body
    still todo!() — the trivial accessors step 2 asks you to implement
    stay implemented. Then propose the skeleton as its own commit, so the
    reviewed design is a retrievable git object rather than a
    conversation, and let the user make it. Committing is theirs to
    authorize; this workflow reaching step 4 is not that authorization.
  5. Track the holes deterministically — todo!() is a diverging panic the
    compiler happily accepts, so nothing tracks it for you. Prefer the
    clippy lint for todo!(): warn during the fill phase, deny as the
    completion gate. A grep -rn 'todo!(' baseline is the fallback, and
    it is a lower bound rather than a census — it misses a hole written
    todo! () or produced by a macro, and counts occurrences in comments
    and string literals. Take the baseline at the skeleton commit, account
    for every changed line per fill, and let the lint, never the grep,
    decide that the holes are closed.
  6. Review the skeleton before any body lands: apply the
    sd-rust-review probe lens to the skeleton diff and route the change
    through the sd-review lane, which owns the verdict. Design repairs
    land as skeleton amendments, before filling starts.
  7. Fill the holes in a later pass, one body at a time: run the check
    after each fill to narrow the next hole's types, sweep the filled
    function's marker, account for its inventory lines, and hold each
    body to sd-rust-quality. A fill that needs a signature, derive, or
    type change has found a skeleton defect — stop, amend the skeleton as
    its own reviewed change, then resume filling. Never let a fill mutate
    the surface in passing.
  8. Close out: remove the remaining dead-code allowance, flip the hole
    lint to deny or show the grep returning nothing, and confirm the
    surface carries no marker whose reason is stale.

Safety rules

  • Never mix the passes: a change that both alters the type surface and
    implements behavior defeats the point and must be split before it
    lands.
  • Never let a fill silently change a signature, derive, visibility, or
    error variant; surface changes are skeleton amendments with their own
    review.
  • Do not over-claim what the green skeleton proves: it shows the design
    composes, not that behavior is correct — derives and runtime semantics
    still need inspection and tests.
  • Keep the hole inventory honest: no fill unit closes while a hole it
    owns survives, and no marker outlives the truth of its reason.
  • Review verdicts on either pass belong to the sd-review lane; this
    workflow schedules reviews, it does not decide them.

Final report

  • Surface summary — the public types with their business rules and
    forbidden states, per the design record;
  • Skeleton commit — the commit that carries the surface and its
    green check, lint, and format evidence;
  • Hole inventory — holes opened, holes filled, holes remaining, and
    the tracking mechanism (lint level or grep baseline);
  • Marker status — expect-markers and dead-code allowances still
    standing and the units that will remove them;
  • Fill progress — bodies filled this pass and the per-fill check
    results; and
  • Handoffs — reviews routed to the sd-review lane.

Lineage

Re-authored from the typed-holes skill in
github.com/Shearerbeard/claude-skills (plugins/rust/skills/typed-holes/,
revision c79fe3a). That repository ships no licence file — LICENSE,
LICENSE.md, LICENSE.txt and COPYING are all absent as of that revision —
so its terms are unstated rather than permissive. Nothing here is copied
verbatim: the ideas were rewritten in this pack's conventions, which is what
the absence of stated terms permits and is why this section says so plainly
instead of naming a licence it cannot cite.

It reached this pack by two hops. It was written as se-typed-holes in
platypeeps/se-ai-command-pack commit 9de85c3 (2026-08-27), one of the
thirteen se-* skills of that pack's Engineer family, and folded here as
sd-typed-holes in 56ba92eb (2026-08-31, #640) alongside sixty-three
siblings.

What was left upstream, and why it matters here. Upstream is a two-layer
practice. Layer 1 is the type-checked skeleton this skill kept. Layer 2 —
whole-frame golden tests written from the spec so that they fail on arrival —
was not carried over. Layer 2 is test-first under another name, so dropping it
is worth knowing: what reads as a skill opposing test-first is a skill missing
the half that supplied it, not a practice that rejected it.

How this skill relates to sd-tdd is not settled here. The obvious answer —
that the type surface and the todo!() bodies are exempt from test-first while
the bodies that get filled are not — does not survive contact with step 2,
which also lands derives, From/Into impls, and trivial accessors
implemented rather than held open. Each of those has a real body and real
runtime semantics, and a getter returning the wrong same-typed field compiles
and passes clippy. This skill's safety rules already say a green skeleton shows
the design composes and not that behavior is correct. Writing the boundary
precisely enough to be followed was tried and failed review three times, so it
is named as an open question rather than stated wrongly a fourth.

Four of the rules above look arbitrary and are each a corrected error, from the
review rounds that followed the original: 419f9131, 10b32167, 78f3dc2b
and 037d6137. They fixed a skeleton gate that demanded every body still be a
hole while also demanding trivial accessors be implemented; two cases where
#[expect(unused_variables)] is unfulfillable the moment it is written,
because the lint fires on neither a receiver nor an underscore-prefixed
parameter; and the standing of grep -rn 'todo!(', which is a lower bound
rather than a census and sits behind the clippy lint for that reason.