ntime is planned before it is written, and the plan is in the repository.
That is unusual and it is deliberate: the specifications catch design mistakes
that would otherwise be found by writing the wrong code twice.
Where it stands: cycle 0.0.1 is done, so there is a skeleton — an empty
umbrella, one placeholder module per src/ directory, a consumer that imports
and runs, and CI. The first code that computes anything is src/core/ at
0.0.4. harness/run.py is a floor until 0.0.2 replaces it, and it has no
self-check yet, so a green run from it is an unfalsified claim rather than a
tested one.
Read, in this order:
meta/specs/SAFETY.md— the constraintsmeta/specs/TIME_MODEL.md— the type set, and why each distinction existsmeta/DECISIONS.md— why things are the way they aremeta/roadmap/ROADMAP.md, then the current cycle'sREADME.md
Every change belongs to a subcycle. The current cycle's README.md has the
checklist; a change that is not on it either goes on it or is a finding to be
recorded first.
A specification change is a decision. If your change requires the library
to behave differently from what meta/specs/ says, the specification is
amended and a numbered decision recorded in meta/DECISIONS.md, in the same
commit. A settled decision's text is never rewritten — supersede it.
Every change is green under the full harness. --only and --quick are
for iterating and never for concluding; nothing is committed on the strength of
a filtered run.
The first four are design. The last two were measured by cycle 0.0.0's probes, against the real compiler, and each one falsified something a document had asserted — which is why they are here rather than in a specification only.
-
Every public
error:this library declares becomes a mandatorypickarm in every consuming program'sfailsafe. The language enforces it and forgetting one is a compile error. The budget is three, it is a ceiling, and adding a fourth is a major version. A distinction the caller cares about rides as a field on the returned value, not as a new error. -
Only
src/host/may touch the machine. Everything else is a pure function of its arguments — no clock, no syscall, no environment. That is what makes the library reproducible and testable to the nanosecond without a double, andcheck_purityfails the build if it stops being true. -
There is no format string, and there never will be. No
strftime, nolayout_from_pattern("%Y-%m-%d"). A layout is a typed value the compiler checks. The temptation to add the convenience is obvious, which is whycheck_no_format_stringexists. -
Calendar arithmetic is not associative and not invertible, on purpose.
2026-01-31 + 1 month + 1 monthis not+ 2 months, and+ 1 month − 1 monthdoes not return to the start.SPAN_MODEL.md§3 has the worked examples. Do not "fix" it — every alternative trades one surprise for a worse one, and this one is written down. -
exit 0does not mean nothing leaked, andVec<T>is not bounds-checked. Two measurements, one lesson: the guarantee attaches to something narrower than the word suggests. D-151 watcheswildallocations only, so aVec<string>whose block is freed and whose elements are not retains its elements — 125 MiB over two million of them — and exits 0 (TM-106). And the bounds check attaches to the type: slices, arrays and simd lanes trap, a bare pointer does not, andVec<T>.itemsandBytes' body are both reached as one (TM-108). So every accessor checks its index in code,0 <= ias well asi < count— an index from a narrower signed field can be negative, andi < countaccepts it. -
npkcexiting 0 is not "this program is well-formed". It accepted a root file withmainand nofailsafeat exit 0, emitting IR whose trap paths called a@npk_failsafenothing defined; only the linker refused it (TM-112, andtests/probe/defect/missing_failsafe/is the reproduction). The compiler has since fixed that particular case, and the habit outlives it: pair every exit code with the artefact it should have produced. A status that disagrees with an artefact is the tell.
- Expectations live in the test file, as markers, and assert on codes and exit codes — never on message text.
- A negative test with no expectation is a failing test. And so is a test
with no marker at all:
harness/run.pypartitions the tree and an uncovered.npkundertests/is a finding, not a silence (TM-115). Three files sat outside that sweep for two days and were exactly the three whose expectations had gone stale. - Every sweep prints its denominator. A sweep that matched nothing and a sweep that opened nothing produce the same output otherwise, so the count of files opened is part of the result.
- A test with a PRECONDITION says so in its header and exits a code no substantive assertion in that file uses (TM-116). Otherwise an unmet precondition arrives dressed as a verdict, and a verdict is believed.
- Unexpected diagnostics fail a test as surely as missing ones.
- Where a property can be checked over its whole domain, it is — the civil round trip covers every day in the supported range, not a sample.
- Anything that reads a clock runs forty times, not once.
- A red under stress is a stop sign, never a retry.
You will find them; the library is written against a compiler that is itself under construction. Record the reproduction, stop, and raise it in the compiler repository. Do not work around it in library code: a workaround buried here outlives the bug, is never removed, and is indefensible at verification time.
Match the surrounding code. Public names carry their module's short prefix
(cal_, span_, zone_, fmt_, host_); types are PascalCase; constants
are SCREAMING_SNAKE. meta/specs/BUILD.md §7 lists the reserved words that
read like ordinary names and the substitutes this library uses instead — use
those, so the tree is consistent.
And one that is not in that table: stack. It is a memory qualifier beside
wild, it is the natural name for a parser local, and it does not fail where
you wrote it — PARSE-002 at the declaration, then "this { is never
closed" pointing at main's closing brace. It reads as a brace imbalance
dozens of lines away and gets bisected as one; a sibling library lost about an
hour to it. If a parse error claims an unclosed brace and the braces balance,
look for a local named after a qualifier before you touch the braces.