assertcheck-feature
Build a new TypeScript feature with the guard block first — every invalid state declared before a single line of logic is written.
"An elegant program's quality is not that it does what it's supposed to; it's that it does almost nothing else." — Fabian Giesen, Negative space in programming
When to use it
- "I'm creating a new function that…"
- "New service / class / module for…"
- "How do I write this feature with NSP?"
- You have a function signature but no body yet
How it works
The skill enforces a 3-phase sequence. It will not produce any code until the interview is complete.
Phase 1 — Contract table (negative space map)
After a short interview, the skill fills a contract table — one row per boundary:
| Boundary | Invalid state | Assert with |
|:------------------|:-------------------------------|:--------------------------------|
| param orderId | null, empty string | assert.string + assert.notEmpty |
| prior state | order not in pending status | assert.equal(order.status, …) |
| external response | missing transactionId | assert.notNil(res.id, {…}) |
| output total | zero or negative | assert.greater(total, 0) |Every row must have a non-empty "Assert with" column before any code is written.
Phase 2 — Guard block first
Every function is scaffolded with guards before logic — no exceptions:
import { assert, check } from "assertcheck"
function featureName(param1: Type, param2: Type): ReturnType {
// ── guards — declare what must never enter ───────────────────
// one assertion per contract table row
// ── logic — runs with proven invariants ──────────────────────
// no ?., no ??, no if (!x) return
}Phase 3 — Logic block
The logic block runs with proven invariants. No defensive checks needed — the boundary is already clean.
Before and after
❌ Before — TypeScript types + optional chaining + silent return:
function filterProductsByCategory(
products?: Product[] | null,
category?: ProductCategories
) {
return products?.filter(product => product?.category === category)
// products is null → returns undefined silently. Caller has no idea.
}✅ After — guard block declares the negative space:
import { assert, check } from "assertcheck"
function filterProductsByCategory(
products: Product[],
category: ProductCategories
): Product[] {
// ── guards ────────────────────────────────────────────────────
check(products)
.notEmpty({
msg: "products must be a non-empty array",
note: "check that the upstream service returned results before calling this",
})
.allInstanceOf(Object, "all products must be valid objects")
assert.string(category, "category must be a string")
// ── logic ─────────────────────────────────────────────────────
return products.filter(p => p.category === category)
}
// null products → immediate, traceable failure at the right place.
// Before: null propagated silently, surfaced as a confusing downstream error.✅ Service method with state guard:
function createOrder(customerId: string, items: CartItem[]): Order {
// ── guards ────────────────────────────────────────────────────
assert.string(customerId, "customerId must be a non-empty string")
assert.notEmpty(customerId, "customerId must not be empty")
check(items)
.notEmpty("cart must have at least one item before creating an order")
.all(i => i.quantity > 0, {
msg: "all items must have a positive quantity",
note: "remove items with quantity ≤ 0 before calling createOrder()",
})
// ── logic ─────────────────────────────────────────────────────
const total = items.reduce((sum, i) => sum + i.price * i.quantity, 0)
return { id: crypto.randomUUID(), customerId, items, total, status: "pending" }
}What the skill delivers
- Contract table — boundary → invalid state → assertion (one row per invariant)
- Guarded implementation — guard block before logic, fully typed
- Rejected states summary — one sentence per assertion explaining what invalid state it refuses