Three plans, worked end to end, in three different domains. Each is a real catalog: the version files are named by the hash of their own bytes, and each revision imports its parent by that name — so the lineage is genuine, not illustrative.
Compass evaluates these: they are the acceptance suite (tests/examples.rs).
Each version file is read by evaluating it in the embedded engine, and reading
reproduces its content-hash filename. They also show what authoring a plan looks
like. The authoring surface is specified in
context/06-api/.
| Example | Domain | What it shows |
|---|---|---|
| hypothesis-dies | engineering | a plan that turns out wrong, and why that is the point |
| editorial-review | writing / research | the model is not about code; a human sign-off is a criterion |
| two-machines | any | two agents revise at once; divergence, then reconciliation |
A plan is a TypeScript module. A step is a named declaration, so its name is its identity. A dependency is a reference to another step's binding — never a string — so a dependency that does not resolve is a name that does not exist, caught where it is written.
export const measure = step({ work: "...", accept: evidence.measurement({ of: "build-phases" }) })
export const fix = step({ work: "...", dependsOn: [measure], accept: /* ... */ })
export default plan({ author: "cos", goal: "...", why: "...", steps: [measure, fix] })A revision imports its parent and is a function of it. It can edit, add, and retire — it has no way to remove a step, because every step is carried forward by the revision itself. A step that is no longer wanted is retired, and stays in the record marked as such.
import prior from "./001-<hash>.ts"
export default prior.revise({ author: "cos", why: "...", retire: [prior.steps.fixCache], add: [ /* ... */ ] })The words inside accept(...) — test, measurement, review, waiver, and
their attributes — are not Compass's. A use case declares its own vocabulary as
typed constructors, so a mistyped attribute is a compile error while authoring,
and Compass stays neutral about what any of it means.
Every filename is the first 12 hex of the SHA-256 of the file's bytes:
for f in $(find . -name '*.ts'); do
want=$(basename "$f" | sed 's/^[0-9]*-//;s/.ts//')
got=$(sha256sum "$f" | cut -c1-12)
[ "$want" = "$got" ] && echo "ok $f" || echo "BAD $f"
done