828 lines
42 KiB
Markdown
828 lines
42 KiB
Markdown
# WW Project Continuation Plan
|
|
|
|
Status date: 2026-08-05
|
|
|
|
Canonical baseline: `master` at `3d7973596422f1c9e2275016a5f264a2ae504ceb`
|
|
|
|
This is the durable handoff for the next Codex session. Read this file before
|
|
starting implementation. It records the repository audit, the test-suite audit,
|
|
the branch cleanup, the first T0 implementation slice, and the recommended order
|
|
of work.
|
|
|
|
## 0. T0 first-slice update
|
|
|
|
The focused topic branch is `t0-harness-integrity`, based directly on the
|
|
canonical `master` commit above. This slice did not touch compiler features,
|
|
CSP, bootstrap design, the cast-diagnostic worktree, recovery artifacts, or the
|
|
existing unrelated generated/untracked paths.
|
|
|
|
Completed in this slice:
|
|
|
|
- `test/run` now materializes the complete 337-source corpus before fan-out,
|
|
records atomic started and terminal records, captures launcher failures, and
|
|
checks discovered, started, completed, classified, cached, excluded, and
|
|
not-run counts by identity.
|
|
- Worker results distinguish pass, fail, explicit exit-77 skip, timeout, and
|
|
harness error. Every C wrapper has a 900-second outer GNU `timeout` with a
|
|
kill-after grace period. A private child-status record plus a separate GNU
|
|
`timeout --verbose` diagnostic distinguishes actual expiration from tests
|
|
that themselves return reserved codes 124-127 or 137.
|
|
- `make test-unit` prints all eight intentional phase-2 exclusions. Unexpected
|
|
skips, timeouts, missing binaries, malformed/incomplete records, launcher
|
|
failures, empty corpora, and corpus shrinkage make required targets fail.
|
|
- Successful wrapper output is visible. The whole-wrapper prerequisite skips in
|
|
`530_w6a_parsenum`, `810_dyn`, `989_dynentry_run`, and
|
|
`989_structlocal_frame` now return the explicit skip code instead of success.
|
|
- The cache key includes tracked and relevant nonignored untracked inputs,
|
|
unstaged-deletion markers, built tools, the runtime archive, cached gate
|
|
executables, and harness configuration. Ambient `WW_W6*`/library/cache
|
|
overrides are removed from required-suite workers. Inputs are fingerprinted
|
|
again after both cache hits and misses, publication is atomic, custom workers
|
|
disable caching, and the host-dependent `996_dyn_ww` gate is never cached.
|
|
- `test/run_test.sh`, wired as `make test-harness`, exercises pass, fail, skip,
|
|
TERM-resistant timeout, genuine reserved exit codes, timeout-wrapper failure,
|
|
missing binary/capture/result, empty/shrunken corpora, failed launchers,
|
|
zero-duration rejection, cache publication/hits, unstaged tracked deletion,
|
|
uncached host-dependent gates, and visible `test-unit` exclusions entirely in
|
|
temporary directories.
|
|
- The regex gate now runs the external black-box unit and the in-package module
|
|
root as two separate `-T` binaries. It requires all 33 black-box tests and all
|
|
15 named white-box tests exactly once. The obsolete zero-test
|
|
`lib/regex/wb/regex_test.ww` scaffold and its duplicate byte-ID row are gone.
|
|
- `989_test_filter.c` uses one named four-entry bound for both expectation arrays
|
|
and loops; the redundant fifth initializer is gone, and its dedicated Make
|
|
rule compiles with `-Werror`.
|
|
- `989_lib_byteid.c` now pins its enrolled corpus at 42 entries, so deleting a
|
|
byte-ID row cannot silently shrink that cross-stage gate.
|
|
|
|
Verification on 2026-08-05:
|
|
|
|
| Command | Result | Reported scope and time |
|
|
| --- | --- | --- |
|
|
| `sh test/run_test.sh` | Pass | All 16 synthetic harness scenarios |
|
|
| `make test-harness out/bin/test_regex_run out/bin/test_test_filter` | Pass | Harness self-test plus focused binaries |
|
|
| `BIN="$PWD/out/bin" timeout 300 ./out/bin/test_regex_run` | Pass | Regex black-box 33/33; white-box 15/15 |
|
|
| `BIN="$PWD/out/bin" timeout 60 ./out/bin/test_test_filter` | Pass | Five filter rows; `ww == ww_ww` output |
|
|
| `BIN=out/bin out/bin/test_lib_byteid` | Pass | 36 byte-identical, four pinned divergences, two pinned WW rejects across 42 units |
|
|
| `make test-unit` | Pass | Discovered 337; started/completed/pass 329; fail/skip/timeout/harness-error 0; eight explicit exclusions; 76 seconds |
|
|
| `make test` | Pass | C harness 337/337 with zero fail/skip/timeout/harness-error; 159 language files containing 1,224 tests; 153 language byte-ID files; 106/106 `runww` cases; 308 seconds |
|
|
|
|
The pre/post generated-artifact path scan contained the same 533 paths; neither
|
|
required run introduced a new source-tree artifact path. Final logs are in
|
|
`/tmp/ww-t0-test-unit-final.log` and `/tmp/ww-t0-test-full-final.log`, which are
|
|
not durable.
|
|
|
|
Remaining T0 and adjacent risks:
|
|
|
|
- `runww` still uses shared `/tmp/runww.err` and `/tmp/runww.bin`, has no per-case
|
|
timeout, and has no pinned 106-case minimum. Close these paths in the first
|
|
replacement-runner vertical slice rather than extending the legacy wrapper.
|
|
- The WW-native `lib/test` runner still needs T2's child completion token,
|
|
timeout/capture protocol, skip reason API, and failure-count clamping; an
|
|
explicit stale-record/256-failure regression therefore remains outstanding.
|
|
- Several legacy wrappers have partial stage-missing branches that print a skip
|
|
and continue after other assertions. Required Make prerequisites made none of
|
|
those branches fire in either verified run, and their output is now visible,
|
|
but converting them to structured whole-test/subtest outcomes remains work.
|
|
- Warning-fatal compilation is local to `989_test_filter.c`; broader harness
|
|
`-Werror` requires resolving existing unrelated missing-initializer and path
|
|
truncation warnings first.
|
|
- The regex module-root route is deliberately temporary and C-driver-only.
|
|
T1 must implement package-aware white-box/external test planning symmetrically
|
|
in `ww` and `ww_ww`, after which `regex_whitebox.ww` can become a canonical
|
|
`*_test.ww` file.
|
|
- Manifest and planning appends still rely on the fresh temporary filesystem
|
|
remaining writable, and cached gates treat ordinary host `PATH` utilities as
|
|
part of the machine baseline rather than fingerprinting each utility. These
|
|
are reasons not to expand the legacy cache/harness design.
|
|
|
|
Strategic direction recorded on 2026-08-05: the 337-wrapper/manual-Make test
|
|
architecture is a temporary migration oracle, not a design to keep extending.
|
|
After landing this branch, design the declarative replacement and migrate
|
|
`runww` as its first vertical slice; the new runner must provide unique temp
|
|
roots, per-case timeouts, a pinned corpus, and structured outcomes from the
|
|
start. Retire old wrappers and manual rules only after coverage-equivalence
|
|
checks pass. Do not integrate the cast-diagnostic WIP into this branch.
|
|
|
|
## 1. Executive decision
|
|
|
|
The project is alive and its current test commands pass. The first T0 slice has
|
|
closed the host C harness's missing-worker and vacuous-regex false greens, but the
|
|
remaining `runww`, package-driver, and WW-native runner contracts still prevent
|
|
the test system from being the final trustworthy development gate. The largest
|
|
immediate risk remains test architecture, not a single compiler feature.
|
|
|
|
Proceed in this order:
|
|
|
|
1. Preserve the current state and make the test result trustworthy.
|
|
2. Split compiler unit tests, compiler conformance tests, package unit tests,
|
|
integrations, differential tests, and bootstrap tests into explicit suites.
|
|
3. Finish the small compiler-stability tail, including the active cast-diagnostic
|
|
work.
|
|
4. Produce a usable developer release: SDK installation, documentation, CI, and
|
|
import/export and error-handling cleanup.
|
|
5. Start the CSP/runtime vertical slice only after renewed explicit approval.
|
|
6. Treat bootstrap independence as the final milestone, not the next task.
|
|
|
|
Do not start by rewriting the compiler, changing the backend, or doing a large
|
|
test-directory rename. First eliminate false-green paths and define stable suite
|
|
contracts.
|
|
|
|
## 2. Preservation and branch cleanup
|
|
|
|
### 2.1 Repository state
|
|
|
|
- There is no configured Git remote. Local history has no off-machine safety net.
|
|
- The main worktree is `/home/kimchi/src/ww` on `t0-harness-integrity`, based
|
|
directly on `master` at the canonical commit above.
|
|
- `docs/spec.md` exists but is untracked. It appears to be intended as a
|
|
normative language specification and must not be discarded.
|
|
- `ref/hare` and `ref/plan9front` are gitlinks, but there is no `.gitmodules`
|
|
file. `ref/inferno-os` and `ref/qbe` are untracked trees. Make their provenance
|
|
reproducible before calling the repository portable.
|
|
- Ignored bootstrap binaries exist under `bootstrap/amd64`.
|
|
- Generated output currently exists under `build/`, several
|
|
`test/wcc/data/*/out/` directories, `scratch/`, and other untracked paths.
|
|
Classify these paths before deleting them; they were not part of the branch
|
|
cleanup.
|
|
- `.ai/` is ignored and contains older handoffs. Use this document as the current
|
|
source of truth unless an older note is explicitly cited.
|
|
|
|
### 2.2 Recovery artifacts created before cleanup
|
|
|
|
The following files are in the repository root and are currently untracked:
|
|
|
|
| File | Purpose | SHA-256 |
|
|
| --- | --- | --- |
|
|
| `branch-backup-20260805.bundle` | Complete pre-cleanup Git history and refs | `a96f48588aa406ab74c52ba8e94fdd635bfbb4e80c2602811d33c5b28a7793aa` |
|
|
| `wip-29-castdiag-20260805.patch` | Tracked dirty changes from the active cast-diagnostic worktree | `c7a5de8606ee8d9cbba32dbc5fd420c694b0c2929b673f35155db4f7066ba2d7` |
|
|
| `wip-29-cast-fixture-20260805.tar.gz` | Untracked `cast_unknown_type` fixture | `27a16b43ee83dde28c207f22050738591c1414ab917509529fb2d9d5519b5192` |
|
|
|
|
`git bundle verify branch-backup-20260805.bundle` reports a complete history.
|
|
The bundle contains the original 107 local branch refs plus the stash, tag, and
|
|
worktree refs. Copy these three artifacts to a different disk or remote storage;
|
|
an untracked backup on the same disk is not a permanent backup.
|
|
|
|
To recover one deleted branch without disturbing current refs:
|
|
|
|
```sh
|
|
git bundle verify branch-backup-20260805.bundle
|
|
git fetch ./branch-backup-20260805.bundle \
|
|
refs/heads/OLD_NAME:refs/heads/restore/OLD_NAME
|
|
```
|
|
|
|
To reconstruct the dirty cast work on a fresh worktree:
|
|
|
|
```sh
|
|
git worktree add ../ww-cast-restore -b restore/castdiag master
|
|
git -C ../ww-cast-restore apply \
|
|
/home/kimchi/src/ww/wip-29-castdiag-20260805.patch
|
|
tar -xzf /home/kimchi/src/ww/wip-29-cast-fixture-20260805.tar.gz \
|
|
-C ../ww-cast-restore
|
|
```
|
|
|
|
### 2.3 Branch cleanup result
|
|
|
|
The repository started with 107 local branches. Cleanup deleted 105:
|
|
|
|
- 90 branch tips were direct ancestors of `master`.
|
|
- 14 branches looked unmerged by graph ancestry but were audited and found to be
|
|
patch-equivalent to, or superseded by, later work on `master`.
|
|
- `wip-buga` was already merged; its clean worktree was removed and the branch
|
|
was deleted.
|
|
|
|
Before T0 implementation, only these branches remained. The focused T0 branch
|
|
was then added:
|
|
|
|
| Branch | State | Decision |
|
|
| --- | --- | --- |
|
|
| `master` | Clean tracked baseline at `3d79735` | Keep |
|
|
| `wip-29-castdiag` | Checked out at `/home/kimchi/ww-29`; contains uncommitted source and fixture changes | Keep until reviewed and integrated |
|
|
| `t0-harness-integrity` | Checked out at `/home/kimchi/src/ww`; first T0 gate-integrity slice | Review and merge separately |
|
|
|
|
The active WIP adds a clean diagnostic for a cast to an unknown type in
|
|
`selfhost/cmd/wcc/check.ww`, plus a fixture under
|
|
`test/wcc/data/cast_unknown_type/`. Do not delete this worktree merely because
|
|
its branch tip is already reachable from `master`; the valuable part is the
|
|
dirty working tree. The patch and fixture archive above are secondary recovery
|
|
copies.
|
|
|
|
A detached worktree remains at `/home/kimchi/src/ww-f0` on `e8977a4`. It is not
|
|
a branch and was therefore not removed. Audit it separately before deciding
|
|
whether to remove it.
|
|
|
|
The 14 non-ancestor branches were matched to later `master` work as follows:
|
|
|
|
- `e3-c1-flip`, `e3-oracle`: separate-compilation flip later landed around
|
|
`33edc38`.
|
|
- `f1-stack-v1`, `f1-stack-v2`, `f1-stack-v3`: superseded by `9bd0d8b`,
|
|
`b9dd297`, `c138605`, `ac63951`, and later type-chase work.
|
|
- `impl-26`: superseded by `9fcb3be`.
|
|
- `impl-ascii-bytes-cut`, `impl-ascii2-complete`: superseded by `07fed80` and
|
|
`2b893b9`.
|
|
- `impl-strconv`: finalized through `6a5cdbd`, `a117852`, and `db5c5b6`.
|
|
- `impl-strings-cutrcut`: patch-equivalent to `38a906c`.
|
|
- `t28`, `t28-parked`: superseded by `c40b2df` and `330792b`.
|
|
- `wip/io5-handle-seeker`: superseded by `06c00e0` and `532b0a8`.
|
|
- `worktree-impl-e8`: superseded by `b842f93`, `10cb835`, and `7d39f6d`.
|
|
|
|
The bundle remains the authoritative record if any of those classifications
|
|
must be revisited.
|
|
|
|
## 3. Verified build and test baseline
|
|
|
|
The following commands were run on `master` at the baseline commit before this
|
|
document and branch-only cleanup:
|
|
|
|
| Command | Result | Observed scope and time |
|
|
| --- | --- | --- |
|
|
| `make test-unit` | Pass, 329/329 C harness entries | About 95 seconds |
|
|
| `make test` | Pass | C harness 337 entries; `test/lang` 159 files; language byte-ID pass over 153 files; `runww` 106 cases; about 313 seconds total |
|
|
|
|
The full audit log was written to `/tmp/ww-tests-health-full.log`; `/tmp` is not
|
|
durable, so rerun the commands when a fresh log is needed.
|
|
|
|
These historical green results prove that the canonical baseline is buildable.
|
|
They did not prove that every named test executed useful assertions; the first
|
|
T0 slice above closes the missing-worker and empty regex-table paths without
|
|
changing this preserved baseline record.
|
|
|
|
No source code changed during the branch cleanup and English-document rewrite,
|
|
so the full suite was not rerun afterward.
|
|
|
|
## 4. Current test architecture
|
|
|
|
The project already contains substantial test material. The problem is that
|
|
several different kinds of tests are mixed behind numeric C wrappers and broad
|
|
Make targets.
|
|
|
|
### 4.1 C harness under `test/wcc`
|
|
|
|
- 337 C test sources are registered through roughly 337 manual Make rules.
|
|
- The sources contain about 89,519 lines.
|
|
- Static inspection found subprocess orchestration in approximately 333 tests
|
|
(`fork`, `exec`, `system`, or `popen`).
|
|
- Only a handful, approximately the `000`, `100`, `200`, `300`, and `738`
|
|
families, resemble direct compiler-component unit tests.
|
|
- Most files are integration wrappers around compiler commands, generated
|
|
programs, output matching, byte-ID checks, or bootstrap behavior.
|
|
|
|
Therefore `make test-unit` is currently misnamed. It omits a few heavy phase-2
|
|
tests, but still runs most integrations and includes `989_lib_byteid`, which
|
|
alone took roughly 42 seconds in the audit. It does not run the 1,224-test
|
|
`test/lang` corpus or the `runww` fixtures, but C wrappers do indirectly launch
|
|
the library `@test` files. The first T0 slice makes all 458 library tests
|
|
effective, including the 15 regex white-box tests.
|
|
|
|
### 4.2 Language tests under `test/lang`
|
|
|
|
- 159 source files contain exactly 1,224 source-level `@test` functions.
|
|
- Six files are `_runonly_test.ww` variants.
|
|
- The current Make targets compile/run this corpus and also perform byte-ID
|
|
comparison for most of it.
|
|
|
|
This is valuable language and compiler coverage, but file layout and target
|
|
naming do not clearly separate package unit behavior from compiler conformance
|
|
behavior.
|
|
|
|
### 4.3 Library tests
|
|
|
|
- 35 test-named library source files contain 443 `@test` functions. Eleven use
|
|
`_test.ww`; 24 use other names ending in `test.ww`.
|
|
- `lib/regex/regex_whitebox.ww`, a production-named source file, contains 15
|
|
additional `@test` functions.
|
|
- There are therefore 36 files that actually contain tests and 458 source-level
|
|
library tests in total.
|
|
|
|
Together, `test/lang` and `lib` contain 1,682 real source `@test` functions,
|
|
excluding generated combined files.
|
|
|
|
### 4.4 Directive fixtures through `runww`
|
|
|
|
There are 106 directive-driven cases:
|
|
|
|
- 100 `//ww:error` cases.
|
|
- 5 `//ww:run-exit` cases.
|
|
- 1 `//ww:run` case.
|
|
- 0 `//ww:compile` cases.
|
|
|
|
The rejection coverage is useful, but this is not yet a balanced compiler
|
|
conformance suite. Rejections do not identify whether failure was expected in
|
|
lexing, parsing, checking, code generation, assembly, or linking. Accept/run
|
|
cases use only the C stage, while rejects exercise two stages.
|
|
|
|
### 4.5 Current `@test` implementation
|
|
|
|
The compiler's `-T` path synthesizes a `__wwtests` value table and test main.
|
|
`@test` functions are expected to have the shape `fn() void`. Normal builds
|
|
type-check tests and then strip them. The runtime in `lib/test` forks once per
|
|
test, so an abort, signal, or nonzero exit does not stop subsequent tests. The
|
|
runner also supports glob filtering and treats zero matches as success.
|
|
|
|
The per-test fork model and compiler-generated value table are good foundations
|
|
and should be preserved. The package driver and child/parent result protocol need
|
|
to be completed.
|
|
|
|
### 4.6 Target coupling and differential caveats
|
|
|
|
- Despite its name, `make test-run` is not an isolated `runww` target. Its
|
|
order-only prerequisites build the C harness and run `test-lang` plus
|
|
`test-lang-byteid` first. The redesigned target graph must remove this
|
|
surprising coupling.
|
|
- `test-lang-byteid` reads only `test/lang`. The six positive `runww` fixtures
|
|
are not checked for stage-by-stage assembly identity.
|
|
- `989_lib_byteid` has 42 rows: 36 require identity, four are declared
|
|
divergences, and two are expected WW-stage rejects. A green result does not
|
|
mean complete standard-library stage parity.
|
|
- `runww` itself is compiled by the C-stage compiler and then invokes that same
|
|
stage. It is useful coverage but not an independent sole oracle. Retain an
|
|
independent host-side runner or cross-validate the harness during migration.
|
|
|
|
## 5. Correctness risks in the current test result
|
|
|
|
Treat the following as gate-integrity bugs, not cosmetic cleanup.
|
|
|
|
### 5.1 Vacuous regex test: closed in the first T0 slice
|
|
|
|
The former `lib/regex/wb/regex_test.ww` root contained no tests while importing
|
|
regex as a dependency, so `-T` stripped all 15 intended white-box tests. The T0
|
|
gate now resolves `regex` itself as the root module, keeps it separate from the
|
|
external `regex_test` binary, and asserts every expected name plus the exact
|
|
15/15 summary. The empty scaffold was removed. T1 still needs to replace this
|
|
temporary module-root route with ordinary package-aware test assembly.
|
|
|
|
### 5.2 Harness false-green paths
|
|
|
|
Closed in the first T0 slice:
|
|
|
|
- `test/run` no longer masks either `xargs` launcher. It collects from a complete
|
|
manifest and fails on missing starts, missing/malformed terminal records,
|
|
launcher errors, or any count/identity mismatch.
|
|
- Pass, fail, explicit skip, timeout, and harness error are distinct outcomes;
|
|
required targets fail on every unexpected non-pass outcome.
|
|
- Successful wrapper output and every expected `test-unit` exclusion are visible.
|
|
- The cache hashes nonignored untracked inputs plus effective built inputs,
|
|
represents tracked deletions, revalidates hits and misses at run end, and
|
|
publishes atomically only after complete green accounting. The host-dependent
|
|
dynamic gate is deliberately uncached.
|
|
- The dead nested `test/lang` scan is gone.
|
|
- `989_test_filter.c` has one named expectation count, no excess initializer,
|
|
and a rule-local `-Werror` gate.
|
|
|
|
Remaining:
|
|
|
|
- Existing generated artifacts outside the new harness result/temp directories
|
|
have not been broadly relocated or classified.
|
|
- Partial prerequisite skips inside legacy wrappers are not yet structured
|
|
subtest outcomes. None fired in the recorded runs, and whole-wrapper skips now
|
|
use exit 77.
|
|
- Broad warning-fatal harness compilation remains blocked by pre-existing
|
|
warnings outside `989_test_filter.c`.
|
|
|
|
### 5.3 `runww` limitations
|
|
|
|
- It uses shared fixed paths such as `/tmp/runww.err` and a fixed binary name,
|
|
which prevents safe parallel execution and risks stale-file interference.
|
|
- It supplies a nil environment to subprocesses.
|
|
- Negative cases check a diagnostic substring but do not identify the failure
|
|
phase.
|
|
- There is no per-case timeout.
|
|
- Missing arguments fail, but there is no expected/minimum corpus count. A suite
|
|
accidentally reduced from 106 fixtures to one can still pass without a
|
|
corpus-shrinkage alarm.
|
|
|
|
### 5.4 Package-driver limitations
|
|
|
|
- `ww test DIR` discovers only immediate `_test.ww` files and does not recurse.
|
|
- Files are not sorted deterministically.
|
|
- Each discovered file is built separately instead of assembling one package
|
|
test unit. Same-package helper sharing therefore does not work as expected.
|
|
- Production enumeration excludes all `*test.ww`, while test discovery includes
|
|
only `_test.ww`; the naming rules disagree.
|
|
- Only the first glob argument reaches the runner even though the runner can
|
|
support more than one.
|
|
- A single file with no tests can silently return success, while a directory
|
|
with no recognized tests can error. Define one consistent contract.
|
|
- Imported dependency tests are stripped. This is normally correct, but root
|
|
package files containing tests must be assembled into the root test build.
|
|
- `-c` without `-o` can leave a temporary test executable behind.
|
|
|
|
### 5.5 Runner-protocol limitations
|
|
|
|
- A test can call `os.exit(0)` before completing and the parent reports it as a
|
|
pass. The parent needs an explicit completion token from the child.
|
|
- The runner returns the raw number of failures. At 256 failures, the Unix exit
|
|
status can wrap to zero.
|
|
- There is no timeout, structured capture, duration reporting, skip reason,
|
|
expected-abort protocol, cleanup hook, or per-test temporary directory.
|
|
- Invalid `@test` declarations are checked too narrowly and mainly under `-T`.
|
|
Exported tests, prototypes, arguments, variadics, non-void returns, duplicate
|
|
annotations, and other invalid forms need deterministic diagnostics in normal
|
|
and test builds.
|
|
|
|
## 6. Target model: Go/Hare-style separation
|
|
|
|
The desired result is not a copy of either project, but it should adopt their
|
|
separation of concerns.
|
|
|
|
### 6.1 Lessons from Go
|
|
|
|
The local Go 1.25.4 source tree demonstrates two distinct systems:
|
|
|
|
- Compiler/runtime conformance fixtures live outside ordinary package unit
|
|
tests and use explicit execution/error directives.
|
|
- Ordinary `*_test.go` files are assembled per package into a generated test
|
|
main, with support for same-package tests, external-package tests, filtering,
|
|
caching, timeouts, parallelism, and structured output.
|
|
- Compiler internals also have direct component unit tests rather than wrapping
|
|
every assertion in a compiler subprocess.
|
|
|
|
WW needs the same conceptual split: compiler correctness fixtures are not the
|
|
same thing as user-facing package unit tests.
|
|
|
|
### 6.2 Lessons from Hare and harec
|
|
|
|
The vendored `ref/hare` test command demonstrates useful package-test behavior:
|
|
|
|
- Recursive module discovery when no explicit module is given.
|
|
- Deterministic sorting, multiple globs, and a test-only build tag.
|
|
- First-class skip, require, expected-abort, current-test, capture, timing, and
|
|
backtrace behavior.
|
|
|
|
The upstream Hare compiler suite uses feature-grouped positive and negative
|
|
fixtures and distinguishes outcomes such as success, user error, lex failure,
|
|
parse failure, check failure, and abnormal failure. The vendored `ref/harec`
|
|
copy is incomplete and lacks the full compiler test corpus; pin an upstream
|
|
version or import a documented reference snapshot before using it as a durable
|
|
oracle.
|
|
|
|
Keep WW's fork isolation and generated source value table. Do not copy Hare's
|
|
same-process recovery mechanism or unrelated linker-specific structure.
|
|
|
|
## 7. Proposed suite contracts
|
|
|
|
Use semantic directories and explicit metadata. Numeric prefixes may remain as
|
|
stable case IDs during migration, but they must no longer determine what a test
|
|
means or when it runs.
|
|
|
|
```text
|
|
test/
|
|
unit/ Direct host-side compiler/library API tests; no subprocesses
|
|
compiler/ Source conformance fixtures grouped by language feature
|
|
package/ Fixtures for `ww test` discovery and package assembly
|
|
integration/ CLI, import graph, archive, ELF, FFI, and toolchain behavior
|
|
differential/ C-stage versus WW-stage and byte-ID comparisons
|
|
bootstrap/ Fixed-point, self-host, and no-C-compiler scenarios
|
|
harness/ Shared runners, manifests, and assertion helpers
|
|
```
|
|
|
|
Actual package unit tests should stay beside their code as canonical
|
|
`*_test.ww` files. `test/package` is for testing the package-test driver itself,
|
|
including multi-file layouts, helper sharing, external test packages, empty
|
|
packages, recursion, and failures.
|
|
|
|
Define these Make targets:
|
|
|
|
| Target | Contract |
|
|
| --- | --- |
|
|
| `test-unit` | Direct in-process compiler and library API tests only; zero child compiler processes |
|
|
| `test-compiler` | Positive, negative, run, compile, assembly, and multi-file language conformance fixtures |
|
|
| `test-package` | Real `ww test` package tests and package-driver fixtures |
|
|
| `test-integration` | CLI, separate compilation, archives, ELF, FFI, and graph behavior |
|
|
| `test-differential` | C-stage/WW-stage output and byte-identity checks |
|
|
| `test-bootstrap` | Fixed point, self-host, and `nocc`; explicitly slow |
|
|
| `test-lint` | Harness integrity, fixture metadata, duplicate IDs, empty corpora, and warning checks |
|
|
| `test-fast` | Unit tests plus a documented compiler/package smoke set |
|
|
| `test` | Complete required pre-merge set, with no hidden skips |
|
|
| `test-all` | `test` plus bootstrap and any explicitly labeled slow suites |
|
|
|
|
Every target must print discovered, passed, failed, skipped, timed out, and not
|
|
run counts. A target may intentionally exclude another named suite, but it may
|
|
not silently skip entries within its declared corpus.
|
|
|
|
Compiler fixtures need explicit metadata for at least:
|
|
|
|
- Mode: check, compile, run, run-with-exit, reject, assembly match, or multi-file.
|
|
- Expected stage: lex, parse, check, codegen, assemble, link, run, signal, or
|
|
success.
|
|
- Expected diagnostic, stdout, stderr, exit status, or signal.
|
|
- Timeout and optional platform/tool prerequisites.
|
|
- Stable feature group and case ID.
|
|
|
|
Use one declarative manifest or one clearly documented directive grammar. Do not
|
|
continue adding one manual Make rule and one custom C subprocess wrapper for
|
|
every source fixture.
|
|
|
|
## 8. Required `ww test` semantics
|
|
|
|
The language specification requires both same-package white-box tests and an
|
|
external `<package>_test` black-box package. A package-under-test invocation must
|
|
produce one top-level result covering both, but the implementation cannot simply
|
|
link two current `-T` units: every `-T` unit owns global `main` and `__wwtests`
|
|
symbols, dependencies are compiled without `-T`, and `.wwi` does not carry test
|
|
descriptors.
|
|
|
|
Use this implementation sequence:
|
|
|
|
1. Treat `*_test.ww` only as the candidate-file discovery rule. Classify a file
|
|
as white-box or black-box from its declared package (`package foo` versus
|
|
`package foo_test`), not from its suffix alone.
|
|
2. Compile production files plus same-package test files into one white-box root
|
|
unit.
|
|
3. Compile the external package against only the public API. Initially, build a
|
|
second test binary and aggregate both binary results in the driver. A later
|
|
design may instead emit linkable test descriptors and generate one aggregator
|
|
main, but it must first solve the current symbol and interface limitations.
|
|
4. Exclude test bodies from imported dependencies unless that dependency is the
|
|
package under test.
|
|
5. Give each test a canonical package-qualified ID such as
|
|
`<import-path>.<function>`. Bare leaf names are ambiguous across the white-box
|
|
and black-box units and are not sufficient for output or filtering. The
|
|
generated descriptor must also refer to the callable through its owning
|
|
package rather than assuming a bare function reference.
|
|
6. Produce one top-level package result even if it is internally implemented by
|
|
two test binaries.
|
|
7. Support multiple glob filters and a recursive package pattern equivalent in
|
|
purpose to `./...`.
|
|
8. Use one canonical file naming rule: `*_test.ww`.
|
|
|
|
Normal production enumeration must exclude the entire `*_test.ww` file,
|
|
including test-only helpers and imports. An `@test` declaration placed in a
|
|
production file must still be fully checked in a normal build before its function
|
|
is stripped. These are separate driver and checker responsibilities.
|
|
|
|
Make ordering an explicit compatibility decision. The recommended first
|
|
contract is to sort package and source discovery paths, then preserve declaration
|
|
order within each source. Do not silently change the existing documented
|
|
source/collection behavior to a global name sort.
|
|
|
|
Define all empty cases separately:
|
|
|
|
- An explicitly requested package with no tests reports `[no tests]` and
|
|
succeeds.
|
|
- An explicitly requested test file containing no `@test` declaration is an
|
|
error because it is likely a fixture mistake.
|
|
- A filter matching zero tests reports `[no matches]` and succeeds, preserving
|
|
the current useful filtering behavior.
|
|
- Recursive discovery reports packages with no tests visibly, but a pattern that
|
|
resolves to zero packages is an error.
|
|
- A required suite with an unexpectedly empty or shrunken corpus is a harness
|
|
error regardless of the user-facing command rules.
|
|
|
|
Validate every `@test` declaration during normal checking, even when test bodies
|
|
are later stripped. At minimum reject parameters, variadics, non-void returns,
|
|
prototypes without bodies, invalid export combinations, `@test(...)`, unknown
|
|
attributes, placement on non-functions, and duplicate attributes with stable
|
|
diagnostic text. Put both the C-stage and self-hosted parser/checker through the
|
|
same acceptance fixtures.
|
|
|
|
Define compile-only behavior rather than deleting its output: `ww test -c`
|
|
should preserve a deterministic `<package>.test` binary by default, and `-o`
|
|
should select its path. Specify whether `-o` without `-c` is invalid; the
|
|
recommended contract is to require `-c` so output preservation is unambiguous.
|
|
|
|
Keep one process per test, but add a control pipe from child to parent. A normal
|
|
return must write a completion record. `os.exit(0)` without that record is a
|
|
failure. The same protocol can carry skip, expected-abort, failure reason, and
|
|
captured-output metadata. Clamp the process exit code to `0` for no failures and
|
|
`1` for any failure instead of returning the raw failure count.
|
|
|
|
## 9. Test-system implementation plan
|
|
|
|
### T0: Make the existing green result trustworthy
|
|
|
|
Do this before moving directories. Status after the first focused slice:
|
|
|
|
- [x] Make `test/run` compare discovered, started, and completed test counts.
|
|
- [x] Remove `|| true` masking around worker execution; collect worker failure
|
|
as a harness failure.
|
|
- [x] Represent pass, fail, skip, timeout, and harness error separately.
|
|
- [x] Print skip reasons/output and fail required targets on unexpected skips.
|
|
- [~] Harness records and new regression artifacts are private temporary files,
|
|
and relevant source/configuration inputs are in the cache key. Broad legacy
|
|
source-tree artifact relocation remains.
|
|
- [x] Give every host C-harness subprocess an outer timeout and kill its process
|
|
group on expiry. WW-native enforcement remains T2 work.
|
|
- [ ] Replace shared `runww` paths with a unique per-case temporary directory.
|
|
- [x] Fail the C-harness target on zero or shrunken corpora and incomplete worker
|
|
results. Add the equivalent pinned minimum to `runww` next.
|
|
- [x] Fix the `mustnot[4]` initializer and related loops through one named count.
|
|
- [x] Prove all 15 regex white-box tests execute in a separate root-module
|
|
binary without combining conflicting `-T` units.
|
|
- [~] Sixteen harness scenarios cover fail, skip, TERM-resistant timeout,
|
|
reserved child exits, timeout-wrapper failure, lost/incomplete workers,
|
|
failed launchers, missing binary/result/captures, empty/shrunken corpora,
|
|
invalid bounds, cache safety, and expected exclusion. A fresh per-run result
|
|
directory prevents stale reuse; the WW-native 256-failure case remains.
|
|
|
|
The host C-harness portion of the completion criterion is met: a killed or
|
|
skipped worker cannot leave a required target green, and the regex test reports
|
|
15 discovered and 15 passed white-box tests. Finish the unchecked `runww` items
|
|
before declaring all of T0 complete.
|
|
|
|
### T1: Implement package-aware `ww test`
|
|
|
|
- Introduce a package test-plan data structure in the driver.
|
|
- Unify production-file exclusion and candidate discovery on `*_test.ww`, then
|
|
classify candidates by their package declarations.
|
|
- Assemble production files and same-package tests into one white-box root.
|
|
- Build the required external `<package>_test` unit as a second test binary first,
|
|
and aggregate its result with the white-box binary at the driver level. Do not
|
|
attempt to link two current `-T` mains together.
|
|
- Keep imported dependency tests stripped.
|
|
- Add package-qualified test IDs, deterministic recursive discovery, and
|
|
multiple filter arguments.
|
|
- Implement the documented `-c` output contract and all four no-test/no-match
|
|
cases above.
|
|
- Add C-stage and self-hosted compiler diagnostics for all invalid `@test` and
|
|
attribute shapes.
|
|
- Convert the regex white-box case into an ordinary, non-vacuous package test.
|
|
|
|
Completion criterion: two test files in one package can share a private helper,
|
|
dependency tests do not leak in, filters work deterministically, and empty or
|
|
invalid packages produce the documented result. The C-stage `ww` and self-hosted
|
|
`ww_ww` must discover the same fixtures and produce matching output classes and
|
|
exit statuses.
|
|
|
|
### T2: Finish runner semantics
|
|
|
|
- Add the required OS/runtime wrappers for pipes, process-group creation, and
|
|
process-group signals before depending on them in the WW-native runner.
|
|
- Add the child completion/control protocol.
|
|
- Add skip and require helpers, expected abort, current test identity, cleanup,
|
|
per-test temporary directories, timeouts, captured output, and duration.
|
|
- Drain stdout, stderr, and control pipes while the child is running; waiting
|
|
before draining can deadlock when a pipe buffer fills. Add polling/nonblocking
|
|
support as needed.
|
|
- Ensure signals and premature `os.exit(0)` are classified correctly.
|
|
- Offer a stable human-readable output and a machine-readable event stream.
|
|
|
|
Completion criterion: the runner's own conformance suite covers every outcome
|
|
and never wraps failures into exit status zero.
|
|
|
|
### T3: Build the compiler conformance engine
|
|
|
|
- Create the explicit fixture schema and stage-aware outcome model.
|
|
- Migrate `runww` first because it is already directive-driven.
|
|
- Keep an independent host-side fixture runner as the gate, or cross-check the
|
|
WW-native harness so the compiler under test is not its own sole oracle.
|
|
- Add balanced positive/check/compile/run cases beside rejection cases.
|
|
- Add multi-file, diagnostic location, exit, signal, stdout/stderr, and assembly
|
|
matching support.
|
|
- Pin the external Hare/harec reference version used for design comparison.
|
|
|
|
This is a replacement program, not a permanent adapter around `test/run`.
|
|
Freeze the current C wrapper layer as a comparison oracle, migrate by declared
|
|
suite and outcome, and remove each old path when the new engine proves the same
|
|
coverage. Do not add new numeric wrappers or hand-written Make registrations for
|
|
cases that fit the new fixture schema.
|
|
|
|
Completion criterion: adding a language fixture normally requires source plus
|
|
metadata, not a new C wrapper or Make rule.
|
|
|
|
### T4: Migrate and shrink `test/wcc`
|
|
|
|
Classify every existing C wrapper as unit, compiler fixture, package, integration,
|
|
differential, bootstrap, or obsolete duplicate. Move direct API tests first.
|
|
Mechanically migrate simple subprocess wrappers into fixtures. Keep C only where
|
|
the assertion genuinely needs host APIs, ABI inspection, or custom orchestration.
|
|
|
|
Completion criterion: `test-unit` launches no compiler subprocess, suite
|
|
membership is discoverable without numeric-prefix knowledge, and the giant
|
|
manual Make registry is replaced by generated discovery plus a small manifest.
|
|
|
|
### T5: Add CI cadence
|
|
|
|
- Pre-commit/local: `test-fast`.
|
|
- Required pre-merge: `test` plus harness lint.
|
|
- Scheduled or release: `test-all`, bootstrap, sanitizers, and expensive
|
|
differential/byte-ID jobs.
|
|
- Archive structured results and fail on unexpected skips or corpus shrinkage.
|
|
|
|
Completion criterion: a fresh checkout can reproduce the declared test matrix
|
|
without ignored local binaries or undocumented reference trees.
|
|
|
|
## 10. Broader project roadmap
|
|
|
|
### P0: Preserve and normalize the repository
|
|
|
|
- Copy the recovery artifacts off-machine.
|
|
- Add a remote or another durable backup.
|
|
- Decide which of `docs/spec.md`, reference trees, probes, and scratch artifacts
|
|
are source, vendored dependencies, or disposable output.
|
|
- Track reference provenance through submodules, pinned archives, or documented
|
|
fetch scripts.
|
|
- Commit this plan and the chosen specification files. Do not commit generated
|
|
output or the bundle merely to make `git status` quiet.
|
|
|
|
### P1: Establish the test foundation
|
|
|
|
Execute T0 through at least T3 before broad compiler feature work. T4 can proceed
|
|
incrementally after the contracts stabilize.
|
|
|
|
### P2: Finish the compiler-stability tail
|
|
|
|
- Review and integrate `wip-29-castdiag`, including a regression fixture.
|
|
- Finish or explicitly close the large aggregate return (`sret`, especially
|
|
values over 24 bytes) edge cases.
|
|
- Re-audit stale issue-number tests and convert unresolved cases into explicit
|
|
fixtures.
|
|
- Finish type-information (`tinfo`) consistency work and remove duplicated or
|
|
stage-specific behavior where possible.
|
|
- Preserve separate-compilation and byte-ID guarantees while changing these
|
|
paths.
|
|
|
|
Each item needs a focused branch, a regression test in the correct new suite,
|
|
and a clean full required test run before merge.
|
|
|
|
### P3: Produce a developer-usable v0.1 release
|
|
|
|
- Finish import/export membership rules and diagnostics.
|
|
- Normalize `errno` and error propagation across the standard library, especially
|
|
the existing error/I/O tail.
|
|
- Turn `make install` into an actual SDK installation. It currently copies only
|
|
the `ww` executable and `libwcc.a`; define and install the compiler, standard
|
|
library sources/artifacts, headers or metadata, and version information.
|
|
- Add a README with bootstrap prerequisites, build, test, install, and first
|
|
program instructions.
|
|
- Track the language specification and label implemented, reserved, and planned
|
|
behavior.
|
|
- Add CI from a fresh checkout and publish one reproducible release artifact.
|
|
- Document the current allocation lifetime honestly: both the compiler's
|
|
`free(x)` lowering and `os.free(p, n)` ultimately reach the current no-op
|
|
`rt_free`, so neither reclaims memory today. Decide and test a real reclamation
|
|
policy separately before promising `free` semantics.
|
|
|
|
Release criterion: a developer can clone, build, run the required tests, install
|
|
to a staging prefix, and compile a small program using the installed SDK without
|
|
knowledge of this worktree.
|
|
|
|
### P4: CSP/runtime vertical slice, only after explicit approval
|
|
|
|
The existing design direction is a cooperative M:1 runtime with `swapctx`, a
|
|
run queue, and an unbuffered channel implemented library-first, followed by
|
|
syntax. `epoll`, `alt`/`select`, broader scheduling, and optimization come later.
|
|
|
|
However, the recorded project status says CSP work was explicitly put on hold on
|
|
2026-06-18. Do not infer that a general request to resume the project cancels
|
|
that hold. Ask for renewed explicit approval before implementing CSP/runtime
|
|
features. The specification may reserve the design in the meantime.
|
|
|
|
When approved, implement one narrow end-to-end slice: spawn two cooperative
|
|
tasks, rendezvous over one unbuffered channel, shut down deterministically, and
|
|
cover it in package, integration, and differential tests.
|
|
|
|
### P5: Bootstrap independence last
|
|
|
|
`make bootstrap` already checks a fixed point, `make nocc` exists, and ignored
|
|
stage-0 binaries are present. The process is not yet a clean independent bootstrap
|
|
because the C driver and local artifacts still orchestrate important steps.
|
|
|
|
Freeze bootstrap only after the language, package graph, tests, SDK layout, and
|
|
runtime surface are stable. Then pin stage 0, document trust inputs, build stage
|
|
1 and stage 2 in a clean environment, compare the intended artifacts, and prove
|
|
the process without a C compiler where promised.
|
|
|
|
## 11. Next-session checklist
|
|
|
|
The next Codex session should do the following, in order:
|
|
|
|
1. Read `CLAUDE.md`, this file, and `docs/spec.md`; do not rely on `.ai/` notes
|
|
without checking their date and status.
|
|
2. Inspect `t0-harness-integrity` and its final commit/diff against `master` at
|
|
`3d79735`; do not repeat the repository-wide audit unless that state changed.
|
|
3. Verify the three recovery artifact hashes and arrange an off-machine copy.
|
|
4. Inspect `/home/kimchi/ww-29` and compare its working tree with
|
|
`wip-29-castdiag-20260805.patch` and the fixture archive. Do not delete it.
|
|
5. Review and merge the first T0 branch separately, preserving all unrelated
|
|
untracked/generated paths. Re-run required targets if the diff changes.
|
|
6. Specify the replacement test manifest, structured result protocol, suite
|
|
boundaries, and coverage-equivalence report; keep fork-per-test isolation.
|
|
7. Migrate `runww` as the first vertical slice, implementing unique temp roots,
|
|
per-case timeout, and the pinned 106-case corpus in the new engine rather
|
|
than further entrenching the old wrapper architecture.
|
|
8. Begin package-aware `ww test` assembly after that first replacement slice;
|
|
keep white-box and external-package binaries separate while generated
|
|
`main`/`__wwtests` symbols still conflict.
|
|
9. Integrate the cast-diagnostic WIP as its own reviewed branch once the new test
|
|
placement is available, then remove `wip-29-castdiag` and its worktree.
|
|
10. Do not start CSP or bootstrap redesign unless the prerequisites and approval
|
|
above have been satisfied.
|
|
|
|
## 12. Working rules for future branches
|
|
|
|
- One branch should represent one reviewable outcome, not an indefinite work
|
|
queue.
|
|
- Record the intended suite and completion criterion before implementing.
|
|
- Rebase or merge promptly, then delete the branch after verifying reachability
|
|
and a durable backup.
|
|
- Never classify a branch only with `git branch --merged`; inspect dirty
|
|
worktrees, patch equivalence, fixture files, and later superseding commits.
|
|
- Keep generated output out of topic branches.
|
|
- A green target is acceptable only when it reports a complete corpus and
|
|
explicit skips.
|
|
|
|
The immediate success condition is not more test count. It is the ability to
|
|
state exactly which compiler unit tests, compiler fixtures, package tests, and
|
|
integrations ran—and to know that none of them passed vacuously.
|