- Node.js 24.20.0
- npm with the committed lockfile
- TypeScript 6
Install the pinned runtime through asdf, then use npm ci.
The repository enforces these native gates:
npm run format:checknpm run lintnpm run typechecknpm run docs:checknpm testnpm run test:coveragenpm run test:packagenpm run check
Do not replace native commands with a Mill- or Factory-only runner. CI invokes the same definitions.
npm run docs:check inspects changed Markdown for broken local links and a
small set of empty stock phrases. It cannot establish accuracy, voice, or
approval. Use the writing guide for the human review that those
checks cannot perform.
The maintainer-only mill.yaml delegates to those same scripts in the exact
offline OCI image. Read docs/canaries/maintainer-verifier.md for its bootstrap
status, separate dependency preparation, source/dependency immutability and
scratch limits. It is not a new supported downstream stack. Cleanup retains
generated output roots so they can be mounted scratch directories; Vitest's
native config loader and cache/report locations avoid writing into dependencies.
The constrained pnpm workspace path has one exercised OCI canary. It pins Node
24, pnpm 10.23.0, lockfile version 9, a shallow packages/* workspace, direct
workspace manifests, and a verifier image whose Corepack cache already contains
that pnpm version. The canary runs a service and CLI, a local client, SQLite
scratch state, an offline read-only verifier, and a retained scenario report. It
also proves cleanup after an expected failure, deadline expiry, and
cancellation. It rejects .npmrc, pnpm hook files, lifecycle scripts,
native-build allowlists, and arbitrary workspace layouts. This is evidence for
that pinned fixture only; it does not support arbitrary pnpm repositories,
native dependencies, or customer workloads.
A command may opt in to retain a small set of verifier-generated regular files.
Declare the paths and limits in retainedArtifacts; the verifier collects them
before it removes the container, validates their type, path, count, and bytes,
then binds each digest to the candidate, command, and verifier image. The
candidate cannot choose new paths while it runs.
retainedArtifacts:
paths: [reports/scenario.json]
required: true
maxFiles: 1
maxFileBytes: 4096
maxTotalBytes: 4096Use millctl --json artifacts --run <run-id> to inspect descriptors. It returns
the declared relative path, digest, and byte count, never file bytes or the
private state-store path. A missing required report fails verification. Artifact
descriptors establish provenance; their application-specific interpretation
remains with the repository that produced them.
The optional command field executableFixtureScratch: true is permitted only
for OCI test and package commands. It provides fixed /mill-fixtures
scratch (256 MiB, exec/nosuid/nodev); set temporary fixture paths there
explicitly. Omitting the field preserves default noexec containment. It is an
authority change that requires requalification, not a workaround that a builder
may add to its own command controls. All source/dependency mounts remain
read-only and verification remains offline. The maintainer runner keeps its
writable npm cache separate and places temporary repositories outside
/workspace. The explicit fixture grant also enables Docker's init process to
reap orphaned test children without changing the default command process setup.
The frozen implementation in
src/runtime/delivery.ts uses requiredChecks
for exact pull-request-head observation and postMergeRequiredChecks for
resulting-main finalization. The optional propose.postMergeRequiredChecks
field accepts a nonempty list whose names must already occur in
propose.requiredChecks. Without it, the effective post-merge list is the
complete PR list. Both effective lists enter new proposal digests and persisted
delivery records. New records also persist postMergePolicySource as
configured when the optional field is present or implicit_default when it is
omitted; continuity checks reject later policy drift. Keep the full PR gate,
independent exact-candidate review, separately approved draft delivery, and
human readiness/merge boundaries intact.
Legacy delivery records may lack postMergeRequiredChecks. Only finalization
can bind an explicitly configured subset once, and only after GitHub proves the
recorded PR was merged onto the default branch by an allowed merger using an
allowed method, with the exact reviewed candidate tree. The task, candidate
commit/tree, repository, remote, base, actor, original PR checks, review policy,
and merger/method bindings must still match. Each selected name must have been
required before merge. The implementation persists the subset and
postMergePolicySource: legacy_migrated and legacyPostMergePolicyConfigDigest
and emits delivery.legacy_post_merge_policy_bound; subsequent readback must
match that bound configuration digest and list. It does not rewrite the original
delivery approval, relax pre-merge checks, grant another push, or permit
repeated policy rebinding. An unmerged PR returns HUMAN_MERGE_PENDING without
persisting the legacy binding.
The prepared compatibility extension also admits a historical record whose
postMergeRequiredChecks exactly equals its original requiredChecks list,
including order, but whose postMergePolicySource and prior legacy binding are
absent. It reads mill.yaml from the recorded candidateCommit, validates it
as a Mill configuration, and requires omission of
propose.postMergeRequiredChecks. An unreadable source produces
LEGACY_POST_MERGE_POLICY_SOURCE_UNAVAILABLE; invalid YAML or configuration
produces LEGACY_POST_MERGE_POLICY_SOURCE_INVALID. An explicitly configured
full list cannot be treated as an implicit default. New records carrying either
configured or implicit_default cannot enter this historical extension. The
same merge and continuity checks above must pass before the one-time local
binding is persisted; later configuration drift cannot rebind it.
checkDecision treats absent checks and incomplete results as pending. Every
matching completed result for a required name must conclude success; skipped
and failed results cannot satisfy either phase. Finalization retains merged
while checks are pending and records POST_MERGE_CHECKS_FAILED for failed
required resulting-main checks. Only passing authoritative evidence permits
post_merge_verified and closure. Tree mismatch still requires fresh exact-tree
validation; changing the check list cannot bypass it.
Frozen regressions in
test/runtime-delivery.test.ts cover
distinct lists in a new proposal and a legacy subset binding that is not
persisted before human merge. Schema checks in
test/schemas.test.ts cover the configuration
contract. These are existing oracles for lifecycle validation, not evidence that
this documentation task has run or passed them. Use the declared native
npm run check gate for authoritative validation.
Mill's maintainer-prepared mill.yaml now selects [validate, codeql] for
resulting-main checks and retains [validate, dependency-review, codeql] for
exact PR-head checks. The frozen delivery tests also contain a seeded historical
implicit-default migration and rejection of an explicitly configured full-list
change. These fake-adapter fixtures are not live recovery receipts. The
migration record describes
the required evidence for the named historical delivery. The
earlier canary preserves the preceding
blocked policy. Downstream native commands and GitHub checks continue to operate
without Mill.
src/repository/intelligence.ts is a deterministic static extractor. Keep it
read-only: use the safe-path reader for source bytes, maintain fixed traversal
and byte budgets, and verify every parsed source file and package manifest
against its blob in the captured clean HEAD tree. Preserve explicit
unresolved/external classifications, including nonliteral module loads, and
treat option-bearing test commands as unknown rather than partially interpreting
their arguments. Do not add dependency installation, target execution, model
calls, watches, or a write-side graph store. The TypeScript compiler API is an
exact runtime dependency because the installed package parses the target source
itself. It is bundled into Mill's packed artifact so the offline packed-package
canary can exercise discovery without an unqualified registry fetch.
The evaluator in test/repository-intelligence.test.ts owns repeatability,
freshness, source-path containment, unresolved-import, no-execution, and
importer-lead cases. scripts/test-package.mjs installs the packed tarball and
exercises the public command against a clean disposable Git repository. The
attended JSON Server check is external fixture evidence in
docs/canaries/brownfield-discovery.md; do not vendor or execute that source
without a new approved scope.
Only applicable tiers are active. A skipped required lane blocks promotion.
| Tier | V1 posture | Examples |
|---|---|---|
| Unit | active | canonicalization, schema and transition rules |
| Integration | active from Wave 2 | SQLite, worktree, process and adapter boundaries |
| End-to-end | active from Wave 2 | packed CLI against disposable repositories |
| Acceptance | active | exact task acceptance IDs |
| Hardening | active by risk | hostile paths/config, cancellation, recovery |
| Chaos | targeted | crash boundaries and external-effect ambiguity |
| Performance | measured where relevant | budgets and bounded output |
| Soak | deferred | only after routine unattended operation exists |
| Contract | active | schemas, CLI JSON and exit codes |
| UAT | active before public alpha | clean-machine founder journey |
| Scenario | active | normal, exception, degradation, recovery, adversarial |
| Cross-system | Wave 3+ | Codex, OCI and GitHub canaries |
Wave 3 keeps deterministic fake Codex, OCI, GitHub, and Git adapters in CI and runs the packed CLI through the human-merge gate in a disposable repository. A real Codex/OCI or GitHub canary remains attended maintainer evidence, never a CI job with personal credentials. The realistic scenario set covers:
- normal approval, build, lifecycle commit, verification, and clean review;
- negative controls for failed, stale, inspect-only, or interrupted baseline qualification, changed command configuration, mutable command-control paths, bound-input/output overlap, dirty checkout, ignored-file contamination, hostile Git metadata, unauthorized paths, symlinks, replacement/graft history substitution, hidden index flags, authority drift, and attempted automatic Codex escalation approval;
- degradation from provider failure, missing OCI runtime/image, nonzero command, deadline, cancellation, and output exhaustion;
- recovery through crash-released writer leases, PID-reuse-safe orphan reconciliation, explicit OCI container cleanup, provisional workspace cleanup, exact-candidate repair revalidation, per-candidate review budgets, validated state backup/restore, quarantine of worktrees newer than a restored backup, external-effect readback, one readback-authorized retry, retry exhaustion, coordinator-level attendance enforcement, changing blocker identity, and purge only after a locally reviewed or terminal state;
- provenance through exact base, context, candidate commit/tree, validation, and review identity checks;
- remote delivery through wrong-actor/fork/remote denial, stale approvals, expected-head pushes, effect-before-receipt recovery, unknown-effect blocking, cancellation before and during mutations, paginated exact-head inline and top-level review feedback, one aggregated repair, stable PR identity and open-draft preflight before retry whether an ambiguous push is absent or landed, unauthorized merger and disallowed merge-shape rejection, merge-tree binding, and non-false-green post-merge checks;
- hostile filesystem coverage for Docker bind paths containing commas without weakening read-only/no-network verification;
- restore recovery through an immutable pre-commit quarantine manifest and a database swap as the final fallible commit point;
- packaging through installation of the generated tarball and execution of its public CLI and schema exports.
Wave 4A adds contract and negative-control coverage for source authority, canonical proposal approval, semantic regeneration diffs, impact exceptions, duplicate source and stable product IDs, outcome-to-impact binding, item-scoped attestation claims, command-bound scenarios, instruction precedence and path-set drift, immutable worker admission, launch-before-spawn, atomic process-exit and result settlement, expired-authority readback, and malformed or conflicting provider events. The repository dogfoods its approved product, scenario, impact, and selected web-recipe contracts. Those tests prove contract behavior; they do not replace exact-candidate review or CI because a candidate cannot certify itself by changing its own oracle.
Wave 4B adds deterministic greenfield and adoption plan/apply fixtures, exact
recipe-asset digesting, ownership/detach checks, failed-staging cleanup,
lock/image-bound dependency preparation, installed-tree drift rejection,
cancellation cleanup, and founder coordinator recovery. Adversarial cases cover
target-lock contention, preserved preexisting state, symbolic-link target
ancestors, direct API attendance and trust bypasses, untrusted or incomplete npm
lock sources, frozen-lock drift, missing installer output, exact
PRD/source/outcome/acceptance authority, canonical-target aliasing, target
creation between approval and reservation, future approval times,
credential-like adoption files including .npmrc, PRDs inside builder-writable
source scope, cross-outcome scenarios, unprovable invariant modes, unsafe
generated-file ancestors, risk evidence understatement, older nonterminal runs
hidden by newer terminal records, and adoption with missing or modified oracle
bytes. Dependency cases validate the root lock consumed by npm even when another
lock is listed first and reject credential/query-bearing registry URLs.
Recipe-generated task evidence requires a named recipe-specific oracle; a
generic command reference blocks. The recipe itself is also exercised in the
exact pinned Playwright image with network disabled, a read-only root and source
tree, read-only dependencies, declared top-level tmpfs scratch, bounded Chromium
shared memory, and native
format/lint/type/unit/integration/browser/build/package commands. This is one
qualified recipe tuple, not evidence for arbitrary stacks.
Wave 5 adds three promotion layers. First, millctl audit performs a read-only
assessment of the clean exact repository candidate across product, code, UX,
Accessibility, security, dependency, architecture, operations, and release
categories. Second, the packed-package test runs five dependent reviewed
candidates from the prior accepted output and a separate seeded-fault branch;
the public-alpha assessor rejects gaps, discontinuity, stale support, invented
usage, skipped canaries, or concealed preservation failure. Third, the release
workflow compares two clean exact-tag builds, preserves one tarball, qualifies
that file, and publishes the same bytes through trusted npm OIDC only in a
separately authorized run.
The reliability/brownfield foundation adds deterministic state-routing tests
over every lifecycle status and generated interruption/reconciliation
combinations, plus a small local evaluation pack for inherited-repository
failure modes. The pack evaluates Mill's evidence routing, not a foundation
model. Provider cache-input tokens are recorded only when the completed event
provides them, and currency remains unavailable. continuation is a read-only
projection; tests must prove it does not disclose private state or select a
mutation ahead of reconciliation. An explicit isolated-builder request must fail
closed until a separately qualified external adapter and negative-boundary tests
exist.
The exact web recipe's required native commands include test:browser. That
lane is both delivered-surface verification and the recipe's current
Accessibility hook. It must remain part of npm run check for the supported
shape; adding a more specialized accessibility oracle requires a product and
scenario change, not an undocumented CI-only check.
The Wave 5 package canary uses deterministic fake provider/forge adapters to
prove lifecycle composition without credentials. Live Codex, GitHub, clean
builder, npm, and registry-readback evidence is collected only through the
attended genesis procedure in docs/release.md. Do not record the deterministic
fixture as a qualified real support tuple.
The npm dependency target is exactly node_modules; writable scratch paths must
be comma-free top-level repository directories. They cannot already exist in the
exact candidate because a mount would hide candidate content. The verifier also
rejects more than 256 top-level entries, top-level symbolic links, unsupported
filesystem entries, and top-level names containing commas. The workspace path
itself may contain commas because Mill creates and verifies an exact temporary
alias. These restrictions are current product limits, not silent portability
claims.
Task-packet version 1 is accepted only to resume or inspect work that began
before the continuity contract. Baseline qualification and every new run require
version 2, including an approved impact manifest and explicit acceptance,
invariant, scenario, coverage, and evidence bindings. Do not rewrite an
in-flight version 1 task: its canonical bytes and digest remain unchanged.
The real-provider canaries use the maintainer's personal Codex and GitHub accounts, a pre-pulled digest-pinned image, and an explicitly named disposable repository. They may exercise only the wave's approved effects and must preserve authoritative readback evidence. No test may provision a repository, mark a PR ready, merge, deploy, or rerun remote checks.
The completed Wave 3 canary is recorded in
docs/canaries/wave-3-real-github.md. It also
shows why provider-authoritative usage must be budgeted: even a tiny task can
consume substantial context tokens while currency cost remains unavailable. The
Wave 4B recipe qualification is recorded in
docs/canaries/wave-4b-recipe.md. The package
test must load the installed tarball's recipe and assert that packable aliases
render required dotfiles and untrusted product strings remain valid source
literals. Integration tests must also prove the same approved plan digest
appears in the plan result and generated mill.lock. The Wave 5 implementation
and remaining live evidence are recorded in
docs/canaries/wave-5-public-alpha.md.
Before medium/high-risk code, answer:
- What exact source owns the behavior or state?
- What identity/digest makes it fresh and unambiguous?
- Who may mutate it, under what explicit grant?
- How does cancellation/crash/retry behave?
- What prevents a model, repo file, or available credential from widening authority?
- Which delivered surface and realistic scenario prove the outcome?
- How is the downstream repository still operable without Mill?
Run one architecture/threat pass before medium/high-risk implementation and one complete exact-candidate review after validation. Batch all actionable findings into one systemic repair. Recurring same-subsystem P1 findings return to design.