build: route .ww directories as packages

This commit is contained in:
2026-08-22 23:39:06 +09:00
parent 2e5451a601
commit ca0e533c13
5 changed files with 683 additions and 30 deletions

View File

@@ -10244,6 +10244,138 @@ No serialized format changes accompany this omission. Build workdir format
remains `18`, test workdir format remains `19`, semantic storage format remains
`3`, and the slice adds no cache or persistent record.
### 11.52 Implemented `.ww`-spelled directory build routing
An existing local literal passed to `ww build` whose requested final basename
ends `.ww` is a directory-package request when ordinary `stat` reports a
directory. This includes a direct directory named `.ww` and a visible
`_test.ww` symlink to a directory. The suffix does not turn the directory into
a raw source and does not trigger the non-directory test-source omission in
11.51.
#### Pinned authority and applicability
- **behavior directly implemented or asserted by pinned Go** — official Go
1.26.5 commit `c19862e5f8415b4f24b189d065ed739517c548ba` implements
symlink-following `Stat` in `cmd/go/internal/fsys/fsys.go:633638`.
`PackagesAndErrors` enters named-file mode only when an operand ends `.go`,
`Stat` succeeds, and the result is not a directory
(`cmd/go/internal/load/pkg.go:29032932`, especially 29112918). Local
literals that do not enter that route are matched and directory-loaded by
`cmd/go/internal/modload/load.go:251307,526597` and
`cmd/go/internal/search/search.go:276293`. `runBuild` uses that loader at
`cmd/go/internal/work/build.go:459477`.
- **behavior directly implemented or asserted by pinned Go** — official
`cmd/go/testdata/script/list_ambiguous_path.txt:115,2936` directly proves
that directory `./foo.go` is a package while regular file `./a.go` is a
`command-line-arguments` package. Official
`cmd/go/testdata/script/mod_symlink_dotgo.txt:19,1117` directly asserts
that `dir.go -> dir` is not a source entry; `go/build/build.go:886900`
implements that directory-enumeration rule.
- **behavior derived from the pinned implementation** — because the initial
`Stat` follows the terminal symlink, a requested `.go` path whose target is a
directory takes the directory package route under build. That file-kind rule
applies directly to WW's existing local raw-source/directory distinction and
needs no module, manifest, registry, cache, network resolution, generalized
import syntax, or build expression.
#### Ownership and command boundary
- **directly measured WW behavior** — before this change, Cstage already
stat-routed a valid `visible_test.ww -> pkgdir` build, produced a normal
directory graph and executable, and returned status 0 with empty streams.
WWstage instead returned status 1, empty stdout, exact
`ww: cannot read source\n` stderr, and no artifact. The same split occurred
for `visible.ww -> pkgdir` and a real directory named `literal.ww`; a
`regular_test.ww` symlink to a regular source retained the aligned 11.51
omission.
- **directly measured WW behavior** — the true owner is the
requested-kind branch in `selfhost/cmd/ww/main.ww::dobuild`, after its
existing `Stat`, prefix exclusion, and non-directory `_test.ww` check and
before logical resolution. Cstage and both test fronts already have the
required classification and do not change.
- **behavior directly implemented or asserted by pinned Go** — `go run` has a
deliberately different front door: `cmd/go/internal/run/run.go:95112`
consumes leading `.go` suffix operands as named files without build/test's
directory guard, after which `GoFilesPackage` rejects a directory at
`cmd/go/internal/load/pkg.go:32743281`.
- **behavior derived from the pinned implementation** — therefore this slice
does not change the shared WW resolver or `ww run`. Multiple operands,
recursive patterns, logical names, ordinary directories, regular and
non-regular sources, dangling symlinks, raw `ww test`, `test -c`, and
`test -S` retain their existing front doors.
#### Build, test, package, and import effects
- **directly measured WW behavior** — build is the primary
axis. The selected request enters the same directory enumeration, graph,
action, output, and transaction route as its direct target and the Cstage
spelling. A requested `_test.ww` basename is only request metadata; ordinary
directory production selection still excludes actual `*_test.ww` entries.
- **directly measured WW behavior** — package selection is
the mechanism. The requested symlink spelling and physical target remain
loader/presentation metadata; downstream canonical local package, graph,
action, symbol, artifact, `.wwi`, publication, and persistence identities are
unchanged. No fake raw root or spelling-specific generation is created.
- **directly measured WW behavior** — imports are exactly
the selected directory package's existing dotted imports. The change adds no
qualifier, syntax, search order, edge kind, cycle rule, or identity. It makes
the established graph reachable instead of failing before directory load.
- **directly measured WW behavior** — raw `ww test` was already aligned because
both stages independently stat literal test requests. Running tests, `-c`
retained binaries, `-S` directory diagnostics, stdout/stderr, and binary
bytes matched through the `.ww` symlink before the build fix. Test-process
topology and `-run` matching are explicit non-effects.
#### Diagnostics, artifacts, and lifecycle
- **directly measured WW behavior** — CLI parsing,
multi-root/tree delegation, leading-prefix selection, and non-directory
`_test.ww` header diagnostics keep their precedence. After directory
selection, no-source, package/import/source, output, producer, publication,
and collision diagnostics use the existing directory order and requested
path presentation. The false raw-source read diagnostic disappears only for
this build route.
- **directly measured WW behavior** — file output,
output-directory publication, exact `/dev/null`, assembly-only `-S`, default
output, and persistent `-w` reuse use the existing directory actions and
transaction. Cold success creates the same units, `.wwi`, assembly, objects,
archives, initializer products, and optional executable as Cstage. Cold
source or producer failure commits no partial generation; warm injected
compiler failure and signaled-linker failure preserve every prior public and
semantic byte and leave no `.new`, install backup, or `.wwtxn.*`.
- **directly measured WW behavior** — source/import diagnostics, compiler
failure, and a signaled linker preserve the equivalent directory request's
prior output and work bytes. The focused concurrent row proves isolated
Cstage/WWstage selected requests. The classifier itself is request-local and
read-only; unchanged directory machinery continues to own assembler,
archiver, ordinary linker and publication failures, shared action locking,
driver interruption, process reaping, rollback, and filesystem cleanup.
- **directly measured WW behavior** — direct `SIGTERM` of either driver while a
selected warm build is blocked in compilation is an inherited lifecycle
non-effect, not part of the classifier change. Both stages terminate with
shell status 143, reap the complete owned process group, and preserve the
prior public output and committed semantic bytes, but the existing directory
machinery leaves three request-private `.new` files. That independently
verified cleanup gap remains open and this slice does not describe it as
fixed.
- **directly measured WW behavior** — Cstage and WWstage agree byte-for-byte
on status, stdout, stderr, diagnostics, public output, and every semantic
artifact for selected success and failure rows. Complete
within-stage preservation includes the invoking driver's `.wwtool.ww`
provenance snapshot; cross-stage semantic comparison excludes only those
intentionally different producer bytes.
The focused WW-native observer directly measures direct and symlinked `.ww`
directories, the visible `_test.ww` spelling, regular-file omission, directory
no-source and source/import precedence, a reachable dotted dependency,
default/file/directory/null/assembly outputs, cold and warm
reuse/invalidation/rollback, compiler failure and signaled-linker interruption,
runtime reachability, selected-route concurrency, cleanup, and the exact
test/run command boundaries. No serialized representation changes: build
workdir format remains `18`, test workdir format remains `19`, semantic storage
format remains `3`, and no cache or result record is added.
## 12. Candidate architectures and hard-gate decision
Five candidates were developed as coherent systems, not as feature bins.