11972 lines
758 KiB
Markdown
11972 lines
758 KiB
Markdown
# WW package, dependency, build, and bootstrap architecture
|
||
|
||
Status: **binding architecture decision**
|
||
|
||
Decision date: 2026-08-10
|
||
|
||
Implementation status: specified, not yet implemented
|
||
|
||
This document selects the production architecture that replaces WW's current
|
||
package driver, source-like interface protocol, work-directory reuse scheme,
|
||
Make orchestration, test coordinator, and bootstrap chain. It is a greenfield
|
||
decision. Migration effort is recorded only to plan implementation; it did not
|
||
influence the selection.
|
||
|
||
The words **MUST**, **MUST NOT**, **SHOULD**, and **MAY** are normative.
|
||
|
||
## 1. Executive decision
|
||
|
||
WW will have one integrated command backed by one typed, content-addressed
|
||
action graph. Language imports describe the language-package subgraph. A small,
|
||
declarative `ww.mod` file describes only facts that source imports cannot:
|
||
distribution requirements, products, generated inputs, native providers, and
|
||
unusual link steps. Both descriptions lower to the same graph, scheduler,
|
||
sandbox, cache, and explanation machinery. There is no general build language
|
||
and no arbitrary build script. A one-directory, zero-dependency executable
|
||
needs no manifest. Distributed projects use an exact lock file; fetching and
|
||
updating are explicit commands, while build, run, test, documentation, and
|
||
installation never access the network or rewrite project metadata. Packages
|
||
produce target-specific binary export data and one object, importers consume
|
||
only direct export data, and final products link a declared ordered closure.
|
||
Every cached action names its compiler, target, profile, tools, sysroot, runtime,
|
||
native inputs, environment, and content. The official toolchain owns these
|
||
protocols and ships a pinned tool closure, but WW does not permanently own an
|
||
assembler or linker.
|
||
|
||
The decisive insight is that **the package graph and the build graph are not the
|
||
same graph**. Imports are a complete and desirable description of WW-language
|
||
dependencies. They cannot honestly describe a C header tree, a host generator,
|
||
an assembler, a linker script, a CRT, or a sysroot. Making imports pretend to do
|
||
so hides native inputs; making every project use a programmable build framework
|
||
destroys the simple ordinary path. Two small declarative front ends lowering to
|
||
one action engine are simpler as a system than either lie.
|
||
|
||
The architecture is named **WW Action Build** in this document. That is a label,
|
||
not another user-facing product: the command remains `ww`.
|
||
|
||
### 1.1 The Pike lens and attribution
|
||
|
||
Pike explicitly documented and defended these Go design choices and principles:
|
||
|
||
- language-defined imports make dependencies explicit, clear, and mechanically
|
||
computable;
|
||
- unused imports and import cycles are errors; rejecting cycles improves package
|
||
boundaries and independent maintenance;
|
||
- compilation speed and short edit/build cycles are primary design properties;
|
||
- a direct dependency's compiled artifact can carry the deeper public type facts
|
||
needed by its clients, so an importer opens only direct dependency artifacts;
|
||
and
|
||
- orthogonal, predictable concepts, fewer ways to express a construct, and a
|
||
simple user experience are worth substantial implementation work.
|
||
|
||
Those points are stated in Pike's 2009 Go talk, the 2012 SPLASH article, and his
|
||
2015 simplicity talk
|
||
([2009 talk](https://go.dev/talks/2009/go_talk-20091030.pdf),
|
||
[2012 article](https://go.dev/talks/2012/splash.article),
|
||
[Simplicity is Complicated](https://go.dev/talks/2015/simplicity-is-complicated.slide)).
|
||
The collective Plan 9 papers add system-wide placement of complexity, focused
|
||
interfaces, and transparent text or explicitly encoded binary data. `Go in Go`
|
||
documents one contingent case in which owning more of the toolchain simplified
|
||
Go; it does not establish permanent toolchain ownership as a general Pike
|
||
principle ([Go in Go](https://go.dev/talks/2015/gogo.slide)).
|
||
|
||
Plan 9's `mk` constructs
|
||
the dependency graph before execution, rejects cycles and ambiguous recipes,
|
||
and schedules independent work in parallel. Plan 9 used a target-specific
|
||
compiler/assembler/loader family and portably encoded target object conventions
|
||
([mk](https://9p.io/sys/doc/mk.html),
|
||
[mkfiles](https://9p.io/sys/doc/mkfiles.html),
|
||
[compilers](https://9p.io/sys/doc/comp.html)).
|
||
|
||
Modern module-path/version semantics, Minimal Version Selection, `go.sum`, the modern Go build cache,
|
||
automatic toolchain selection, and current supply-chain policy are later Go-team
|
||
designs, not principles uniquely attributable to Pike
|
||
([module reference](https://go.dev/ref/mod),
|
||
[`go` command](https://go.dev/cmd/go/),
|
||
[toolchain selection](https://go.dev/doc/toolchain),
|
||
[toolchain rebuilding](https://go.dev/blog/rebuild),
|
||
[supply-chain policy](https://go.dev/blog/supply-chain)). This decision borrows
|
||
some invariants from those systems but does not attribute them to Pike.
|
||
|
||
The following are this document's inferences from the documented principles:
|
||
|
||
- strict directory packages and direct binary export data are the smallest way
|
||
to keep dependencies computable and compilation fast;
|
||
- a declarative native/action layer is necessary for an unmanaged language,
|
||
because omitting it moves complexity into ambient shell state;
|
||
- one shared action engine is simpler than independent language and outer-build
|
||
caches;
|
||
- given WW's complete-graph, frozen-build, and explainable-key hard gates,
|
||
arbitrary graph-producing programs are rejected; they would require executing
|
||
dependency host code before the graph is inspectable and add another permanent
|
||
user programming model; and
|
||
- WW should specify a toolchain closure but should not maintain an assembler and
|
||
linker forever when pinned external tools make the whole system smaller.
|
||
|
||
Modern native requirements force deliberate departures from historical Plan 9
|
||
and early Go: cryptographic source identities, lock files, explicit build/host/
|
||
target separation, sysroot and SDK identity, hostile dependency acquisition,
|
||
cross-platform sandboxes, and cache-miss explanations were not their complete
|
||
problem statement. WW adopts their architectural restraint, not their ambient
|
||
host assumptions.
|
||
|
||
### 1.2 What follows from being unmanaged and native
|
||
|
||
Being unmanaged/native genuinely requires the build model to know:
|
||
|
||
- the target data layout and C ABI;
|
||
- foreign symbol spelling and visibility;
|
||
- object format, relocation model, CPU features, and assembly dialect;
|
||
- ordered objects, archives, shared libraries, linker scripts, and archive-group
|
||
semantics;
|
||
- the libc, CRT, dynamic loader, SDK, runtime, and sysroot closure;
|
||
- freestanding entry and runtime policy;
|
||
- build-machine tools that generate host- or target-machine inputs; and
|
||
- ABI compatibility among compiler, runtime, native providers, and final link.
|
||
|
||
It does **not** follow that WW needs multiple dependency versions, semantic
|
||
version ranges, a network resolver in every build, programmable build scripts,
|
||
feature unification, a global namespace, or its own linker. In particular, the
|
||
absence of a garbage collector says nothing about version resolution.
|
||
|
||
### 1.3 Binding answers to the critical questions
|
||
|
||
| Question | Binding answer |
|
||
|---|---|
|
||
| Package identity | One canonical import path: the owning module identity for its root package, otherwise that identity plus `/` and the normalized package-relative path. The declared package name is a source qualifier, not identity. |
|
||
| Identity versus location/origin/version/content | All are separate. A resolver record maps identity and selected version to an origin and source-tree digest; a workspace maps identity to a local location. |
|
||
| Directory membership | Exactly one package per directory. Immediate selected source files belong to it. Nested directories never do. |
|
||
| Single-file packages | Deleted. A one-file directory package remains configuration-free. |
|
||
| Language dependency graph | The compiler-parsed imports alone define it. Manifest native/action edges extend the build graph, never the language graph. |
|
||
| Import interfaces | Direct dependencies only. Each direct `.wwe` contains the deep public type information needed to understand its own API. |
|
||
| `.wwi` | Deleted and replaced by deterministic, versioned binary `.wwe` export data. Canonical source prototypes are not an interchange format. |
|
||
| Package invalidation | The package action key changes when its selected own sources/generated inputs, direct export digests, compiler/toolchain, target/profile, declared environment, or protocol changes. A private transitive change does not invalidate it. |
|
||
| Cache key | Domain-separated SHA-256 over the canonical action record defined in section 6.6. |
|
||
| Cache scope | A per-user global local content store plus a project-local graph-history index. Remote import/export is explicit, never part of ordinary build. |
|
||
| Corruption/upgrades | Every object is rehashed on read; corrupt entries are quarantined. Tools and protocol versions are content inputs, so upgrades change keys. |
|
||
| Multiple versions | One selected version of a module identity. Incompatible major releases use distinct module identities ending `/vN`, so those identities may coexist. |
|
||
| Build scripts | Arbitrary scripts are forbidden. A finite declarative action may run a pinned build-machine tool in a denied-by-default sandbox. |
|
||
| Action authority | Exact readable inputs, writable outputs, argv, environment, execution platform, and tool closure. No network, shell, ambient `PATH`, clock, randomness, or undeclared filesystem access. |
|
||
| Acquisition | `add`, `update`, `lock`, `fetch`, `toolchain fetch`, cache transfer, and explicitly authorized remote observation may use the network. Artifact build/analysis and ordinary tests may not; running the finished user program is outside acquisition. |
|
||
| Manifest for a trivial program | No. A standalone directory containing a `main` package is sufficient. A manifest is required for distribution dependencies, multiple products, native providers, or generated inputs. |
|
||
| Configuration placement | Imports in source; identity, requirements, products, native declarations, and actions in `ww.mod`; exact selected closure in `ww.lock`; local paths in `ww.work`; ephemeral target/profile/output choices on the command line. |
|
||
| Local overrides | `ww.work` maps a module identity to a local source tree and records its observed digest. Imports do not change. |
|
||
| Target-specific files | A fixed filename-suffix selection rule; no source-level build expressions and no user-programmable selector. |
|
||
| OS distribution | A distributor may vendor the locked source closure or supply an exact `ww.work`/native-provider map. Substituted files and tools get new digests; frozen mode never silently consults the host. |
|
||
| Reproduction input | For supported official targets: project source, complete locked dependency-source bytes (vendor/CAS export), `ww.lock`, named immutable toolchain bundle, target/profile, and every declared external seed/signing input. Hashes without bytes are insufficient. Impure profiles forfeit the promise. |
|
||
| Assembler/linker ownership | No permanent ownership. The toolchain descriptor pins complete implementations. The current WW tools may bridge migration only. |
|
||
| Stage zero | One release-generated, checked-in portable C99 compiler snapshot plus a tiny declarative bootstrap plan and digest file. |
|
||
|
||
### 1.4 Corrective protocol boundary (2026-08-11)
|
||
|
||
The first Phase 0 experiment over-scoped the protocol freeze. It turned package
|
||
resolution, manifest parsing, compiler projections, action lowering, provider
|
||
recursion, graph traversal, scheduling, cache policy, failure precedence, and
|
||
bootstrap assertions into a declarative expression language. Its checker then
|
||
implemented those operations again. That experiment is preserved as recoverable
|
||
migration evidence, but it is not the production architecture.
|
||
|
||
The correction follows the separation visible in the pinned Go source. Go reads
|
||
imports from source with an imports-only parse and resolves them in ordinary
|
||
loader code ([`go/build/read.go`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/go/build/read.go#272),
|
||
[`cmd/go/internal/load/pkg.go`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/pkg.go#1775)).
|
||
The compiler writes a narrow export representation in compiler code
|
||
([`cmd/compile/internal/noder/writer.go`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/compile/internal/noder/writer.go)),
|
||
while `cmd/go` builds and schedules an in-memory action graph with ordinary Go
|
||
functions ([`work/action.go`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/action.go#85),
|
||
[`work/exec.go`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/exec.go#73)).
|
||
Action IDs and cache storage/validation are executable hashing and storage
|
||
operations, not schema programs
|
||
([`work.buildActionID`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/exec.go#260),
|
||
[`internal/cache`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/cache/cache.go#95)).
|
||
Go's `cmd/dist` performs concrete staged builds and checks that the final targets
|
||
are not stale. Separate compiler reproducibility tests compare repeated outputs
|
||
byte-for-byte, while the release process independently rebuilds and compares
|
||
archives bit-for-bit
|
||
([`cmd/dist/build.go`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/dist/build.go#1404),
|
||
[`reproduciblebuilds_test.go`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/compile/internal/test/reproduciblebuilds_test.go),
|
||
[`rebuild` account](https://go.dev/blog/rebuild)).
|
||
|
||
WW adopts that division, not Go's module/network/toolchain policy. Normal typed
|
||
C/WW code MUST own source loading, parsing, resolution, compiler behavior,
|
||
lowering, orchestration, storage, and bootstrap execution. Declarative schemas
|
||
MUST describe wire representation only. Tests MUST verify executable behavior;
|
||
a schema or proof-shaped record MUST NOT stand in for running it. A generator is
|
||
permitted only for repetitive codec data and MUST be small, generic,
|
||
deterministic, and byte-for-byte reproducible.
|
||
|
||
Phase 0 therefore freezes only WWAR framing and primitive canonical encoding;
|
||
record/enum/union tags, field order, encoded defaults and record kinds; exact
|
||
domain-separated digest and action-key byte formulas; compact positive and
|
||
malformed-wire vectors; a small reference codec; deterministic data-only codec
|
||
generation; and its repository gate. It does not freeze algorithms for deriving
|
||
the represented records. Every declared record tag remains encoded, including
|
||
an optional field's empty `encoded_default`; absence is not default insertion.
|
||
|
||
The owning implementation phases are binding:
|
||
|
||
| Behavior removed from the Phase 0 experiment | Owning phase |
|
||
|---|---|
|
||
| source imports, package graph/cycles, `.wwe`/`.wwlm`, compiler export and public type/ABI projections | Phase 1 |
|
||
| action construction, graph traversal, scheduling, CAS/cache, environment/sandbox and build failure behavior | Phase 2 |
|
||
| manifest/lock/work/vendor text parsing, module/source resolution, fetching, source-store policy and source-tree construction | Phase 3 |
|
||
| native/provider recursion, lowering, link-plan construction, tool adapters and platform policy | Phase 4 |
|
||
| actual staged bootstrap, fixed-point rebuild and byte comparison | Phase 6 |
|
||
|
||
WW-specific guarantees remain stronger and explicit: frozen artifact builds are
|
||
deterministic and offline, selections are locked, artifacts are content-addressed,
|
||
cached objects are rehashed on read, and bootstrap is established by rebuilding and
|
||
comparing actual bytes. At cutover there is one user-facing build path, as
|
||
already required by the migration plan.
|
||
|
||
## 2. Normative vocabulary
|
||
|
||
| Term | Exact meaning |
|
||
|---|---|
|
||
| **package** | The WW declarations selected from one directory, compiled together under one declared package name and one package identity. |
|
||
| **module** | A distributable, versioned source tree rooted by one `ww.mod`, declaring one globally stable module identity and containing zero or more packages. |
|
||
| **project** | The module or standalone package selected by the user's current command, including its declared products. |
|
||
| **workspace** | A local, non-published set of module-identity-to-directory overlays described by `ww.work`. It changes location, never identity. |
|
||
| **dependency** | A typed directed edge: package import, generated-input edge, tool edge, native-provider edge, runtime edge, ordered link edge, source-input edge, or bootstrap-record edge. A source-input edge is content-rooted and has no producer action; it is valid in template/final action inputs but never in `GraphEdgeV1`. A bootstrap-record edge selects the producer action-record or action-result record for `bootstrap.compare`. The edge kind is never implicit. |
|
||
| **target/platform descriptor** | A canonical architecture/platform/ABI/object/CPU/runtime description. An action labels descriptors by role: execution `B`, product `H`, and optional compiler-output `T`. A target triple is only a short lookup name. |
|
||
| **artifact** | An immutable byte string or canonical directory tree produced by an action and named by a content digest. Materialized files are copies or links, not the artifact's identity. |
|
||
| **toolchain** | An immutable descriptor and content closure containing the compiler, action protocol, export/ABI versions, target descriptors, resource files, runtime implementations, and pinned assembler/linker/archive tools. |
|
||
| **sysroot** | A content-identified target filesystem tree containing the exact headers, libraries, CRT objects, loader metadata, linker scripts, and SDK files exposed to target actions. |
|
||
| **source identity** | `sha256` of the canonical source-tree encoding in section 4.5. It is independent of download URL and checkout path. |
|
||
| **version** | An immutable SemVer release label associated with one module identity and one source identity. It is selection metadata, not package identity. |
|
||
| **product** | A named requested result: executable, static library, shared library, object bundle, test binary, generated tree, documentation tree, or toolchain component. |
|
||
| **action** | A pure, finite build step with a typed canonical record, declared input artifacts, one execution platform, and declared output paths. |
|
||
| **build platform (B)** | The platform on which the build actions execute. |
|
||
| **host platform (H)** | The platform on which the requested product will execute. |
|
||
| **target platform (T)** | For a compiler-like product, the platform for which that product emits code. It is absent for an ordinary executable or library. |
|
||
|
||
Module and package identities are slash-separated ASCII paths. They are
|
||
NFC-normalized, case-sensitive, contain no empty, `.` or `..` segment, and do
|
||
not depend on filesystem case folding. A non-root package identity is written
|
||
`module-id/package/path`; the root package identity is `module-id`. The selected
|
||
module catalog records which module owns each package identity. If two selected
|
||
modules would supply the same package identity, resolution fails rather than
|
||
choosing a longer prefix.
|
||
|
||
A no-manifest invocation gives its sole root package the reserved internal
|
||
identity `@standalone/root`; any external test package gets the reserved identity
|
||
`@test/<first-128-bits-of-SHA256(production-package-identity)>`. These namespaces cannot be
|
||
declared by a module or imported from ordinary source. The default standalone
|
||
executable materializes as `main`, independent of directory basename. A
|
||
standalone package cannot contain/import another local package or be published
|
||
until `ww init` gives it a stable module/package identity.
|
||
|
||
## 3. Source and package rules
|
||
|
||
### 3.1 One directory, one package
|
||
|
||
A package directory contains its immediate regular source files and source-name
|
||
symlinks that resolve to regular files. A source-name symlink to a directory is
|
||
ignored. Nested directories are separate packages. Every selected production
|
||
source MUST begin with the same canonical `package name;` clause. The declared
|
||
name MUST be a valid WW identifier. It need not repeat the directory leaf
|
||
because identity and source qualifier are separate concepts.
|
||
|
||
The following current forms are errors after the migration:
|
||
|
||
- importing a single `.ww` file as if it were a package;
|
||
- placing multiple package blocks in one compilation unit;
|
||
- satisfying an unresolved import from an inline package block;
|
||
- selecting a literal source file as the build root; and
|
||
- finding packages through ordered `-I` search roots.
|
||
|
||
`ww build ./cmd/tool` selects a directory. A directory with one source file is
|
||
still the smallest package and needs no extra metadata.
|
||
|
||
### 3.2 File membership and target selection
|
||
|
||
The current toolchain has one honest target, `linux/amd64`. Production
|
||
candidates are immediate visible names ending `.ww`, excluding selected
|
||
`*_test.ww` files. Directory entries beginning `.` or `_` are ignored. Candidate
|
||
names are byte-sorted before any selected source is opened, parsed, or checked.
|
||
|
||
WW applies Go 1.26.5's filename suffix algorithm to the portion of the basename
|
||
before its first dot. A final `_test` token is removed for this decision. If the
|
||
last two remaining underscore-delimited tokens are a known OS followed by a
|
||
known architecture, both must match `linux/amd64`. Otherwise a final known OS
|
||
or architecture must match. A known mismatch excludes the file; an unknown or
|
||
misplaced token leaves it ordinary. The pinned known sets are:
|
||
|
||
```text
|
||
OS: aix android darwin dragonfly freebsd hurd illumos ios js linux nacl
|
||
netbsd openbsd plan9 solaris wasip1 windows zos
|
||
ARCH: 386 amd64 amd64p32 arm armbe arm64 arm64be loong64 mips mipsle
|
||
mips64 mips64le mips64p32 mips64p32le ppc ppc64 ppc64le riscv
|
||
riscv64 s390 s390x sparc sparc64 wasm
|
||
```
|
||
|
||
The suffix requires a nonempty prefix and an underscore. Thus `linux.ww` and
|
||
`plan9_test.ww` are ordinary files, `x_plan9_test.ww` is excluded,
|
||
`x_linux_amd64.ww` is selected, and `x_windows_amd64.ww` is excluded. The first
|
||
dot ends inspection: `x.extra_windows.ww` is ordinary. Pair recognition takes
|
||
precedence over the final single token; `x_windows_amd64.ww` does not match just
|
||
because `amd64` does. Conversely `x_amd64_linux.ww` has no OS/architecture pair
|
||
and matches its final single `linux` token, exactly as Go does.
|
||
|
||
Selection is additive, not replacement-based: every matching file belongs to
|
||
the package. The production variant then excludes `*_test.ww`; internal and
|
||
external test classification uses only the already platform-selected test
|
||
files. After those decisions, distinct selected basenames in one canonical
|
||
directory MUST NOT be equal under Go 1.26.5's Unicode simple-fold comparison.
|
||
The check spans the production, internal-test, and external-test selections of
|
||
one `ww test` product without merging those source units. An ordinary
|
||
`ww build` sees production names only. Exact basename reuse by another action
|
||
view of that directory is not a collision.
|
||
|
||
An excluded file creates no source occurrence, collision, import, dependency
|
||
edge, package/action/variant identity, compiler input, export, archive member,
|
||
link input, artifact, status, or persistence dependency. Adding or editing one
|
||
is a producer no-op. Adding, removing, or editing a selected noncolliding file
|
||
changes the owning unit normally. This applicability is deliberately narrower
|
||
than Go's `Package.AllFiles`: WW omits wrong-platform and `*_test.ww` names
|
||
from an ordinary build because those files are not loaded in WW's
|
||
fixed-target, manifest-free source model.
|
||
|
||
WW implements no source-level build expressions, user tags, target descriptor,
|
||
`UseAllFiles` escape, `+tag` replacement scheme, or manifest-defined selector.
|
||
Those would introduce a second build language or a manifest model and are
|
||
outside the local, manifest-free product.
|
||
|
||
### 3.3 Imports, names, and resolution
|
||
|
||
The canonical forms are:
|
||
|
||
```ww
|
||
import "example.org/codec/hex";
|
||
import wire "example.org/protocol/hex";
|
||
```
|
||
|
||
The quoted string is the package identity. A module package may abbreviate its
|
||
own module prefix with a relative import written `import "./sub/path";`;
|
||
resolution replaces `./` with the importing module identity and normalizes the
|
||
remainder without permitting `..`. Bare dotted imports and filesystem imports
|
||
are deleted. Standalone packages cannot use relative imports.
|
||
|
||
The default source qualifier is the imported package's declared name. An alias
|
||
changes only that qualifier. Two imports producing the same qualifier are an
|
||
error unless one is explicitly aliased. Importing the same identity twice,
|
||
resolving one identity to two sources, or resolving two selected module records
|
||
to the same module identity is a loud collision error.
|
||
|
||
Resolution is exact:
|
||
|
||
1. Build the locked/workspace package catalog by joining every selected module
|
||
identity with its package directories.
|
||
2. Require exactly one catalog owner for the requested package identity; zero is
|
||
unresolved and two is an identity collision, even when one module prefix is
|
||
longer.
|
||
3. Verify that the catalog directory exists in that module source tree and has
|
||
the expected package clause.
|
||
4. Never search another root and never choose by filesystem accident.
|
||
|
||
Imports are parsed by the compiler front end, not a line scanner. Their union
|
||
forms package edges, but name visibility remains file-scoped. Every imported
|
||
qualifier must be used. Package cycles, including self-imports, are reported
|
||
before compilation with one stable identity path through the cycle.
|
||
|
||
If an import's catalog owner is outside the importing module, that owner MUST be
|
||
a direct `require` in the importing module's own `ww.mod`; availability through
|
||
another dependency is not enough. This keeps distribution dependencies as
|
||
explicit as package imports and prevents accidental reliance on a transitive
|
||
selection. `ww add` creates the requirement; source is never rewritten.
|
||
|
||
The sole exception is the toolchain's intrinsic standard module, whose identity
|
||
and source-tree digest are part of the selected toolchain descriptor. It is
|
||
available without a manifest requirement, including to a standalone package;
|
||
it is not searched from an installation directory or upgraded independently.
|
||
|
||
### 3.4 Visibility and internal packages
|
||
|
||
Existing exported-versus-private declaration rules survive. An `internal`
|
||
directory segment adds one resolution rule: a package under
|
||
`M/P/internal/Q` may be imported only by the package `M/P` or a package having
|
||
`M/P/` as a segment prefix. For `M/internal/Q`, the allowed root is module `M`
|
||
and its descendants. This is checked against the catalog's owning module and
|
||
package identities, not checkout paths. There are no friend lists or manifest
|
||
visibility overrides.
|
||
|
||
### 3.5 Tests, examples, documentation, and generated WW
|
||
|
||
Only `*_test.ww` files are test sources. `package p;` tests compile with package
|
||
`p`; `package p_test;` tests compile as a separate external package importing
|
||
the production package normally. Test sources of dependencies are never in a
|
||
consumer graph. `ww test .` tests one package; `ww test ./...` discovers package
|
||
directories under the selected module, excluding hidden, underscore-prefixed,
|
||
vendor, cache, and output directories. Discovery is deterministic and does not
|
||
follow directory symlinks. Test compilation is cached; each selected test binary
|
||
is executed on every command and independent binaries may run in parallel.
|
||
|
||
Each test invocation gets only its declared `test-data` mounted read-only under
|
||
`/data`, its literal `test-env`, a private writable temporary directory, and the
|
||
selected runner/runtime closure. Project/home/host files and network are denied.
|
||
Because execution is an observation rather than an artifact action, real clock,
|
||
process IDs, scheduling, and OS randomness may be exposed and are recorded as
|
||
runner capabilities; their output is never cached or part of byte reproduction.
|
||
|
||
The same-package test action uses the production package identity with the
|
||
non-importable action variant `same-test`; it compiles production and test
|
||
sources together so private names remain visible. An external test uses the
|
||
reserved `@test/<128-bit-production-identity-digest>` package identity and has a
|
||
normal direct import of the production package. Neither identity can collide
|
||
with or be imported by published source.
|
||
|
||
An example is an ordinary package or named product under `examples/`; it has no
|
||
special dependency semantics. Documentation is derived from source comments and
|
||
`.wwe` declarations, not by compiling examples during an ordinary build.
|
||
|
||
Generated WW source MUST be declared as an output of an action and as a generated
|
||
input of exactly one package. It uses the suffix `.wwgen`, does not appear in the
|
||
source tree, may not contain `import` or `package` clauses, and therefore cannot
|
||
discover new graph edges after graph construction. It may refer to built-ins and
|
||
declarations already in its owner package. A generator needing another package
|
||
must have a checked-in owner file that imports it. This restriction keeps the
|
||
complete package graph inspectable before executing generators.
|
||
|
||
A generated fragment may contain a foreign declaration only when the owning
|
||
`package` clause already names its provider slot and the declaration explicitly
|
||
names that slot. It cannot add a native requirement. After generation, the
|
||
compiler verifies imports/package clauses are absent and the observed foreign
|
||
slots exactly match the predeclared set; mismatch is a generator/protocol error.
|
||
|
||
## 4. Dependency distribution model
|
||
|
||
### 4.1 When metadata is required
|
||
|
||
A standalone one-directory executable with no non-toolchain dependency builds
|
||
without metadata. `ww init MODULE` creates a module when the program needs a
|
||
stable import identity, distribution dependencies, multiple packages/products,
|
||
generated inputs, or native declarations.
|
||
|
||
A module tree contains exactly one `ww.mod` at its root; nested manifests are an
|
||
error. A workspace composes separate module roots instead of nesting ownership.
|
||
|
||
`ww.mod` is declarative UTF-8 data. It is not WW code: it has no expressions,
|
||
variables, imports, include files, macros, loops, user functions, or host
|
||
conditionals. Strings use JSON escaping; lists preserve source order and record
|
||
key order is non-semantic. Unknown fields are errors unless a later manifest schema is explicitly
|
||
selected.
|
||
|
||
A minimal module is:
|
||
|
||
```text
|
||
ww-manifest 1
|
||
module = "example.org/hello"
|
||
language = "1"
|
||
toolchain = { id = "ww.org/toolchain", minimum = "v1.4.0" }
|
||
|
||
require "example.org/codec" {
|
||
minimum = "v1.2.3"
|
||
source-index = "https://example.org/codec/.well-known/ww-source"
|
||
}
|
||
```
|
||
|
||
The complete set of top-level clause kinds in schema 1 is `require`, `product`,
|
||
`package`, `action`, and `native`. Global scalar keys are only `module`,
|
||
`language`, and `toolchain`. `require` has required `minimum` and optional
|
||
credential-free `source-index`; the latter maps origin without changing identity.
|
||
The schema tables in section 6.9 close all remaining fields. There is
|
||
deliberately no general `[settings]` escape hatch.
|
||
|
||
The root `main` package is the default executable product, named after the
|
||
module's last segment, with explicit normalized linkage `dynamic` and runtime
|
||
`hosted`. Libraries need no product declaration to be imported.
|
||
Additional or non-default outputs are explicit:
|
||
|
||
```text
|
||
product "inspect" {
|
||
kind = "exe"
|
||
root = "cmd/inspect"
|
||
linkage = "dynamic"
|
||
}
|
||
```
|
||
|
||
### 4.2 Selection rule
|
||
|
||
Versions are `vMAJOR.MINOR.PATCH` SemVer labels with the usual prerelease order.
|
||
A requirement is one minimum version, never a range. Selection chooses the
|
||
greatest minimum requested for each module identity over the complete transitive
|
||
closure and repeats until stable. This is intentionally the small, monotonic
|
||
part of Minimal Version Selection, not every behavior of the Go module command.
|
||
The selected result is written exactly to `ww.lock` by `add`, `update`, or
|
||
`lock`; build never resolves a newer version.
|
||
|
||
Exactly one version of a module identity is selected. A backward-incompatible
|
||
major version `N >= 2` MUST declare a module identity ending `/vN`, and imports
|
||
name that identity. Consequently incompatible releases may coexist as distinct
|
||
identities without an aliasing version resolver. Two versions of the same
|
||
identity cannot coexist.
|
||
|
||
There are no feature sets, optional-dependency activation, target-dependent
|
||
version constraints, upper bounds, wildcard versions, or dependency-wide
|
||
configuration unification. Target variation belongs in source selection and
|
||
native-provider declarations after one source closure is selected.
|
||
|
||
The selected source manifests also contribute one minimum for the same
|
||
toolchain identity. The root lock chooses one exact installed/catalog version at
|
||
least as high as every minimum and records its descriptor/bundle digests. A
|
||
different toolchain identity or unsupported language/export/runtime protocol is
|
||
an error; SemVer alone never overrides protocol compatibility. Dependency
|
||
manifests do not pin the consumer to their development compiler, while an
|
||
application remains exactly reproducible from its lock.
|
||
|
||
### 4.3 Lock file
|
||
|
||
`ww.lock` is generated, canonical, and committed for applications and toolchains.
|
||
Published libraries SHOULD commit it for their own tests, but consumers resolve
|
||
from `ww.mod` requirements. A lock record is:
|
||
|
||
```text
|
||
ww-lock 1
|
||
root-manifest = "sha256:9c..."
|
||
toolchain "ww.org/toolchain" {
|
||
version = "v1.4.0"
|
||
descriptor = "sha256:31..."
|
||
bundle = "sha256:80..."
|
||
origin = "https://dist.wwlang.org/toolchain/v1.4.0/"
|
||
}
|
||
module "example.org/codec" {
|
||
version = "v1.2.3"
|
||
origin = "https://example.org/codec/.ww/v1.2.3.tar.zst"
|
||
archive = "sha256:4a..."
|
||
tree = "sha256:f7..."
|
||
manifest = "sha256:55..."
|
||
signature = "ed25519:key-id:base64..."
|
||
provenance = "https://example.org/codec/.ww/v1.2.3.intoto.jsonl"
|
||
}
|
||
```
|
||
|
||
Records are sorted by identity. Required semantic fields are version, immutable
|
||
origin, archive digest, canonical source-tree digest, and manifest digest.
|
||
Signature and provenance are optional records whose verification policy is
|
||
configured by the user or distributor; hashes are never optional. A signature,
|
||
when present, covers schema, module identity, version, tree digest, and manifest
|
||
digest. Lock files never contain local overlay paths or credentials.
|
||
|
||
### 4.4 Acquisition and network policy
|
||
|
||
`ww add M@V` discovers `M` by the HTTPS convention
|
||
`https://M/.well-known/ww-source`, unless `--from=URL` or a user-configured
|
||
longest-prefix source map supplies an index. The index returns immutable archive
|
||
locations and signed digest records. Redirects and the final URL are recorded.
|
||
The downloaded module manifest MUST declare exactly `M`; the signed index/lock
|
||
record, not source text, binds `V` to its tree digest. Private indexes use the
|
||
same protocol and obtain credentials from the fetch command's credential
|
||
helper; credentials never enter build actions or lock files.
|
||
|
||
`(module identity, version)` is immutable: observing two signed tree digests for
|
||
the same pair is an equivocation error recorded in the source store, never an
|
||
automatic replacement. Yank metadata may prevent new selection but cannot alter
|
||
or invalidate an already locked digest.
|
||
|
||
Only these operations may initiate network requests:
|
||
|
||
- `ww add`, `ww update`, and `ww lock` while selecting metadata;
|
||
- `ww fetch --locked` while materializing the already locked source/toolchain
|
||
closure;
|
||
- `ww toolchain fetch` for an explicitly named toolchain; and
|
||
- explicit `ww cache pull` and `ww cache push`; and
|
||
- explicitly authorized `ww observe` remote execution, which is not a build,
|
||
test-build, or cached artifact action.
|
||
|
||
The build/analysis phases of `ww build`, `run`, `test`, `doc`, `install`,
|
||
`graph`, and `explain` deny network access even when an input is absent. They report the missing source digest and
|
||
the exact `ww fetch --locked` command. They never modify `ww.mod`, `ww.lock`, or
|
||
`ww.work`. `--frozen` additionally requires those files to be present,
|
||
canonical, mutually consistent, and unchanged by selection. `--offline` is an
|
||
explicit assertion of the already mandatory no-network build policy.
|
||
|
||
### 4.5 Source identity and storage
|
||
|
||
A module source tree contains only directories and regular files; symlinks,
|
||
devices, sockets, FIFOs, absolute paths, `..`, duplicate normalized paths, and
|
||
case-fold collisions are rejected. Its identity is:
|
||
|
||
```text
|
||
SHA256("ww-source-tree-v1\0" ||
|
||
for each byte-sorted relative path:
|
||
LP(path) || type || executable-bit || LP(SHA256(file-bytes)))
|
||
```
|
||
|
||
`LP(x)` is an unsigned 64-bit big-endian byte length followed by `x`. Directory
|
||
entries are included with type `dir`; regular files with type `file`. Ownership,
|
||
timestamps, archive compression, checkout path, and non-executable permission
|
||
bits are excluded. Archives are checked both against their blob digest and the
|
||
unpacked tree digest. The source store is immutable and keyed by tree digest.
|
||
|
||
### 4.6 Workspaces, vendoring, and distributors
|
||
|
||
`ww.work` is local, declarative, and normally uncommitted:
|
||
|
||
```text
|
||
ww-work 1
|
||
use "example.org/codec" {
|
||
path = "../codec"
|
||
expect = "sha256:f7..."
|
||
}
|
||
```
|
||
|
||
An overlay replaces only the location for the named module identity. The module
|
||
at that path must declare the same identity. Its current canonical tree digest
|
||
is an action input; `expect` makes accidental drift loud but may be updated by
|
||
`ww work sync`. No import or lock identity changes.
|
||
|
||
`ww vendor` materializes every locked module under `vendor/sha256/<tree>` and
|
||
writes a canonical identity-to-tree `vendor/index.wwv`. Frozen builds may select
|
||
that source store with `--vendor`; the vendored bytes must match the lock. There
|
||
is no flattened import tree and no rewritten import statement.
|
||
|
||
An operating-system distributor has three honest options: ship this vendor
|
||
store, prefill WW's immutable source store, or provide an exact workspace/source
|
||
map to distro-owned trees. Native system libraries are substituted only through
|
||
the explicit provider mechanism in section 8.8. A mutable `/usr` lookup is an
|
||
impure system profile, is local-cache-only, and is rejected by frozen builds.
|
||
|
||
### 4.7 Closed metadata grammar
|
||
|
||
`ww.mod`, `ww.lock`, `ww.work`, vendor indexes, and toolchain/native descriptors
|
||
share this lexical grammar; each schema separately closes its allowed headers,
|
||
clauses, fields, value types, and cardinalities:
|
||
|
||
```text
|
||
document = header newline { statement } EOF
|
||
header = schema-name SP unsigned
|
||
statement = assignment | clause
|
||
assignment = key ws "=" ws value ws newline
|
||
clause = key ws string ws "{" newline
|
||
{ assignment } "}" ws newline
|
||
value = string | unsigned | boolean | list | record
|
||
list = "[" ws [ value { ws "," ws value } [ ws "," ] ] ws "]"
|
||
record = "{" ws [ pair { ws "," ws pair } [ ws "," ] ] ws "}"
|
||
pair = key ws "=" ws value
|
||
key = ALPHA { ALPHA | DIGIT | "_" | "-" }
|
||
string = JSON-string-with-valid-UTF-8
|
||
unsigned = "0" | ("1"…"9" { DIGIT })
|
||
boolean = "true" | "false"
|
||
ws = { SP | TAB | newline | comment }
|
||
comment = "#" { any-character-except-newline }
|
||
```
|
||
|
||
`schema-name` is exactly `ww-manifest`, `ww-lock`, `ww-work`, `ww-vendor`,
|
||
`ww-toolchain`, `ww-native-map`, `ww-native-sidecar`, `ww-install`, or
|
||
`ww-bootstrap`. A clause
|
||
body contains assignments only, so nesting cannot grow into a language.
|
||
Duplicate keys, duplicate singleton clauses, invalid UTF-8, unknown fields,
|
||
integer overflow, and a comment marker inside an unclosed string are errors.
|
||
|
||
Whitespace, comments, assignment order, record-key order, and clause order where
|
||
the schema declares identity keys are non-semantic. List order is semantic.
|
||
Parsing produces a typed record whose canonical semantic encoding is
|
||
`WWAR(record)`, not the original text. Its semantic digest is the applicable
|
||
kind/schema-bound `record_id` from section 6.6. `ww fmt` writes two-space
|
||
canonical text; generated lock/vendor files MUST already equal that rendering
|
||
in frozen mode.
|
||
|
||
## 5. Build model and graph construction
|
||
|
||
### 5.1 One graph, constructed before execution
|
||
|
||
For every command, `ww` constructs a typed graph in these deterministic phases:
|
||
|
||
1. Select the project, manifest, lock, workspace, toolchain descriptor, target,
|
||
and profile. Verify their schemas, canonical identities, and content digests.
|
||
Missing locked inputs are errors; this phase never fetches.
|
||
2. Enumerate selected checked-in package files by section 3.2. Ask the compiler
|
||
front end to parse package clauses, imports, checked-in foreign declarations,
|
||
and test metadata. Generated artifacts are known future input slots but do not
|
||
yet exist. The build driver never scans source lines itself.
|
||
3. Resolve every import by identity, reject collisions/internal violations, and
|
||
compute the complete acyclic package graph.
|
||
4. Add statically declared generated-input, host-tool, native-provider,
|
||
toolchain, runtime, archive, ordered link, and bootstrap-record comparison
|
||
edges. Match target clauses and reject zero or multiple providers. All
|
||
generated output names and consumers are known here.
|
||
5. Lower nodes to the complete **action-template DAG** and report it. A template
|
||
names every edge/input slot, tool, policy, and output, but its final key remains
|
||
unresolved until every predecessor output or selected record content digest
|
||
is known. Only after this point may a cache be read or a tool execute.
|
||
6. As verified cache results or completed predecessors resolve input artifacts,
|
||
finalize ready action records/keys, query the cache, schedule misses, publish
|
||
successful artifacts atomically, then materialize requested products.
|
||
|
||
No executed action may add a node, input, output, import, library, flag, or
|
||
follow-up command. Native C/assembly declarations name complete header/source
|
||
trees rather than learning dependencies from an ambient compiler depfile. This
|
||
may conservatively rebuild for an unused header change, but the graph remains
|
||
complete before execution and the key is correct.
|
||
|
||
`ww graph --actions --format=json` emits the graph after phase 5. Its canonical
|
||
JSON contains node kind, execution platform, typed input/output slots, incoming
|
||
edge kinds, target/profile/toolchain digests, and the exact ordered link plan.
|
||
A resolved node also has its key/cache status; otherwise it has `key: "pending"`,
|
||
`cache: "unknown"`, and a byte-sorted `waiting-on` list. It contains logical
|
||
paths only. A collision, cycle, missing provider,
|
||
undeclared target, or unresolved tool fails graph construction even if a stale
|
||
cache entry might otherwise satisfy the product.
|
||
|
||
### 5.2 Built-in action kinds
|
||
|
||
Schema 1 has this closed set of semantic action kinds:
|
||
|
||
- `ww.package`: compile one package to export data, object code, and link
|
||
metadata;
|
||
- `ww.init`: synthesize one deterministic retained package-initialization
|
||
dispatcher from precomputed package link metadata;
|
||
- `native.compile`: compile one declared C or assembly source unit;
|
||
- `archive`: construct a static library from an ordered object list;
|
||
- `link`: construct an executable or shared library from an ordered link plan;
|
||
- `generate`: execute one declared build-platform tool;
|
||
- `doc`: render a documentation tree from sources and export data;
|
||
- `bootstrap.compare`: compare canonical stage outputs and manifests.
|
||
|
||
Adding an action kind changes the action schema. There is no generic rule engine,
|
||
phony target, implicit suffix rule, command-string target, or shell recipe. An
|
||
archive is made only for an explicit static-library product or native provider;
|
||
WW packages are not automatically wrapped in one-member archives.
|
||
|
||
`run` and `test.run` are non-cacheable invocation nodes, not semantic artifact
|
||
actions. `test.run` consumes the declared data/environment/runner and uses the
|
||
test sandbox above on every request. `ww run`, after its network-denied build,
|
||
launches the user's program with the user's runtime authority/environment unless
|
||
`--sandbox` is explicitly requested; that execution still cannot affect a build
|
||
cache entry. Both store exit status/logs only as observations. Materialization/install is a third category:
|
||
a request-local side effect consuming an immutable artifact/install manifest.
|
||
Neither category can satisfy or poison an artifact-action cache entry.
|
||
|
||
The semantic graph is independent of process boundaries. An implementation MAY
|
||
run compiler workers in-process or in a bounded pool, but each `ww.package`
|
||
action still has an independent canonical record and outputs. There is no
|
||
required background daemon and no daemon state may affect an output.
|
||
|
||
### 5.3 The finite escape hatch
|
||
|
||
Unusual generation and packaging use a declarative `action`, not a build script:
|
||
|
||
```text
|
||
action "protocol-bindings" {
|
||
tool = "product:tools/schema-gen"
|
||
platform = "build"
|
||
inputs = {
|
||
schema = { file = "protocol/schema.idl" }
|
||
}
|
||
outputs = {
|
||
ww = { file = "generated/protocol.wwgen" }
|
||
}
|
||
argv = ["--input", "/in/schema", "--ww", "/out/ww"]
|
||
env = { LANG = "C", TZ = "UTC" }
|
||
}
|
||
|
||
package "protocol" {
|
||
generated = ["action:protocol-bindings:ww"]
|
||
}
|
||
```
|
||
|
||
The tool is either a named executable in the immutable toolchain or a named WW
|
||
product built for `H = B`. `/in/NAME` inputs are read-only mounts and
|
||
`/out/NAME` outputs are initially absent, exclusive writable mounts. The working
|
||
directory is the empty logical `/work`. Output type is exactly `file` or `tree`;
|
||
undeclared files fail the action. `argv` is passed directly, never through a
|
||
shell. Input and output names are identifiers and each path appears through its
|
||
fixed mount, so there is no template language.
|
||
|
||
The sandbox exposes only the declared tool closure at fixed logical `/tool`
|
||
paths, `/in`, `/out`, the literal
|
||
environment map, deterministic locale/time-zone data, and bounded CPU/memory
|
||
resources. Network, process inspection, host devices, user/home directories,
|
||
ambient `PATH`, ambient environment, wall clock, writable source, and filesystem
|
||
paths outside the mounts are denied. Randomness is absent unless a declared
|
||
seed artifact is mounted. A tool may spawn only executable inputs declared in
|
||
its tool closure. These isolation rules apply equally to built-in compiler, C,
|
||
assembler, archiver, linker, documentation, test, and bootstrap executions.
|
||
Strong enforcement is required for frozen/shared-cache builds;
|
||
an unsupported host must fail rather than silently weaken isolation.
|
||
|
||
This action can perform arbitrary computation over finite declared inputs, so it
|
||
is sufficient for code generators, image/file-system builders, binding tools,
|
||
and signing-input preparation. It cannot inspect the project and invent more
|
||
work. Dependency modules may declare actions only for outputs consumed by their
|
||
own packages/products; they cannot register hooks that run merely because the
|
||
module is present.
|
||
|
||
Every artifact-producing action declares `reproducibility = "required"` in a
|
||
frozen or official build. Isolation removes undeclared external inputs, but it
|
||
cannot prove that arbitrary tool internals avoid PIDs, uninitialized memory,
|
||
ASLR-derived values, or race-dependent output. Such variance is a tool/action
|
||
defect. Official releases and first shared-cache publication of a custom
|
||
generator repeat it from clean sandboxes and compare outputs. A node explicitly
|
||
classified `observation` is never result-cached/shared and may not feed an
|
||
artifact action; tests and hardware execution use that class. Impure development
|
||
actions are local-only and outside the byte promise.
|
||
|
||
### 5.4 Build, host, and target
|
||
|
||
WW uses the conventional three-platform meaning rigorously:
|
||
|
||
```text
|
||
B: execution platform on which build actions run
|
||
H: platform ABI of the produced artifact; executable products are intended to run here
|
||
T: output platform of a compiler-like artifact that itself is built for H
|
||
```
|
||
|
||
For an ordinary program `T` is absent. The familiar
|
||
`ww build --target=aarch64-unknown-linux-gnu` spelling sets `H`; it means “build
|
||
the program that runs on this target.” A compiler product may additionally set
|
||
`--host=H --target=T`. Any generator used while producing it still executes on
|
||
`B`; if the generator is itself WW source, its product is compiled with `H = B`.
|
||
|
||
Every action record carries all applicable descriptors, even when two are equal.
|
||
No rule may infer `H` or `T` from the kernel running `ww`. Cross compilation is
|
||
therefore the same graph with a different explicit host/target descriptor, not
|
||
a mode that edits environment variables.
|
||
|
||
In record/JSON field names these are `execution-platform`, `product-platform`,
|
||
and optional `compiler-output-platform`. Source suffix selection, ordinary
|
||
native-provider `when`, sysroot, CRT, runtime, and linker selection always match
|
||
the product platform H. A build-tool dependency instead has its own H equal to
|
||
the parent action's B. CLI `--target` is only the familiar spelling for selecting
|
||
the ordinary product platform; it does not rename the GNU roles internally.
|
||
|
||
### 5.5 Scheduling and failure
|
||
|
||
After graph construction, ready actions run in a deterministic priority order
|
||
with a user-selected concurrency bound. Priority affects latency only; output
|
||
bytes and link order come from records, never completion order. Independent
|
||
actions may finish after another branch fails, but no dependent action starts.
|
||
On the first observed failure WW stops launching work and cancels its owned
|
||
in-flight actions. Which failure triggers cancellation is observational and may
|
||
vary with concurrency; every concurrently observed failure is sorted by stable
|
||
logical node in the report. `--keep-going` instead continues branches whose
|
||
dependency closure remains healthy and reports all failures in that stable
|
||
order. Interrupts cancel only processes owned by this invocation and leave no
|
||
published partial result.
|
||
|
||
Tool stdout and stderr are captured as artifacts and streamed with node labels.
|
||
Diagnostics use module-relative logical paths. `--verbose` may display physical
|
||
mount paths separately, marked non-semantic. A successful action is published
|
||
only after all declared outputs exist, have valid type/mode, are canonicalized
|
||
where required, and have been hashed. A failed action is never entered in the
|
||
action cache.
|
||
|
||
### 5.6 Atomic publication and materialization
|
||
|
||
CAS files and action-result records are written to same-filesystem unique
|
||
temporary names, flushed, rehashed, then atomically renamed to their digest
|
||
locations. For crash durability, WW flushes the parent directory after rename;
|
||
it publishes and flushes every output before the result mapping. A concurrent
|
||
publisher of the same digest verifies equality and
|
||
discards its temporary file. A directory artifact is a canonical tree object
|
||
whose leaves are CAS blobs. An action-result mapping is published last, so no
|
||
reader can observe a result before its outputs.
|
||
|
||
Materialization is a request-local side effect outside the action-template DAG.
|
||
By default requested
|
||
products appear in `out/<target>/<profile>/`; `--out` and `ww install --prefix`
|
||
change only where immutable artifacts are copied or copy-on-write reflinked.
|
||
Hardlinks/symlinks are permitted only when the backing store is enforced
|
||
immutable against the user and mode changes cannot affect its inode. Executable bits are
|
||
set by the artifact record, never by a later ambient `chmod`. Replacement uses
|
||
temporary siblings and atomic rename. `ww clean` removes materialized/project
|
||
state only; `ww cache gc` is the separate explicit global-cache operation.
|
||
|
||
### 5.7 Reproducibility contract
|
||
|
||
For official supported targets, WW promises byte-identical artifacts when every
|
||
artifact action satisfies `reproducibility = "required"` and these are identical:
|
||
|
||
- canonical project source and `ww.lock`;
|
||
- immutable toolchain descriptor and complete bundle;
|
||
- target descriptor and build profile; and
|
||
- all declared action inputs, including generated seeds and signing material.
|
||
|
||
The engine guarantees input isolation, logical paths, and canonical publication;
|
||
repeat-build certification checks arbitrary tool determinism. The resulting promise is independent of absolute checkout, source-store, cache, output,
|
||
and temporary paths; wall time, locale, process order, username, UID, and host
|
||
environment are absent. Logical paths are module/package paths. Debug information
|
||
uses those logical paths and fixed prefix maps. Archive metadata is canonical;
|
||
timestamps and ownership are zeroed; deterministic linker build IDs derive from
|
||
the link key. Official toolchains reject tools that cannot meet this contract.
|
||
|
||
A project source archive plus the complete locked dependency source bytes (a
|
||
vendor/source-CAS export), its lock, the named immutable toolchain bundle, and
|
||
every declared external seed/signing input is therefore a complete offline
|
||
reproduction input. A lock's hashes alone cannot recreate absent bytes. Runtime behavior that depends on a shared library
|
||
outside the pinned runtime/sysroot closure is not covered, and frozen official
|
||
profiles prohibit such a dependency. An explicitly selected impure system
|
||
profile receives no byte-identity promise, cannot publish to a shared cache, and
|
||
prints every ambient input it accepted. `ww verify reproducible` runs isolated
|
||
uncached builds under two physical roots and compares every result artifact and
|
||
action manifest, not just the final executable.
|
||
|
||
## 6. Action records and cache protocol
|
||
|
||
### 6.1 Canonical encoding
|
||
|
||
Action records use **WWAR 1**, this deterministic byte encoding:
|
||
|
||
```text
|
||
WWAR(record) = 0x57 0x57 0x41 0x52 | u16be(1) | value(record)
|
||
value(v) = type:u8 | u64be(payload-length) | payload
|
||
|
||
type 0x01 bytes: payload is the bytes
|
||
type 0x02 string: payload is valid NFC UTF-8 with no NUL
|
||
type 0x03 uint: payload is minimal unsigned big-endian; zero is one 0x00
|
||
type 0x04 bool: payload is exactly 0x00 or 0x01
|
||
type 0x05 list: u32be(count) | each (u64be(value-length) | value)
|
||
type 0x06 map: u32be(count) | each (u64be(key-length) | key-UTF-8 |
|
||
u64be(value-length) | value)
|
||
type 0x07 record: u32be(count) | each (u32be(field-tag) |
|
||
u64be(value-length) | value)
|
||
```
|
||
|
||
Record fields are strictly increasing by numeric tag. Map entries are strictly
|
||
increasing by raw UTF-8 key bytes. Duplicate/out-of-order keys or tags, leading
|
||
zeroes in a uint, invalid booleans/UTF-8/NFC, mismatched counts/lengths, unknown
|
||
schema tags, and trailing bytes are errors. Lists preserve declared order.
|
||
Schema defaults are always encoded, so no semantic field is inferred from
|
||
absence. Floats, signed integers, null, and indefinite lengths do not exist.
|
||
|
||
One byte string/string is at most `2^31-1` bytes, a container has at most
|
||
`2^24-1` members, and nesting depth is at most 64. A content/container-relative
|
||
logical path string uses `/`, is relative, has no NUL/backslash, empty/`.`/`..`
|
||
segment, and passes the schema's ASCII-identity or NFC-source-path rule. A field
|
||
that explicitly permits `.` as its complete root sentinel is the sole exception.
|
||
These are protocol limits, not host `size_t` limits. Human-readable JSON is a
|
||
lossless rendering, not the hashed representation. Phase-0 golden vectors
|
||
include empty/nested records, ordered lists, sorted maps, every rejection, and
|
||
their complete bytes/digests.
|
||
The normative empty-record vector is
|
||
`57574152000107000000000000000400000000`, SHA-256
|
||
`138c6acb7f01e91df73cb1d9c3356d18f19d7b8eb8b0a15426bef32e515d0de0`.
|
||
|
||
Each schema assigns every path field a path class. Artifact, source, generated
|
||
output, install-destination, bundle-relative, sysroot-relative, and
|
||
vendor-relative paths use the relative rule above. Sandbox-execution paths are
|
||
path-independent absolute paths only in the closed virtual namespaces `/work`,
|
||
`/in`, `/out`, `/tool`, and `/data`; schema-1 action working directory is exactly
|
||
`/work`, and exact sandbox path spellings in argv are encoded. Platform-validated
|
||
target-runtime paths are a separate type and may be absolute in H's namespace.
|
||
Workspace locations and observation physical paths are separately typed and
|
||
never enter an artifact action record or key as host locations. Absolute host
|
||
paths, filesystem device/inode numbers, mtimes, cache locations, and command
|
||
process IDs are invalid in action templates and final action records. A physical
|
||
input enters only through a logical name, content digest, type, and semantic
|
||
mode.
|
||
|
||
### 6.2 Required action-record fields
|
||
|
||
Every record contains, in this order:
|
||
|
||
1. WWAR schema and action kind/version;
|
||
2. language edition, compiler protocol, export protocol, object ABI, runtime ABI,
|
||
manifest schema, and lock schema;
|
||
3. B, H, and optional T descriptor digests plus the expanded target fields;
|
||
4. toolchain identity, selected descriptor-slice/closure digest,
|
||
compiler/backend digest, and every executable/shared/resource digest actually
|
||
used by the action; the distribution bundle root/version authenticates
|
||
acquisition but unused targets/tools do not invalidate this action;
|
||
5. profile fields: optimization, debug, assertions, overflow, panic, sanitizers,
|
||
LTO, relocation/code model, symbol stripping, and reproducibility policy;
|
||
6. logical package/product/action identity and sandbox-virtual working directory
|
||
(schema 1 exactly `/work`);
|
||
7. exact argument vector and a sorted literal environment map;
|
||
8. byte-sorted named inputs, each with edge kind, logical path, semantic artifact
|
||
kind, semantic mode, content digest, and—where applicable—origin package identity;
|
||
9. direct export-data inputs byte-sorted by package identity for `ww.package`
|
||
actions;
|
||
10. selected source-membership list and target-selection explanation;
|
||
11. typed native declarations: headers, objects, archives, shared libraries,
|
||
sysroot, SDK, libc, CRT, dynamic loader, linker scripts and their include
|
||
closures, assembler/linker/archive tools, and ABI-provider slots;
|
||
12. the exact ordered link plan, retaining archive groups, whole-archive markers,
|
||
as-needed state, and repeated libraries;
|
||
13. named output paths, types, modes, and canonicalization policies; and
|
||
14. sandbox policy/version, resource bounds, and reproducibility classification.
|
||
|
||
Fields irrelevant to an action are encoded as empty values, not inferred. Native
|
||
flags exist only as typed fields whose meaning is part of a tool adapter. A raw
|
||
flag can be used only in a custom toolchain declaration and then its exact bytes
|
||
are part of the record; the official profile has no hidden default flags.
|
||
|
||
### 6.3 Environment and tool discovery
|
||
|
||
No inherited environment variable is semantic. Built-in actions receive the
|
||
fixed environment specified by their toolchain adapter. A declarative action
|
||
receives only its `env` record. `PATH`, compiler-driver defaults, `pkg-config`,
|
||
shell initialization, host include/library directories, and current directory
|
||
are never consulted to discover an input.
|
||
|
||
User configuration may choose a cache location, concurrency, output directory,
|
||
credential helper, source mirror, or display preference; these do not enter an
|
||
action because they cannot alter output bytes. Choosing a toolchain, target,
|
||
profile, workspace overlay, native provider, environment value, raw option, or
|
||
impure system mapping can alter bytes and therefore always enters the record.
|
||
|
||
### 6.4 Package action inputs and invalidation
|
||
|
||
A `ww.package` action consumes:
|
||
|
||
- the exact selected production or test source files and generated fragments;
|
||
- their ordered membership metadata;
|
||
- only the `.wwe` artifacts of direct imported packages;
|
||
- the compiler/backend and toolchain resources;
|
||
- B/H/T, target descriptor, profile, language/compiler/export/object/runtime
|
||
protocols, and manifest/lock schemas;
|
||
- package-specific predeclared native-provider slots, distinct from selected
|
||
concrete provider declarations; and
|
||
- its literal built-in environment and sandbox policy.
|
||
|
||
It emits `.wwe`, one target object, and canonical link metadata. A private change
|
||
in a dependency changes that dependency's object and the final link key, but not
|
||
the importer's action key. A public change changes the dependency's `.wwe` and
|
||
therefore its direct importers. If a rebuilt importer emits byte-identical
|
||
`.wwe`, the invalidation stops there. Link-only input changes only invalidate
|
||
link/archive actions; materialization merely recopies a newly selected immutable
|
||
artifact when its requested result digest changes.
|
||
|
||
A package's own source bytes remain part of its action key even if a compiler
|
||
could prove a change dead. A target/profile/tool/runtime ABI change creates a
|
||
different key. There is no timestamp freshness shortcut and no “artifact exists”
|
||
predicate.
|
||
|
||
### 6.5 Link action inputs
|
||
|
||
The link action consumes every reachable package/native object digest, explicit
|
||
archive/shared-library digest, CRT object, runtime object, dynamic-loader choice,
|
||
linker script closure, sysroot descriptor, target/profile, exact linker tool and
|
||
resources, and the ordered plan. Objects are ordered by stable package identity;
|
||
an explicit static product's `members` list controls only that archive's member
|
||
order. Native archives retain declared
|
||
order; repeated archives remain repeated; group and whole-archive boundaries are
|
||
semantic. `-L`/`-l` token collections are not an internal representation.
|
||
|
||
The link result is cacheable. A warm identical build need not invoke the linker.
|
||
Changing output/materialization path alone does not change the link key. Changing
|
||
a private package implementation normally preserves importer objects but changes
|
||
the final link key through that package's object digest.
|
||
|
||
### 6.6 Complete cache-key formula
|
||
|
||
Let `R` be the complete WWAR record from sections 6.2–6.5. The action key is:
|
||
|
||
```text
|
||
K = SHA256("WW-ACTION-KEY\0" || uint64be(len(WWAR(R))) || WWAR(R))
|
||
```
|
||
|
||
Input entries contain the SHA-256 digest of their canonical artifact bytes/tree,
|
||
not merely the producer's action key. Thus semantically identical outputs stop
|
||
rebuild propagation even when their producing source/action key changed. Ordered
|
||
fields remain ordered; only fields specified as maps are sorted. The domain
|
||
separator and schemas prevent a digest from one protocol being reinterpreted in
|
||
another.
|
||
|
||
A successful result record contains `K`, result-schema version, output
|
||
name/type/mode/digest tuples only. Stdout, stderr, exit/diagnostic presentation,
|
||
timing, worker identity, resource use, and physical paths go in a separate
|
||
invocation-observation record. Thus one action key has exactly one semantic
|
||
successful result even if its logs differ. Observation records may be
|
||
content-addressed, but never participate in action mapping, cache hits, or
|
||
reproducibility comparison.
|
||
|
||
CAS identities are type-separated. Blob bytes use their own domain; every
|
||
structured object is additionally bound to its top-level record kind and schema:
|
||
|
||
```text
|
||
blob_id = SHA256("WW-BLOB\0" || u64be(length) || bytes)
|
||
|
||
record_id(kind, schema, record) =
|
||
SHA256("WW-RECORD\0" || u32be(kind) || u32be(schema) ||
|
||
u64be(length(WWAR(record))) || WWAR(record))
|
||
```
|
||
|
||
Schema 1 reserves these top-level `kind` numbers: 1 tree, 2 manifest, 3 lock,
|
||
4 workspace, 5 vendor index, 6 native map, 7 platform descriptor, 8 toolchain,
|
||
9 profile, 10 action template, 11 action record, 12 action result,
|
||
13 observation, 14 graph snapshot, 15 native sidecar, 16 native ABI contract,
|
||
17 link plan, 18 export, 19 package link metadata, 20 install manifest,
|
||
21 bootstrap plan, and 22 selected-tool closure. An unknown kind is never
|
||
decoded as another record. `TypedDigestV1` is a record with tag 1 domain
|
||
(`blob` or `record`), tag 2 algorithm (schema 1 only `sha256`), tag 3 record kind
|
||
(`0` for a blob), tag 4 record schema (`0` for a blob), and tag 5 the exact
|
||
32 digest bytes. A field whose type is “typed digest” always means this record;
|
||
a bare hexadecimal string is only a text rendering.
|
||
|
||
A tree record is schema 1 plus a list sorted by entry-name UTF-8 bytes. An entry
|
||
is `(name, kind=file|tree, executable:boolean, typed-child-digest)`. `name` is
|
||
one normalized path segment. Empty directories are explicit tree children;
|
||
symlinks, hardlink identity, devices, xattrs, uid/gid, mtimes, and non-executable
|
||
permission bits do not exist. Duplicate normalized or case-fold-colliding names
|
||
are errors. Validation recursively checks every typed child to a blob; verifying
|
||
only a root digest is insufficient.
|
||
|
||
### 6.7 Storage, sharing, and corruption
|
||
|
||
The default cache is per-user, global across that user's checkouts, local, and
|
||
private to the account:
|
||
|
||
```text
|
||
<cache>/v1/cas/sha256/aa/bb...
|
||
<cache>/v1/actions/sha256/aa/bb...
|
||
<cache>/v1/quarantine/
|
||
```
|
||
|
||
The first path stores blob objects and kind/schema-bound structured records; the
|
||
second maps an action key to `(action-record digest, result-object digest)`. A small ignored
|
||
project index `.ww/state-v1` references the previous successful graph snapshot,
|
||
whose logical nodes point to action-record/key/result digests. It roots that
|
||
history until replacement so explanation can compare records and follow causes;
|
||
it is disposable and never proves freshness. After explicit GC removes history,
|
||
`explain` reports `history-unavailable` rather than inventing “stale.” A
|
||
system-wide cache service requires authenticated isolated writers and the same
|
||
signed-mapping policy as a remote cache.
|
||
|
||
On every cache read, WW verifies the requested object's digest and canonical
|
||
type, decodes the mapped action record, recomputes `K` from it, and requires
|
||
`recomputed K = lookup K = ActionResultV1.tag2` plus
|
||
`ActionResultV1.tag3 = the mapping's typed action-record digest`. It then verifies
|
||
all output objects before use or materialization. A mismatch moves only that
|
||
explicit entry to quarantine, removes its action mapping, reports corruption,
|
||
and rebuilds.
|
||
`ww cache verify` walks the store; `ww cache gc` traces retained action results
|
||
and materializations. A tool upgrade changes its content/descriptor fields and
|
||
cannot reuse the old key.
|
||
|
||
If two executions of one `reproducibility=required` action key produce different
|
||
semantic result digests, WW publishes neither as an authoritative replacement,
|
||
records both observations/artifact sets in quarantine, and fails with a
|
||
nondeterminism diagnostic. Impure actions have no reusable action mapping.
|
||
|
||
Shared caches are opt-in explicit transports. `ww cache pull` imports only
|
||
content-addressed objects and action mappings in an Ed25519 signed envelope over
|
||
`"WW-CACHE-MAP\0"`, cache namespace, action key, action-record digest, result
|
||
digest/schema, and reproducibility/policy classification. The envelope carries
|
||
a signing-key ID; configured trust policy handles rotation/revocation. Hashes
|
||
prove bytes; the trusted cache signing key authorizes the asserted key-to-result
|
||
mapping. All hashes are reverified. An unsigned/untrusted mapping is treated as a miss
|
||
even if its referenced blobs exist. `ww cache push` refuses impure,
|
||
non-reproducible, secret-bearing, or policy-incompatible actions. Literal secret
|
||
environment values are forbidden; a required secret is a classified file input,
|
||
redacted from JSON/explain, and makes the action non-shareable. Ordinary build
|
||
does not contact a shared cache.
|
||
|
||
### 6.8 Explainability
|
||
|
||
For every node, WW retains its last local record and current record. `ww explain
|
||
NODE` reports one of `hit`, `not-built`, `missing-result`, `corrupt-result`,
|
||
`policy-rejected`, or `key-changed`. For `key-changed` it prints the first and,
|
||
with `--all`, every differing typed field, for example:
|
||
|
||
```text
|
||
codec/hex: key changed
|
||
input direct-export example.org/base: 71… -> a4…
|
||
caused by base: exported type Header layout changed
|
||
link hello: key changed
|
||
package-object example.org/codec/hex: 19… -> 27…
|
||
```
|
||
|
||
`ww explain --path NODE` follows the shortest changed-input path to a source,
|
||
tool, target, native provider, or policy root. `--format=json` exposes both WWAR
|
||
renderings and field paths. Export-data differences use the normative `ExportV1`
|
||
semantic field/type diff; if old content was explicitly GC'd the command reports
|
||
`history-unavailable`. Cache misses are never explained merely as “stale.”
|
||
|
||
### 6.9 Version-1 semantic record schemas
|
||
|
||
The following tables freeze schema-1 semantic fields and WWAR numeric tags.
|
||
`1` means exactly one, `0/1` optional, `*` a list, and `map` unique string keys.
|
||
Every absent optional value encodes the stated empty/default. Identity-keyed
|
||
lists are byte-sorted by identity; lists marked `ordered` preserve source/link
|
||
order. Nested records use the field tags in their named table. Enums reject
|
||
unknown values rather than passing them to a tool.
|
||
|
||
#### Project and distribution records
|
||
|
||
| Record/tag | Field | Type/cardinality | Rule/default |
|
||
|---|---|---|---|
|
||
| `ManifestV1/1` | schema | uint/1 | `1` |
|
||
| `/2` | module | string/1 | canonical module identity |
|
||
| `/3` | language | string/1 | language edition |
|
||
| `/4` | toolchain | `ToolchainRef`/1 | compatible ID and minimum |
|
||
| `/5` | requires | `Require`/* | sorted by module |
|
||
| `/6` | products | `Product`/* | sorted by name |
|
||
| `/7` | packages | `PackageConfig`/* | sorted by relative path |
|
||
| `/8` | actions | `GenerateDecl`/* | sorted by name |
|
||
| `/9` | natives | `NativeProvider`/* | sorted by name |
|
||
| `ToolchainRef/1` | id | string/1 | toolchain identity |
|
||
| `/2` | minimum | string/1 | minimum compatible SemVer |
|
||
| `Require/1` | module | string/1 | module identity |
|
||
| `/2` | minimum | string/1 | SemVer minimum |
|
||
| `/3` | source-index | string/0/1 | empty means HTTPS convention |
|
||
| `Product/1` | name | string/1 | unique identifier |
|
||
| `/2` | kind | enum/1 | `exe`, `static`, `shared`, `object`, `generated` |
|
||
| `/3` | root | string/0/1 | package-relative path; required except generated |
|
||
| `/4` | linkage | enum/1 | `dynamic`, `pie`, `static`, `static-pie`, `shared`, `none`; kind-valid |
|
||
| `/5` | runtime | string/1 | `hosted` default, `minimal`, `none`, or slot |
|
||
| `/6` | entry | string/0/1 | empty selects typed toolchain default |
|
||
| `/7` | native | string/* | required slots, sorted |
|
||
| `/8` | linker-script | `ArtifactRef`/0/1 | empty |
|
||
| `/9` | providers | `ProviderSelection`/* | sorted by slot |
|
||
| `/10` | members | string/* ordered | static/archive members; root only by default |
|
||
| `/11` | action | string/0/1 | required only for generated product |
|
||
| `/12` | install-name | string/0/1 | platform-validated, empty |
|
||
| `ProviderSelection/1` | slot | string/1 | ABI slot |
|
||
| `/2` | use | string/1 | `module#native-clause` |
|
||
| `PackageConfig/1` | path | string/1 | normalized relative path; `.` root |
|
||
| `/2` | generated | string/* | sorted `action:NAME:OUTPUT` refs |
|
||
| `/3` | native | string/* | sorted provider slots |
|
||
| `/4` | test-data | `InputDecl`/* | sorted names, read-only under `/data` |
|
||
| `/5` | test-env | map | literal non-secret test environment |
|
||
|
||
`ArtifactRefV1` is permitted in declarative configuration records (including
|
||
toolchain/native records) and action templates, but never in a final action
|
||
record. Its tags are: 1 `ArtifactNamespace` (`source`, `generated`, `package`,
|
||
`toolchain`, `sysroot`, `provider-output`, `cas`, or `graph`); 2 owner identity
|
||
(empty only for a root source);
|
||
3 normalized logical name/path; 4 semantic artifact kind (`file`, `tree`,
|
||
`object`, `archive`, `shared`, `import-library`, `script`, `crt`, `loader`,
|
||
`native-sidecar`, `native-abi`, `export`, `package-link`, `action-record`, or
|
||
`action-result`);
|
||
5 optional expected `TypedDigestV1`; and 6 mode (`data` or `executable`). A local
|
||
source may omit tag 5 because analysis hashes it. A `cas`, external prebuilt,
|
||
toolchain, or sysroot reference must include it. A generated/package/provider
|
||
output gets its digest only from the declared predecessor output. Absolute host
|
||
paths are invalid.
|
||
|
||
`InputSlotRefV1`, `TemplateInputV1`, `ResolvedInputV1`, built-in/template/final
|
||
action-output records, and `ResultOutputV1` use that same closed semantic
|
||
artifact-kind enum; `GenerateDecl.OutputDecl` remains restricted to `file` or
|
||
`tree`. In schema 1, `file`, `object`, `archive`, `shared`, `import-library`,
|
||
`script`, `crt`, and `loader` require a blob digest. `tree` requires record kind
|
||
1, `native-sidecar` kind 15, `native-abi` kind 16, `export` kind 18, and
|
||
`package-link` kind 19, each at record schema 1. Schema-1 artifact-kind values 14
|
||
`action-record` and 15 `action-result` require record kinds 11 and 12,
|
||
respectively, at record schema 1. They are input-only and valid only for
|
||
`bootstrap.compare`; they are invalid in built-in, template, or final action
|
||
outputs and in `ResultOutputV1`. Any other digest domain, record kind, or schema
|
||
is invalid kind substitution.
|
||
|
||
The `graph` namespace has one exact form. Its consumer is `bootstrap.compare`,
|
||
the `TemplateInputV1` edge kind is `bootstrap-record`, and
|
||
`ArtifactRefV1.tag2` is the producer logical node. Tag 3 is the Identifier
|
||
selector `action_record` for artifact kind `action-record` or `action_result`
|
||
for artifact kind `action-result`; tag 5 is absent. `ArtifactRefV1.tag6` and
|
||
`TemplateInputV1.tag5` are `data`, `TemplateInputV1.tag4` repeats the
|
||
corresponding artifact kind, and `TemplateInputV1.tag6` is empty. No other
|
||
consumer, edge kind, selector, kind, expected digest, or mode is valid for this
|
||
namespace. These inputs and edges are bijective: each `graph` template input has
|
||
exactly one `bootstrap-record` `GraphEdgeV1`, and each such edge has exactly one
|
||
`graph` template input. The edge's consumer node is the enclosing template node,
|
||
its consumer input slot equals `TemplateInputV1.tag1`, its producer node equals
|
||
`ArtifactRefV1.tag2`, and its selector equals `ArtifactRefV1.tag3`.
|
||
|
||
`InputSlotRefV1` has tag 1 slot name and tag 2 expected semantic artifact type.
|
||
A final action record contains no `ArtifactRefV1`: every artifact-bearing field is recursively lowered
|
||
to an `InputSlotRefV1`. `TemplateInputV1` tags are 1 unique slot name, 2 edge
|
||
kind, 3 `ArtifactRefV1`, 4 expected semantic type, 5 semantic mode, and 6
|
||
optional origin package identity. `ResolvedInputV1` tags are 1 the same slot
|
||
name, 2 edge kind, 3 normalized logical name/path, 4 semantic artifact type, 5
|
||
semantic mode, 6 the resolved `TypedDigestV1`, and 7 optional originating
|
||
package identity. It contains no producer node, producer action key, action-
|
||
template digest, physical output path, or unresolved filesystem lookup. Thus all
|
||
content that a native plan, link plan, source-selection record, or tool closure can read is
|
||
also present exactly once in action-record tag 10 under a named slot.
|
||
|
||
`GenerateDecl` fields are fixed as follows: tag 1 name; 2 tool artifact/product
|
||
reference; 3 platform enum (schema 1 only `build`); 4 `TargetConstraint` or empty;
|
||
5 input map of `InputDecl`; 6 output map of `OutputDecl`; 7 ordered string argv;
|
||
8 literal string environment map; 9 `ResourcePolicy`; 10 reproducibility enum
|
||
`required` or `impure`. `InputDecl` is tag 1 kind (`file`, `tree`, `artifact`,
|
||
`tool`), 2 logical reference, 3 optional expected typed digest, 4 semantic mode.
|
||
`OutputDecl` is tag 1 kind (`file`, `tree`), 2 logical output path, 3 executable
|
||
boolean. `ResourcePolicy` is tags 1 max CPU count, 2 memory bytes, 3 output bytes,
|
||
4 process count; zero selects the toolchain's recorded bound, never “unlimited.”
|
||
|
||
| Record/tag | Field | Type/cardinality | Rule/default |
|
||
|---|---|---|---|
|
||
| `LockV1/1` | schema | uint/1 | `1` |
|
||
| `/2` | root-manifest | typed digest/1 | semantic manifest record |
|
||
| `/3` | toolchain | `ToolchainLock`/1 | exact closure |
|
||
| `/4` | modules | `ModuleLock`/* | sorted identity |
|
||
| `/5` | native-map | `LockedObject`/0/1 | empty |
|
||
| `ToolchainLock/1…5` | id, version, descriptor, bundle, origin | strings/digests | all required |
|
||
| `ModuleLock/1` | module | string/1 | identity |
|
||
| `/2` | version | string/1 | selected SemVer |
|
||
| `/3` | origin | string/1 | exact final archive URL |
|
||
| `/4` | archive | blob digest/1 | required |
|
||
| `/5` | tree | tree digest/1 | required |
|
||
| `/6` | manifest | record digest/1 | required |
|
||
| `/7` | signature | bytes/0/1 | empty |
|
||
| `/8` | provenance | string/0/1 | empty |
|
||
| `LockedObject/1…3` | origin, digest, signature | string/digest/bytes | origin+digest required |
|
||
|
||
`WorkV1` is tag 1 schema, tag 2 sorted `Use` records, tag 3 sorted local provider
|
||
overrides. `Use` tags are module, path, expected source-tree digest. A provider
|
||
override has slot, provider ID, product-platform constraint, contract digest,
|
||
artifact-tree digest, and provenance in tags 1–6. `VendorV1` is tag 1 schema,
|
||
tag 2 lock-record digest, tag 3 sorted entries `(module, version, source-tree
|
||
digest, vendor-relative path)` in tags 1–4. `NativeMapV1` is tag 1 schema, tag 2
|
||
exact product-platform descriptor digest, tag 3 sorted provider overrides, and
|
||
tag 4 signer/provenance record.
|
||
|
||
#### Profiles, templates, actions, results, and trees
|
||
|
||
A profile is toolchain data, not an open project map:
|
||
|
||
| Tag | `ProfileV1` field | Values |
|
||
|---|---|---|
|
||
| 1 | name | identity |
|
||
| 2 | optimization | `0`, `1`, `2`, `3`, `size` |
|
||
| 3 | debug | `none`, `line`, `full` |
|
||
| 4 | assertions | boolean |
|
||
| 5 | overflow | `trap`, `wrap` |
|
||
| 6 | panic | `abort`, `runtime` |
|
||
| 7 | sanitizers | sorted toolchain capability IDs |
|
||
| 8 | LTO | `none`, `thin`, `full` |
|
||
| 9 | relocation | effective `static`, `pic`, `pie` |
|
||
| 10 | code-model | exact target capability ID |
|
||
| 11 | TLS default | exact target capability ID |
|
||
| 12 | strip | `none`, `debug`, `all` |
|
||
| 13 | reproducibility | `required`, `impure` |
|
||
|
||
| Tag | `ActionTemplateV1` field | Rule |
|
||
|---|---|---|
|
||
| 1 | schema | `1` |
|
||
| 2 | kind/version | exact built-in kind or generate version |
|
||
| 3 | protocol record | language/compiler/export/object/runtime/manifest/lock; compiler protocol is distinct from compiler/backend byte identity |
|
||
| 4 | platform roles | B, H, optional T descriptor refs |
|
||
| 5 | selected tool closure | identity plus semantic closure digest/resources |
|
||
| 6 | profile | complete `ProfileV1` |
|
||
| 7 | logical identity/cwd | normalized identity; cwd exactly `/work`, path-independent |
|
||
| 8 | argv | ordered strings |
|
||
| 9 | environment | sorted literal map, no secrets |
|
||
| 10 | input slots | sorted `(name, edge kind, producer/output or source ref, type, mode)` |
|
||
| 11 | source selection | ordered selected membership plus reasons |
|
||
| 12 | native/link template | closed predeclared provider slots, concrete providers, and ordered link records |
|
||
| 13 | outputs | sorted name/path/type/mode/canonicalization |
|
||
| 14 | sandbox/reproducibility | exact policy/version/bounds/class |
|
||
|
||
`ActionRecordV1` has the same top-level tags, but tag 10 contains sorted
|
||
`ResolvedInputV1` records and every `ArtifactRefV1` elsewhere in the template is
|
||
replaced by the corresponding `InputSlotRefV1`. The tag-12 native/link value is
|
||
therefore a resolved plan; it cannot contain an unresolved artifact reference,
|
||
producer, physical path, or readable artifact locator/digest outside tag 10.
|
||
ABI/layout/contract digests embedded in a referenced sidecar or contract are
|
||
semantic verification values, not authority to read another object. No producer
|
||
action key substitutes for a content digest.
|
||
|
||
The tag-12 native/link record separately encodes the sorted predeclared provider
|
||
slots, concrete selected-provider declarations, and the optional ordered link
|
||
policy or resolved plan. A `ww.package` action contains exactly its
|
||
`PackageConfigV1` native-slot list and empty concrete-provider and link-policy/
|
||
plan values; finalization copies that slot list unchanged. Concrete provider
|
||
selection does not enter a package action merely because the provider satisfies
|
||
one of those slots.
|
||
|
||
Finalization interns every source, direct export, package/native object, archive,
|
||
shared library, header/sysroot tree, generated output, tool/resource, CRT,
|
||
loader, script, and init dispatcher into exactly one named template input.
|
||
For `bootstrap.compare`, it also interns every selected raw action record and
|
||
action result as a separate named input. Finalization erases the `graph`
|
||
namespace, producer node, and unresolved selector form. The corresponding
|
||
tag-10 `ResolvedInputV1` retains edge kind `bootstrap-record`, logical selector
|
||
`action_record` or `action_result`, matching artifact kind, `data` mode, and the
|
||
resolved typed digest; that digest is the sole authority to read the raw record.
|
||
Predecessor output and selected-record digests resolve those slots lazily. The
|
||
producer logical node, producer output path, producer key, and template digest
|
||
are graph/provenance facts only and do not enter the consumer's `ActionRecordV1`
|
||
or `K`. Two producers that deliver the same typed bytes to the same semantic
|
||
slot therefore produce the same downstream record and key.
|
||
|
||
`ActionResultV1` tags are: 1 schema, 2 the 32-byte action key, 3 typed
|
||
action-record digest, and 4 sorted `ResultOutputV1` records. `ResultOutputV1`
|
||
tags are 1 unique output name, 2 semantic artifact type, 3 mode (`data` or
|
||
`executable`), and 4 `TypedDigestV1`. `ObservationV1` separately uses tags 1 schema,
|
||
2 logical invocation, 3 optional action key, 4 exit status/signal, 5 stdout blob,
|
||
6 stderr blob, 7 timing/resources, and 8 physical runner metadata; it is never
|
||
an action result.
|
||
|
||
`TreeV1` tags are 1 schema and 2 ordered entries. `TreeEntryV1` tags are 1 name,
|
||
2 kind (`file`, `tree`), 3 executable boolean (false for tree), and 4 typed child
|
||
digest. `GraphSnapshotV1` tags are 1 schema, 2 logical root, 3 sorted
|
||
`GraphNodeV1` records, and 4 sorted `GraphEdgeV1` records. `GraphNodeV1` tags are
|
||
1 logical node ID, 2 typed action-template digest, 3 optional 32-byte action key,
|
||
4 optional typed action-record digest, and 5 optional typed action-result digest.
|
||
`GraphEdgeV1` tags are 1 consumer node ID, 2 consumer input slot, 3 producer node
|
||
ID, 4 producer output name, and 5 edge kind; edges sort by that five-field tuple.
|
||
Tag 4 is an ordinary producer output name except that a `bootstrap-record` edge
|
||
uses selector `action_record` or `action_result`. That branch resolves the
|
||
actual producer `GraphNodeV1.tag4` or tag 5, respectively; it never selects an
|
||
`ActionOutputV1` or `ResultOutputV1`. If the selected producer tag is absent,
|
||
the input remains unresolved and blocks finalization. The `source-input` kind is
|
||
invalid in `GraphEdgeV1`. Non-action source inputs live only in the consumer
|
||
template rather than invented graph nodes. The project index contains only its
|
||
typed graph-snapshot digest.
|
||
|
||
#### Target, toolchain, native, interface, and handoff records
|
||
|
||
| Tag | `PlatformDescriptorV1` field | Rule |
|
||
|---|---|---|
|
||
| 1 | schema | `1` |
|
||
| 2 | name | canonical lookup name |
|
||
| 3 | arch/vendor/os/environment/object format | five exact enums |
|
||
| 4 | endian/address spaces/pointers | complete integer-width map |
|
||
| 5 | integer/data-layout | widths, alignments, aggregate algorithm |
|
||
| 6 | C ABI/data model | exact IDs and calling-convention table |
|
||
| 7 | float/variadic/name decoration | exact ABI records |
|
||
| 8 | CPU baseline/features/atomics | baseline plus required/forbidden sets |
|
||
| 9 | minimum OS/SDK | typed version record |
|
||
| 10 | TLS/unwind capabilities | sets plus defaults |
|
||
| 11 | relocation/code capabilities | supported sets plus defaults |
|
||
| 12 | executable/shared/page rules | typed object-format rules |
|
||
| 13 | hosted policy | hosted/freestanding plus capability set |
|
||
| 14 | object/runtime ABI protocols | exact IDs |
|
||
|
||
`TargetConstraintV1` tags 1–17 are, respectively: optional exact descriptor
|
||
digest; arch; vendor; OS; environment; object format; hosted; C ABI; data model;
|
||
float ABI; CPU baseline; required feature set; forbidden feature set; minimum
|
||
SDK; relocation; code model; PIC requirement. Empty scalar/set means no
|
||
constraint. Matching is exactly section 8.4; no expression field exists.
|
||
|
||
`ToolchainV1` tags are: 1 schema; 2 ID; 3 version; 4 the same complete protocol
|
||
record used by action tag 3; 5 sorted `Tool` records; 6 sorted platform
|
||
descriptors; 7 sorted profiles; 8 sorted link policies; 9 runtime/provider
|
||
records; 10 bundle tree digest/signature provenance.
|
||
A `Tool` is `(name, bundle-relative path, executable blob digest, ordered dynamic
|
||
tool dependencies, resource-tree digests, adapter record)` tags 1–6. A link
|
||
policy is `LinkPolicyV1`: tag 1 product-platform descriptor; 2 product kind; 3
|
||
linkage; 4 profile constraint; 5 runtime selector (`hosted`, `minimal`, `none`,
|
||
or an exact provider slot); 6 one ordered link-policy token template; and 7
|
||
output ABI/install policy. Policies sort by the five-field selection key and a
|
||
zero/multiple match is an error. CRTs and scripts are `ArtifactRefV1` tokens,
|
||
not basenames. A dynamic loader is one restricted `dynamic-loader` token holding
|
||
both its artifact and runtime interpreter path; PE/COFF platform-image policy is
|
||
an ordered provider token rather than a fabricated loader artifact.
|
||
`SelectedToolClosureV1` deterministically
|
||
projects only the relevant tools/resources/platform/profile/policy into tags
|
||
1–7; that projection—not unrelated bundle members—is action-key input.
|
||
|
||
#### Native artifact and ABI subrecords
|
||
|
||
Compact manifest paths are lowered to `ArtifactRefV1` before WWAR encoding and
|
||
then to action input-slot references before execution. The native records are:
|
||
|
||
| Tag | `IncludeTreeRefV1` field | Rule |
|
||
|---|---|---|
|
||
| 1 | tree | `ArtifactRefV1` of kind `tree` |
|
||
| 2 | class | `quote`, `user`, `system`, or `framework` |
|
||
| 3 | subdirectory | normalized tree-relative path; `.` default |
|
||
|
||
The provider's include list is ordered because header search order is semantic.
|
||
The same tree may occur more than once with another class or subdirectory.
|
||
|
||
| Tag | `NativeSourceV1` field | Rule |
|
||
|---|---|---|
|
||
| 1 | name | unique provider-local identity |
|
||
| 2 | source | `ArtifactRefV1` of kind `file` |
|
||
| 3 | language | exact toolchain capability ID, such as `c11` or `gnu-assembly` |
|
||
| 4 | preprocessing | `none` or `c-preprocessor` |
|
||
| 5 | include-indices | ordered indexes into the provider include list; empty means all |
|
||
| 6 | defines | sorted literal macro map; duplicates with provider defines error |
|
||
|
||
Target, profile, relocation/PIC/code/TLS policy, tool, and dialect adapter come
|
||
from the enclosing `native.compile` record. Raw source flags do not exist.
|
||
|
||
| Tag | `PrebuiltObjectV1` field | Rule |
|
||
|---|---|---|
|
||
| 1 | name | unique provider-local identity |
|
||
| 2 | object | `ArtifactRefV1` of kind `object` |
|
||
| 3 | sidecar | `ArtifactRefV1` of kind `native-sidecar` |
|
||
| 4 | contract | `ArtifactRefV1` of kind `native-abi` |
|
||
|
||
| Tag | `ArchiveV1` field | Rule |
|
||
|---|---|---|
|
||
| 1 | name | unique provider-local identity |
|
||
| 2 | archive | `ArtifactRefV1` of kind `archive` |
|
||
| 3 | sidecar | archive-level `ArtifactRefV1` of kind `native-sidecar` |
|
||
| 4 | members | ordered `ArchiveMemberV1` list in physical order |
|
||
| 5 | contract | `ArtifactRefV1` of kind `native-abi` |
|
||
|
||
`ArchiveMemberV1` tags are 1 member name, 2 member blob `TypedDigestV1`, and 3
|
||
object-sidecar `ArtifactRefV1`. Duplicate names are legal only at distinct
|
||
positions; member order is never sorted. The referenced archive sidecar records
|
||
the ordered member-sidecar record digests as well as the physical member facts.
|
||
|
||
| Tag | `SharedImportLibraryV1` field | Rule |
|
||
|---|---|---|
|
||
| 1 | name | unique provider-local identity |
|
||
| 2 | kind | `elf-shared`, `macho-dylib`, or `pe-import` |
|
||
| 3 | link-artifact | shared object/dylib/import-library `ArtifactRefV1` |
|
||
| 4 | link-sidecar | `ArtifactRefV1` of kind `native-sidecar` for tag 3 |
|
||
| 5 | runtime-identity | exact SONAME, install-name, or DLL name |
|
||
| 6 | runtime-artifact | exact deployable shared object/dylib/DLL `ArtifactRefV1` |
|
||
| 7 | runtime-sidecar | `ArtifactRefV1` of kind `native-sidecar` for tag 6 |
|
||
| 8 | contract | `ArtifactRefV1` of kind `native-abi` |
|
||
| 9 | runtime-requires | sorted `NativeRuntimeRequirementV1` list |
|
||
|
||
ELF and Mach-O tags 3 and 6 may resolve to the same bytes. For PE, tag 3 is
|
||
the import library and tag 6 its matching DLL. A platform image still supplies
|
||
tag 6 as a content-identified artifact within that image.
|
||
|
||
`NativeProviderV1` tags are therefore: 1 name; 2 provided slot; 3
|
||
`TargetConstraintV1`; 4 ordered `IncludeTreeRefV1`; 5 ordered `NativeSourceV1`;
|
||
6 sorted provider define map; 7 ordered `PrebuiltObjectV1`; 8 ordered
|
||
`ArchiveV1`; 9 ordered `SharedImportLibraryV1`; 10 sorted required slots; 11
|
||
ordered link-token templates; and 12 an `ArtifactRefV1` of kind `native-abi`.
|
||
Every ABI contract and sidecar is an independently encoded, content-addressed
|
||
record. In a resolved action, those records and every artifact field above are
|
||
`InputSlotRefV1` values; source/action/provider output digests live only in
|
||
action tag 10. A sidecar's internal artifact digest must equal the corresponding
|
||
object/archive/shared input-slot digest, and its contract digest must equal the
|
||
kind-16 `TypedDigestV1` of the referenced native-ABI input record.
|
||
Section/layout/provenance digests inside a sidecar are verification facts, not
|
||
locators from which the action may read undeclared content.
|
||
|
||
| Tag | `NativeABIContractV1` field | Rule |
|
||
|---|---|---|
|
||
| 1 | schema | `1` |
|
||
| 2 | slot | exact ABI-provider slot |
|
||
| 3 | platform | `NativeABIPlatformV1` |
|
||
| 4 | symbols | sorted `NativeSymbolContractV1` list |
|
||
| 5 | types | sorted `NativeTypeContractV1` list |
|
||
| 6 | runtime-requires | sorted `NativeRuntimeRequirementV1` list |
|
||
| 7 | features | `NativeFeatureContractV1` |
|
||
| 8 | minimum-platform | optional `PlatformVersionV1` |
|
||
| 9 | code | `NativeCodeContractV1` |
|
||
|
||
Its typed record identity is `record_id(16, 1, contract)` as defined in section
|
||
6.6. Every schema-1 digest identifying a complete `NativeABIContractV1` is the
|
||
corresponding record-domain, kind-16, schema-1 `TypedDigestV1`. WW computes it; a
|
||
supplied digest is never accepted in place of the record. Subordinate layout,
|
||
calling-convention, type-contract, and header-contract digests remain their
|
||
separately specified semantic values.
|
||
|
||
| Tag | `NativeABIPlatformV1` field | Rule |
|
||
|---|---|---|
|
||
| 1 | object-format | exact format capability ID |
|
||
| 2 | object-class | exact class/word-size ID |
|
||
| 3 | endian | `little` or `big` |
|
||
| 4 | machine-ABI | exact architecture object ABI ID |
|
||
| 5 | C-ABI | exact C ABI ID |
|
||
| 6 | data-model | exact data-model ID |
|
||
| 7 | data-layout | canonical layout digest |
|
||
| 8 | calling-conventions | canonical convention-table digest |
|
||
| 9 | float-ABI | exact ID |
|
||
| 10 | variadic-ABI | exact ID |
|
||
| 11 | symbol-ABI | exact decoration/versioning ABI ID |
|
||
| 12 | object-ABI | exact object protocol ID |
|
||
| 13 | runtime-ABI | required WW runtime ABI ID or empty |
|
||
|
||
`NativeSymbolContractV1` tags are: 1 exact external name; 2 exact version or
|
||
empty; 3 kind (`function`, `data`, `tls`, `ifunc`); 4 role (`define`, `require`);
|
||
5 binding (`strong`, `weak`); 6 visibility (`default`, `protected`, `hidden`);
|
||
7 calling-convention ID or empty; 8 canonical function/object type-contract
|
||
digest; and 9 optional byte size. Symbols sort by `(name,version,kind,role)`;
|
||
duplicate keys error.
|
||
|
||
`NativeTypeContractV1` tags are: 1 stable binding/header-qualified identity; 2
|
||
kind (`opaque`, `scalar`, `enum`, `struct`, `union`, `function`); 3 exposure
|
||
(`opaque`, `layout`); 4 canonical target-specific layout/signature digest; 5
|
||
optional size; 6 optional alignment; and 7 optional canonical header/macro
|
||
contract digest. Types sort by identity and duplicates error.
|
||
|
||
`NativeRuntimeRequirementV1` tags are 1 provider slot, 2 required ABI-contract
|
||
digest, 3 phase (`link`, `load`, `both`), and 4 optional SONAME/install-name/DLL
|
||
identity. They sort by `(slot,phase,runtime-identity)`; conflicting requirements
|
||
for one slot error. `NativeFeatureContractV1` tags are 1 CPU baseline or empty,
|
||
2 sorted required feature IDs, 3 sorted forbidden feature IDs, and 4 sorted
|
||
atomic-capability IDs; required and forbidden sets must be disjoint.
|
||
|
||
`PlatformVersionV1` tags are 1 version-family ID and unsigned 2 major, 3 minor,
|
||
4 patch, 5 revision. Versions compare lexicographically over tags 2–5 only after
|
||
tag 1 equality. `NativeCodeContractV1` tags are 1 PIC (`any`, `required`,
|
||
`forbidden`); 2 sorted TLS-model IDs; 3 unwind ABI ID or `none`; 4 sorted
|
||
personality/runtime symbols; and 5 sorted required/forbidden relocation records,
|
||
each record being tag 1 capability ID and tag 2 requirement (`required` or
|
||
`forbidden`).
|
||
|
||
`NativeSidecarV1` is evidence, not a second contract. Its tags are: 1 schema; 2
|
||
artifact `TypedDigestV1`; 3 evidenced `NativeABIPlatformV1`; 4 sorted evidenced
|
||
`SectionFactV1`; 5 sorted evidenced `SymbolFactV1`; 6 sorted evidenced
|
||
`RelocationFactV1`; 7 evidenced sorted architecture attribute/notes map; 8
|
||
evidenced `NativeMachineFactsV1`; 9 native ABI-contract digest; 10 sorted
|
||
`NativeRuntimeRequirementV1`; and 11 `ProvenanceV1`. An evidenced value is
|
||
`EvidenceV1`: tag 1 enum (`inspected` or `declared`) and tag 2 the value whose
|
||
type is fixed by the containing field. `NativeMachineFactsV1` tags are 1
|
||
`NativeFeatureContractV1` and 2 `NativeCodeContractV1`.
|
||
|
||
`SectionFactV1` tags are 1 name, 2 format type, 3 flag set, 4 size, 5 alignment,
|
||
6 optional content digest. `SymbolFactV1` tags are the nine
|
||
`NativeSymbolContractV1` fields plus tag 10 section and tag 11 value/offset.
|
||
`RelocationFactV1` tags are 1 section, 2 offset, 3 exact relocation ID, 4 symbol,
|
||
5 signed addend encoded as `(negative:boolean,magnitude:uint)`, and 6 target
|
||
section. `ProvenanceV1` tags are 1 producer/tool typed digest, 2 source/build
|
||
record typed digest, 3 attestation bytes, and 4 signer/policy ID. A frozen opaque
|
||
input requires accepted attestation for every `declared` value.
|
||
|
||
`LinkTokenTemplateV1` and final `LinkTokenV1` share tags: 1 kind; 2 artifact; 3
|
||
provider slot; 4 string value; 5 enabled boolean; 6 validated path; 7 runtime
|
||
path; and 8 ordered nested tokens. Tag 2 is `ArtifactRefV1` in a template and
|
||
`InputSlotRefV1` in a final action. Valid nonempty combinations are exactly:
|
||
object/archive/shared/linker-script/version-script/export-map/def-file use tag 2;
|
||
the template-only provider kind uses tag 3; group/whole use tag 8; as-needed uses tags 5 and 8;
|
||
runtime-search uses tags 4 and 6; install-name, entry, and retain use tag 4; and
|
||
dynamic-loader uses tags 2 and 7. Every other field encodes its empty/default
|
||
value. A final `LinkTokenV1` forbids `provider`; provider selection and its
|
||
ordered fragment are recursively expanded at that exact position before the
|
||
plan is final. Section 8.6 constrains valid nesting. A toolchain `LinkPolicyV1`
|
||
template additionally permits `splice` (tag 4 is exactly `product-objects`,
|
||
`init-dispatch`, `native-providers`, or `product-controls`) and
|
||
`script-slot` (tag 2 is an optional policy-default script). Those two kinds are
|
||
forbidden in project/native link declarations and in a final plan.
|
||
|
||
The selected policy template is flattened in list order. Each splice kind occurs
|
||
exactly once and expands to its already computed ordered product list;
|
||
the single required `script-slot` becomes one `linker-script` at the same list
|
||
position using the product's explicit script when present, otherwise the policy
|
||
default, and disappears only when both are empty. A product script therefore
|
||
replaces, never combines with, the default. Ordinary policy tokens—including CRT
|
||
objects, compiler runtime, dynamic loader, and system-provider slots—stay exactly
|
||
where declared. System providers are ordered template tokens, not a sorted set.
|
||
Each expands to its selected provider's concrete token fragment; dependencies
|
||
expand recursively, and a provider cycle is an analysis error. Every expanded
|
||
artifact, sidecar, and ABI contract is a tag-10 input. A provider such as a PE
|
||
platform image that adds no linker token instead contributes its resolved
|
||
contract slot to the plan's non-link policy field. After expansion no provider
|
||
or splice partition remains.
|
||
|
||
`LinkPlanV1` tags are 1 schema; 2 the exact product-platform/kind/linkage/
|
||
profile/runtime-policy selection record; 3 the single fully expanded ordered
|
||
`LinkTokenV1` stream; 4 selected linker/tool/resource slot refs; 5 selected
|
||
non-link platform/runtime/provider ABI-contract and sidecar slot refs; and 6
|
||
output ABI/install policy. Every file-bearing token and verification record
|
||
references action tag 10. Only
|
||
this resolved flattened plan enters the link action key.
|
||
|
||
`ExportV1` (the WWAR body after `.wwe` magic) tags are: 1 schema; 2 reader
|
||
capabilities; 3 language/type protocol; 4 product-platform/C/object/runtime ABI;
|
||
5 package identity/name; 6 sorted exported-surface origin/type contract table; 7
|
||
canonical type graph; 8 sorted exported declarations/constants/foreign symbols;
|
||
9 public initialization/ABI facts; 10 public-type digest; 11 public-ABI digest. Section 7.2
|
||
defines excluded non-semantic fields. `PackageLinkV1` (`.wwlm`) tags are 1 schema,
|
||
2 package identity, 3 platform/object/runtime ABI, 4 package-object digest, 5
|
||
defined/required foreign symbols, 6 predeclared provider slots/contracts, 7 init
|
||
symbol/dependency facts, 8 install/link requirements. Tag 6 contains exactly one
|
||
compiler-derived `ProviderContractV1` for each package action tag-12 predeclared
|
||
slot, and its sorted slot projection must equal that predeclared list. It cannot
|
||
add a provider slot or graph edge.
|
||
|
||
`InstallManifestV1` tags are 1 schema, 2 product identity/key, 3 sorted entries
|
||
`(artifact digest, mode, relative destination)`, 4 runtime-resolution policy, 5
|
||
sorted shared/runtime closure, 6 target/toolchain/ABI provenance. Absolute prefix
|
||
is deliberately absent. `BootstrapPlanV1` tags are 1 schema, 2 bootstrap-host
|
||
contract, 3 ordered source refs/digests, 4 portable-C compiler/output settings,
|
||
5 recorded host-C command/tool closure, 6 stage-1 outputs, 7 production toolchain
|
||
closure, 8 identical logical stage-2/3/4 action roots, 9 semantic fixed-point
|
||
output roles, and 10 raw-record fixed-point roles. No clause or executable step
|
||
exists beyond that closed plan.
|
||
|
||
These sections fix the architectural fields, but they do not make Phase 0 an
|
||
executable specification of every reference or key transformation. Phase 0
|
||
transcribes only their wire-visible record fields, tags, enum values, union
|
||
discriminants, encoded defaults, field order, record kinds, wrapper framing, and
|
||
digest preimage formulas into the checked-in compact schemas. Cross-field
|
||
validity, construction, resolution, projection, lowering, and failure behavior
|
||
belong to the executable phase that implements them. The Phase 0 generator and
|
||
golden vectors determine bytes, not future build-engine semantics. No phase may
|
||
silently add a wire field, renumber an assignment, change an encoded default, or
|
||
alter a frozen digest formula.
|
||
|
||
## 7. Interface and artifact protocol
|
||
|
||
### 7.1 Package outputs
|
||
|
||
Every `ww.package` action, including a root package, emits the same three named
|
||
artifacts:
|
||
|
||
```text
|
||
export.wwe deterministic binary export data
|
||
package.o one target object
|
||
link.wwlm deterministic package link metadata
|
||
```
|
||
|
||
These are names inside an immutable action result, not globally meaningful
|
||
filenames. The cache is keyed by digests and logical package identity, so there
|
||
is no `__root` special case and no dotted import path used as an artifact
|
||
basename. A root object and dependency object obey identical protocols.
|
||
|
||
`link.wwlm` declares the package object's target, object ABI, defined/required
|
||
foreign symbols, required native-provider slots, initialization ordering, and
|
||
runtime ABI. It attests facts/edges already present in the action-template DAG;
|
||
it may not introduce a provider, dependency, or action after compilation, and a
|
||
mismatch is a compiler/build-protocol error. It does not contain raw linker flags. Ordinary package objects are
|
||
fed directly to the product link. An archive exists only when an explicit
|
||
static-library product asks the `archive` action to combine its ordered declared
|
||
`members` (default: root package only). Transitive package/native dependencies
|
||
remain typed link requirements in the library's install manifest and are not
|
||
silently copied into multiple archives. A deliberately self-contained archive
|
||
must list every member explicitly and pass duplicate-symbol/provider checks.
|
||
|
||
Language initialization never depends on linker input order. `ww.init` consumes
|
||
all reachable `.wwlm` artifacts, topologically orders initialization by package
|
||
imports with byte-sorted ties, diagnoses duplicate/cyclic init facts, and emits
|
||
one dispatcher object. The link plan explicitly roots that dispatcher and every
|
||
referenced init symbol against section garbage collection.
|
||
|
||
### 7.2 WW Export Data 1 (`.wwe`)
|
||
|
||
`.wwe` is a cache/build protocol, not source text and not a long-term binary
|
||
distribution promise. It starts with the eight-byte magic `WWEX\0\0\0\1` and a
|
||
WWAR-encoded body. The magic is fixed framing that is reconstructed and verified
|
||
around the body; it does not create a second blob identity. The typed `.wwe`
|
||
identity is `record_id(18, 1, ExportV1)` over that body. The body contains:
|
||
|
||
1. export schema, language edition, type-system protocol, and required reader
|
||
capabilities;
|
||
2. target descriptor, C ABI, object ABI, and runtime ABI digests;
|
||
3. full package identity and declared package name;
|
||
4. a sorted table of originating package/type identities and declaration-level
|
||
public ABI digests actually referenced by the exported surface;
|
||
5. a canonical type graph sufficient for type checking, layout, calling
|
||
convention, and code generation of every exported declaration;
|
||
6. exported constants, variables, functions, methods, types, and explicit
|
||
foreign symbols; and
|
||
7. the public initialization/ABI facts needed by an importer.
|
||
|
||
Declarations are sorted by `(kind, exported name, stable overload discriminator)`;
|
||
type-graph nodes are assigned by deterministic structural traversal. Integer and
|
||
floating constants use canonical target-independent bit encodings until a
|
||
target conversion is part of their type. Function parameter **names**, source
|
||
locations, comments, unused imports, private function bodies, and declaration
|
||
order are not semantic and are omitted. Documentation/source mapping is a
|
||
separate optional artifact and cannot invalidate an importer.
|
||
|
||
Unmanaged layout sometimes depends on facts that are private at the source
|
||
level. An exported representation therefore records size, alignment, field/base
|
||
offsets, calling convention, niche/tag rules, and relevant private padding or
|
||
opaque-field descriptors without exposing private names. `@repr("c")` types
|
||
also record the exact C data model and layout algorithm version. Opaque types
|
||
record only the operations and layout promises permitted to clients.
|
||
|
||
### 7.3 Direct imports with deep public closure
|
||
|
||
An importer opens one `.wwe` for each direct import and no transitive interface
|
||
file. If a direct dependency's API mentions a type originating in a deeper
|
||
package, its `.wwe` embeds a canonical deep descriptor for the portion of that
|
||
type required to understand and lay out the direct API. The descriptor retains
|
||
the originating package/type identity and digest of that exact referenced
|
||
contract—not the originating package's entire public ABI. It does not pretend
|
||
the type belongs to the middle package.
|
||
|
||
This rule gives both correctness and bounded reads:
|
||
|
||
```text
|
||
source/package imports -> direct .wwe inputs
|
||
direct .wwe -> complete meaning of that direct API
|
||
link graph -> all reachable package objects
|
||
```
|
||
|
||
A public change in a leaf rebuilds direct reverse dependencies. Propagation
|
||
continues only while each rebuilt package's `.wwe` bytes change. A private leaf
|
||
change never enters an importer key. This replaces source-like transitive
|
||
interface prepending and its quadratic composed units.
|
||
|
||
This bounds interface **opens and reparsing**, not necessarily total descriptor
|
||
bytes: heavily re-exported type graphs can duplicate deep descriptors. Phase 1
|
||
measures total `.wwe` size and structural duplication on the real library graph.
|
||
Only if that is material may a later export-schema revision intern immutable
|
||
per-declaration descriptors; direct-import semantics do not change.
|
||
|
||
### 7.4 Public and ABI digests
|
||
|
||
The `.wwe` content digest identifies its complete target-specific bytes. It also
|
||
contains two domain-separated hashes:
|
||
|
||
- **public type digest** over names, types, constants, visibility, and language
|
||
semantics; and
|
||
- **public ABI digest** over target layouts, calling conventions, exported
|
||
symbol contracts, runtime ABI, and representation facts.
|
||
|
||
Compile actions normally depend on the whole `.wwe` content digest. Tools such as
|
||
documentation may depend only on the public type digest when their action kind
|
||
explicitly permits it. Link compatibility checks use the ABI digest. Digest
|
||
subsetting is protocol-defined; callers cannot choose arbitrary ignored fields.
|
||
|
||
### 7.5 Symbols and identity
|
||
|
||
Internal WW symbols are mangled from a protocol-versioned hash of the full
|
||
package identity plus declaration identity, never from a leaf name or artifact
|
||
filename. Resolver rules ensure only one source/version supplies that package
|
||
identity. An explicitly foreign symbol is exactly the source-declared spelling
|
||
and participates in duplicate-provider checks.
|
||
|
||
Package version and distribution origin are absent from mangling because they
|
||
are not identity. An incompatible major version has a different `/vN` module
|
||
identity and therefore different WW symbols. Native C symbols do not gain this
|
||
protection; their provider slots and link collision rules must reject
|
||
incompatible co-selection.
|
||
|
||
### 7.6 Compatibility and deterministic serialization
|
||
|
||
A consumer accepts only the exact export/type/object/runtime protocol combination
|
||
declared compatible by its immutable toolchain descriptor. A new optional record
|
||
still requires a new export schema and reader capability. Unknown records are
|
||
not silently dropped. Target descriptor and ABI mismatches are errors before a
|
||
compiler or linker runs.
|
||
|
||
Because `.wwe` is rebuilt from locked source, WW does not need an indefinitely
|
||
stable compiler-internal export format. A toolchain upgrade changes action keys
|
||
and may rebuild the graph. Public native-library ABI stability is a separate,
|
||
explicit provider contract. Release/bootstrap byte comparisons include `.wwe`,
|
||
objects, link metadata, action records, and executables.
|
||
|
||
## 8. Native integration and cross compilation
|
||
|
||
### 8.1 Complete target descriptors
|
||
|
||
A target triple is a user-facing alias. Before graph construction it expands to
|
||
an immutable target descriptor containing at least:
|
||
|
||
- architecture, vendor, operating system, environment, and object format;
|
||
- endianness, pointer widths/address spaces, integer/long widths, alignment and
|
||
aggregate-layout rules;
|
||
- C ABI/data model, calling conventions, name decoration, variadic convention,
|
||
TLS ABI capabilities/default, floating ABI, and unwind model;
|
||
- baseline CPU, required/forbidden CPU features, minimum OS/SDK version, and
|
||
atomic capability;
|
||
- supported/default relocation and code models, executable/shared-library rules,
|
||
and page constraints;
|
||
- hosted versus freestanding policy; and
|
||
- compatible object ABI and runtime ABI protocol identifiers.
|
||
|
||
The triple `x86_64-unknown-linux-gnu` is insufficient by itself to identify CPU
|
||
features, sysroot, glibc, loader, or linker. Those are separate descriptor/input
|
||
digests. `--cpu` and `--feature` produce a new canonical expanded descriptor;
|
||
the host CPU is never probed to select target features unless the user explicitly
|
||
requests the impure alias `native`, which is rejected by frozen/shared builds.
|
||
|
||
The descriptor supplies ABI invariants plus supported/default policy values. A
|
||
profile/product selects the effective relocation, code, PIC/PIE, and TLS policy
|
||
from those permitted sets; the normalized effective values appear once in the
|
||
action record. A conflicting or unsupported selection is rejected, never
|
||
resolved by precedence between duplicate fields.
|
||
|
||
This follows the native facts exposed by LLVM data layouts and Clang's cross
|
||
compilation/toolchain documentation, while making their often-driver-selected
|
||
inputs explicit
|
||
([LLVM data layout](https://llvm.org/docs/LangRef.html#data-layout),
|
||
[Clang cross compilation](https://clang.llvm.org/docs/CrossCompilation.html),
|
||
[Clang toolchain](https://clang.llvm.org/docs/Toolchain.html)).
|
||
|
||
### 8.2 Toolchain closure (`toolchain.wwt`)
|
||
|
||
An immutable toolchain bundle has a canonical `toolchain.wwt` descriptor with:
|
||
|
||
```text
|
||
ww-toolchain 1
|
||
id = "ww.org/toolchain"
|
||
version = "v1.4.0"
|
||
protocols = { language = "1", compiler = "1", export = "1", object = "1",
|
||
runtime = "1", manifest = 1, lock = 1 }
|
||
|
||
tool "wwc" { path = "bin/wwc", digest = "sha256:..." }
|
||
tool "cc" { path = "bin/clang", digest = "sha256:..." }
|
||
tool "as" { path = "bin/llvm-mc", digest = "sha256:..." }
|
||
tool "ld" { path = "bin/ld.lld", digest = "sha256:..." }
|
||
tool "archive" { path = "bin/llvm-ar", digest = "sha256:..." }
|
||
|
||
target "aarch64-unknown-linux-gnu" {
|
||
descriptor = "targets/aarch64-linux-gnu.wwt"
|
||
sysroot = { tree = "sha256:...", path = "sysroots/aarch64-linux-gnu" }
|
||
runtime = "runtime:aarch64-linux-gnu@1"
|
||
libc = "c:glibc@2.39"
|
||
link-policies = [
|
||
{ kind = "exe", linkage = "dynamic", profile = ["debug", "release"],
|
||
runtime = "hosted",
|
||
tokens = [
|
||
{ kind = "object", artifact = "sysroot:lib/crt1.o" },
|
||
{ kind = "object", artifact = "sysroot:lib/crti.o" },
|
||
{ kind = "splice", value = "product-objects" },
|
||
{ kind = "splice", value = "init-dispatch" },
|
||
{ kind = "splice", value = "native-providers" },
|
||
{ kind = "splice", value = "product-controls" },
|
||
{ kind = "provider", slot = "c:compiler-rt@1" },
|
||
{ kind = "provider", slot = "c:glibc@2.39" },
|
||
{ kind = "dynamic-loader",
|
||
artifact = "sysroot:lib/ld-linux-aarch64.so.1",
|
||
runtime-path = "/lib/ld-linux-aarch64.so.1" },
|
||
{ kind = "script-slot", artifact = "toolchain:lib/ldscripts/elf.lds" },
|
||
{ kind = "object", artifact = "sysroot:lib/crtn.o" }
|
||
] }
|
||
]
|
||
}
|
||
```
|
||
|
||
Every path is bundle-relative and every executable, shared tool dependency,
|
||
resource directory, built-in header tree, target descriptor, runtime, sysroot,
|
||
CRT, default script, and adapter is covered by the bundle's canonical tree
|
||
digest. The engine invokes exact paths and passes explicit target/sysroot/resource
|
||
arguments. A tool's compiled-in search outside the sandbox cannot resolve.
|
||
The compact `sysroot:`/`toolchain:` references in the example normalize to full
|
||
`ArtifactRefV1` records containing the individual typed digest obtained from
|
||
that authenticated tree; the shorthand itself never enters WWAR.
|
||
|
||
The whole bundle digest authenticates acquisition. An action key uses the
|
||
transitive selected descriptor slice/tool/resource/sysroot/runtime closure only;
|
||
adding an unused target or unrelated tool to a republished bundle does not cause
|
||
global recompilation. Changing any selected byte/protocol still changes the key.
|
||
|
||
Official bundles may use LLVM, GNU binutils, or another implementation per
|
||
target; the architecture does not expose that choice as project semantics.
|
||
Tool adapters translate WW's typed record to exact argv and declare all injected
|
||
inputs. A custom bundle must do the same and pass conformance/reproducibility
|
||
tests before frozen mode accepts it.
|
||
|
||
WW permanently owns the language compiler, export/object/runtime ABI protocols,
|
||
target descriptor schema, action engine, and official bundle definitions. It
|
||
does **not** permanently own the assembler, linker, archiver, C compiler, or SDK.
|
||
The current `w6a`/`w6l` may serve as migration inputs, then are removed once a
|
||
pinned external closure passes parity. This is the smaller long-term system.
|
||
|
||
### 8.3 C ABI and foreign declarations
|
||
|
||
Foreign declarations are explicit source contracts:
|
||
|
||
```ww
|
||
@abi("c") @symbol("write")
|
||
@provider("c:libc")
|
||
fn c_write(fd s32, data *u8, count usize) ssize;
|
||
|
||
@repr("c")
|
||
type Header struct { tag u32; length u16; };
|
||
```
|
||
|
||
The compiler checks that every type has a defined representation for the
|
||
selected C ABI and records symbol, calling convention, variadic status, layout,
|
||
and explicitly named provider slot in `.wwe`/`.wwlm`. `@provider` is mandatory
|
||
for each foreign declaration (a group annotation may supply it lexically), and
|
||
the owning package metadata must require that slot; WW never infers it from a
|
||
symbol spelling or link position. A foreign declaration with no provider, two
|
||
definitions of a strong symbol, incompatible calling conventions, or mismatched
|
||
layout digest is a pre-link diagnostic where possible and a mandatory link
|
||
failure otherwise.
|
||
|
||
C headers are not searched or parsed implicitly. Bindings are either checked-in
|
||
WW source produced by an explicit `ww bindgen c` command, or a declared
|
||
`generate` action whose inputs include the exact header trees, target descriptor,
|
||
preprocessor, macro map, include roots, and binding tool. The generated result
|
||
records the declared whole input-tree digests, observed include trace as
|
||
non-semantic audit metadata, and C ABI digest. The trace cannot add an input; a
|
||
future finer-grained scan would require a new built-in action still keyed by the
|
||
complete allowed include-tree digest. No build invokes ambient
|
||
`pkg-config`; `ww native snapshot-pkg-config` is an explicit, impure acquisition
|
||
command that converts one selected host configuration into a reviewable native
|
||
provider record and content snapshot.
|
||
|
||
### 8.4 Native declarations
|
||
|
||
Schema 1 uses two connected declarations. A package lists the ABI slots it
|
||
requires:
|
||
|
||
```text
|
||
package "compress/zlib" {
|
||
native = ["c:zlib@1"]
|
||
generated = ["action:zlib-bindings:ww"]
|
||
}
|
||
```
|
||
|
||
A provider declares exact target artifacts and dependencies:
|
||
|
||
```text
|
||
native "zlib-linux-aarch64" {
|
||
provides = "c:zlib@1"
|
||
when = { os = "linux", arch = "aarch64", environment = "gnu",
|
||
c-abi = "aapcs64", float-abi = "hard",
|
||
requires-features = ["neon"],
|
||
minimum-sdk = "linux:5.10.0.0" }
|
||
include-trees = [
|
||
{ tree = "native/zlib/include", class = "user", subdirectory = "." }
|
||
]
|
||
sources = [
|
||
{ name = "adler32", source = "native/zlib/adler32.c",
|
||
language = "c11", preprocessing = "c-preprocessor",
|
||
include-indices = [0], defines = {} }
|
||
]
|
||
defines = { ZLIB_CONST = "1" }
|
||
objects = []
|
||
archives = []
|
||
shared = []
|
||
requires = ["c:libc"]
|
||
link = [
|
||
{ kind = "object",
|
||
artifact = { namespace = "provider-output",
|
||
owner = "zlib-linux-aarch64",
|
||
name = "adler32", kind = "object", mode = "data" } }
|
||
]
|
||
abi = { file = "native/zlib.wwabi" }
|
||
}
|
||
```
|
||
|
||
Allowed provider fields are exactly `provides`, `when`, `include-trees`,
|
||
`sources`, `defines`, `objects`, `archives`, `shared`, `requires`, `link`, and
|
||
`abi`. `when` is a finite conjunction. It may contain exact
|
||
`descriptor-digest`, `arch`, `vendor`, `os`, `environment`, `object-format`,
|
||
`hosted`, `c-abi`, `data-model`, `float-abi`, `cpu-baseline`, `relocation`,
|
||
`code-model`, and `pic`; `requires-features`/`forbids-features` use subset/
|
||
disjoint-set matching; `minimum-sdk` matches only a product platform whose
|
||
declared minimum is at least that value. It has no general expression. All
|
||
matching candidates are retained: identical provider/artifact digests coalesce,
|
||
while multiple different matches require the product's explicit provider map
|
||
rather than a specificity guess.
|
||
|
||
The textual `abi = { file = PATH }` form parses `PATH` as one complete canonical
|
||
`NativeABIContractV1` subdocument, encodes it as top-level record kind 16, and
|
||
lowers the provider field to an `ArtifactRefV1` containing that typed record
|
||
digest; an inline complete record is equivalent. The local source blob and
|
||
parsed contract are both hashed. The file form is not a digest assertion or a
|
||
build-time include, and partial contracts are invalid.
|
||
|
||
`sources` entries support only toolchain-declared C language editions and
|
||
assembly dialects. Each source has an exact file digest and sees only the listed
|
||
include trees/defines and toolchain headers. `objects`, `archives`, and `shared`
|
||
name content-identified prebuilt artifacts plus their target/object/ABI records.
|
||
A local `path` is content-hashed during analysis; a literal expected digest is
|
||
needed only for an external/prebuilt record. A provider may mix source and prebuilt inputs, but every produced object is its
|
||
own `native.compile` action. There is no filesystem library search.
|
||
|
||
`abi` is not an opaque user assertion. It is the recomputed digest of a canonical
|
||
native ABI contract containing slot, product-platform ABI/data model, calling
|
||
conventions, symbol names/versions/kinds, referenced C layout/header-contract
|
||
digests, required runtime slots, CPU/features, minimum SDK, and PIC/TLS/unwind
|
||
requirements. Foreign bindings carry the expected contract or compatible
|
||
declaration-level subset. WW cross-checks the contract against compiled objects,
|
||
shared/import-library sidecars, and declared providers before link.
|
||
|
||
### 8.5 Assembly and object files
|
||
|
||
Assembly source declares an official external-tool dialect (`gnu`,
|
||
`llvm-integrated`, or another exact toolchain capability), preprocessing mode,
|
||
target, and CPU feature contract. The current `w6a` Plan-9-style dialect is a
|
||
migration input and is not accepted after cutover.
|
||
The selected assembler executable and resources are action inputs. A source for
|
||
one target cannot be selected for another by extension alone.
|
||
|
||
Prebuilt objects carry a sidecar native record with content digest, object
|
||
format, architecture, ABI, required CPU features, defined/undefined symbols,
|
||
PIC/TLS/unwind properties, and producer provenance. WW verifies the object
|
||
format/class/endian/machine header, sections, symbol table, relocations, notes,
|
||
and architecture attributes against every mechanically inferable sidecar fact;
|
||
the same inspection recurses into archive members and shared/import libraries.
|
||
Source-level C contract, libc/runtime compatibility, and provenance are not
|
||
fully inferable from object bytes, so frozen opaque prebuilts additionally need
|
||
a signature/attestation accepted by policy. A missing or contradictory record
|
||
is an error, not permission to ask the host linker what happens.
|
||
|
||
### 8.6 Static/shared libraries and ordered linking
|
||
|
||
Native `link` is an ordered list of typed template tokens:
|
||
|
||
```text
|
||
{ kind = "object", artifact = "object:NAME" }
|
||
{ kind = "archive", artifact = "archive:NAME" }
|
||
{ kind = "shared", artifact = "shared:NAME" }
|
||
{ kind = "provider", slot = "c:zlib@1" }
|
||
{ kind = "group", items = [...] }
|
||
{ kind = "whole", items = [...] }
|
||
{ kind = "as-needed", enabled = true, items = [...] }
|
||
{ kind = "linker-script", artifact = "file:NAME" }
|
||
{ kind = "version-script", artifact = "file:NAME" }
|
||
{ kind = "export-map", artifact = "file:NAME" }
|
||
{ kind = "def-file", artifact = "file:NAME" }
|
||
{ kind = "runtime-search", policy = "origin-relative", path = "lib" }
|
||
{ kind = "install-name", value = "@rpath/libname.so" }
|
||
{ kind = "dynamic-loader", artifact = "file:LOADER", runtime-path = "/lib/ld.so" }
|
||
{ kind = "entry", symbol = "_start" }
|
||
{ kind = "retain", symbol = "ww_init_abcd" }
|
||
```
|
||
|
||
Those are the complete schema-1 project/native template kinds. `provider` is
|
||
recursively replaced at its exact position by the chosen provider fragment;
|
||
the final kinds are every listed kind except `provider`. The toolchain-only
|
||
`splice` and `script-slot` kinds also lower away as specified in section 6.9.
|
||
Every file-bearing final token resolves
|
||
to a declared typed artifact and digest. Nested `items` contain only link tokens;
|
||
repetition is represented by repeating a list entry and is never deduplicated.
|
||
`group` contains archives or provider templates that resolve only to archives,
|
||
`whole` contains archives only, and `as-needed` contains shared inputs or
|
||
provider templates that resolve only to shared inputs; any other expansion or
|
||
nesting is invalid.
|
||
Runtime-search/install-name values are validated by the selected platform
|
||
adapter; frozen bundled policy permits only relocatable origin-relative paths.
|
||
Entry/retain tokens become the pinned linker's typed entry/undefined-root
|
||
mechanism. Raw flags exist only inside a content-identified custom toolchain
|
||
adapter.
|
||
|
||
The plan is not a set and is never alphabetically reordered. The selected
|
||
toolchain policy template determines global position: it can place start CRT
|
||
before the product-object splice and end CRT after runtime providers, rather
|
||
than relying on one universal ordering rule. Inside `product-objects`, WW
|
||
objects use stable package-identity order. Inside `native-providers`, fragments
|
||
use requester-before-provider topological order, which gives `libA` before the
|
||
`libB` it requires. `product-controls` carries the declared entry/retain/install
|
||
tokens; `init-dispatch` carries its single retained object when needed. Cyclic
|
||
static archives must be represented by one explicit `group`; an undeclared
|
||
provider cycle is an error. Repetition, whole-archive, as-needed, export maps,
|
||
and symbol-version scripts remain exact records in the flattened canonical plan.
|
||
|
||
An archive action preserves declared member order and canonicalizes header
|
||
timestamps, ownership, modes, and string tables. A shared-library input includes
|
||
its link-time artifact, SONAME/install-name, ABI digest, transitive runtime
|
||
requirements, and deployable runtime artifact digest. Merely finding the same
|
||
basename in a host directory is never equivalence.
|
||
|
||
The installation manifest also fixes runtime resolution. ELF bundled policy
|
||
copies the exact shared closure under a digest-namespaced relative `lib/` and
|
||
uses an origin-relative RUNPATH; Mach-O uses exact `@rpath`/install names; Windows
|
||
places named DLL artifacts in the declared application directory beside their
|
||
matching import libraries. A platform-image provider may instead bind an exact
|
||
loader/system tree. An OS-managed mutable shared library is an impure runtime
|
||
policy: link bytes can still be recorded, but WW does not promise that execution
|
||
will load a particular digest.
|
||
|
||
Linker scripts are declared content inputs. The adapter resolves/audits only
|
||
file-bearing directives such as `INCLUDE`, `INPUT`, `GROUP`, and `SEARCH_DIR`
|
||
for the pinned linker dialect; included files and permitted sysroot trees are in
|
||
the record. The pinned linker—not WW—interprets section placement, expressions,
|
||
symbols, memory regions, and target semantics inside the closed sandbox.
|
||
Unresolved `SEARCH_DIR`, absolute host paths, and implicit default scripts are
|
||
errors. GNU `ld` documents that scripts and archive order change link semantics;
|
||
WW therefore preserves rather than abstracts them away
|
||
([GNU ld scripts](https://sourceware.org/binutils/docs/ld/Scripts.html),
|
||
[GNU linker](https://sourceware.org/binutils/docs/ld.html)).
|
||
|
||
### 8.7 libc, CRT, SDK, loader, and freestanding products
|
||
|
||
A hosted platform entry names one exact sysroot/SDK and the available libc,
|
||
system, compiler-runtime, and WW-runtime providers; it does not name one
|
||
universal CRT sequence or loader. The selected toolchain link policy for
|
||
`(product-platform descriptor, product kind, linkage, profile, runtime
|
||
selector)` supplies the exact ordered token template containing CRTs, compiler
|
||
runtime, system-provider slots, script slot, and any platform-appropriate loader
|
||
contract. Compiler and linker
|
||
drivers run through no-defaults adapters and receive only that declared closure,
|
||
so they cannot fall back to B's `/usr`.
|
||
|
||
A product chooses a runtime policy:
|
||
|
||
```text
|
||
product "kernel" {
|
||
kind = "exe"
|
||
root = "kernel"
|
||
linkage = "static"
|
||
runtime = "none"
|
||
entry = "_start"
|
||
native = ["freestanding:boot@1"]
|
||
linker-script = "native/kernel.ld"
|
||
}
|
||
```
|
||
|
||
For an executable, `linkage` is exactly `dynamic`, `pie`, `static`, or
|
||
`static-pie`; shared-library products use `shared`. The toolchain maps
|
||
`(product kind, linkage, profile, product-platform, runtime selector)` to one
|
||
exact ordered policy template; selection never ignores `runtime`. Loader
|
||
presence follows the platform's executable rules. On an ABI with
|
||
an explicit program interpreter, `dynamic` and `pie` executables must name its
|
||
runtime path and exact provider artifact; `static` and `static-pie` must not. A
|
||
shared library has a runtime identity and dependencies but no executable program
|
||
interpreter. PE/COFF-style platforms without a separate interpreter bind the
|
||
exact platform-image/loader contract through system-provider policy rather than
|
||
inventing a pathname. Different product policies therefore cannot accidentally
|
||
share one CRT/loader sequence.
|
||
|
||
`runtime` is `hosted`, `minimal`, `none`, or a named provider. `none` supplies no
|
||
libc, CRT, loader, or WW runtime; compiler helper routines must be supplied by a
|
||
declared provider or rejected. `minimal` names an exact freestanding runtime.
|
||
Entry symbol, memory/linker script, relocation/code model, panic/stack policy,
|
||
and any boot image action are explicit. Kernel-style targets never inherit the
|
||
hosted target's defaults.
|
||
|
||
Schema 1 permits `none` only for object/static products and `static` or
|
||
`static-pie` executables. Its selected link template must contain no CRT,
|
||
dynamic-loader, libc, compiler-runtime, or WW-runtime token. `minimal` and named
|
||
providers declare their valid product/linkage set as capabilities; `hosted`
|
||
uses the platform's hosted set. A product/linkage/runtime tuple outside that set
|
||
is rejected during graph construction. The policy's single `script-slot` uses
|
||
the product's `linker-script` when present, replacing the default at the same
|
||
ordered position.
|
||
|
||
The target/toolchain declares the runtime capability required by every
|
||
compiler-emitted helper and language operation. During graph construction a
|
||
`none`/`minimal` product is rejected if selected source operations require an
|
||
unavailable allocation, panic, stack, arithmetic, TLS, unwind, or other runtime
|
||
capability; this is not deferred to an unexplained undefined linker symbol.
|
||
|
||
### 8.8 Provider conflicts and system substitution
|
||
|
||
One link namespace may select exactly one provider digest for an ABI slot such
|
||
as `c:zlib@1`, `c:libc`, or `runtime:ww@1`. Multiple requirements for the same
|
||
slot coalesce only if they resolve to the same provider and ABI digest. Different
|
||
providers, ABI major slots that export colliding unversioned symbols, and two
|
||
native modules claiming the same strong symbols are loud identity-collision
|
||
errors. WW never chooses whichever library appears first.
|
||
|
||
When more than one contract-compatible provider matches, the root product must
|
||
select one explicitly:
|
||
|
||
```text
|
||
product "hello" {
|
||
kind = "exe"
|
||
root = "."
|
||
linkage = "dynamic"
|
||
providers = [
|
||
{ slot = "c:zlib@1", use = "example.org/zlib#zlib-linux-aarch64" }
|
||
]
|
||
}
|
||
```
|
||
|
||
The provider ID is `(declaring module identity, native-clause name)`, rendered
|
||
with `#` only in metadata. Selection cannot change a dependency's required ABI
|
||
contract; the chosen provider must satisfy every declaration-level contract.
|
||
|
||
Two incompatible native versions can coexist only if they use distinct provider
|
||
slots **and** their symbols/runtime names are namespaced or versioned so the link
|
||
record proves no collision. Otherwise the build must adapt one behind a wrapper,
|
||
use dynamic isolation, or fail. Language-level multiple-version selection cannot
|
||
solve a C global-symbol collision.
|
||
|
||
A distro system provider is a normal provider record mapping exact logical
|
||
artifacts to content digests and ABI metadata. If those files live under `/usr`,
|
||
the mapping snapshots/re-hashes them before graph construction and changes the
|
||
key whenever they change. It is marked impure unless the directory tree itself
|
||
is immutable and content-identified. Raw `-L`, `-l`, `LD_LIBRARY_PATH`, compiler
|
||
defaults, and build-time `pkg-config` are not accepted substitutes.
|
||
|
||
A portable distributor substitution uses a closed `ww-native-map 1` file:
|
||
|
||
```text
|
||
ww-native-map 1
|
||
target = "sha256:product-platform-descriptor..."
|
||
provider "c:zlib@1" {
|
||
use = "distro.example/native#zlib"
|
||
contract = "sha256:..."
|
||
artifact-tree = "sha256:..."
|
||
provenance = "https://distro.example/provenance/zlib.jsonl"
|
||
}
|
||
```
|
||
|
||
`ww lock --native-map=FILE` records the map digest/origin in `ww.lock`; frozen
|
||
mode accepts only that exact signed/content-verified map. `ww.work` may contain
|
||
the same `provider` clause for local development, but it is an impure overlay and
|
||
frozen mode rejects it. This gives OS packagers an offline substitution mechanism
|
||
without changing imports or silently consulting `/usr`.
|
||
|
||
### 8.9 Cross-compilation behavior
|
||
|
||
All code-generating tools execute on B. WW/C/assembly compilation for the
|
||
requested ordinary product emits H objects using only H's target descriptor,
|
||
sysroot, headers, runtime, and native providers. A compiler-like product built
|
||
for H may later emit T code, but no T program executes during its own build.
|
||
Object headers and sidecars are checked before linking, so a host object cannot
|
||
silently enter a target product.
|
||
|
||
`ww test --target=H` always builds target test binaries. It executes them only
|
||
when `H = B` or the toolchain declares an explicit content-identified runner
|
||
(local emulator or simulator plus immutable image) as an invocation tool. Otherwise
|
||
it reports “built, not run” unless `--require-run` was requested, in which case
|
||
it fails. The runner and its platform image are action inputs; no ambient emulator
|
||
is discovered.
|
||
|
||
Remote hardware/device testing is a separate explicit
|
||
`ww observe test --runner=NAME` operation with declared endpoint/capability
|
||
authority. It may use network/devices but is a non-build observation: remote
|
||
state is reported, it never populates artifact/shared caches, and it is outside
|
||
byte-reproducibility claims. Ordinary `ww test` retains the no-network policy.
|
||
|
||
This model supports new targets without running a compiler on them: an existing
|
||
host toolchain adds a target descriptor, backend, object adapter, sysroot/runtime,
|
||
and native providers, then builds and tests through a declared runner or hardware
|
||
step. GNU's build/host/target distinction is useful vocabulary, but WW records
|
||
the complete descriptors rather than only triplets
|
||
([Autoconf triplets](https://www.gnu.org/software/autoconf/manual/autoconf-2.71/html_node/Specifying-Target-Triplets.html)).
|
||
|
||
## 9. Command-line design
|
||
|
||
### 9.1 The ordinary path
|
||
|
||
The default workflow is deliberately short:
|
||
|
||
```sh
|
||
ww init example.org/hello
|
||
ww build
|
||
ww run . argument
|
||
ww test .
|
||
```
|
||
|
||
`ww init MODULE` creates `ww.mod`, a root `main.ww` only when the directory is
|
||
empty, and a lock selecting the currently invoked immutable toolchain. It does
|
||
not add a dependency. In an existing one-directory `main` package, `ww build`
|
||
works without `init`; the invoking toolchain and standalone source identity are
|
||
shown in verbose output.
|
||
|
||
`ww build [DIR|PRODUCT]` builds the default root product or one named product.
|
||
The default profile is the fully specified `debug` profile; `--profile=release`
|
||
selects the toolchain's immutable release profile. `ww run` first performs that
|
||
same build, then runs only a product with `H = B`. After one explicit run target
|
||
is selected, every remaining operand is program input and is never interpreted
|
||
as a build option. A leading `--` is not the target boundary.
|
||
|
||
There is no command that means “build and opportunistically download whatever is
|
||
missing.” If a locked source or toolchain is absent, the diagnostic names its
|
||
digest and asks for `ww fetch --locked`.
|
||
|
||
### 9.2 Tests, examples, docs, and installation
|
||
|
||
```sh
|
||
# Exactly one package.
|
||
ww test ./internal/codec
|
||
|
||
# Every package below the current module root.
|
||
ww test ./...
|
||
|
||
# Compile cross-target tests and require a declared runner.
|
||
ww test ./... --target=aarch64-unknown-linux-gnu --require-run
|
||
|
||
# Build an ordinary example product and render documentation.
|
||
ww build example:examples/packet
|
||
ww doc ./... --out=out/doc
|
||
|
||
# Materialize a named release product under a prefix.
|
||
ww install inspect --profile=release --prefix=/opt/ww
|
||
```
|
||
|
||
Test package discovery and result reporting remain deterministic under `-j N`.
|
||
Compilation is cached, but every selected test binary runs. An installation
|
||
manifest lists every copied artifact, digest, mode, runtime dependency, and
|
||
relative destination and is materialized as `<product>.wwinstall`. Installation never discovers libraries in the prefix and
|
||
never mutates the cache artifact.
|
||
|
||
### 9.3 Inspecting the graph and cache
|
||
|
||
```sh
|
||
ww graph --packages
|
||
ww graph --actions
|
||
ww graph --actions --format=json > graph.json
|
||
ww explain example.org/hello/internal/codec
|
||
ww explain --path --all product:hello
|
||
ww cache verify
|
||
ww verify reproducible --profile=release
|
||
```
|
||
|
||
`graph` performs analysis but no build action. A node whose producer output does
|
||
not yet exist has a known action shape and incoming edges but a `pending` key;
|
||
its final key is computed when predecessor content digests become available.
|
||
`explain` compares available current records with the project index and likewise
|
||
does not build. These commands never fetch.
|
||
|
||
### 9.4 Adding, fetching, updating, freezing, and vendoring
|
||
|
||
```sh
|
||
# Query the module's conventional source index, add a minimum, and lock closure.
|
||
ww add example.org/codec@v1.2.3
|
||
|
||
# The same operation with an explicit private or non-conventional origin.
|
||
ww add corp.example/codec@v1.2.3 --from=https://packages.corp/codec/
|
||
|
||
# Materialize exactly the existing lock without changing any project file.
|
||
ww fetch --locked
|
||
|
||
# Change one direct minimum and recompute the complete lock atomically.
|
||
ww update example.org/codec@v1.4.0
|
||
|
||
# Recompute after an intentional manifest edit.
|
||
ww lock
|
||
|
||
# Materialize the exact locked source closure in the project.
|
||
ww vendor --locked
|
||
|
||
# A frozen, offline build from already present locked inputs.
|
||
ww build --frozen --offline --vendor
|
||
```
|
||
|
||
`add` and `update` write `ww.mod` and `ww.lock` together through temporary files
|
||
only after the entire selection and integrity check succeeds. `lock` writes only
|
||
`ww.lock`. `fetch` and `vendor` never change selection. Without `--vendor`, WW
|
||
uses the immutable source store; with it, every vendor digest is reverified.
|
||
`add --from=URL` records that credential-free index as the requirement's
|
||
`source-index`; archive redirects/final origin remain exact lock metadata.
|
||
|
||
An ordinary non-frozen build still never updates an inconsistent lock: it fails
|
||
with the exact `ww lock` command. Frozen mode additionally rejects workspaces,
|
||
impure providers, noncanonical metadata, unlocked tools, and any source digest
|
||
not named by the lock. `--offline` is useful in automation as an assertion but
|
||
does not weaken or strengthen the normal build network denial.
|
||
|
||
### 9.5 Cross compilation and toolchain selection
|
||
|
||
```sh
|
||
# Select a product host platform (the familiar cross-build form).
|
||
ww build --target=aarch64-unknown-linux-gnu --profile=release
|
||
|
||
# Select exact CPU semantics rather than probing the build machine.
|
||
ww build --target=x86_64-unknown-linux-gnu \
|
||
--cpu=x86-64-v3 --feature=-avx512f
|
||
|
||
# Build a compiler that runs on H and emits code for T.
|
||
ww build compiler:wwc \
|
||
--host=aarch64-unknown-linux-gnu \
|
||
--target=riscv64-unknown-none-elf
|
||
|
||
# Acquire and lock an exact toolchain before building; only fetch uses network.
|
||
ww toolchain fetch ww.org/toolchain@v1.4.0
|
||
ww lock --toolchain=ww.org/toolchain@v1.4.0
|
||
ww build --toolchain=ww.org/toolchain@v1.4.0
|
||
```
|
||
|
||
The selected command toolchain must match the common ID, satisfy every minimum,
|
||
and equal the root lock's exact descriptor. A digest
|
||
selection is exact; an ID/version selection resolves only through the lock or
|
||
installed signed catalog and never during build. `ww toolchain list --targets`
|
||
shows descriptors and sysroot/runtime digests, not just triples. `ww lock
|
||
--toolchain` changes only the lock's exact toolchain selection when the chosen
|
||
version satisfies every manifest minimum; it does not rewrite those minimums.
|
||
|
||
### 9.6 Deliberately absent commands/options
|
||
|
||
There is no `ww build --fetch`, build-time package-manager hook, raw `-L`/`-l`,
|
||
global import search path, arbitrary compiler/linker environment injection,
|
||
manifest evaluator, or command that installs dependencies into a mutable global
|
||
source namespace. Expert escape hatches are explicit toolchains, native provider
|
||
records, and finite declarative actions; all remain visible in the graph/key.
|
||
|
||
## 10. Toolchain and bootstrap design
|
||
|
||
### 10.1 The durable stage-zero seed
|
||
|
||
The smallest credible recovery seed is:
|
||
|
||
```text
|
||
bootstrap/ww0.c generated portable C99 snapshot
|
||
bootstrap/bootstrap.plan canonical source/tool/output plan
|
||
bootstrap/SHA256SUMS expected seed and plan digests
|
||
```
|
||
|
||
`ww0.c` is generated at release time from the same compiler sources as the
|
||
production compiler, with a deliberately non-optimizing portable C backend and
|
||
the minimal support routines concatenated into one translation unit. It is not
|
||
a second hand-maintained compiler and is never used in ordinary production
|
||
builds. The resulting `ww0` retains that portable C-emission path: it contains
|
||
only enough compiler, export writer, C output, and fixed-plan execution to emit
|
||
stage-1 C from the enumerated source closure and have the named host C closure
|
||
compile it. It has
|
||
no resolver, network client, general manifest engine, cache, test coordinator,
|
||
or installation framework.
|
||
|
||
The release process regenerates `ww0.c` and fails if its bytes differ from the
|
||
checked-in snapshot. Keeping portable source rather than four opaque host
|
||
binaries permits recovery on a new architecture with a C99 implementation. The
|
||
cost of the simple C emitter is accepted because it bounds and exposes the seed;
|
||
it is a release backend, not another production path.
|
||
|
||
The bootstrap-host contract is narrower than “any C99”: hosted C99 with
|
||
`CHAR_BIT == 8`, exact `uint8_t/uint32_t/uint64_t`, two's-complement signed
|
||
integers, binary file I/O, at least 32-bit address space and the published source/
|
||
object size limits. The snapshot uses no host floating-point result or undefined
|
||
signed overflow. Compile-time assertions plus a tiny I/O/integer conformance
|
||
probe run before compilation. Supported implementation modes and required
|
||
headers are enumerated in `bootstrap.plan`; an implementation outside the
|
||
contract is not silently called portable.
|
||
|
||
### 10.2 Stage transitions and fixed point
|
||
|
||
Recovery uses these exact stages:
|
||
|
||
1. A named host C implementation compiles `ww0.c` to `ww0`. Its executable,
|
||
version output, command, headers, libc, assembler, and linker are recorded in
|
||
`bootstrap-host.wwar`; they are part of the trusted base, not silently blessed.
|
||
2. `ww0 bootstrap/bootstrap.plan` runs on B, emits portable C for the locked
|
||
production compiler/driver, and uses that same recorded host C closure to
|
||
produce **stage 1 with H = B**. Stage 1 must run locally; distributable cross
|
||
compilers are built only after the local fixed point.
|
||
3. Stage 1 uses the pinned production target/tool closure to perform a normal
|
||
frozen build of the same sources for `H = B`, producing **stage 2**.
|
||
4. Stage 2 repeats the identical logical build to produce **stage 3**.
|
||
5. Stage 3 repeats it to produce **stage 4**.
|
||
6. `bootstrap.compare` first requires stage-2 and stage-3 **semantic output
|
||
sets**—compiler/driver executables, export/object/runtime artifacts, and the
|
||
installed semantic bundle tree—to be byte-identical. Producer action records
|
||
and provenance are excluded because stage 2 was built by stage 1 while stage
|
||
3 was built by stage 2. Once those compiler bytes converge, it requires
|
||
stage-3 and stage-4 semantic outputs **and raw action/result records** to be
|
||
byte-identical; their producer compiler digests are then equal. Each raw
|
||
record is a separately named `action-record` or `action-result` input in
|
||
action tag 10; comparison metadata or a digest outside tag 10 is not read
|
||
authority.
|
||
|
||
Stage 1 need not equal stage 2: portable-C and production backends may generate
|
||
different code. Stage 2 MUST equal stage 3 semantically, and stage 3 MUST equal
|
||
stage 4 completely. A canonical stage semantic manifest lists only role/output
|
||
artifact digests, never its producer. A mismatch reports the first differing
|
||
output or action field and is a release failure. Two absolute roots and two
|
||
concurrency levels are used for the official fixed-point job.
|
||
|
||
This fixed point proves self-consistency and path/order reproducibility; it does
|
||
not by itself defeat Ken Thompson's trusting-trust attack. Official releases
|
||
also perform **diverse seed compilation** with two independently sourced host C
|
||
toolchains where available, publish both bootstrap-host records, regenerate the
|
||
C snapshot from the converged WW source/compiler, and compare converged semantic
|
||
outputs before signing. This is additional evidence, not a claim of formal
|
||
diverse-double-compilation proof.
|
||
|
||
### 10.3 Trusted-computing-base accounting
|
||
|
||
The bootstrap report lists, by content digest:
|
||
|
||
- `ww0.c`, `bootstrap.plan`, and their tiny C support layer;
|
||
- host C compiler/preprocessor, headers, libc, assembler, linker, loader, and OS
|
||
kernel used to create/run `ww0`;
|
||
- bootstrap assembler/linker/archive tools and their shared/resource closure;
|
||
- source/lock/toolchain descriptor trees; and
|
||
- the SHA-256 and signature verification implementations/keys.
|
||
|
||
That is the reproducible software/input closure. The operational trusted
|
||
computing base additionally includes CPU, firmware, memory/storage behavior,
|
||
kernel, and execution environment; the report names the available hardware/
|
||
firmware attestations but does not pretend a source hash removes physical trust.
|
||
|
||
Nothing is called “trusted” merely because it was found on `PATH`. A recovery
|
||
build with unpinned system tools may establish a new local fixed point but cannot
|
||
claim byte identity with an official release. An official reconstruction uses a
|
||
published content-identified host/bootstrap closure and compares its advertised
|
||
digests.
|
||
|
||
### 10.4 Toolchain distribution and selection
|
||
|
||
Each release publishes source plus locked-source-closure archive, `ww0.c`, lock
|
||
file, platform toolchain bundles, `toolchain.wwt`, stage-2/3/4 semantic and
|
||
action/result manifests, fixed-point report,
|
||
digests, signatures, and provenance. Binary bundles are conveniences verified
|
||
against the descriptor, not irreplaceable seeds. A user either selects the
|
||
project-locked toolchain or an exact command-line digest; WW never downloads a
|
||
new compiler while building.
|
||
|
||
Runtime ABI, export protocol, object ABI, and action-schema compatibility are
|
||
declared independently. A compiler refuses a runtime whose ABI it does not
|
||
support. Toolchain upgrades can retain source compatibility while intentionally
|
||
invalidating all relevant action keys.
|
||
|
||
### 10.5 New-architecture and no-compiler recovery
|
||
|
||
For a new H satisfying the bootstrap-host contract, compile `ww0.c`; `ww0` emits
|
||
the modified production compiler as portable C and the H C compiler builds the
|
||
locally runnable stage 1. Add/pin H's production object/assembler/linker closure,
|
||
then reach the stage-2/3/4 fixed point. Alternatively an existing B toolchain may
|
||
cross-build that H compiler, but it executes only through an explicit runner.
|
||
For a new T only, no target-local compiler is required: add the backend/target
|
||
descriptor, object tests, sysroot or freestanding runtime, and linker provider
|
||
to an existing B/H toolchain.
|
||
|
||
When no suitable WW compiler exists, the checked-in C seed is sufficient. When
|
||
no C compiler exists either, a platform must provide one previously built `ww0`
|
||
binary plus its exact source/digest, or bootstrap a C implementation; WW does not
|
||
claim a smaller physical trusted base than the machine can execute.
|
||
|
||
## 11. Current-system assessment
|
||
|
||
This section records the verified baseline at commit
|
||
`ca2cadeb4173e8190cd4c8bcc25e7da25bcdb0bc`. Line references describe that
|
||
commit and are implementation evidence, not requirements for the replacement.
|
||
|
||
### 11.1 Current invariants
|
||
|
||
- POSIX Make selects ambient `CC`, `AR`, optional `ccache`, and flags; builds the
|
||
Cstage tools; then uses the Cstage driver to build WWstage tools into separate
|
||
work directories. Make repeats manually enumerated transitive source
|
||
prerequisites for each self-hosted target
|
||
([Makefile](../Makefile), lines 7–20 and 105–279).
|
||
- `ww build` creates fixed-array package nodes keyed by dotted import spelling,
|
||
discovers imports with a hand-written scanner separate from the compiler
|
||
parser, rejects directory-package cycles, visits dependencies in
|
||
DFS postorder, and invokes packages serially. The graph is capped at 256
|
||
packages ([C driver](../cmd/ww/main.c), lines 333–370 and 670–700).
|
||
- An imported directory is a separately compiled package. An imported `.ww`
|
||
file is recursively folded into the importing unit and has no node, identity,
|
||
interface, object, or link artifact of its own. Inline package blocks can also
|
||
satisfy otherwise missing imports (C driver, lines 396–428 and 498–613).
|
||
- A directory package selects all immediate `.ww` files except `*_test.ww`, sorts
|
||
them by bytes, and has no target-specific selection rule (C driver, lines
|
||
239–301). The build path follows source symlinks while the test coordinator
|
||
rejects them.
|
||
- Resolution translates dotted imports to paths and performs a global
|
||
directory-before-file search over the entry root, `-I` roots, and inferred
|
||
source library. Thus a directory in a later root beats a file in an earlier
|
||
root (C driver, lines 152–224 and 966–1003).
|
||
- Every dependency emits source-like `.wwi`. Every importer receives the whole
|
||
transitive `.wwi` closure, tagged with out-of-band module comments and prepended
|
||
to a composed `.unit.ww`; the compiler reparses that unit (C driver, lines
|
||
702–809; [interface writer](../cmd/w6c/wwi.c), lines 1–24 and 505–570).
|
||
- The root compiles without compiler `-I`, emits no `__root.wwi`, bypasses the
|
||
dependency export-signature path, and receives special `main` handling; only
|
||
dependency nodes emit interfaces. `ww test` also injects the resolvable `test`
|
||
package as a synthetic root edge even when source has no such import, while
|
||
runtime is an implicit link edge. Imports do not fully describe even today's
|
||
complete graph (C driver, lines 1066–1083 and 1131–1146).
|
||
- `.wwi` records exported prototypes and direct import text but no compiler,
|
||
format, target, data-layout, object ABI, or runtime ABI identity. It includes
|
||
non-semantic parameter names and import spelling. The compiler's `-I` flag
|
||
both requests interface output and changes `main` symbol handling
|
||
([compiler entry](../cmd/w6c/main.c), lines 25–56 and 83–110).
|
||
- For `P` reachable directory packages including root, a normal driver build
|
||
launches `P` compiler processes, `P` assembler processes, and one linker.
|
||
It writes `P-1` dependency archives itself. The link is root object, dependency
|
||
archives in reverse topological order, runtime, then separately accumulated
|
||
`-L` and `-l` values, losing their original interleaving (C driver, lines
|
||
1095–1249 and 1368–1460).
|
||
- `-w DIR` is a caller-owned mutable reuse directory, not a cache. Freshness is
|
||
exact composed-unit bytes, copied driver/compiler/assembler bytes, a text mode
|
||
stamp, and artifact existence/nonzero size. The graph and units are rebuilt
|
||
in memory and the final executable is relinked on every invocation.
|
||
Publication through `.new` files with the unit committed last is usefully
|
||
atomic (C driver, lines 867–952, 1016–1059, and 1110–1213).
|
||
- Without `-w`, a build creates and deliberately retains
|
||
`<output-stem>.sepwork`; repeating while it exists fails. With `-w`, the caller
|
||
must create and serialize the directory. Normal driver products are always
|
||
root executables linked with the runtime; there is no library-only product
|
||
path, and `-S` merely stops after assembly.
|
||
- `ww test DIR` delegates to a separate coordinator. It groups same-package
|
||
`package p;` and external `package p_test;` tests from `*_test.ww`, excludes
|
||
dependency tests, composes generated source roots, and parallelizes independent
|
||
test binaries with deterministic reporting
|
||
([package coordinator](../internal/wwpackage/package.ww), lines 278–417,
|
||
508–648, and 725–1057).
|
||
- Explicit `ww test FILE` bypasses the directory `*_test.ww` classifier and
|
||
accepts an arbitrarily named source root. Universal directory packages delete
|
||
that distinct test mode.
|
||
- Current bootstrap is mixed C/self-hosted. Make keeps the C driver fixed, uses
|
||
self-hosted compiler stages to produce `ww2`, `ww3`, and `ww4`, and compares
|
||
`ww2 == ww3` and `ww3 == ww4`. The self-hosted driver itself is outside that
|
||
fixed-point chain. The planned four stage-zero binaries are absent; the
|
||
“no C compiler” route still uses host `ar` ([Makefile](../Makefile), lines
|
||
825–883; [bootstrap notes](../BOOTSTRAP.md)).
|
||
|
||
### 11.2 Conflated identities and accidental behavior
|
||
|
||
This table records the baseline that the implemented slices below replaced;
|
||
sections 11.6–11.18 are authoritative where they conflict with it.
|
||
|
||
| Concept that must be separate | Current conflation or accident |
|
||
|---|---|
|
||
| package identity | Before the local-package slices, dotted import spelling was simultaneously graph key, module/symbol prefix, artifact basename, and link identity. The implemented loader now separates source spelling, expanded canonical identity, physical directory, and storage locator. |
|
||
| declared name | Before section 11.18, imported directories required their declared name to equal the import-path leaf and `.wwi` retained only that leaf. The implemented compiler/export path now carries the declaration independently. |
|
||
| filesystem location | Ordered search roots silently choose/shadow a location; the same physical directory may be compiled under two import identities, while duplicate locations for one spelling produce no collision diagnostic. Paths are lexical, not content identities. |
|
||
| package versus file | Directories create separate-compilation nodes; files disappear into owners. The same `package` syntax means two compilation models. |
|
||
| artifact versus identity | `<dotted-path>.wwi/.s/.o/.a` names artifacts; root aliases to `__root`, which can collide with a real import. |
|
||
| public versus non-semantic interface | Parameter names and AST-preserved type/import spellings influence `.wwi` bytes and reverse rebuilds. Imports/declarations are otherwise canonically sorted; whitespace/comments and original declaration order generally do not. |
|
||
| compiler interface mode versus link identity | `w6c -I` both emits `.wwi` and classifies the package as a dependency for `main` mangling. |
|
||
| native dependency versus linker search | Raw `-L` and `-l` names carry no selected file, ABI, order relationship, target, or content identity. |
|
||
| cache location versus cache key | The explicit `-w` directory is both mutable namespace and freshness state; callers must serialize it. |
|
||
| source root versus command UX | Help historically describes `.` like a basename file, while implementation stats and builds it as a directory. |
|
||
|
||
Other accidental constraints include fixed 256/1024-byte name/path buffers. The
|
||
compiler parser silently truncates dotted full imports beyond 255 bytes, while
|
||
the C driver scanner can stop advancing and hang on an import identifier at that
|
||
limit; the dynamically sized WWstage scanner differs. There is no regression
|
||
test for this stage divergence. Compiler, assembler, and linker launches now use
|
||
structured argument vectors in both stages. Both drivers honor exact executable
|
||
paths in `WW_W6C`, `WW_W6A`, and `WW_W6L` and otherwise select their
|
||
stage-specific sibling tools. Both drivers distinguish the package-source root
|
||
selected by `WW_SRCLIB` from the runtime-artifact root selected by `WW_LIB`, and
|
||
apply the same empty-value and repository/install fallbacks. The two
|
||
implementations remain parallel production algorithms rather than one protocol
|
||
implementation.
|
||
|
||
Build and test disagree about source symlinks. External package tests are built
|
||
from a generated single-file root plus `-I`; an external import of a multi-file
|
||
production package can resolve and fold only its canonical same-named file rather
|
||
than the directory package. Test work-directory names flatten `/` to `_`, so
|
||
distinct lexical paths can collide. These are consequences of routing tests
|
||
around, rather than through, one package model.
|
||
|
||
`make install` copies only `ww`, `wwtest`, and `libwcc.a`, while the driver needs
|
||
sibling compiler/assembler/linker tools and `libwwrt.a`; the installed result is
|
||
not a self-contained functional toolchain outside the build tree.
|
||
|
||
### 11.3 Scaling, invalidation, and hidden inputs
|
||
|
||
The driver performs deterministic linear action interning but now grows every
|
||
package dependency vector dynamically (section 11.14). Every package compiler
|
||
reads exactly one interface per direct dependency; transitive dependencies enter
|
||
only the executable archive closure. Package compiler/assembler work within one
|
||
driver remains serial; Make gains parallelism only by launching independent
|
||
top-level driver builds.
|
||
|
||
The observed invalidation rules are:
|
||
|
||
- a private change in a directory dependency rebuilds that package and the
|
||
unconditional final link, but not importers;
|
||
- an exported change rebuilds direct importers and continues through an ancestor
|
||
only while the regenerated direct-dependency export bytes change, stopping at
|
||
the first byte-identical regenerated interface;
|
||
- a private change in a folded file import rebuilds its entire owner;
|
||
- a link-only option reruns the always-executed link but not package compiles;
|
||
- changing copied compiler or assembler bytes rebuilds every package; and
|
||
- nonzero corruption of `.s`, `.o`, `.a`, or `.wwi` may be accepted because
|
||
content is not rehashed.
|
||
|
||
Hidden or incompletely modeled inputs include `CC`, `AR`, `PATH`, `ccache`, Make
|
||
flags, compiler built-ins, assembler/linker defaults,
|
||
inferred `argv[0]` library locations, current working directory, file mode, runtime
|
||
archive, linker binary, native-library resolution, host libc/CRT/loader, SDK,
|
||
CPU, target, and environment. Make does not invalidate existing C objects when
|
||
the host compiler or C flags change. Persistent package workdirs now bind the
|
||
exact driver executable, conservatively covering its graph, unit, archive, and
|
||
commit semantics; the remaining ambient inputs are not thereby promoted into a
|
||
cache protocol. WW has no target triple, sysroot, conditional source, generator,
|
||
manifest, lock, source digest, or frozen/offline concept.
|
||
|
||
### 11.4 Measurements and disposable experiments
|
||
|
||
Measurements ran on Linux 6.12.76_1 x86-64 with eight logical CPUs, GCC 14.2.1,
|
||
binutils 2.44, and no `ccache`. They used successful clean builds and isolated
|
||
temporary source fixtures; no production migration was begun. Clean/full means
|
||
use two timed samples and representative cold means three, without CPU isolation
|
||
or OS-cache flushing, so they are observed baselines rather than universal
|
||
performance claims.
|
||
|
||
| Measurement | Result |
|
||
|---|---|
|
||
| clean `make all`, `-j1` | 24.847 s mean |
|
||
| clean `make all`, `-j8` | 15.515 s mean; only 1.60× speedup |
|
||
| warm `make all -j8` | 0.02365 s mean at Make level |
|
||
| clean tool trace | 69 package compiles/assembles in six driver workdirs; 71 `w6c`, 76 `w6a`, six `w6l`, 63 in-driver archives; package work inside each driver stayed serial |
|
||
| small / 8-package / 15-package cold driver build | 0.0103 / 0.1326 / 9.6706 s |
|
||
| same warm driver builds | 0.00814 / 0.01347 / 0.05302 s; each still linked |
|
||
| `out/` | 34,464,015 bytes, 398 files |
|
||
| six WW build workdirs | 28,609,092 bytes, 351 files; 9,954,428 bytes (34.8%) duplicate beyond the first content copy |
|
||
| 15-package root composed unit | 14 `.wwi` sections, 1,464,581 bytes; 62 interface insertions across graph, 1,928,898 composed-unit bytes versus 23,664 distinct interface bytes |
|
||
|
||
A three-package `root -> mid -> leaf` fixture confirmed that root consumes both
|
||
direct and transitive interfaces. A private leaf implementation edit rebuilt
|
||
only leaf plus link. Adding a compatible public leaf API rebuilt all three even
|
||
though `mid` emitted identical `.wwi`. A link-only `-L` change ran only the link.
|
||
|
||
Switching the compiler executable by byte content invalidated all packages.
|
||
Appending data to a nonzero cached `mid.s` was not detected; the old object was
|
||
reused and the build succeeded. This directly rejects artifact-presence caching.
|
||
|
||
Two builds from different absolute source roots produced the same 398 relative
|
||
paths and all sampled WW-generated executables/package artifacts were byte
|
||
identical. The full trees were not: 45 Cstage host objects/copied tools differed,
|
||
including GCC `DW_AT_comp_dir`. Thus current checkout-independent byte identity
|
||
holds for measured WW artifacts, not for the complete build.
|
||
|
||
Cstage and WWstage drivers building the same eight-package graph produced a
|
||
byte-identical final executable and all 38 non-tool artifacts, but took 0.138 s
|
||
and 0.356 s respectively. The audit also found that Cstage formerly returned
|
||
success after an ambient `chmod` lookup failed and left mode 0644, while WWstage
|
||
created mode 0755 directly. Cstage now calls `chmod(2)` on the exact output path
|
||
and reports failure, removing that host-tool and path-splitting asymmetry.
|
||
|
||
### 11.5 What survives and what is deleted
|
||
|
||
The replacement retains these sound concepts:
|
||
|
||
- explicit source imports, package clauses, exported/private declarations, and
|
||
loud directory-package-cycle errors, strengthened to every package after file
|
||
folding (whose cycles were merely visit-deduplicated) is deleted;
|
||
- directory package boundaries, made universal rather than optional;
|
||
- same-package and external `*_test.ww` semantics, dependency-test exclusion,
|
||
deterministic discovery/reporting, and always executing selected tests;
|
||
- deterministic sorting/serialization, atomic artifact publication, fixed-point
|
||
bootstrap checks, and byte-identity tests; and
|
||
- the ordinary `ww build`, `run`, and `test` user experience.
|
||
|
||
The replacement deletes these concepts rather than emulating them indefinitely:
|
||
|
||
- file imports, inline multi-package units, bare dotted imports, `-I` search
|
||
roots, directory-before-file precedence, and the `__root` artifact alias;
|
||
- `.wwi`, `//ww:module` wrappers, `.unit.ww`, transitive interface prepending,
|
||
source-prototype interchange, automatic per-dependency archives, and `-w`;
|
||
- raw ambient `-L`/`-l`, compiler/linker/sysroot defaults, and build-time
|
||
`pkg-config` discovery;
|
||
- separate C and self-hosted production drivers, the production Make graph, and
|
||
the separate source-composing test coordinator; and
|
||
- the current Cstage bootstrap path and permanently owned assembler/linker after
|
||
the generated C seed and pinned external tool closure replace them.
|
||
|
||
There will be no compatibility alias that silently translates an old import,
|
||
interface, workdir, or link search into the new model.
|
||
|
||
### 11.6 Implemented local package slice
|
||
|
||
The first executable package slice is intentionally smaller than the final
|
||
module design above. It is local, offline, and manifest-free. The supported
|
||
form is:
|
||
|
||
```sh
|
||
out/bin/ww build -I /work/acme -o app /work/acme/cmd/app
|
||
```
|
||
|
||
Every selected source uses the existing syntax:
|
||
|
||
```ww
|
||
package main;
|
||
import lib.math;
|
||
```
|
||
|
||
A source import is translated from dots to path separators, expanded through
|
||
the nearest eligible local `vendor` directory described in section 11.16, then
|
||
falls back to directory lookup through the entry package's directory, explicit
|
||
`-I` roots in command order, and the toolchain source-library root. A same-named
|
||
`.ww` file is neither a match nor a shadow for an import, so a later root
|
||
containing the directory wins over an earlier file decoy. There is no network,
|
||
manifest, or imported-file fallback. Explicit single-file CLI roots retain
|
||
their raw-unit compatibility path. The loader uses the compiler frontend's
|
||
imports-only parser, retains every real import occurrence with its owning
|
||
source file and position, byte-sorts and deduplicates the resulting canonical
|
||
direct edges, interns canonical directory actions, and reports self-imports and
|
||
stable cycle chains before compilation. Occurrence retention makes contextual
|
||
`internal` and `vendor` checks run at every import site; it does not duplicate
|
||
package actions or compiler inputs.
|
||
|
||
A directory package consists of its immediate `.ww` entries whose basenames do
|
||
not begin `.` or `_`: regular files and symlinks targeting regular files are
|
||
included under the entry name, while symlinks targeting directories are
|
||
ignored. The production variant excludes `*_test.ww`; each variant retains
|
||
byte-sorted filename order. Every selected production file must declare the
|
||
same package name, but that declaration is independent of the directory name
|
||
and every component of the canonical import path. A selected command directory
|
||
declares `package main` while retaining its complete canonical import identity.
|
||
A source import of a command package from a
|
||
different directory is rejected; the one same-directory exception is an
|
||
external `main_test` variant's canonical import of its effective augmented
|
||
test action. Two
|
||
ordinary logical identities for one physical directory are rejected rather
|
||
than compiled twice; section 11.16 records the deliberate exception for
|
||
distinct expanded vendor routes that converge through symlinks.
|
||
|
||
Packages compile serially in dependency-first postorder. The compiler emits the
|
||
existing deterministic `.wwi` interface for every directory-package action,
|
||
including an executable root. Its primary section contains that package's
|
||
byte-sorted direct imports and exported declarations. The compiler then appends
|
||
byte-sorted, origin-tagged sections for only the foreign type and constant facts
|
||
recursively reachable from the primary public signatures. Reachable owner-local
|
||
private nominal types are carried without `export`: they make the export
|
||
self-contained for type checking, but qualified source lookup still rejects
|
||
their names. Checked fixed array dimensions are emitted as numeric type facts,
|
||
so a public layout never requires exposing the private constant spelling that
|
||
produced its length.
|
||
|
||
A package compilation unit contains only that package's own byte-sorted sources,
|
||
deterministic `//ww:module-reset` separators, and sorted driver-private
|
||
resolution metadata; it never contains a dependency source body. Each
|
||
**direct** import is a separate
|
||
`--import <canonical-path> <dependency.wwi>` compiler input, sorted by canonical
|
||
path and deduplicated by the loader; a source spelling expanded through
|
||
`vendor` additionally receives the non-dependency `--import-map` described in
|
||
section 11.16. No transitive `.wwi` is passed.
|
||
Origin-tagged facts inside those direct artifacts are compiler data, not source
|
||
imports: a source qualifier is visible only in the source file that directly
|
||
imports it. The qualifier is the imported export's declared package name, not
|
||
the source spelling or import-path leaf. Private members, transitive-only
|
||
qualifiers, bare values, and bare types remain compiler errors. In `-c` package
|
||
mode the compiler parses each
|
||
export independently, then coalesces repeated exported type/constant facts with
|
||
the same origin, kind, and name, preserving one nominal type identity across
|
||
diamonds; raw non-package `w6c` retains its existing one-source behavior. The
|
||
source-like `.wwi` syntax remains a transitional export encoding pending the
|
||
binary `.wwe` format described above, but the separate direct-input ownership
|
||
boundary is live in production Cstage and WWstage compilers and drivers.
|
||
|
||
A selected production root is one normal package action. Its finalized
|
||
canonical import identity tags its owner-only unit; it receives only direct
|
||
exports, emits `.wwi`, `.o`, and a deterministic `.a`, and is compiled exactly
|
||
once. The declared package name is semantic package content but never validates,
|
||
shortens, aliases, or replaces that identity. After loading and identity
|
||
finalization, the
|
||
declaration also selects the terminal build action: `package main` is a command
|
||
and every other valid declaration is a compile-only library. A command root
|
||
receives the narrow compiler `--entry` flag, which controls bare `main` codegen,
|
||
then the linker receives that root archive first, the complete reachable
|
||
package-archive closure, and the runtime archive; it never receives `.wwi`. A
|
||
non-main root receives no `--entry` and never enters the linker. `main` validates
|
||
command kind but never replaces or truncates an identity such as `cmd.tool`.
|
||
The explicit package-less single-file compatibility path has no directory
|
||
package declaration to classify and remains a raw command unit; it does not
|
||
participate in canonical directory-package interning.
|
||
The package driver still uses the parser-only `--command-package` marker for
|
||
command test variants that must remain ordinary archive code. Neither marker
|
||
changes export identity, and imported interfaces retain independent canonical
|
||
owner and declared-name records. The linkers seed `main` before archive selection, so the existing
|
||
WWAR member protocol needs no special root object or format change.
|
||
|
||
Publication is separate from that semantic action choice. `ww build -o lib.a
|
||
DIR` or `ww build -I ROOT -o bar.a foo.bar` automatically publishes a non-main
|
||
root's deterministic archive and self-contained compiler export at
|
||
`FILE.wwi`, without invoking the linker; the latter retains `foo.bar.*` symbols.
|
||
Without `-o`, a non-main root and its dependencies are compiled in the selected
|
||
scratch or persistent work directory and no cwd product is invented. For a
|
||
command, `-o` continues to name the executable publication path. Output names,
|
||
request order, and whether publication was requested never enter package or
|
||
action identity. The historical action-selecting `-p` exception is removed and
|
||
rejected as an unknown build flag. Assembly-only `-S` still stops before object,
|
||
archive, publication, or link production. A literal directory is
|
||
reverse-resolved through the active source roots or receives the deterministic
|
||
local identity described below; its declaration can never invent or truncate
|
||
that identity. Two cold builds with identical inputs are required to produce
|
||
byte-identical requested products. Compiler intrinsics keep their package-mode
|
||
runtime ABI independent of transitive source interfaces (for example, `alloc`
|
||
lowers to the runtime allocator without requiring an `rt.wwi` compiler input).
|
||
|
||
This rule follows the pinned official Go 1.26.5 source at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`. `go/build.Package` stores source
|
||
directory, declared name, and import path independently, and defines a command
|
||
solely as a package named `main`
|
||
([`go/build/build.go`, lines 436–449](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L436-L449),
|
||
[`go/build/build.go`, lines 514–519](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L514-L519)).
|
||
The Go builder's `AutoAction` links only `main` and returns the archive compile
|
||
action for every other package
|
||
([`cmd/go/internal/work/action.go`, lines 450–456](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L450-L456)).
|
||
The build command invents a default output only for one `main`, applies an
|
||
explicit `-o` to either AutoAction result, and otherwise builds each requested
|
||
package without conflating publication and semantic kind
|
||
([`cmd/go/internal/work/build.go`, lines 473–478](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L473-L478),
|
||
[`cmd/go/internal/work/build.go`, lines 508–548](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L508-L548),
|
||
[`cmd/go/internal/work/build.go`, lines 551–558](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L551-L558)).
|
||
|
||
Both WW stages represent the rule with the existing loaded declaration and
|
||
stable root action index; no package, dependency, ownership, locator, traversal,
|
||
or closure allocation is added. `ww run` adds only a command-kind requirement:
|
||
a successfully loaded, cycle-free non-main root produces the deterministic
|
||
`package PATH is not a main package` diagnostic before any compiler, assembler,
|
||
or linker invocation; package and graph failures retain precedence. Before a
|
||
non-main `-o` build invokes a producer, both stages validate the longest atomic
|
||
publication spelling, `FILE.wwi.new`, so an incomplete archive/export pair is
|
||
never caused by a late path-overflow failure. Package loading, cycle detection,
|
||
and closure validation retain diagnostic precedence over this publication-only
|
||
check, and `-S` does not validate a publication path it never consumes.
|
||
Build workdir format 14 and test workdir format 13 invalidate older unit
|
||
vouchers before reuse because source binding and vendor-directory identity now
|
||
participate in compiler argv and persistent unit semantics. Thereafter
|
||
an equivalent warm library build invokes no tools, a private dependency change
|
||
stops at its unchanged export, and an export change recompiles its direct
|
||
importer under the existing propagation rule.
|
||
|
||
### 11.7 Implemented directory package-test slice
|
||
|
||
Directory tests now enter that same local package loader and build path. The
|
||
supported manifest-free forms include `ww build DIR...`, `ww build DIR/...`,
|
||
`ww test DIR...`, and `ww test DIR/...`, with overlapping direct and recursive
|
||
roots. Test retains its existing `-run`, `-filter`, `-list`, `-timeout-ms`,
|
||
`-j`, `-c`, and `-w` forms. `ww test -c -o test.bin DIR` names the result when
|
||
the request selects one canonical directory, including a directory with both
|
||
same-package and external-package test sources. The coordinator rejects one
|
||
output name only when it would fan out over multiple directory products.
|
||
Explicit `ww test FILE` retains its compatibility path.
|
||
|
||
The test coordinator still discovers requested directories, classifies the
|
||
selected test package names, executes one binary per test-bearing canonical
|
||
directory, and emits captured results in byte-sorted directory order. It no
|
||
longer concatenates a
|
||
generated production/test root, resolves imports, or starts one package graph
|
||
per declared test package. Instead it sends one ordered build request containing
|
||
one product descriptor per selected directory, with optional production,
|
||
same-package, and external-package selectors, to the Cstage or WWstage command.
|
||
It also carries output destinations, coordinator-private completion paths,
|
||
import search roots, and the optional command-scoped work-directory policy.
|
||
The command owns source selection, package loading, substitution, compiler
|
||
inputs, archive construction, the single generated main, and linking:
|
||
|
||
- The ordinary production action selects the directory's byte-sorted non-test
|
||
files. A no-test request uses this action directly. Ordinary builds and
|
||
dependencies outside a tested closure continue to use it.
|
||
- The internal production-plus-test variant selects the byte-sorted production
|
||
files followed by byte-sorted matching `package p` test files. It is distinct
|
||
from production, exports declarations contributed by internal test files, and
|
||
replaces the ordinary action throughout the applicable tested closure.
|
||
- When production sources establish `p`, the external variant selects only
|
||
matching `package p_test` files, where `p` is the production declaration
|
||
rather than an import-path leaf. A test-only directory may establish its own
|
||
`p`, `p_test`, or valid `p`/`p_test` pair, matching pinned `go/build`
|
||
classification. The external action's import of the package under test binds
|
||
to the augmented internal action when it exists. Importers affected by that
|
||
replacement are copied and rewired transitively; an ordinary and augmented
|
||
instance of one canonical package never coexist in the linked test closure.
|
||
- Generated main is a separate package action whose owner-only generated unit
|
||
declares `package main` and imports every applicable internal/external target
|
||
plus test support. It consumes those direct `.wwi` files, emits its own
|
||
`.wwi/.o/.a`, and alone receives compiler `-T --entry`. Repeated byte-sorted
|
||
`--test-target-package <canonical-path>` arguments identify the target set.
|
||
Those compiler-private canonical qualifiers prevent declared-name collisions;
|
||
they are not user alias syntax.
|
||
|
||
The coordinator groups one test product by canonical directory, but physical
|
||
location is not a compiler/package identity. The authoritative action key uses
|
||
the finalized canonical dotted import identity, semantic variant, role, and,
|
||
for a copy made by recompile-for-test, the owning canonical directory product's
|
||
stable test identity. The semantic variants are production,
|
||
production-plus-same-package-test, external `_test`, directory generated main,
|
||
and recompiled-for-test. The declared package name, local import binding,
|
||
request spelling, path leaf, source filename, artifact basename, product
|
||
ordinal, output path, and discovery order are presentation or source-location
|
||
state and never substitute for that key.
|
||
|
||
A literal directory root may enter the interner before its full import spelling
|
||
is known. It is provisionally interned by canonical directory and variant, and
|
||
a later source import of that directory binds and reuses the provisional action.
|
||
After all source discovery, but before generated-main construction or any tool
|
||
invocation, each still-unbound directory is finalized by this exact algorithm:
|
||
|
||
1. For every import-resolution context that reached the directory, walk that
|
||
context's roots in its normal forward precedence: the selected package's
|
||
directory, explicit `-I` roots in command order, then `WW_SRCLIB` or the
|
||
selected toolchain source root. A request pattern never becomes an import
|
||
root and therefore cannot shorten, replace, or donate package identity.
|
||
2. Canonicalize each candidate root and require the package directory to be a
|
||
strict descendant. Every relative path component must be a non-keyword WW
|
||
identifier. Convert separators to dots, then resolve that relative spelling
|
||
again through the complete ordered context. Accept it only if ordinary
|
||
forward lookup selects the same canonical directory. Thus an earlier shadow
|
||
invalidates a name inferred from a later or nested root.
|
||
3. Bind the first precedence-valid candidate from each reaching context through
|
||
the command-global bidirectional interner. An identity supplied by successful
|
||
logical package lookup, such as `encoding.utf8`, is already bound and is
|
||
preserved exactly. That forward-selected identity is authoritative: reverse
|
||
derivation applies only to still-unbound literal roots, so a nested active
|
||
root cannot rename an explicitly resolved package.
|
||
4. If no active root can represent the directory, bind the reserved,
|
||
non-source-importable identity
|
||
`__wwlocal.p<escaped-canonical-absolute-directory>`. The
|
||
escape is injective and reversible over path bytes: ASCII letters and digits
|
||
are copied, `_` becomes `_u`, `/` becomes `_s`, and every other byte becomes
|
||
`_xHH` with lowercase hexadecimal. Source imports of `__wwlocal` or any of
|
||
its children are rejected, so this command-local identity creates no alias.
|
||
|
||
The selected full identity is never validated against the ordinary declared
|
||
package name. Production and internal variants retain the production
|
||
declaration; when production exists, an external variant is admitted only as
|
||
`<production-declared-name>_test`. A test-only directory instead establishes
|
||
one consistent test package declaration itself. The one command-kind rule is that a selected
|
||
command family declares `main`/`main_test` while keeping the finalized ordinary
|
||
identity unchanged. A source import of that command from another
|
||
directory rejects as a program before tools; a colocated external command test
|
||
may reuse the canonical production action. There is no fallback from an empty
|
||
import path to a declaration name. Relative, absolute, and symlink spellings
|
||
converge through the canonical directory; two unrelated local directories with
|
||
the same declaration therefore remain distinct. One bound import path mapping
|
||
to two directories and one directory acquiring two incompatible ordinary
|
||
import paths are command-global deterministic errors before any compiler,
|
||
assembler, archiver, or linker ambiguity. The same check spans variants: an
|
||
external action cannot hide a different directory's production package behind
|
||
its derived `_test` compiler path.
|
||
|
||
The derivation and diagnostics are implemented symmetrically in
|
||
`cmd/ww/main.c` and `selfhost/cmd/ww/main.ww`. The package coordinator in
|
||
`internal/wwpackage/package.ww` supplies canonical selected directories and
|
||
variant descriptors, preserves an explicitly resolved identity only for one
|
||
direct request, and forwards a caller's `-w` semantic-action store unchanged.
|
||
It never derives identity or persistent layout from a pattern traversal prefix
|
||
and does not add that prefix to import search. `w6c` and `wcc` consume the
|
||
finalized dotted identity as export/symbol owner while reading the declared
|
||
name independently from export data; neither tool performs directory lookup or
|
||
introduces a package registry.
|
||
|
||
Artifact publication follows the semantic action instead of product order:
|
||
production uses the full finalized ordinary identity, internal appends
|
||
`-internal-test`, external appends `_test-external-test`, and the one
|
||
directory-owned generated main appends `-test-main`. Its package identity is
|
||
`__wwtestmain.<canonical-directory-product-base>.main`, independent of either
|
||
declared test name. Equivalent roots therefore converge on one directory
|
||
product and reuse already interned actions and persistent-workdir slots
|
||
regardless of discovery or request order.
|
||
The narrow raw single-file compatibility path alone retains `__root`.
|
||
|
||
A deterministic dependency-first traversal of the complete command union
|
||
invokes the compiler, assembler, and in-driver deterministic archiver once per
|
||
interned action. This is compile-time interning, not linker-argument
|
||
deduplication. Each canonical directory product is linked once from its single
|
||
generated-main root archive and the complete reachable archive closure. The
|
||
shared plan remains package-test-specific; it is not a generalized scheduler,
|
||
action schema, cache, or protocol.
|
||
|
||
Each selected directory retains the ordinary entry-directory-first resolution
|
||
context from the local package slice: its directory, explicit `-I` roots in
|
||
command order, then the toolchain source root. Same and external variants of
|
||
one directory share that context; unrelated directory roots never acquire
|
||
lookup precedence from their request order. When multiple contexts reach one
|
||
canonical production package, the loader verifies that every directory import
|
||
binding is identical before reusing its compile action. A different binding is
|
||
a deterministic package-resolution failure for the roots that reach it, rather
|
||
than a first-root-wins build.
|
||
|
||
A production action failure is attributed to exactly the roots that reach it,
|
||
but the complete command is one publication transaction. The driver may
|
||
continue enough of the already validated plan to retain deterministic action
|
||
and product diagnostics, but one failed producer, linker, status stage, or
|
||
commit suppresses every new action voucher, tool record, product, and status
|
||
from that request. The coordinator therefore runs no sibling test binary from
|
||
a rejected union build. After one successful union build, the completed test
|
||
products share the coordinator's existing `-j` process bound; captured output
|
||
is still emitted only in byte-sorted directory/package order.
|
||
|
||
Ordinary production loading never selects dependency `*_test.ww` files.
|
||
Imports that occur only in selected test files add edges only to the applicable
|
||
internal or external action. Recompile-for-test may create a product-scoped copy
|
||
of an ordinary transitive importer, but that copy retains the importer's
|
||
production source unit and changes only canonical dependency targets. Each
|
||
compiler unit contains only its action's owned source set, while its invocation
|
||
receives only the byte-sorted direct dependency `.wwi` artifacts as separate
|
||
inputs.
|
||
Variant compiles receive `--test-package`, which validates and retains private
|
||
`@test` declarations as compiler-only export metadata without synthesizing an
|
||
entry point. The distinct directory generated-main action consumes that
|
||
metadata from every direct target export and synthesizes one dispatcher with
|
||
`-T`.
|
||
|
||
The generated-main action, rather than the tested variant, owns the implicit
|
||
direct test-runtime support edge. The command-scoped plan compiles the common
|
||
support production package once for the complete test request. The command
|
||
resolves that edge from the selected toolchain source tree, not the user search
|
||
path; the support package's own imports are also loaded in that toolchain
|
||
context. Normally its graph
|
||
qualifier is `test`, so an explicit source `import test` coalesces with the same
|
||
canonical package. When a real user package occupies that identity, the command
|
||
presents the runtime edge to the compiler under the reserved `__wwtest`
|
||
qualifier. This keeps a production package named `test` available to external
|
||
tests. Explicit raw single-file `ww test FILE` fixtures retain the narrow fused
|
||
`-T` compatibility path because an anonymous multi-package raw unit is not a
|
||
canonical directory package; that path still consumes support as a direct
|
||
export and emits a root `.wwi/.a`.
|
||
|
||
The reserved support action and an ordinary source-imported package `test` may
|
||
coexist only because the former is explicitly rebound to the compiler-only
|
||
qualifier `__wwtest`. This is the sole role-based directory alias and cannot be
|
||
created by a source import. The separate expanded-vendor-route exception in
|
||
section 11.16 is canonical source-tree identity, not a role alias. All ordinary
|
||
and test actions use canonical action identity and the global bidirectional
|
||
import-path checks above. External self-import substitution changes the target
|
||
action, never the source spelling or file-local binding. There is no role-based
|
||
tolerance for duplicate ordinary import identities and no late product-closure
|
||
ambiguity to resolve.
|
||
|
||
Production, internal, and external actions may select source from one physical
|
||
directory, but the final directory test closure is strict: wherever the
|
||
augmented internal action substitutes for production, every affected direct and
|
||
transitive edge is rewired before tools. A closure containing both ordinary
|
||
`p` and its augmented `ptest` is rejected rather than hidden by initialization
|
||
or linker filtering. The external action therefore sees internal-test exports
|
||
through `ptest`, and the one linked process owns exactly one package state.
|
||
Variant-only archives never leak into an unrelated directory product. All
|
||
ordinary logical and physical package-identity collision checks remain
|
||
unchanged; only distinct expanded vendor routes receive the section 11.16
|
||
symlink-convergence exception.
|
||
|
||
Both stage linkers receive the generated-main archive first, followed by the
|
||
complete reverse-topological reachable package-archive closure, runtime, and
|
||
explicit `-L`/`-l` values through a structured argument vector. No `.wwi` or
|
||
special root `.o` appears in linker argv, and no fixed flattened command buffer
|
||
can truncate a large closure. WWstage emits joined `-Ldir` and `-lname`
|
||
arguments accepted by its native linker, while Cstage preserves the equivalent
|
||
split forms. Generated artifact paths are bounds-checked before any unit is
|
||
opened, so distinct root keys cannot alias by truncation.
|
||
Recursive discovery groups by physical directory before sorting filenames, and
|
||
one stable escape of the canonical discovery directory names the persistent
|
||
command work directory. It contains neither a declared package leaf nor a
|
||
product ordinal, so equivalent path spellings and reordered products select the
|
||
same request state.
|
||
Every selected `*_test.ww` package variant is built even when its files only
|
||
declare helpers and contain no `@test`, so its package clause and imports are
|
||
still checked; that is a real zero-test package and runs one empty combined
|
||
harness. A directory with no selected test files instead follows the no-real-run
|
||
path: validate/compile ordinary production as needed, publish status only, and
|
||
create no support action, generated main, link, binary, result, or process. The
|
||
coordinator alone emits its `[no test files]` report.
|
||
|
||
Persistent workdirs keep a global driver/compiler/assembler/stamp identity and
|
||
per-action committed units. When that global identity is stale, the command
|
||
forces every requested action cold while preserving the complete old generation
|
||
as rollback state. New tool records, artifacts, units, products, statuses, and
|
||
the new stamp become visible only in the request-wide commit after every product
|
||
has staged successfully. A rejected request leaves the old generation
|
||
byte-identical, and a retry cannot reuse any uncommitted work from the rejection.
|
||
|
||
Warm reuse compares the staged owner-only unit, committed artifacts, and the
|
||
actual bytes of each direct dependency export. A changed shared dependency is
|
||
compiled once; its direct importers are reconsidered once; and propagation
|
||
stops as soon as a regenerated importer export is byte-identical. Stable
|
||
semantic artifact keys make that behavior independent of which ordinary or
|
||
test product first discovered the action.
|
||
|
||
The completed topology and its pinned Go 1.26.5 evidence are specified in
|
||
section 11.22. WW borrows that command-global action boundary without adding
|
||
Go's build cache, import-configuration format, or module system.
|
||
|
||
### 11.8 Implemented exact package-tool invocation slice
|
||
|
||
The local package builder now launches the compiler, assembler, and linker as
|
||
an executable plus an argument vector in both Cstage and WWstage. No package
|
||
source path, work-directory artifact path, output path, test-support qualifier,
|
||
or link-closure member is flattened into a shell command. Paths containing
|
||
spaces therefore retain one argument boundary from the package coordinator
|
||
through compilation, assembly, and final executable linking.
|
||
|
||
`WW_W6C`, `WW_W6A`, and `WW_W6L` each name one exact executable path. They are
|
||
not shell fragments and are not searched through `PATH`. With no override,
|
||
Cstage keeps its `w6c`/`w6a`/`w6l` siblings and WWstage keeps its
|
||
`w6c_ww`/`w6a_ww`/`w6l_ww` siblings. The coordinator preserves these variables
|
||
when it starts the one command-scoped package build, so the same contract covers
|
||
ordinary directory builds, same-package tests, external tests, recursive test
|
||
requests, and persistent-workdir tool identity. A failed overridden compiler or
|
||
assembler remains attributed to its owning package in both stages. The Cstage
|
||
linker also sets executable mode with `chmod(2)` on the exact output path rather
|
||
than invoking an ambient command.
|
||
|
||
Source imports still own the graph, each directory is still one production
|
||
package, compiler actions receive direct dependency exports as individual
|
||
arguments beside an owner-only `.unit.ww`, and links receive the complete
|
||
per-root `.a` closure. Repository-native coverage wraps all three real stage
|
||
tools at executable paths containing spaces, records every argument boundary,
|
||
inspects `.unit.ww`, `.wwi`, `.a`, and root archive placement, runs the published
|
||
binary, compares repeated Cstage/WWstage artifacts and traces, and removes one
|
||
direct export at compiler entry to compare package-attributed diagnostics.
|
||
|
||
Go 1.26.5 keeps the same responsibility boundary: its work executor passes the
|
||
selected compiler or linker tool and a constructed argument slice to the
|
||
builder, while package loading and action construction remain separate
|
||
([`cmd/go/internal/work/exec.go`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/exec.go)).
|
||
WW adopts that exact-tool boundary without adding a command schema, generalized
|
||
action graph, scheduler, manifest, cache protocol, or package-manager behavior.
|
||
|
||
### 11.9 Implemented package and runtime library-root parity slice
|
||
|
||
Cstage and WWstage now apply the same two-root contract. A nonempty
|
||
`WW_SRCLIB` selects the toolchain package-source search root. It is appended
|
||
after the entry directory and explicit `-I` roots for every package context,
|
||
and compiler-generated test support is resolved from that toolchain root rather
|
||
than from a user package that happens to have the same name. A nonempty
|
||
`WW_LIB` independently selects runtime artifacts; executable and test links use
|
||
`$WW_LIB/libwwrt.a`. If that archive is absent, both stages pass their sibling
|
||
`start.o` and `syscall.o` runtime objects instead. Missing and explicitly empty
|
||
values use the same deterministic fallbacks in both stages.
|
||
|
||
Bare logical build and run targets search the current directory, explicit
|
||
`-I` roots, then one selected library root. That last root is a nonempty
|
||
`WW_SRCLIB`, else a nonempty `WW_LIB`, else an existing
|
||
`<selfdir>/../../lib`, else an existing `./lib`, else
|
||
`<selfdir>/../lib`. Once a target is resolved, its import graph retains the
|
||
ordinary entry-directory-first context and its separate source-root policy:
|
||
without `WW_SRCLIB`, that policy prefers the repository and `./lib` source
|
||
trees before falling back to the runtime root. This preserves Cstage's
|
||
existing distinction between locating a requested package and selecting the
|
||
toolchain source tree used by that package's imports.
|
||
|
||
The variables select local directories only. They do not add manifests,
|
||
dependency declarations, network lookup, package-manager behavior, or a second
|
||
graph: source `import` declarations still create every language edge, resolved
|
||
directories still intern to canonical package identities, compilers still
|
||
receive only direct `.wwi` exports, and final links still receive the complete
|
||
reachable `.a` closure. Directory tests continue to build same-package and
|
||
external-package variants through the same command-scoped package universe.
|
||
|
||
Repository-native coverage uses distinct source and runtime roots whose paths
|
||
contain spaces, resolves a bare logical target found only through `WW_SRCLIB`,
|
||
places a same-named decoy under `WW_LIB`, records exact compiler, assembler, and
|
||
linker arguments, inspects `.unit.ww`, `.wwi`, `.a`, diagnostics, binaries, and
|
||
runtime results, and compares both stages. It separately exercises the runtime
|
||
object fallback and explicitly empty variables. The package-test observer copies
|
||
the toolchain source library to a selected root, marks the compiler-generated
|
||
test-support source, and proves that both the marker and the selected runtime
|
||
archive reach real same-package test builds through the coordinator.
|
||
|
||
The ownership boundary follows the pinned Go 1.26.5 implementation: source
|
||
headers supply imports in
|
||
[`go/build/read.go`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/go/build/read.go#272),
|
||
the loader canonicalizes and reuses packages in
|
||
[`cmd/go/internal/load/pkg.go`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/pkg.go#633),
|
||
tests remain real package variants in
|
||
[`cmd/go/internal/load/test.go`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/load/test.go#85),
|
||
and direct compile dependencies are expanded separately for linking in
|
||
[`cmd/go/internal/work/action.go`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/action.go#628).
|
||
|
||
### 11.10 Implemented persistent-workdir driver identity slice
|
||
|
||
The package driver is now an explicit content input to every persistent
|
||
`-w DIR` package action. Both stages copy the exact invoking executable to
|
||
`.wwtool.ww`, alongside `.wwtool.w6c`, `.wwtool.w6a`, and the mode/format
|
||
stamp. A warm invocation byte-compares all applicable live executables before
|
||
considering any committed unit reusable. A missing or changed driver copy
|
||
invalidates every `.unit.ww` voucher before compilation; old artifacts may
|
||
remain recoverable, but none can be reused without a freshly committed unit.
|
||
That slice introduced workdir format revisions 8 for ordinary builds and 9 for
|
||
tests. Later package-identity slices supersede those revisions; the current
|
||
formats are recorded in section 11.16.
|
||
|
||
This closes a real hidden-input boundary. The driver, rather than `w6c`, owns
|
||
canonical directory interning, source-derived graph construction, owner-only
|
||
unit composition, direct-export argument construction, deterministic dependency
|
||
ordering, single-member package archive serialization, and the artifact commit
|
||
sequence. Unit equality alone
|
||
cannot identify changes to those algorithms, and a manually maintained format
|
||
number can be forgotten. Exact driver bytes conservatively cover them during
|
||
the transitional plain-file reuse scheme. This may rebuild after an unrelated
|
||
driver change, but it cannot falsely reuse a package after a relevant one.
|
||
|
||
The linker remains outside the recorded package identity because persistent
|
||
reuse never skips a final link: each invocation reconstructs the complete
|
||
reachable `.a` closure, selects current runtime inputs and link flags, and runs
|
||
the selected linker. Thus a linker or runtime change affects the requested
|
||
binary immediately without forcing unrelated package compilation.
|
||
|
||
Repository-native coverage runs a three-directory import graph through copied,
|
||
independently mutable Cstage and WWstage drivers. Exact compiler, assembler,
|
||
and linker wrappers prove a cold dependency-first build, an unchanged warm
|
||
compile/assemble skip with a deliberate relink, and full package invalidation
|
||
after only the invoking driver's bytes change. The test inspects owner-only
|
||
`.unit.ww` inputs, separate direct `.wwi` arguments, `.a`, identity files,
|
||
transitive link order, diagnostics before tool execution, published binary
|
||
bytes, runtime exit, and stage equivalence.
|
||
|
||
Go 1.26.5 draws the same semantic line with a richer cache: its build action ID
|
||
binds compiler/assembler tool identities, configuration, selected source
|
||
content, and direct dependency content IDs in
|
||
[`cmd/go/internal/work/exec.go`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/exec.go#261),
|
||
while its link action ID separately binds linker configuration and the package
|
||
closure in
|
||
[`cmd/go/internal/work/exec.go`](https://go.googlesource.com/go/+/refs/tags/go1.26.5/src/cmd/go/internal/work/exec.go#1504).
|
||
WW adopts only the correctness boundary in its existing inspectable `cmp`-based
|
||
workdir. It does not add build IDs, hashes, a CAS, an action graph, a scheduler,
|
||
or a manifest.
|
||
|
||
### 11.11 Implemented directory-only source-import slice
|
||
|
||
Cstage and WWstage now use directory packages for every parsed source import,
|
||
including imports selected only by a package-test variant and real imports in
|
||
the test-support package. Source imports first probe the bounded vendor
|
||
candidates in section 11.16, then make one ordered fallback pass for
|
||
`<root>/<import-path>/`; they never probe `<root>/<import-path>.ww`. The
|
||
compiler-generated edge to test support remains synthetic. Unit composition
|
||
consequently writes only the owning package's byte-sorted source files and
|
||
never copies a dependency interface or imported source body. Missing imports
|
||
retain the importing source position and the same stable diagnostic in both
|
||
stages.
|
||
|
||
Root selection remains a separate compatibility boundary. A literal `.ww` CLI
|
||
target, or a bare CLI target found as `<root>/<name>.ww` after the global
|
||
directory search, can still create one raw single-file root. Its historical
|
||
inline package clauses may satisfy compiler-fixture bindings inside that raw
|
||
unit. Directory roots cannot use that exemption, and no filesystem source
|
||
import can reach it. This preserves low-level compiler fixtures without
|
||
weakening package-graph identity.
|
||
|
||
The self-hosted tools no longer depend on the removed behavior. `w6a/` and
|
||
`w6l/` are executable `package main` directories whose sorted source sets are
|
||
compiled once. The compiler backend is one `wcc/` directory package with a
|
||
narrow exported check/codegen façade; `w6c` and `wwdump` import that package
|
||
from its parent search root instead of importing its implementation files.
|
||
Legacy test fixtures were converted to directories, except for one intentional
|
||
compiler leaf-collision probe that now invokes `w6c` on an explicitly composed
|
||
raw unit. The Lisp example likewise imports a `lispcore/` directory package.
|
||
|
||
The focused native regression puts only `example/foo.ww` in an earlier import
|
||
root and a two-source `example/foo/` package in a later root. Both stages select
|
||
the directory, emit the exact sorted package-owned unit, consume its direct
|
||
dependency export, produce byte-identical deterministic `.wwi` and `.a`
|
||
artifacts, link and run a transitive archive closure, and repeat the resolution
|
||
through a real directory-package test. With only the file root present, both
|
||
stages reject the import with byte-identical package-attributed stderr. The
|
||
existing exact-tool observer remains the non-duplicated proof that each
|
||
canonical production action compiles once, compiler units contain only owned
|
||
sources, compile argument vectors contain exactly direct `.wwi` inputs, and
|
||
linker vectors contain the complete reachable `.a` closure and no `.wwi` path.
|
||
|
||
### 11.12 Implemented direct compiler-export input slice
|
||
|
||
Cstage and WWstage now share one small package-compiler convention:
|
||
`--import <canonical-import-path> <export.wwi>` may repeat before the one owning
|
||
source unit. It is valid only with `-c`; paths must be nonempty, strictly sorted,
|
||
and unique. Both compilers read and parse every export independently under the
|
||
supplied canonical identity before parsing the owner unit, then pass the merged
|
||
semantic declaration list through the existing checker, deterministic export
|
||
writer, and primary-only code generator. Missing export bytes therefore fail at
|
||
the compiler boundary as `w6c: import <path>: cannot read <file>`, followed by
|
||
the driver's stable owning-package attribution. No import configuration file,
|
||
manifest, schema, package database, or network lookup is involved.
|
||
|
||
Both drivers construct those arguments directly from the package node's sorted,
|
||
deduplicated outgoing edges. They never walk grandchildren for compilation.
|
||
Every `.unit.ww` contains the node's byte-sorted source files, reset separators,
|
||
and any sorted driver-private vendor/import-map voucher comments, but no
|
||
dependency body. When exact source spelling differs from a selected expanded
|
||
canonical identity, the drivers also pass sorted, unique
|
||
`--import-map <source-spelling> <canonical-import-path>` triples. A map must
|
||
target an ordinary direct `--import`; it adds no export input or graph edge.
|
||
The compilers rewrite only the matching primary import's canonical semantic key
|
||
before merging interfaces. They then obtain that target's declared package name
|
||
from its direct export and install it as the default qualifier in the owning
|
||
source file. Source spelling and position remain intact; generated/synthetic
|
||
imports use their explicit compiler-owned bindings. Executable linking
|
||
independently walks the full reachable package
|
||
closure and passes archives, never interfaces. The same path handles an
|
||
ordinary package, the production-plus-internal-test variant, the external test
|
||
package and its effective production-or-augmented self dependency,
|
||
compiler-generated directory test main, and
|
||
the reserved test-support package. Persistent workdirs compare a newly emitted
|
||
export with its committed predecessor before allowing a direct importer to
|
||
reuse owner-identical artifacts, retaining correctness without a new cache
|
||
schema or identity record.
|
||
|
||
The canonical-root regressions additionally prove the following in both
|
||
stages: a literal root under one import root publishes its complete dotted
|
||
identity; logical, literal absolute, equivalent, relative, and symlink routes
|
||
emit byte-identical `.unit.ww`, `.wwi`, and `.a`; root-only and combined
|
||
root/import requests emit those same bytes; dependency-first and root-first
|
||
discovery each compile the shared production action once; recursive `a/foo`
|
||
and `b/foo` directories declaring the same `package foo` publish distinct
|
||
`a.foo` and `b.foo` variants; and two outside-root `package foo` directories
|
||
coexist in one command under distinct reversible local identities. Equivalent
|
||
recursive spellings reuse the same persistent semantic-action store without new
|
||
compilation, while source imports of the reserved local namespace reject before
|
||
tool invocation. The exact-argv command root declares `package main` but keeps
|
||
its non-`main` canonical identity in the unit, export, archive, compiler argv,
|
||
and linker argv; the bootstrap self-rebuild independently proves the same rule
|
||
for the real `w6a` and `w6l` command directories. A focused command-test row
|
||
proves distinct production, internal, external, and generated-main actions,
|
||
colocated external-to-augmented substitution, parser-only command markers,
|
||
stage-equal unit/export/archive bytes, the one combined test binary's runtime
|
||
behavior, and pre-tool
|
||
rejection when another directory tries to import the command.
|
||
|
||
The exact-argv regression uses the real diamond
|
||
`base -> {left,right} -> root`. It proves one compile per node; no input for
|
||
`base`; only `base.wwi` for each middle node; only sorted `left.wwi` and
|
||
`right.wwi` for `root`; exact owner-only unit bytes; the complete four-package
|
||
link closure including the root archive; no link-time `.wwi`; exit status 42;
|
||
and byte-identical units, exports, archives, executables, and tool argument
|
||
vectors across two clean
|
||
Cstage builds and two clean WWstage builds. The existing directory-package
|
||
variant regression checks separate production, internal, external, and
|
||
directory-generated-main actions, exact generated-main direct target/support
|
||
exports, canonical recompile-for-test substitution, and one archive-only link
|
||
closure. It also reverses equivalent product descriptors and compares
|
||
exact compiler and linker trace bytes, then changes a shared direct export in
|
||
persistent workdirs to prove propagation through direct importers stops at the
|
||
first byte-identical regenerated export. Both stages compile and run those
|
||
actions with owner-only units and byte-identical artifacts.
|
||
|
||
The pinned official Go 1.26.5 tag (commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`) supplies the design boundary:
|
||
|
||
- `go/build` represents one selected directory package with its import path,
|
||
package name, ordinary files, internal-test files, external-test files, and
|
||
their imports ([`build.go`, lines 436–493](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L436-L493)).
|
||
Those fields remain separate in Go; WW's final-component/name equality is its
|
||
existing language validation layered on the canonical identity, not a claim
|
||
that Go conflates `Name` with `ImportPath`.
|
||
Its directory reader is required to return name-sorted entries
|
||
([lines 108–111](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L108-L111)),
|
||
and local directory loading reverse-derives a complete import path by checking
|
||
`GOROOT/src` first and then `GOPATH` roots in order. A candidate under a later
|
||
root is rejected when the same relative path resolves through an earlier root
|
||
to another directory; an outside-root directory remains without an ordinary
|
||
import path
|
||
([lines 612–665](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L612-L665)).
|
||
Forward import lookup selects one directory in search order
|
||
([lines 725–767](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L725-L767)),
|
||
and the selected directory alone is scanned
|
||
([lines 859–913](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L859-L913)).
|
||
The sorted scan assigns each accepted source to that package's ordinary,
|
||
internal-test, or external-test list
|
||
([lines 948–1036](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L948-L1036)).
|
||
- `cmd/go/internal/load` derives an outside-root local directory's deterministic
|
||
pseudo-import path from its slash-form absolute directory and establishes the
|
||
package-data cache/promise boundary around that resolved key
|
||
([`pkg.go`, lines 633–647](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L633-L647)).
|
||
WW uses the same reserved full-directory principle but a reversible byte
|
||
escape, strengthening it so two canonical directory spellings cannot collapse
|
||
merely through character sanitization. The Go loader expands source imports
|
||
before recording their canonical paths
|
||
([`pkg.go`, lines 658–669](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L658-L669)).
|
||
It resolves canonical path and directory before consulting the package-data
|
||
cache ([lines 833–842](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L833-L842),
|
||
[lines 863–911](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L863-L911)),
|
||
and the command-global package cache returns the existing package pointer for
|
||
a later root or import of the resolved identity
|
||
([lines 757–775](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L757-L775)).
|
||
Go keeps a command-line `Name == "main"` package as the selected command and
|
||
rejects an import from a different directory, while permitting the
|
||
same-directory test-loader edge
|
||
([lines 799–805](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L799-L805)).
|
||
The package's parsed import list becomes its direct package dependencies,
|
||
rather than a transitive flattening
|
||
([lines 433–440](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L433-L440),
|
||
[lines 2024–2047](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L2024-L2047)).
|
||
- `cmd/go/internal/work` keys its action cache by operation mode plus package
|
||
pointer ([`action.go`, lines 202–206](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L202-L206))
|
||
and returns the already-interned action for that key
|
||
([lines 437–447](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L437-L447)).
|
||
A selected package whose independent `Name` is `main` receives a link action
|
||
([lines 450–455](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L450-L455))
|
||
while retaining its ordinary compiled archive action.
|
||
A compile action depends on only `p.Internal.Imports`
|
||
([lines 628–658](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L628-L658));
|
||
an executable link asks for that same cached root compile action
|
||
([lines 919–957](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L919-L957))
|
||
and separately expands the complete transitive link closure
|
||
([lines 1034–1068](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L1034-L1068)).
|
||
- The work executor derives compiler package mappings from those direct build
|
||
dependencies
|
||
([`exec.go`, lines 864–884](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L864-L884)),
|
||
compiles the package's own source list to `_pkg_.a`
|
||
([lines 928–935](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L928-L935)),
|
||
packs and publishes that package archive
|
||
([lines 1017–1033](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L1017-L1033)),
|
||
and links the compiled main archive with mappings for every dependency
|
||
already expanded onto the link action
|
||
([lines 1592–1624](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L1592-L1624),
|
||
[lines 1635–1647](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L1635-L1647)).
|
||
- Go's test loader explicitly models production, internal
|
||
production-plus-test, external `_test`, and generated main, and states that
|
||
`ptest == p` when production can be reused
|
||
([`test.go`, lines 85–102](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L85-L102)).
|
||
Test imports use the ordinary load cache and compare canonical `ImportPath`
|
||
([lines 118–161](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L118-L161));
|
||
the internal copy is created only when needed
|
||
([lines 175–226](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L175-L226)),
|
||
while external and generated-main packages remain distinct
|
||
([lines 228–293](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L228-L293)).
|
||
Generated main receives its direct support and selected-variant imports
|
||
([lines 307–358](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L307-L358)),
|
||
and copy-on-write rewriting preserves the original package pointers/actions
|
||
for unaffected importers
|
||
([lines 421–472](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L421-L472)).
|
||
- Unified export production begins from the local package, re-exports required
|
||
dependency data, and prunes unnecessary detail
|
||
([`unified.go`, lines 147–168](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/unified.go#L147-L168)).
|
||
It type-checks the package's parsed sources and writes deterministically
|
||
ordered public/private roots
|
||
([lines 314–362](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/unified.go#L314-L362)),
|
||
then finalizes self-contained export data with sorted relocated declaration
|
||
and body indexes and a fingerprint
|
||
([lines 463–570](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/unified.go#L463-L570)).
|
||
- Compiler import handling canonicalizes each source import and rejects self
|
||
import ([`import.go`, lines 125–167](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/import.go#L125-L167)),
|
||
then independently opens and decodes each direct package archive/export
|
||
([lines 170–225](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/import.go#L170-L225)).
|
||
The complete unified section and linker fingerprint are read from that
|
||
selected package file
|
||
([lines 229–296](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/import.go#L229-L296)).
|
||
`ReadPackage` reconstructs a package from its public export root
|
||
([`ureader.go`, lines 28–62](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/importer/ureader.go#L28-L62)),
|
||
interns embedded package descriptors by canonical path and restores their
|
||
import lists
|
||
([lines 152–196](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/importer/ureader.go#L152-L196)),
|
||
and reconstructs declarations from relocated export records
|
||
([lines 391–468](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/importer/ureader.go#L391-L468)).
|
||
|
||
WW adopts those practical ownership and action semantics while retaining its
|
||
small direct CLI representation and existing self-contained `.wwi` encoding.
|
||
|
||
### 11.13 Implemented unbounded semantic package-identity storage slice
|
||
|
||
Canonical package identity is no longer stored in, derived from, or bounded by
|
||
one internal filesystem component. In both drivers every package action now
|
||
keeps these values separately:
|
||
|
||
- `path`: the complete compiler/import identity;
|
||
- `import_base`: the complete canonical ordinary directory identity;
|
||
- `canon`: the complete canonical directory location;
|
||
- `variant` and `role`: the semantic test/action tags; and
|
||
- `storage`: an internal scratch basename that is never passed as package
|
||
identity.
|
||
|
||
`canon` participates in command-local directory-action interning, diagnostics,
|
||
and storage-address derivation. The complete `path`, together with the
|
||
semantic `variant` and `role`, is the persisted/compiler owner carried through
|
||
source-import edges, module-reset and export ownership, compiler `--import`
|
||
arguments, generated-main construction, and symbol qualification; `storage`
|
||
participates in none of those identities. The reversible outside-root form is
|
||
`__wwlocal.p<escaped-canonical-absolute-directory>` and is
|
||
allocated to its exact length. It is neither truncated nor replaced by a
|
||
digest, and `__wwlocal` remains unavailable to source imports. Package
|
||
declarations classify package kind and contribute semantic export content; they
|
||
do not validate a path leaf, supply a missing identity, or alter a command
|
||
package's canonical path.
|
||
|
||
Short actions retain their established `.unit.ww`, `.wwi`, `.s`, `.o`, and
|
||
`.a` basenames when the basename plus `.unit.new` fits the 255-byte supported
|
||
filesystem component bound and the complete path fits the host pathname API.
|
||
An action that does not fit uses this bounded storage locator:
|
||
|
||
```text
|
||
__wwpkg.v<variant>.r<role>.h<lowercase-sha256>
|
||
```
|
||
|
||
The SHA-256 byte input is exactly:
|
||
|
||
```text
|
||
"ww-package-storage-v2:"
|
||
|| ASCII(<variant> ":" <role> ":")
|
||
|| complete semantic path
|
||
|| NUL
|
||
|| complete canonical directory
|
||
```
|
||
|
||
WW package paths and host paths cannot contain NUL, so that boundary is
|
||
unambiguous. Variant and role are present in both the digest input and the
|
||
visible locator tag. The digest is only an action-storage address: units still
|
||
begin with `//ww:module-reset <complete-path>` and may append deterministic
|
||
driver-private resolution comments, while exports begin with
|
||
`//ww:module <complete-path>`, compiler imports carry the complete path, and
|
||
qualified declarations use it in generated symbols. A selected executable
|
||
entry retains its intentional bare linker spelling. User-selected `-o`
|
||
publication paths bypass this derivation completely.
|
||
|
||
Storage assignment is command-global and finishes before any tool is invoked.
|
||
If two actions prefer the same legacy basename, every unhashed member is
|
||
readdressed through the complete-action formula instead of rejecting a valid
|
||
package graph. If two already-addressed, unequal complete actions ever produce
|
||
the same locator, both drivers issue the same full-identity storage-collision
|
||
diagnostic before compilation. A persistent workdir also validates every
|
||
existing regular `.unit.ww` voucher against the requested complete semantic
|
||
owner before stale-tool invalidation or reuse; a missing voucher is cold state,
|
||
while a malformed, non-regular, or wrong-owner voucher is a pre-tool error.
|
||
Thus ordinary preferred-name collisions are resolved, and a digest collision
|
||
cannot silently alias two live or warm package actions. That storage slice
|
||
introduced build version 10 and test version 11 so an older flat-layout voucher
|
||
was never accepted as current state. Section 11.16 records the current
|
||
superseding formats.
|
||
|
||
The persisted semantic owner is deliberately the complete canonical import
|
||
path, not the canonical host directory: host location must not enter compiler
|
||
artifacts. Variant and role are encoded in the locator itself. Canonical
|
||
directory remains part of command-local action interning and the digest input,
|
||
so distinct locations normally receive distinct slots. In the hypothetical
|
||
case that two locations with the same import path, variant, and role also
|
||
collide in SHA-256, they are still one semantic package identity: the freshly
|
||
composed owner unit must byte-equal the committed unit before reuse, so
|
||
different sources rebuild and identical sources produce the same deterministic
|
||
artifacts. A digest collision between different semantic paths fails the
|
||
existing complete-path owner check before tools. This preserves collision
|
||
checking without serializing machine-specific canonical directories into units
|
||
or exports and without a sidecar, registry, or new metadata protocol.
|
||
|
||
The package coordinator derives no persistent container from a request
|
||
directory or pattern. `-w DIR` names the driver's semantic-action store itself,
|
||
and the driver independently derives every action locator in that store from
|
||
the full semantic tuple above and validates each committed semantic owner.
|
||
Equivalent direct, logical, relative, absolute, dotted, recursive, duplicate,
|
||
and explicit-root-symlink requests that select the same canonical actions can
|
||
therefore reuse the same slots; request shape cannot split or alias persistent
|
||
state. For a delegated request only, a missing caller `-w` directory is created
|
||
after graph, identity, visibility, cycle, closure, and output preflight. An
|
||
explicit root symlink is followed and canonicalized; a source entry symlink to
|
||
a regular file is followed under the entry name, a source-shaped symlink to a
|
||
directory is ignored, and symlinked recursive children are not traversed.
|
||
|
||
The old `SEP_IMPORT_PATH_MAX` and all corresponding 255-byte WWstage import,
|
||
variant, local-identity, and generated-main checks are removed. Package names,
|
||
canonical identities, reverse-resolved dotted identities, generated-main
|
||
identities, compiler import paths, and Cstage assembler symbols now use exact
|
||
allocations. Cstage's assembler no longer copies a line, operand, `TEXT`, or
|
||
`DATA` symbol through 256-byte arrays, and the C checker no longer resolves a
|
||
qualified type through a 128-byte prefix buffer. `PATH_MAX` remains only at
|
||
actual host pathname and syscall boundaries; the 255-byte constant remains
|
||
only as the conservative internal basename component bound. The former
|
||
`SEP_MAXPKG`, `SEP_MAXPRODUCT`, and `SEP_MAXCONTEXT` action-count limits are
|
||
removed by the dynamically sized package-universe implementation in the next
|
||
section.
|
||
|
||
The existing native observers exercise the new boundary with ordinary dotted
|
||
identities over 255 bytes and punctuation-heavy reversible local identities
|
||
over 255 bytes. They inspect the complete owner in units and exports, exact
|
||
direct sorted/deduplicated `.wwi` compiler inputs, long mangled assembler
|
||
symbols, complete archive-only link closures, runtime results, and independent
|
||
Cstage/WWstage artifact bytes. Two deep outside-root directories declaring
|
||
the same leaf coexist under distinct reversible identities. A long command
|
||
package's internal, external, and one directory generated-main actions remain
|
||
distinct while retaining its canonical package identity. Logical and literal
|
||
roots, dependency-first and root-first
|
||
discovery, equivalent and symlink spellings, reordered products, and warm
|
||
requests reuse the same production action and persistent slot. The persistent
|
||
diamond observer also changes a shared dependency export, proves rebuilding of
|
||
its direct importers, and proves propagation stops when the regenerated export
|
||
is byte-identical.
|
||
|
||
This separation follows the pinned official Go 1.26.5 tag at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`, without adopting Go's cache,
|
||
build IDs, importcfg, module machinery, or scheduler:
|
||
|
||
- Source imports are expanded to canonical paths before being recorded
|
||
([`pkg.go`, lines 658–669](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L658-L669),
|
||
[`pkg.go`, lines 1150–1178](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1150-L1178)).
|
||
Local directories receive a deterministic pseudo-import identity derived
|
||
from the full directory while directory and import path stay separate
|
||
([`pkg.go`, lines 633–647](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L633-L647),
|
||
[`pkg.go`, lines 863–907](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L863-L907)).
|
||
Resolution/package caches retain and reuse those complete values
|
||
([`pkg.go`, lines 833–842](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L833-L842),
|
||
[`pkg.go`, lines 909–985](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L909-L985),
|
||
[`pkg.go`, lines 1008–1029](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1008-L1029)).
|
||
- `go/build` reverse-resolves directory ownership through ordered roots and
|
||
performs the matching forward lookup while keeping directory, import path,
|
||
declared name, and source lists separate
|
||
([`build.go`, lines 612–665](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L612-L665),
|
||
[`build.go`, lines 725–767](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L725-L767),
|
||
[`build.go`, lines 436–493](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L436-L493)).
|
||
- Go interns an action by operation and package pointer, returns an existing
|
||
action for repeated compilation requests, and attaches only direct package
|
||
dependencies
|
||
([`action.go`, lines 202–206](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L202-L206),
|
||
[`action.go`, lines 437–447](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L437-L447),
|
||
[`action.go`, lines 628–658](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L628-L658)).
|
||
- Its `Action` keeps `Package`, `Objdir`, and `Target` as independent fields,
|
||
then assigns a short `bNNN/` object directory unrelated to import identity
|
||
([`action.go`, lines 84–109](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L84-L109),
|
||
[`action.go`, lines 383–394](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L383-L394)).
|
||
Direct dependency identities map independently to archive paths, and the
|
||
owner is compiled to fixed `_pkg_.a`
|
||
([`exec.go`, lines 864–884](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L864-L884),
|
||
[`exec.go`, lines 928–935](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L928-L935),
|
||
[`exec.go`, lines 1017–1033](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L1017-L1033)).
|
||
- Linking reuses the compiled root action and separately expands the complete
|
||
reachable archive closure
|
||
([`action.go`, lines 919–957](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L919-L957),
|
||
[`action.go`, lines 1034–1068](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L1034-L1068),
|
||
[`exec.go`, lines 1592–1624](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L1592-L1624),
|
||
[`exec.go`, lines 1635–1647](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L1635-L1647)).
|
||
User `-o` separately controls the publication target
|
||
([`build.go`, lines 508–548](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L508-L548)).
|
||
- Go's test loader models ordinary production, internal production-plus-test,
|
||
external `_test`, and generated-main packages separately, reusing ordinary
|
||
production when possible
|
||
([`test.go`, lines 85–102](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L85-L102),
|
||
[`test.go`, lines 175–226](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L175-L226),
|
||
[`test.go`, lines 228–293](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L228-L293)).
|
||
|
||
### 11.14 Implemented dynamically sized command-global package universe
|
||
|
||
Package, dependency, resolution-context, selected-product, traversal, support,
|
||
order, and closure storage no longer has an arbitrary 256-element boundary.
|
||
This is a storage correction, not a new build abstraction: source imports still
|
||
form one command-global canonical package graph; each semantic package variant
|
||
still has one action; each compiler still receives exactly its direct exports;
|
||
and each executable linker still receives its complete reachable archive
|
||
closure.
|
||
|
||
The Cstage representation is exact and deliberately small:
|
||
|
||
- `sepgraph.pkg` is a dynamically allocated `struct seppkg *` with logical
|
||
count `n` and capacity `pkgcap`;
|
||
- `sepgraph.context` is a dynamically allocated `struct sepcontext *` with
|
||
logical count `ncontext` and capacity `contextcap`;
|
||
- each `seppkg.deps` is a dynamically allocated `int *` with `ndeps` and
|
||
`depcap`;
|
||
- each `seppkg.context_state` is a lazily extended, zero-filled
|
||
`unsigned char *` with `context_cap`;
|
||
- each package owns a dynamically grown import-occurrence vector recording
|
||
kind, source spelling, source file, line, column, and stable dependency
|
||
action index; its separate dependency vector remains sorted/deduplicated;
|
||
- parsed `sepproduct` values are a dynamically allocated vector, and each
|
||
product stores its support-action index directly; and
|
||
- package-load frames and topological-DFS frames are temporary dynamic vectors,
|
||
replacing recursion proportional to graph depth.
|
||
|
||
The WWstage representation is isomorphic. `sepgraph.pkg: []seppkg` and
|
||
`sepgraph.context: []sepcontext` use allocated slice length as capacity and keep
|
||
separate `n`/`ncontext` logical counts. Every `seppkg` owns a dynamically grown
|
||
`bindings: []sepbind`, a dynamically grown `deps: []i32` with `ndeps`, and a
|
||
lazily zero-extended `contextstate: []u8`.
|
||
Products, load frames, and topological frames use typed dynamically allocated
|
||
slices. `internal/wwpackage` continues to construct one union command for all
|
||
selected directory-test groups, but now checks the complete
|
||
`12 + 9*products + 2*includes` builder argument count before allocating or
|
||
starting the driver.
|
||
|
||
All graph and product growth starts at capacity 8 and doubles until it covers
|
||
the requested element count. Cstage clamps before `INT_MAX`, checks the element
|
||
count against `SIZE_MAX / sizeof(element)`, and publishes a `realloc` result only
|
||
after success. WWstage checks against the same signed 32-bit count boundary,
|
||
allocates a replacement typed slice, copies the live prefix, and publishes it
|
||
only after success. Context-state growth copies old bytes and explicitly zeros
|
||
the new tail. The shared deterministic failures are `ww: package graph is too
|
||
large` for an unrepresentable count and `ww: out of memory` for failed storage;
|
||
compiler and linker argument-count arithmetic is checked before allocation and
|
||
before any affected tool invocation. Each driver records allocation/size
|
||
failure during graph discovery and propagates it as a command-fatal load
|
||
result, rather than treating it as one product's semantic failure and starting
|
||
tools for a sibling root. The coordinator uses fallible dynamic storage for
|
||
discovered paths, source/folder/group/plan vectors, process handles, tool
|
||
environments, and complete builder/run argument vectors; it reports an
|
||
oversized product set or allocation failure before the corresponding
|
||
`exec.start` and cleans an already-created request temporary tree. Host pathname,
|
||
filesystem-component, process-argument, and available-memory boundaries remain
|
||
real host constraints; none is used as a disguised package-count maximum.
|
||
|
||
Vector growth never changes semantic references. Dependency edges, resolution
|
||
contexts, selected-product roots and variant roots, generated-main/support
|
||
edges, load/topological frames, order entries, and closure membership are all
|
||
stable `int`/`i32` indices. Code reserves a graph slot before taking an element
|
||
pointer and never carries an element pointer across a graph reserve. Capacity,
|
||
addresses, request order, product order, output names, and workdir location
|
||
therefore cannot enter action identity, sorting, diagnostics, storage locators,
|
||
or artifact bytes. Dependency lists retain byte-sorted insertion and duplicate
|
||
elimination. The iterative loader retains mark-before-child and post-child
|
||
command-import validation; the iterative tri-color DFS retains deterministic
|
||
postorder and the complete live path for cycle diagnostics.
|
||
|
||
No fixed package, product, context, action, support-map, traversal, order, or
|
||
closure cardinality remains in either driver. The unrelated `SEP_MAXLFLAGS ==
|
||
32` limit is retained solely for the existing `-L`/`-l` command-line interface;
|
||
it neither indexes nor bounds package actions. Compiler and linker tools already
|
||
allocate their import/input tables from `argc`; their genuine remaining process
|
||
boundary is the host's executable-argument limit.
|
||
|
||
The native package observers generate rather than commit large fixture trees.
|
||
The extended `long_shared_link_closure_is_complete` builds and runs a chain of
|
||
300 ordinary directory packages under independent cold Cstage and WWstage work
|
||
roots. Its command root directly imports all 300 packages and repeats one import,
|
||
proving an action beyond index 256 compiles, the root receives exactly 300
|
||
sorted/deduplicated direct `.wwi` inputs, every ordinary action receives only its
|
||
one direct export, every `.unit.ww` contains only its two byte-sorted owner
|
||
sources, and the linker receives the root plus all 300 archives exactly once and
|
||
no `.wwi`. A second command root imports only `p000`; it reuses all 300 ordinary
|
||
actions and its exact linker line still contains the root followed by the full
|
||
`p000` through `p299` transitive archive chain and runtime archive, proving that
|
||
closure construction—not the wide root's direct imports—crosses the old boundary.
|
||
The observer compares every unit, export, assembly, object, archive, and binary
|
||
across stages. A second equivalent request against the same persistent store invokes no compiler or
|
||
assembler. Changing `p257`'s export recompiles exactly `p257`, direct importer
|
||
`p256`, and the wide root, and stops before `p255` after `p256` regenerates a
|
||
byte-identical export. Closing the chain at `p299 -> p000` produces the complete
|
||
stage-identical 300-node cycle diagnostic with empty compiler, assembler, and
|
||
linker traces.
|
||
|
||
`dynamic_package_universe_crosses_former_boundary` selects 257 canonical
|
||
directory products in one direct request per stage. Fifty-two directories have
|
||
combined same/external tests and each produces `ptest`, `pxtest`, and one
|
||
directory `pmain`; 205 production-only directories take the no-test path. The
|
||
shared support closure brings the command-global universe to exactly 370
|
||
compile actions and 422 assembler invocations, with 52 generated dispatchers,
|
||
links, binaries, and results. The 205 no-test products have only ordinary
|
||
production actions and statuses: no support-owned target, main, link, binary,
|
||
or result. The observer reverses all directory descriptors between stages,
|
||
proves one compile per action, runs a boundary combined binary, validates
|
||
variant-owned units and external self substitution, and compares representative
|
||
action artifacts, normalized traces, and binaries byte-for-byte.
|
||
|
||
The same observer exercises the public `ww test <tree>/...` coordinator path
|
||
against that persistent action store. The coordinator passes exactly 257
|
||
directory descriptors in one driver request, prints 52 combined `ok` reports
|
||
and 205 no-test `?` reports, and performs no new compilation. An unchanged warm
|
||
request again invokes no compiler or assembler; the 52 real products follow the
|
||
existing explicit-output relink convention while no-test products still create
|
||
no linker work. Existing focused observers continue to prove
|
||
dependency-first/root-first canonical reuse, root-only/combined artifact
|
||
identity, exact reordered-product trace bytes, and request-shape-independent
|
||
persistent action reuse.
|
||
|
||
This representation follows the semantic separation and scalable action
|
||
construction in the pinned official Go 1.26.5 source, identified by
|
||
[`VERSION`, lines 1–2](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/VERSION#L1-L2),
|
||
at commit `c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- Go's loader states that repeated package lookup returns the same pointer
|
||
([`pkg.go`, lines 633–636](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L633-L636)),
|
||
resolves canonical path and directory before package-data lookup
|
||
([lines 863–911](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L863-L911)),
|
||
and reuses the package cached under the resolved `ImportPath`
|
||
([lines 757–768](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L757-L768)).
|
||
- A Go builder has one command-global action cache, while each action's
|
||
dependencies are a dynamically accumulated slice
|
||
([`action.go`, lines 38–45](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L38-L45),
|
||
[lines 84–89](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L84-L89)).
|
||
The cache key is operation plus canonical package pointer and returns the
|
||
existing action
|
||
([lines 202–206](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L202-L206),
|
||
[lines 437–447](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L437-L447)).
|
||
- Go constructs an archive compile action and dynamically appends actions only
|
||
for the package's direct imports
|
||
([lines 628–659](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L628-L659)).
|
||
It separately interns a link action rooted in that cached compile action
|
||
([lines 919–958](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L919-L958))
|
||
and dynamically expands the complete transitive link closure
|
||
([lines 1034–1068](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L1034-L1068)).
|
||
Requested package actions are likewise accumulated with `append`
|
||
([`build.go`, lines 519–534](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L519-L534),
|
||
[lines 551–558](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L551-L558)).
|
||
- During execution, Go builds one package from its own source list
|
||
([`exec.go`, lines 721–790](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L721-L790),
|
||
[lines 928–935](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L928-L935)),
|
||
maps its direct action dependencies into compiler inputs
|
||
([lines 864–884](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L864-L884)),
|
||
and links the root archive with mappings for the complete link-action closure
|
||
([lines 1592–1647](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L1592-L1647)).
|
||
- `go/build` keeps directory, import identity, declared name, and ordinary,
|
||
internal-test, and external-test file lists separate
|
||
([`build.go`, lines 436–493](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L436-L493));
|
||
`ImportDir` explicitly processes the named directory
|
||
([lines 521–525](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L521-L525)),
|
||
reads precisely that directory
|
||
([lines 859–900](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L859-L900)),
|
||
and assigns accepted files to the separate package-owned lists
|
||
([lines 948–1039](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L948-L1039)).
|
||
- Go's test loader explicitly returns generated main, internal production-plus-
|
||
test, and external-test packages, reusing production when valid
|
||
([`test.go`, lines 85–102](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L85-L102));
|
||
constructs the internal, external, and generated-main variants separately
|
||
([lines 175–293](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L175-L293));
|
||
dynamically appends, sorts, and deduplicates generated-main imports
|
||
([lines 315–376](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L315-L376));
|
||
and uses copy-on-write test variants while preserving unaffected package
|
||
objects
|
||
([lines 421–474](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L421-L474)).
|
||
|
||
WW adopts those package/action distinctions and scalable dependency
|
||
accumulation, but not Go's build IDs, module system, importcfg, cache/CAS,
|
||
preloader, parallel action scheduler, or network behavior. Normal local WW
|
||
builds and tests remain offline, manifest-free, registry-free, database-free,
|
||
CAS-free, and network-free.
|
||
|
||
### 11.15 Implemented internal-package import visibility
|
||
|
||
A source import whose complete canonical import path contains a directory
|
||
component named exactly `internal` is now contextual. Locate the final such
|
||
component. Its parent directory is the ownership boundary, and the import is
|
||
legal only when the importing source package's canonical filesystem directory
|
||
is that boundary or a descendant at a real path-component boundary. Thus
|
||
`domain.client` may import `domain.internal.secret`, while `outsider` and
|
||
`domainx.client` may not. `internalx` has no special meaning. For
|
||
`domain.internal.outer.internal.deep`, the final `internal` wins and the owner
|
||
is `domain.internal.outer`, not `domain`.
|
||
|
||
The complete dotted import identity determines whether the rule applies and
|
||
how many components comprise the final `internal` plus its following suffix.
|
||
WW removes those components from that source edge's resolved lexical target
|
||
route, canonicalizes the resulting owner directory physically, and compares it
|
||
with the already canonical physical importer directory. Stripping precedes
|
||
physical canonicalization because a symlink at or below `internal` may point to
|
||
a target with a different name or depth; an action spelling interned by an
|
||
earlier edge is never reused for this contextual calculation. Cstage obtains
|
||
directory canonicalization through `realpath`; WWstage uses its equivalent
|
||
`chdir`/`getcwd` canonicalization. For explicit single-file compatibility
|
||
roots, Cstage uses `realpath` and WWstage's component walker uses
|
||
`lstat`/`readlink` plus the same canonical current-directory representation;
|
||
both preserve component and trailing-directory semantics across symlinks. The
|
||
equality-or-`/`-boundary comparison never uses a raw string prefix. This
|
||
division is intentional: an unrelated physical
|
||
ancestor literally named `internal` does not impose visibility on an import
|
||
whose canonical identity has no such component, while a symlink spelling at or
|
||
below an import-path `internal` cannot move the effective owner or importer.
|
||
Explicit single-file compatibility roots use their canonicalized containing
|
||
directory as the importer context. Directly selecting an internal directory as
|
||
a command root remains legal because selection is not a source import.
|
||
|
||
Visibility is an import-edge property, not part of canonical package or action
|
||
identity. Both drivers resolve the complete target, intern or reuse its one
|
||
canonical production action, and then perform the importer-context check before
|
||
accepting the source binding or dependency edge. Consequently an allowed
|
||
importer may load and compile the target normally, but that cached action cannot
|
||
authorize a later forbidden importer. Reversing requested products or visiting
|
||
the forbidden importer first produces the same result. No declared package
|
||
name, leaf, output name, product ordinal, storage locator, hash, or test variant
|
||
participates in the decision. Legal edges therefore retain the existing
|
||
owner-only byte-sorted unit, exact sorted/deduplicated direct `.wwi` compiler
|
||
inputs, deterministic archive, and complete archive-only linker closure.
|
||
|
||
Cstage represents the rule with the bounded
|
||
`sep_internal_parent_count`/`sep_internal_import_allowed` helpers in
|
||
`cmd/ww/main.c`. WWstage has the isomorphic
|
||
`sepinternalparentcount`/`sepinternalimportallowed` helpers in
|
||
`selfhost/cmd/ww/main.ww`. Neither adds a package field, fixed-size package
|
||
table, second action universe, or action-key input. A distinct
|
||
`SEP_LOAD_INTERNAL` result propagates through the iterative loader. On rejection
|
||
both stages emit the importing parser position followed by exactly:
|
||
|
||
```text
|
||
use of internal package <canonical-import-path> not allowed
|
||
```
|
||
|
||
The command returns immediately from graph loading, before directory-identity
|
||
finalization, unit composition, workdir owner validation, stale-voucher
|
||
invalidation, tool-identity recording, compiler, assembler, in-driver archive
|
||
production, linker, publication, or execution. A cold rejection therefore
|
||
commits no target/importer artifact or `.wwtool.*` state. A forbidden warm
|
||
request cannot use a previously committed target to bypass the check and leaves
|
||
the already committed target voucher and all tool records byte-unchanged.
|
||
Allocation or path canonicalization failure remains a deterministic
|
||
command-fatal pre-tool error; the visibility helper does not change stable
|
||
package indices or growth behavior.
|
||
|
||
Every selected source file reaches the same driver scan. The rule therefore
|
||
applies to ordinary production sources, same-package test sources in the
|
||
internal production-plus-test variant, external `_test` sources, and real
|
||
source imports inside the test-support package. Generated-main-to-variant,
|
||
generated-main-to-support, and coordinator product wiring remain synthetic
|
||
edges and are not retroactively treated as source imports. No coordinator
|
||
change is required: `cmd/wwtest` only dispatches, and
|
||
`internal/wwpackage/package.ww` only discovers and classifies source groups,
|
||
constructs the union request, and runs the driver; neither resolves a source
|
||
import or owns its importing position.
|
||
|
||
This follows only the pinned official Go 1.26.5 source at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `loadImport` resolves and reuses the canonical package first, then explicitly
|
||
checks the rule on every import because the result depends on the importing
|
||
code, and attaches the importing position
|
||
([`pkg.go`, lines 787–791](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L787-L791)).
|
||
- The rule is the tree rooted at the parent of the target's `internal`
|
||
directory
|
||
([`pkg.go`, lines 1463–1471](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1463-L1471)).
|
||
A package named directly on the command line is not an import
|
||
([lines 1498–1502](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1498-L1502)),
|
||
and the import-path boundary is located before filesystem containment
|
||
([lines 1505–1515](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1505-L1515)).
|
||
- Go's filesystem branch cleans the importer and owner, requires a
|
||
path-component-aware prefix, and retries with both paths symlink-expanded
|
||
([`pkg.go`, lines 1534–1546](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1534-L1546)).
|
||
Its rejection text is exactly the diagnostic above
|
||
([lines 1564–1571](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1564-L1571)),
|
||
and its exact-component search deliberately selects the final `internal`
|
||
element as the most restrictive rule
|
||
([lines 1574–1590](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1574-L1590)).
|
||
- Same-package and external test imports both pass through ordinary
|
||
`loadImport` with their own source positions before variant construction
|
||
([`test.go`, lines 102–161](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L102-L161)).
|
||
Generated test-main dependencies are synthesized separately
|
||
([lines 307–330](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L307-L330)).
|
||
- Go's downstream action cache keys canonical package actions independently
|
||
and consumes the already validated direct package imports, so visibility does
|
||
not belong in action identity
|
||
([`action.go`, lines 437–455](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L437-L455),
|
||
[lines 628–657](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L628-L657)).
|
||
|
||
The focused native observer `internal_package_import_visibility` generates its
|
||
lexical package/import tree under a temporary physical ancestor also named
|
||
`internal`, while deliberate symlink destinations live outside that ancestor,
|
||
so that unrelated-host-path case is exercised rather than documented only. It
|
||
builds and runs allowed descendant, nested-final, `internalx`, and symlinked
|
||
physical-owner cases; rejects outsider, sibling-prefix, nested-final, and
|
||
symlink-escape cases at exact source positions with empty tool traces; maps an
|
||
internal target symlinked to a differently shaped physical path back to its
|
||
lexical owner's canonical directory; builds an internal package directly; and
|
||
reverses requested allowed/forbidden product-descriptor order around one reused
|
||
target. It checks ordinary, internal-test, and external-test
|
||
source imports, generated-main transitive-export isolation, owner-only source
|
||
order, direct export inputs, archive-only link closure, runtime results, warm
|
||
no-op package production, rejection-state preservation, and the primary
|
||
production chain's unit, export, assembly, object, archive, binary, and exact
|
||
normalized tool arguments across independent cold Cstage and WWstage work
|
||
roots. Test variants additionally compare their unit/export/archive bytes and
|
||
exercise byte-equivalent runtime output in both stages.
|
||
|
||
### 11.16 Implemented manifest-free local vendor-directory imports
|
||
|
||
The local package loader now expands only imports parsed from source. For a
|
||
source package whose resolved lexical route is `<root>/domain/app`, an import
|
||
of `lib.math` probes these directory packages in order:
|
||
|
||
```text
|
||
<root>/domain/app/vendor/lib/math
|
||
<root>/domain/vendor/lib/math
|
||
<root>/vendor/lib/math
|
||
<ordinary ordered-root lookup for lib/math>
|
||
```
|
||
|
||
The walk stops at that edge's applicable active source root. It never walks an
|
||
arbitrary filesystem ancestor and never acquires a boundary from another
|
||
requested product. Each resolution context carries the current package's
|
||
lexical route and source-root boundary. An explicitly identified root derives
|
||
the boundary by removing and round-trip validating exactly its dotted identity
|
||
components. An unbound literal root chooses the first precedence-valid strict
|
||
ancestor in its own ordered search roots, or the selected directory itself.
|
||
An ordinary child records the exact root that selected it; a vendored child
|
||
inherits the parent's boundary. These values are contextual resolution state,
|
||
not package/action identity.
|
||
|
||
Before source scanning, a literal directory whose lexical route is
|
||
representable below that boundary binds the complete relative dotted identity,
|
||
including any `vendor` components. A truly rootless literal keeps its reversible
|
||
`__wwlocal` identity and cannot be coalesced with a same-physical vendored
|
||
action. Thus selecting a vendored directory directly remains legal without
|
||
letting product order donate its action identity to or from a source import.
|
||
|
||
A candidate shadows outer and ordinary candidates only when its directory
|
||
contains an observed non-directory name ending in `.ww`. This deliberately
|
||
includes `_test.ww` and the bare name `.ww`, matching Go's suffix probe; an
|
||
actual subdirectory named `x.ww` and an unreadable candidate with no observed
|
||
source do not shadow. Once a candidate is selected, normal package enumeration
|
||
reports its real errors, including a test-only or otherwise production-empty
|
||
directory, rather than falling through.
|
||
|
||
Source retains only the effective spelling, such as `lib.math`. Selection
|
||
assigns the target the complete expanded canonical identity, such as
|
||
`domain.app.vendor.lib.math`, and separately canonicalizes its physical
|
||
directory. The target's declared name independently supplies the default
|
||
qualifier in each importing source file. The action key is that expanded
|
||
identity and canonical directory,
|
||
plus the existing variant/role. Different physical vendor copies are distinct;
|
||
different expanded vendor routes remain distinct even when symlinks converge
|
||
on one physical directory; repeated resolutions of the same pair reuse one
|
||
action. Source spelling, importer context, product order, output name, declared
|
||
leaf, and allocation/discovery order do not enter that key.
|
||
|
||
The final exact non-terminal dotted component named `vendor` determines the
|
||
effective suffix and owner. A nested path uses its final `vendor`; `vendorx` is
|
||
ordinary; and a path ending exactly in `vendor` names an ordinary package.
|
||
After resolution and action interning, every source edge first performs vendor
|
||
visibility and then verifies source spelling. An allowed importer that directly
|
||
spells an expanded path receives the source-position diagnostic:
|
||
|
||
```text
|
||
<expanded-path> must be imported as <effective-suffix>
|
||
```
|
||
|
||
An outside importer receives, with visibility taking diagnostic precedence:
|
||
|
||
```text
|
||
use of vendored package not allowed
|
||
```
|
||
|
||
Directly selecting a directory below `vendor` remains legal because a command
|
||
root is not a source import.
|
||
|
||
Visibility derives the owner from the current edge's resolved lexical vendor
|
||
route and only then canonicalizes that owner physically. It never strips
|
||
components from the already-canonical target, whose symlink shape may have a
|
||
different depth. The importer is its canonical physical directory. Equality or
|
||
a real `/`-component descendant is allowed; a raw string prefix is not.
|
||
Consequently an importer reached through a symlink is judged by its physical
|
||
containment, while a vendor target symlinked to a differently shaped physical
|
||
directory keeps the owner established by the lexical vendor route. The check
|
||
runs after intern/reuse on every source edge, so an action loaded by an allowed
|
||
importer cannot authorize a later forbidden spelling or importer.
|
||
|
||
Cstage represents the resolution with `route` and `source_root` in
|
||
`sepcontext`, the bounded `sep_resolve_source_import` and vendor helpers, stable
|
||
integer action references in typed source bindings, and transient
|
||
`{package,context}` loader children. WWstage uses the isomorphic `sepcontext`,
|
||
`sepresolvesourceimport`, typed bindings, and transient child vector. The
|
||
package-global dependency set remains the sorted/deduplicated canonical action
|
||
set used for compilation and linking; contextual child traversal never creates
|
||
a second universe or contaminates action identity. All new storage grows with
|
||
checked allocation, and package/context vectors continue to expose only stable
|
||
integer references across growth.
|
||
|
||
A compile still receives one sorted, deduplicated
|
||
`--import <expanded-path> <dependency.wwi>` triple for each direct dependency.
|
||
When source spelling differs, the driver additionally supplies the sorted,
|
||
unique auxiliary mapping:
|
||
|
||
```text
|
||
--import-map <source-spelling> <expanded-path>
|
||
```
|
||
|
||
Both compilers require the map target to be an existing direct `--import`,
|
||
require source keys to be sorted and unique, and require a matching import in
|
||
the primary source input. No leaf-equality condition exists. After parsing the
|
||
primary input and before prepending imported interfaces, the compiler replaces
|
||
its semantic import key while preserving source position and spelling. It then
|
||
reads the expanded target's declared name from the direct `.wwi` and installs
|
||
that name only in the declaring source file. Thus the map adds no dependency or
|
||
export input, expanded
|
||
identity flows into self-contained `.wwi` ownership and symbols, and direct
|
||
exports still have no transitive leakage. Linking remains independent: each
|
||
executable consumes its root archive and complete reachable archive closure,
|
||
never `.wwi` or import-map inputs.
|
||
|
||
Persistent units record resolution identity in ignored, deterministic comments:
|
||
|
||
```text
|
||
//ww:vendor-dir <hex-canonical-package-directory>
|
||
//ww:import-map <source-spelling> <expanded-path> <hex-canonical-target-directory>
|
||
```
|
||
|
||
Hex encoding keeps arbitrary legal filesystem bytes inside one comment. The
|
||
metadata makes ordinary-to-vendor changes and vendor symlink retargeting
|
||
invalidate the importer even when its source bytes and both already-warm export
|
||
bytes happen to match. It contains no dependency body and does not alter source
|
||
positions. The current workdir formats are build 15 and test 14. An equivalent
|
||
warm request remains a package-production no-op; an export change propagates
|
||
only through ordinary direct-export comparison.
|
||
|
||
Production, same-package internal-test, external `_test`, and real source
|
||
imports inside the test-support package all use this source-edge resolver.
|
||
Generated-main-to-variant, generated-main-to-support, and coordinator product
|
||
edges remain synthetic and receive no map or retroactive source legality.
|
||
`cmd/wwtest` remains a dispatcher. `internal/wwpackage` still discovers and
|
||
classifies source groups and submits one command-global union; it performs no
|
||
vendor resolution. It creates only its removable command-temporary coordination
|
||
tree. The private driver creates a missing delegated `-w` directory and a
|
||
requested output directory only after all semantic graph and output preflight
|
||
succeeds; a rejected request therefore leaves neither directory behind.
|
||
|
||
Resolution, identity collision checks, contextual legality, dependency-failure
|
||
propagation, cycles, command kind, publication paths, and action closures all
|
||
finish before cold scratch acquisition, tool identity staging, producer
|
||
execution, publication, or runtime execution. A request whose every product is
|
||
already invalid returns without acquiring scratch. If a later producer or
|
||
product fails, otherwise viable siblings may have been produced only into the
|
||
same transaction; none is committed or executed. A forbidden or otherwise
|
||
rejected warm request leaves committed vouchers, status files, tool records,
|
||
and products byte-unchanged.
|
||
|
||
This is only manifest-free local source-tree behavior. It does not implement
|
||
Go modules, module vendor mode, `go.mod`, `vendor/modules.txt`, importcfg, build
|
||
IDs, a package database, a CAS, registry access, or network lookup, and it is
|
||
separate from the future locked vendor store in section 4.6.
|
||
|
||
The rule follows the pinned official Go 1.26.5 source at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- source-derived imports are expanded and the expanded vendor path becomes the
|
||
canonical import path
|
||
([`pkg.go`, lines 658–668](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L658-L668));
|
||
- resolution and canonical package-cache reuse occur before the contextual
|
||
internal/vendor checks, which still run with the importing position on every
|
||
source edge
|
||
([`pkg.go`, lines 722–796](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L722-L796));
|
||
- vendor lookup walks importer ancestors nearest-first to the applicable root,
|
||
requires a source-bearing directory, and records the expanded identity
|
||
([`pkg.go`, lines 1213–1263](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1213-L1263));
|
||
- the source-bearing probe accepts any non-directory `.go` suffix and ignores
|
||
directory-read failure
|
||
([`pkg.go`, lines 1418–1429](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1418-L1429));
|
||
- command roots remain legal, while an expanded source spelling must use its
|
||
effective suffix
|
||
([`pkg.go`, lines 1593–1617](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1593-L1617));
|
||
- vendor ownership uses component-aware physical containment and symlink
|
||
expansion
|
||
([`pkg.go`, lines 1620–1667](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1620-L1667));
|
||
- the final exact non-terminal `vendor` component controls the rule
|
||
([`pkg.go`, lines 1670–1688](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1670-L1688));
|
||
- production, internal-test, and external-test imports retain distinct raw
|
||
source spellings/positions but each resolves canonically, while generated
|
||
test-main wiring is synthetic
|
||
([`test.go`, lines 85–173](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L85-L173),
|
||
[`test.go`, lines 175–266](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L175-L266),
|
||
[`test.go`, lines 272–373](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L272-L373),
|
||
[`go/build/build.go`, lines 415–493](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L415-L493)); and
|
||
- action caching consumes the already-resolved package graph, while output
|
||
publication remains a later concern
|
||
([`action.go`, lines 437–455](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L437-L455),
|
||
[`action.go`, lines 628–659](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L628-L659),
|
||
[`build.go`, lines 470–558](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L470-L558)).
|
||
|
||
The native observer `vendor_directory_import_resolution` generates every source
|
||
tree temporarily and runs both stages from independent cold work roots. It
|
||
proves nearest/outer/root/ordinary selection and the active-root boundary;
|
||
source-bearing versus empty candidates; distinct and reused actions, including
|
||
same-physical symlink targets; exact spelling/visibility diagnostics and
|
||
product-order reversal; final-component, terminal-name, component-prefix, and
|
||
symlink behavior; direct vendored roots; production/internal/external/support
|
||
source imports and synthetic-main isolation; owner-only sorted units, exact
|
||
direct exports/import maps, archive-only link closures, runtime output,
|
||
stage-equal normalized argv/artifacts/binaries, warm no-op production, and cold
|
||
and warm rejection-state preservation.
|
||
|
||
### 11.17 Implemented manifest-free recursive local package-pattern selection
|
||
|
||
Build and test now share one local request selector. A positional spelling with
|
||
no `...` is one explicit directory root. In a spelling containing `...`, each
|
||
occurrence in a valid UTF-8 spelling has Go's regular-expression wildcard
|
||
semantics; an invalid UTF-8 pattern matches nothing, and a final `/...` also
|
||
matches the directory before that suffix. WW applies the local matcher to its
|
||
existing manifest-free `DIR/...` interface as well as `./...`, `../...`, and
|
||
absolute spellings. It does not interpret the non-filesystem portion as a
|
||
module or registry path. Multiple direct roots and patterns may be mixed in one
|
||
command.
|
||
For build, `--` before the first positional ends option parsing and every
|
||
following argument is a package selector, including a spelling that begins
|
||
with `-`. Once the first positional has already ended flag parsing, a later
|
||
`--` is itself another package argument.
|
||
|
||
Pattern expansion is request processing only. For each pattern, traversal starts
|
||
at the directory prefix before the first `...` and is bounded to that physical
|
||
tree. The selector never obtains a traversal or source-root boundary from
|
||
another product. It produces canonical physical directory roots; only imports
|
||
parsed from their real source files add dependency edges. The request spelling,
|
||
wildcard prefix, match membership, output name, request order, and discovery
|
||
order never become a package import identity or action key and never enter an
|
||
import search path.
|
||
|
||
The recursive eligibility rules are:
|
||
|
||
- Directory entries are read completely and byte-sorted before processing.
|
||
Every recursively encountered directory whose basename begins `.` or `_`, or
|
||
equals `testdata`, is pruned with its subtree. An explicit literal selection
|
||
bypasses these traversal exclusions, so those directories remain legal direct
|
||
roots.
|
||
- A directory owns only its immediate `.ww` directory entries. Basenames
|
||
beginning `.` or `_` are ignored. As in `go/build`, a source symlink whose
|
||
target is a regular file is read under the symlink entry's byte-sorted name;
|
||
a source-shaped symlink to a directory is ignored. A subdirectory never
|
||
donates sources to its parent.
|
||
- A directory with at least one production or `*_test.ww` source is eligible.
|
||
A recursively encountered source-empty directory is silently skipped. A
|
||
direct source-empty root is an error. A malformed source-bearing directory is
|
||
retained as a root and fails during ordinary package-clause or driver loading;
|
||
malformed files in excluded or source-empty trees do not poison the request.
|
||
- The traversal does not prune `vendor`. Instead a wildcard cannot consume a
|
||
non-terminal exact path component named `vendor`. Thus `DIR/...` may select a
|
||
code-bearing terminal `DIR/vendor` but not `DIR/vendor/x`.
|
||
`DIR/vendor/...` explicitly selects that vendor root and its descendants until
|
||
another non-terminal `vendor` becomes a barrier. `vendorx` is ordinary.
|
||
|
||
The explicit traversal root is opened after following a directory symlink, as
|
||
in Go. It may therefore name a target outside the lexical spelling, but the
|
||
target becomes the canonical traversal boundary. Directory symlinks encountered
|
||
below that root are never followed, so they cannot escape, create cycles, or
|
||
change selection. A cyclic explicit root is rejected while canonicalizing it.
|
||
Relative, absolute, dotted, and explicit-root-symlink spellings that reach one
|
||
physical package collapse to one canonical root. This physical interning is
|
||
WW's stronger command-global identity rule; it deliberately avoids Go's few
|
||
GOPATH cases in which different lexical import paths can retain distinct package
|
||
objects.
|
||
|
||
Raw requested spellings are byte-sorted first and each is then lexically cleaned
|
||
before traversal. Matched source paths are canonicalized, sorted by canonical
|
||
directory and filename, and deduplicated. Products are then byte-sorted by
|
||
canonical directory and variant. Duplicate patterns, overlapping patterns, and
|
||
canonical aliases therefore select one root/product and reuse one action. Go
|
||
itself processes patterns in argv order and suppresses later package objects; WW
|
||
performs the stronger final canonical sort required by its
|
||
request-order-independent command universe. Reversing request or product order
|
||
does not change roots, diagnostics, normalized tool arguments, artifacts, or
|
||
runtime output.
|
||
|
||
An unmatched pattern emits:
|
||
|
||
```text
|
||
ww: warning: "PATTERN" matched no packages
|
||
```
|
||
|
||
`PATTERN` is quoted with the pinned `strconv.Quote` rules, including
|
||
deterministic escapes for quotes, backslashes, controls, non-printing Unicode,
|
||
and malformed UTF-8 bytes. Warnings are emitted in the
|
||
sorted request order. With no remaining roots,
|
||
ordinary build without `-o` succeeds as an empty build, while test reports
|
||
`ww test: no packages to test`. A build with a non-directory `-o` reports no
|
||
packages to build; a directory `-o` reports no main packages to build. A
|
||
non-directory `-o` still requires exactly one production root. An existing
|
||
directory or spelling ending in `/` receives each selected command under its
|
||
canonical directory basename; non-main selected roots receive no named output.
|
||
Two commands with the same destination basename are rejected rather than
|
||
overwriting one another. All selection, canonicalization, package-clause,
|
||
duplicate-output, and unusable-request diagnostics precede producer execution.
|
||
Raw `-o` and `-w` spellings and every derived directory-fan-out output, cold
|
||
scratch name, persistent tool-record name, and package artifact are bounded and
|
||
validated symmetrically before tools; a raw spelling that fits but whose suffix
|
||
or command basename does not fit is rejected with the same Cstage/WWstage
|
||
diagnostic and no filesystem publication.
|
||
For a delegated multi-root or recursive `-S` build, `-w` is required so the
|
||
assembly outputs have caller-owned persistent destinations instead of vanishing
|
||
with the coordinator's temporary plan.
|
||
|
||
Build and test begin with the same eligible canonical directory set. Recursive
|
||
build removes a source-bearing root that has only test files; an explicitly
|
||
selected test-only directory remains an unusable build root and fails. Build
|
||
creates one production product per remaining directory. Test retains test-only
|
||
directories and, after selection, constructs the already specified isolated
|
||
production/no-test, internal production-plus-test, external `_test`, support,
|
||
recompiled-for-test, and one directory-generated-main action. Pattern expansion
|
||
does not create those actions; graph-owned substitution alone makes the
|
||
augmented package visible through applicable external and transitive edges.
|
||
|
||
Vendor selection remains distinct from vendor import resolution. Selecting a
|
||
directory below `vendor`, literally or through an explicitly vendor-rooted
|
||
pattern, keeps its complete canonical local identity; it is never shortened to
|
||
the suffix after `vendor`, and its declaration never renames it. A generic
|
||
recursive pattern does not expose vendored
|
||
descendants as ordinary short command roots. Independently, an allowed real
|
||
source import still searches nearest-first below local `vendor`, creates the
|
||
expanded identity described in section 11.16, supplies the required
|
||
`--import-map`, and performs spelling and visibility checks for that importer
|
||
even when the canonical action already exists.
|
||
|
||
The ownership split is exact:
|
||
|
||
- `cmd/ww/main.c` and `selfhost/cmd/ww/main.ww` recognize recursive and
|
||
multi-root build/test requests symmetrically and delegate them. Their private
|
||
build route consumes production product descriptors in one command-global
|
||
package universe. It records library-root completion without linking and
|
||
links each command product independently. Recursive build forwards `-S`,
|
||
`-L`, and `-l` through the same private product route; assembly-only products
|
||
receive completion markers only after their producer pass succeeds. Both
|
||
stages allocate the same bounded delegation argv and inherit the existing
|
||
environment directly, so delegation adds no WWstage-only environment-copy
|
||
allocation or failure point.
|
||
- `internal/wwpackage/package.ww` owns pattern cleaning and matching, bounded
|
||
directory traversal, source-bearing eligibility, canonical root/product
|
||
sorting and deduplication, build-versus-test product classification, output
|
||
coordination, and deterministic reporting. It does not resolve a source
|
||
import and does not prepend a pattern root to `-I`.
|
||
- `cmd/wwtest` remains a dispatcher. The Cstage and WWstage drivers own package
|
||
enumeration, canonical identity, contextual import resolution, graph loading,
|
||
variants, compilation, archive construction, linking, publication, and
|
||
persistent reuse.
|
||
|
||
Consequently the existing action and tool contracts remain unchanged after
|
||
root selection. Every action unit contains only the owner's byte-sorted source
|
||
files. A compiler receives exactly the sorted, deduplicated `.wwi` exports of
|
||
direct source dependencies and any required vendor import-map binding. Each
|
||
executable link receives its root archive and complete reachable archive
|
||
closure, never a `.wwi`. Canonical duplicate roots reuse the same action; the
|
||
pattern text, declared qualifier, and product receiving an output do not affect
|
||
canonical or persistent action ownership.
|
||
|
||
Selection and package-clause validation finish before the coordinator creates
|
||
its removable temporary plan, and the coordinator never creates persistent
|
||
state. Driver graph, identity, visibility, cycle, closure, and output validation
|
||
finish before a missing delegated work or output directory is created and
|
||
before scratch, voucher, status, tool-state, publication, or producer mutation.
|
||
If later setup of another requested directory fails, both drivers remove every
|
||
empty path prefix created by that setup while preserving all pre-existing caller
|
||
directories. A cold rejected pattern leaves no partial request state. The same
|
||
rejection against an existing caller work root leaves its marker and every
|
||
committed artifact, voucher, and tool record byte-unchanged and invokes no
|
||
producer. A valid equivalent direct or recursive warm request remains a
|
||
package-production no-op; changed exports continue to propagate through direct
|
||
dependencies only.
|
||
|
||
This slice follows only official Go 1.26.5 source at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- local literal versus wildcard handling, the prefix before the first `...`,
|
||
explicit root-symlink following, recursive exclusions, source-empty omission,
|
||
and malformed-directory retention are in
|
||
[`cmd/go/internal/search/search.go`, lines 276–418](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/search/search.go#L276-L418),
|
||
and its quoted unmatched-pattern warning is at
|
||
[lines 424–429](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/search/search.go#L424-L429);
|
||
- wildcard syntax, the empty match for trailing `/...`, and the non-terminal
|
||
`vendor` barrier are in
|
||
[`cmd/internal/pkgpattern/pkgpattern.go`, lines 32–106](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/internal/pkgpattern/pkgpattern.go#L32-L106),
|
||
including invalid-UTF-8 rejection at lines 75–76,
|
||
with non-terminal vendor-element replacement implemented at
|
||
[lines 125–137](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/internal/pkgpattern/pkgpattern.go#L125-L137);
|
||
- manifest-free request expansion, canonical package loading, first-occurrence
|
||
deduplication, and pattern membership are in
|
||
[`cmd/go/internal/load/pkg.go`, lines 2922–2965](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L2922-L2965),
|
||
while source imports alone recurse through package loading at
|
||
[lines 2024–2047](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L2024-L2047);
|
||
- build uses that common matcher, implements single versus directory `-o`, and
|
||
omits wildcard-selected test-only roots at
|
||
[`cmd/go/internal/work/build.go`, lines 459–559](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L459-L559)
|
||
and
|
||
[lines 731–745](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L731-L745);
|
||
- test uses the same package request set, reports an empty set, and constructs
|
||
isolated test variants only afterward at
|
||
[`cmd/go/internal/test/test.go`, lines 684–719](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L684-L719)
|
||
and
|
||
[lines 1133–1226](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1133-L1226);
|
||
- immediate directory ownership and hidden/underscore source-name exclusion
|
||
are in
|
||
[`go/build/build.go`, lines 859–914](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L859-L914)
|
||
(including regular-file source symlink following and symlink-to-directory
|
||
omission at lines 886–900),
|
||
parse-error retention and production/test classification are in
|
||
[lines 931–1036](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L931-L1036),
|
||
and `NoGoError` eligibility is in
|
||
[lines 1076–1082](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1076-L1082); and
|
||
- child symlinks are skipped by `Lstat`-based directory walking and entries are
|
||
traversed in byte order at
|
||
[`cmd/go/internal/fsys/walk.go`, lines 14–59](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/fsys/walk.go#L14-L59)
|
||
and
|
||
[`os/dir.go`, lines 109–125](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/os/dir.go#L109-L125).
|
||
|
||
Build subcommand option termination is delegated by the Go command at
|
||
[`cmd/go/main.go`, lines 312–321](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/main.go#L312-L321),
|
||
with `--` termination implemented by
|
||
[`flag/flag.go`, lines 1074–1089](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/flag/flag.go#L1074-L1089),
|
||
and the parse loop stops at the first positional at
|
||
[lines 1153–1176](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/flag/flag.go#L1153-L1176).
|
||
|
||
Unmatched-pattern quoting uses the pinned `strconv.Quote` decoder and escape
|
||
rules in
|
||
[`strconv/quote.go`, lines 28–123](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/strconv/quote.go#L28-L123),
|
||
including the exported `Quote` entry at lines 117–123, and the `IsPrint`
|
||
algorithm at
|
||
[`strconv/quote.go`, lines 515–559](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/strconv/quote.go#L515-L559),
|
||
with its generated tables in
|
||
[`strconv/isprint.go`, lines 8–733](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/strconv/isprint.go#L8-L733).
|
||
|
||
No module cutoff, `go.mod`, module vendor mode, `vendor/modules.txt`, importcfg,
|
||
build ID, registry, database, CAS, or network behavior is copied.
|
||
|
||
The native observer `recursive_tree_discovery` generates every tree
|
||
temporarily and runs Cstage and WWstage from independent cold roots. It covers
|
||
ordinary and test-only roots, hidden/underscore/testdata exclusions and direct
|
||
exceptions, terminal and explicit vendor patterns, an imported expanded vendor
|
||
dependency at both package-local and ancestor vendor directories,
|
||
overlapping/reversed/duplicate patterns independently in each stage, root,
|
||
child-directory, regular-file, and directory-target source symlinks,
|
||
canonical aliases, source-empty and malformed directories, build/test variant
|
||
selection with an asserted common production-root set, middle-position and
|
||
valid-UTF-8 wildcard edge cases, byte-sorted quoted unmatched diagnostics,
|
||
multi-command directory output and duplicate-destination rejection, recursive
|
||
assembly/link-flag forwarding, build `--` termination, raw-versus-derived
|
||
output/scratch/work-path boundaries with zero producer calls, owner-only units,
|
||
exact direct exports and import maps, archive-only links, normalized stage-equal tool argv and
|
||
artifacts/binaries/output, warm no-op package production, and cold/warm pre-tool
|
||
rejection-state preservation. The existing
|
||
`vendor_directory_import_resolution` observer supplies the exact compiler
|
||
`--import-map` argv proof for imported vendor dependencies, and the existing
|
||
diamond and long-closure observers independently prove sorted/deduplicated
|
||
direct `.wwi` cardinality and archive-only reachable link closures.
|
||
|
||
### 11.18 Implemented canonical identity, declared-name, and file-import-scope slice
|
||
|
||
Directory-package identity and source naming are now independent throughout
|
||
local build and test. For example:
|
||
|
||
```ww
|
||
// canonical import identity: acme.codec
|
||
package wire;
|
||
```
|
||
|
||
is imported with the existing dotted syntax:
|
||
|
||
```ww
|
||
package main;
|
||
import acme.codec;
|
||
export fn main() i32 = { return wire.value(); };
|
||
```
|
||
|
||
The package action, exports, symbols, archives, dependency edges, persistent
|
||
storage ownership, and link closure remain owned by `acme.codec`. Only the
|
||
source-file binding is named `wire`. The path leaf `codec` is not installed as
|
||
another qualifier, and a sibling source file receives no `wire` binding unless
|
||
that file has its own import.
|
||
|
||
The implemented representation keeps six facts distinct:
|
||
|
||
1. source import spelling, including its source file, line, and column;
|
||
2. contextually expanded canonical import identity;
|
||
3. canonical physical directory;
|
||
4. the one declared package name read from eligible source clauses and `.wwi`
|
||
package markers;
|
||
5. the optional explicit alias written at that import occurrence; and
|
||
6. the effective source-file-local qualifier, selected from the explicit alias
|
||
when present and otherwise from the imported declaration.
|
||
|
||
Both drivers retain one dynamically allocated `sepbind` occurrence for every
|
||
real import site. The occurrence stores the source spelling and position plus a
|
||
stable action index. Contextual `internal` and vendor resolution is therefore
|
||
rechecked for every source import even if its target action already exists. A
|
||
separate package dependency vector unions those occurrences, deduplicates by
|
||
canonical action, and sorts by complete canonical identity/variant/role. That
|
||
vector alone supplies dependency traversal and compiler `--import` arguments.
|
||
Patterns, qualifiers, declared names, export closure facts, and generated edges
|
||
never create source dependency edges.
|
||
|
||
The owner-only composed unit preserves byte-sorted source boundaries with one
|
||
`//ww:module-reset <canonical-owner>` separator per file. Parser nodes carry a
|
||
source-section ID as well as canonical owner and declared package name. Each
|
||
real `N_USE` therefore belongs to one source section. `.wwi` emission repeats
|
||
canonical-owner/package markers as needed for contributing source sections and
|
||
retains imports only with the declarations from the file that owned them.
|
||
Interfaces remain source-like transitional data, but canonical owner and
|
||
declared name are no longer collapsed into one token.
|
||
|
||
`w6c` and `w6c_ww` validate every direct export's leading canonical owner
|
||
against its paired `--import` path. After all direct exports are parsed, they
|
||
build canonical-path-to-declared-name metadata from those interfaces, apply any
|
||
vendor `--import-map` only to canonical identity, and bind each primary source
|
||
import through its explicit alias or, when absent, the imported declaration.
|
||
The checkers and code generators select bindings by source-section ID and
|
||
canonical owner. Only a qualified lookup through that effective binding marks
|
||
the owning file's occurrence used; imported declarations are never a bare-name
|
||
fallback. Two files may consequently bind the same name to different canonical
|
||
packages, while the graph still contains one edge/action for each target.
|
||
|
||
Within one file, two imports that produce the same effective qualifier are a
|
||
redeclared binding; the later unused binding is also reported. An unused import
|
||
is reported at its own import position even if a sibling file uses the same
|
||
qualifier or canonical dependency. A package-scope declaration collides with
|
||
an equal import binding from any contributing file, matching Go's reconciliation
|
||
of package and file scopes. Conflicting production package clauses remain a
|
||
loader-owned deterministic error before producers. Compiler-owned scope or use
|
||
errors may invoke the compiler, but every action artifact remains staged under
|
||
an adjacent `.new` name. No completion/status marker is written and no product
|
||
is published after a failed compile. Once every action and product has staged,
|
||
the driver preserves each existing destination under a request-owned backup,
|
||
installs the complete new generation, and rolls all installed destinations back
|
||
if any installation fails. Unit vouchers and the global stamp are transaction
|
||
members rather than early invalidation markers. Thus a rejected or interrupted
|
||
request leaves the previous committed generation byte-identical and removes all
|
||
remaining stages; a mixed `.wwi`/object/archive generation is never reusable.
|
||
|
||
Package kind follows the declaration. `package main`, not a path component,
|
||
marks a command. A path ending in `main` remains importable when it declares a
|
||
different name. Any ordinary source import of a package declared `main` is
|
||
rejected as `package <canonical-path> is a program, not an importable package`,
|
||
regardless of its path leaf. The one pinned loader exception is an external
|
||
test's exact same-directory import of the command production: it is rewired to
|
||
the forced-library test copy. WW admits only that canonical colocated edge.
|
||
|
||
Test naming is likewise declaration-based. Production and internal-test
|
||
variants use the production declared name. When production files exist,
|
||
external files must declare `<production-declared-name>_test`; a test-only
|
||
directory may establish one consistent package name from its test files, as in
|
||
pinned `go/build`. External action identity remains the canonical production
|
||
identity plus the existing external variant suffix where that production
|
||
exists. Imports found only in internal or external test files belong only to
|
||
that action. Support and the directory generated-main retain isolated action
|
||
identities and archive closures. A generated dispatcher privately binds its
|
||
tested targets through repeated, byte-sorted
|
||
`--test-target-package <canonical-path>` arguments so a command variant declared `main`
|
||
does not collide with the dispatcher's own synthesized `main`; this is
|
||
compiler-generated wiring distinct from ordinary source aliases. A real
|
||
zero-test directory product marks all compiler-owned target/support metadata
|
||
imports consumed. Those private bindings are installed or marked consumed only in the generated
|
||
dispatcher's source section; an import from an earlier test-file section
|
||
neither supplies nor satisfies it.
|
||
|
||
Vendor expansion changes only canonical identity and physical selection. A
|
||
source spelling such as `lib.codec` can resolve to
|
||
`domain.app.vendor.lib.codec`, while the vendored package's declaration, for
|
||
example `package wire`, supplies the default file-local qualifier. An explicit
|
||
alias overrides only that qualifier. The driver emits one sorted semantic
|
||
`--import-map lib.codec domain.app.vendor.lib.codec` and one direct export input
|
||
despite repeated import occurrences in separate files. The expanded identity
|
||
continues to own symbols, `.wwi`, archive, voucher, and link inputs.
|
||
|
||
Canonical action interning remains the directory/path/variant model of sections
|
||
11.7 and 11.14. Independent file bindings never clone an action, and a declared
|
||
name or source alias never enters an artifact basename or storage locator.
|
||
Changing a dependency's declaration keeps the same action identity and causes
|
||
each direct importer to be reconsidered. A default-bound importer may then fail
|
||
because its old qualifier disappeared; an explicitly aliased importer keeps its
|
||
binding, regenerates a canonical semantic export, and stops reverse propagation
|
||
when those bytes are unchanged. An alias-only source edit rebuilds its owner but
|
||
likewise leaves canonical export identity unchanged. An identical warm request
|
||
remains a producer no-op. Build workdir format 15 and test format 14 prevent
|
||
reuse of older vouchers that lack these semantics.
|
||
|
||
Compiler argv still contains exactly the sorted, deduplicated `.wwi` exports of
|
||
direct canonical dependencies; no transitive `.wwi` and no qualifier-derived
|
||
path appears. Linker argv still contains only the executable root archive and
|
||
complete reachable archive closure plus runtime/native inputs. Publication and
|
||
completion occur only after the corresponding action/product succeeds.
|
||
|
||
Responsibility is intentionally split as follows:
|
||
|
||
- `internal/wwpackage` classifies production, internal, and external test files
|
||
from their declarations, derives the allowed external name from the
|
||
production declaration, expands request patterns, and submits variant roots.
|
||
It does not resolve imports, choose qualifiers, or create dependency edges.
|
||
- `cmd/ww/main.c` and `selfhost/cmd/ww/main.ww` own per-site parsing and
|
||
contextual resolution, canonical directory/action interning, declared-name
|
||
consistency, imported-command rejection, sorted dependency union, exact tool
|
||
argv, variant/generated-main construction, persistence, linking, and
|
||
publication. Their storage, diagnostics, call positions, and allocation
|
||
failures are isomorphic.
|
||
- `cmd/w6c`/`cmd/wcc` and `selfhost/cmd/w6c`/`selfhost/cmd/wcc` own export
|
||
owner/name reading and writing, ordinary/aliased parse facts, file-local
|
||
binding installation, collision and unused-import diagnostics, name/type
|
||
lookup, canonical symbol ownership, and generated-dispatcher private
|
||
qualification. Cstage and WWstage emit byte-identical applicable interfaces,
|
||
assembly, archives, and binaries.
|
||
- `cmd/wwtest` remains only the test-command dispatcher.
|
||
|
||
The behavior follows pinned official Go 1.26.5 source at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `go/build.Package` stores `Dir`, `Name`, `ImportPath`, production files, and
|
||
test files independently, while package-clause consistency is checked during
|
||
file classification
|
||
([`go/build/build.go`, lines 436–493](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L436-L493),
|
||
[`go/build/build.go`, lines 939–1049](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L939-L1049)).
|
||
- The loader interns by resolved `ImportPath`, keeps `ImportPath` and `Name`
|
||
separate, constructs edges from source imports, and rejects an imported
|
||
package whose `Name == "main"` except for the exact same-directory test case
|
||
([`cmd/go/internal/load/pkg.go`, lines 633–636](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L633-L636),
|
||
[lines 757–806](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L757-L806),
|
||
[lines 2024–2047](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L2024-L2047)).
|
||
- The test loader builds distinct production/internal/external/generated-main
|
||
packages, derives external `Name` from `p.Name + "_test"`, handles the
|
||
same-directory command self-import, and rewrites it to the library-form test
|
||
copy
|
||
([`cmd/go/internal/load/test.go`, lines 144–203](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L144-L203),
|
||
[lines 228–293](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L228-L293),
|
||
[lines 421–472](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L421-L472)).
|
||
- `go/types.Package` stores independent path and name. The resolver creates one
|
||
child scope per source file, uses the imported package's declared name when
|
||
no alias is present, inserts imports into that file scope, reconciles them
|
||
with package declarations, and reports unused imports
|
||
([`go/types/package.go`, lines 26–40](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/package.go#L26-L40),
|
||
[`go/types/resolver.go`, lines 237–350](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L237-L350),
|
||
[lines 463–480](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L463-L480),
|
||
[lines 701–735](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L701-L735)).
|
||
The production compiler mirrors those rules
|
||
([`cmd/compile/internal/types2/resolver.go`, lines 223–335](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L223-L335),
|
||
[lines 473–486](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L473-L486),
|
||
[lines 706–740](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L706-L740)).
|
||
- Compiler export import reconstructs and interns package descriptors by
|
||
canonical path while restoring their independently encoded package names and
|
||
imports
|
||
([`cmd/compile/internal/importer/ureader.go`, lines 152–196](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/importer/ureader.go#L152-L196),
|
||
[`go/internal/gcimporter/ureader.go`, lines 224–244](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/internal/gcimporter/ureader.go#L224-L244)).
|
||
- Work actions consume cached canonical package objects and direct imports,
|
||
while test execution builds and links the isolated test action graph
|
||
([`cmd/go/internal/work/action.go`, lines 437–455](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L437-L455),
|
||
[lines 628–659](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L628-L659),
|
||
[`cmd/go/internal/test/test.go`, lines 1133–1226](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1133-L1226)).
|
||
|
||
Section 11.19 completes ordinary explicit aliases while retaining dotted,
|
||
unquoted paths. Section 11.20 adds blank side-effect imports without adding a
|
||
name. Grouped, quoted, and dot imports remain deliberately unimplemented.
|
||
|
||
The focused native observer
|
||
`declared_name_identity_and_file_import_scope` generates every tree
|
||
temporarily and exercises both stages from independent cold roots. It proves
|
||
the identity/name/qualifier split, file-local collision and unused behavior,
|
||
one-edge/action reuse, command and imported-command rules, all test variants,
|
||
vendor expansion, recursive/direct selection, owner-only units, exact direct
|
||
exports and archive-only links, warm no-op behavior, declared-name invalidation,
|
||
rejection-state preservation, normalized argv, artifact/binary identity,
|
||
allocation-bearing runtime behavior, and request/product-order independence.
|
||
|
||
### 11.19 Implemented ordinary and explicitly aliased file-scoped imports
|
||
|
||
WW now implements the two ordinary binding modes for its local dotted import
|
||
model:
|
||
|
||
```ww
|
||
import acme.codec; // effective qualifier is the declared package name
|
||
import stable acme.codec; // effective qualifier is exactly stable
|
||
```
|
||
|
||
If canonical package `acme.codec` declares `package wire`, the first form
|
||
exposes only `wire.Name`; the second exposes only `stable.Name`. Neither form
|
||
also exposes `codec.Name`, the unused alternative qualifier, or bare `Name`.
|
||
WW has no dot-import form, so an ordinary import never inserts the dependency's
|
||
exported declarations into unqualified lookup. Builtins, lexical declarations,
|
||
and same-package declarations retain ordinary bare lookup.
|
||
|
||
This is the dotted-path counterpart of Go's independent local name and quoted
|
||
path, without adopting quoted paths. The syntax AST stores the optional source
|
||
alias independently from the original dotted spelling, canonical expanded
|
||
identity, imported declared name, effective qualifier, owning source section,
|
||
and source position. `Sym.use_alias` remains the older checker coexistence bit
|
||
for a declaration that shares a leaf with a package qualifier; it is not the
|
||
source-language alias fact.
|
||
|
||
#### Pinned Go evidence
|
||
|
||
The reference is official Go 1.26.5 source at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `go/ast.ImportSpec` stores `Name` and `Path` independently, and `Pos` selects
|
||
the alias position when one exists
|
||
([`go/ast/ast.go`, lines 908–915 and 939–955](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/ast/ast.go#L908-L955)).
|
||
`parseImportSpec` parses the optional local name separately from the path
|
||
([`go/parser/parser.go`, lines 2509–2546](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/parser/parser.go#L2509-L2546)).
|
||
- `go/types` creates one child scope per source file, chooses an explicit alias
|
||
when present and the imported package's declared name otherwise, inserts one
|
||
ordinary package-name object, and inserts bare exports only for an explicit
|
||
dot import
|
||
([`go/types/resolver.go`, lines 237–350](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L237-L350)).
|
||
Package/file collisions and unused occurrences are handled at
|
||
[`resolver.go`, lines 463–480](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L463-L480)
|
||
and
|
||
[`resolver.go`, lines 701–735](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L701-L735).
|
||
The production compiler mirrors those rules at
|
||
[`cmd/compile/internal/types2/resolver.go`, lines 223–335](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L223-L335),
|
||
[lines 472–489](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L472-L489),
|
||
and
|
||
[lines 706–740](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L706-L740).
|
||
- Qualified selection marks the exact file-local package-name object used;
|
||
bare imported declarations are associated only with the dot-import table
|
||
([`go/types/call.go`, lines 682–693](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/call.go#L682-L693),
|
||
[`go/types/typexpr.go`, lines 20–31 and 79–86](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/typexpr.go#L20-L86)).
|
||
Compiler diagnostics are stably sorted by source position before printing
|
||
([`cmd/compile/internal/base/print.go`, lines 70–92](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/base/print.go#L70-L92)).
|
||
- Official testdata permits one path under distinct names, including default
|
||
plus aliases, while keeping every occurrence independently subject to unused
|
||
checking
|
||
([`internal/types/testdata/check/importdecl0/importdecl0a.go`, lines 29–52](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/importdecl0/importdecl0a.go#L29-L52),
|
||
[`test/import.go`, lines 7–23](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/import.go#L7-L23),
|
||
[`test/import1.go`, lines 7–18](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/import1.go#L7-L18)).
|
||
- Canonical package path and declared name are independent in
|
||
[`go/types/package.go`, lines 26–40](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/package.go#L26-L40).
|
||
Unified export writes and restores canonical path and name independently
|
||
([`cmd/compile/internal/noder/writer.go`, lines 430–465](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/writer.go#L430-L465),
|
||
[`cmd/compile/internal/importer/ureader.go`, lines 157–196](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/importer/ureader.go#L157-L196),
|
||
[`cmd/compile/internal/noder/reader.go`, lines 342–376](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/reader.go#L342-L376)).
|
||
- `go/build` keeps production, internal-test, and external-test files/imports
|
||
separate and constructs their source import sets
|
||
([`go/build/build.go`, lines 436–505](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L436-L505),
|
||
[lines 939–1040](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L939-L1040),
|
||
[lines 1061–1063](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1061-L1063)).
|
||
`cmd/go` interns by canonical import path, performs internal/vendor checks at
|
||
every real site, rejects imported `main`, and builds distinct test variants
|
||
([`cmd/go/internal/load/pkg.go`, lines 633–636](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L633-L636),
|
||
[lines 757–806](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L757-L806),
|
||
[lines 2024–2047](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L2024-L2047),
|
||
[`cmd/go/internal/load/test.go`, lines 175–293](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L175-L293),
|
||
[lines 421–484](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L421-L484)).
|
||
- Build actions are keyed by operation and canonical package object, consume
|
||
canonical direct dependencies, and link the reachable canonical closure
|
||
([`cmd/go/internal/work/action.go`, lines 202–206](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L202-L206),
|
||
[lines 437–447](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L437-L447),
|
||
[lines 628–708](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L628-L708),
|
||
[lines 919–968](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L919-L968),
|
||
[lines 1034–1068](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L1034-L1068)).
|
||
Root construction and test execution retain those canonical production and
|
||
generated-test objects
|
||
([`cmd/go/internal/work/build.go`, lines 495–558](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L495-L558),
|
||
[`cmd/go/internal/test/test.go`, lines 1133–1226 and 1297–1366](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1133-L1366)).
|
||
|
||
Go's dot-import branch is negative evidence only: it demonstrates that bare
|
||
foreign declarations require a distinct explicit mode. WW does not implement
|
||
that mode.
|
||
|
||
#### Scope, duplicate, collision, and usage rules
|
||
|
||
Every import occurrence owns its spelling, optional alias, position, source
|
||
section, and used bit. The effective qualifier is installed only in that
|
||
section. A qualified type, value, function, def, const, or variable lookup maps
|
||
the effective qualifier to canonical identity and marks that exact occurrence
|
||
used. A failed bare lookup marks nothing. A sibling file cannot use or satisfy
|
||
the occurrence, while two files may independently reuse one alias for different
|
||
canonical packages.
|
||
|
||
In one source file, equal effective qualifiers are duplicate bindings. The
|
||
later occurrence remains independently unused; at one source position the
|
||
duplicate diagnostic precedes its unused diagnostic. A later bare undefined
|
||
name is printed after the earlier unused-import diagnostic. Equal canonical
|
||
paths are otherwise not a conflict: distinct aliases, or default plus explicit
|
||
alias, are accepted when their effective names differ and each occurrence is
|
||
used. A package-scope declaration colliding with a file import is rejected in
|
||
the existing deterministic reconciliation pass. The unused wording follows
|
||
Go's leaf comparison: a binding equal to the path leaf says `imported and not
|
||
used`; any other binding, including an unusual default declared name, says
|
||
`imported as <name> and not used`.
|
||
|
||
`_` selects the no-binding side-effect mode completed in section 11.20. It is
|
||
never an ordinary effective qualifier and therefore neither collides with
|
||
another `_` occurrence nor receives an unused diagnostic. Grouped imports,
|
||
quoted paths, and dot imports remain deliberately deferred.
|
||
|
||
#### Graph, export, artifact, and persistence identity
|
||
|
||
The imports-only parser and full parser share one import-spec routine and retain
|
||
ordinary alias, blank mode, and dotted path separately. Both drivers sort and
|
||
resolve occurrences by the dotted spelling, perform contextual internal and
|
||
nearest-first vendor checks at every real site, and intern the expanded
|
||
canonical action. `sepbind` and `--import-map` continue to mean source dotted
|
||
spelling to expanded vendor identity; neither contains the alias or `_`.
|
||
Repeated occurrences remain separate file facts but form one sorted canonical
|
||
edge/action.
|
||
|
||
The compiler independently reads the direct dependency's declared name. It
|
||
installs the explicit alias when present or that declared name otherwise, while
|
||
keeping the canonical owner on declarations, symbols, and code generation. A
|
||
source alias cannot bypass imported-`main` rejection. Production, internal-test,
|
||
external-test, support, and generated-main identities remain isolated, and an
|
||
import found only in a test file reaches only its corresponding test variant.
|
||
The coordinator remains responsible only for package/test classification and
|
||
submitting those roots; it does not parse or rewrite imports.
|
||
|
||
`.wwi` data never exports a local alias as package identity. Qualified exported
|
||
type and constant references are normalized to a deterministic compiler-private
|
||
qualifier `__wwi_` followed by the lowercase hexadecimal bytes of the canonical
|
||
path. Matching import records still name the canonical path, and transitive fact
|
||
sections carry the same canonical private spelling. The reader restores the
|
||
real declared name from the direct owner's metadata while treating those
|
||
private names as semantic placeholders. Thus two source aliases for the same
|
||
canonical type produce the same interface bytes, even if two dependencies have
|
||
the same declared name.
|
||
|
||
The source/import and interface protocol change advances persistent build
|
||
workdirs to format 15 and test workdirs to format 14. Older unit vouchers are
|
||
invalidated before reuse, so an interface written with historical implicit-dot
|
||
or declared-name spelling cannot preserve a stale qualifier under the new
|
||
checker.
|
||
|
||
Compiler argv remains exactly one sorted `--import <canonical-path> <direct.wwi>`
|
||
pair per direct dependency plus the exact required vendor import maps. No
|
||
transitive `.wwi` is passed. Symbols, objects, archives, vouchers, stamps,
|
||
persistent directories, and product basenames remain canonical-action owned.
|
||
Linker argv remains root plus reachable archives and native/runtime inputs only;
|
||
it contains neither `.wwi` files nor alias-derived archive names.
|
||
|
||
A dependency declared-name change invalidates its semantic export and
|
||
reconsiders every direct importer. Default-bound unchanged source loses the old
|
||
qualifier and is rejected cleanly. Explicitly aliased source stays valid; after
|
||
its canonical interface regenerates unchanged, invalidation stops before
|
||
unaffected reverse dependencies. An alias-only source edit rebuilds the edited
|
||
owner but likewise cannot rename symbols or alter canonical export identity, so
|
||
unchanged semantic bytes stop reverse rebuilding.
|
||
|
||
Parser, identity, alias, declaration, binding, and scope failures occur before
|
||
publication. Compiler-owned failures may start the compiler, but staged unit,
|
||
interface, assembly, object, archive, voucher, stamp, status, and product state
|
||
is discarded under section 11.20's request transaction.
|
||
|
||
#### Stage and observer ownership
|
||
|
||
The C and WW parsers retain identical alias/path/position facts. The Cstage and
|
||
WWstage drivers resolve only the dotted path; the compiler mains restore the
|
||
declared name and choose the effective binding; the checkers own duplicate,
|
||
collision, usage, and file-scope lookup; the interface writers own canonical
|
||
normalization; and code generators consume checker-stamped canonical types and
|
||
module ownership. WWstage resolves all top-level function signatures in their
|
||
declaring package before checking bodies, matching Cstage and preventing a
|
||
consumer from reinterpreting a later declaration's bare same-package types.
|
||
|
||
The native `explicit_import_alias_binding_modes` observer owns the focused
|
||
ordinary/alias/bare-negative, duplicate, repeated-path, file-scope, canonical
|
||
artifact, `.wwi`, and rejection-state matrix. The existing
|
||
`declared_name_identity_and_file_import_scope` observer owns default-versus-
|
||
stable-alias invalidation and propagation. Existing directory, command-test,
|
||
vendor, recursive, exact-argv, link-closure, persistent-workdir, and
|
||
request-transaction observers retain their broader variant and action ownership.
|
||
Every applicable proof runs Cstage and WWstage from independent cold roots and
|
||
compares diagnostics, normalized tool arguments, artifacts, binaries, and
|
||
runtime output.
|
||
|
||
### 11.20 Implemented blank side-effect imports and package initialization
|
||
|
||
WW now completes the third file-local import mode and the package
|
||
initialization path needed to give it meaning:
|
||
|
||
```ww
|
||
import acme.codec; // qualifier from the dependency declaration
|
||
import stable acme.codec; // explicit file-local qualifier stable
|
||
import _ acme.codec; // no qualifier; initialization side effect only
|
||
```
|
||
|
||
A blank occurrence retains its dotted source spelling, owning file, line,
|
||
column, source section, and resolved canonical action, but creates no source
|
||
binding and is exempt from unused-import checking. It exposes neither
|
||
`wire.Name`, `codec.Name`, nor bare `Name`. Resolution always uses
|
||
`acme.codec`, never `_`: missing-package, self-import, cycle, final-`internal`,
|
||
nearest-first vendor, vendor-spelling, and imported-`main` checks run at every
|
||
blank site exactly as they do for a named occurrence. A vendored blank import
|
||
therefore keeps a source-to-expanded-identity `--import-map`; `_` enters no
|
||
map, action key, task symbol, artifact, voucher, stamp, variant, or link input.
|
||
|
||
Repeated blank imports of one path, in one file or several files, are valid.
|
||
A blank occurrence may coexist with the default binding or any explicit alias
|
||
of the same path. Every named occurrence remains independently subject to its
|
||
ordinary duplicate-binding and usage rules. All occurrences survive in the
|
||
owner unit and per-site validation data, while their package-wide union still
|
||
forms one sorted canonical dependency edge, one package action, and one direct
|
||
compiler export input.
|
||
|
||
#### Pinned Go evidence
|
||
|
||
The reference is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `ast.ImportSpec` keeps an optional local `Name`, including `_`, independent
|
||
from `Path`, and the parser reads that optional name before the path
|
||
([`go/ast/ast.go`, lines 908–915 and 939–955](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/ast/ast.go#L908-L955),
|
||
[`go/parser/parser.go`, lines 2509–2546](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/parser/parser.go#L2509-L2546)).
|
||
Function parsing treats `init` as an ordinary syntactic function name; its
|
||
special meaning is assigned later
|
||
([`go/parser/parser.go`, lines 2784–2842](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/parser/parser.go#L2784-L2842)).
|
||
- `go/types` creates an import object for each occurrence, inserts no binding
|
||
for `_`, exempts `_` from unused checking, and keeps a valid `init` function
|
||
out of package scope while checking its body and signature
|
||
([`go/types/decl.go`, lines 16–33](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/decl.go#L16-L33),
|
||
[`go/types/resolver.go`, lines 103–124](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L103-L124),
|
||
[lines 279–350](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L279-L350),
|
||
[lines 400–433](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L400-L433),
|
||
[lines 701–716](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L701-L716)).
|
||
The production compiler equivalent is
|
||
[`cmd/compile/internal/types2/resolver.go`, lines 90–111](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L90-L111),
|
||
[lines 264–335](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L264-L335),
|
||
[lines 416–444](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L416-L444)
|
||
and
|
||
[lines 706–721](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L706-L721).
|
||
- Official import testdata accepts repeated blanks and blank plus default or
|
||
explicit named imports of the same path, while diagnosing only the unused
|
||
named occurrences
|
||
([`internal/types/testdata/check/importdecl0/importdecl0a.go`, lines 9–31 and 43–52](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/importdecl0/importdecl0a.go#L9-L52)).
|
||
Multiple valid init declarations, invalid signatures, and direct
|
||
invisibility are pinned by
|
||
[`test/init.go`, lines 12–18](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/init.go#L12-L18),
|
||
[`test/noinit.go`, lines 315–326](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/noinit.go#L315-L326),
|
||
[`internal/types/testdata/check/decls0.go`, lines 40–46](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/decls0.go#L40-L46),
|
||
and
|
||
[`decls1.go`, lines 141–146](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/decls1.go#L141-L146).
|
||
- After constants, variable initialization chooses the declaration with the
|
||
fewest unresolved variable dependencies and uses source order as its tie;
|
||
references through functions are dependencies. Cycle reporting is
|
||
deterministic, and graph removal continues so later independent cycles are
|
||
also diagnosed
|
||
([`go/types/initorder.go`, lines 19–185 and 226–335](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/initorder.go#L19-L335),
|
||
[`cmd/compile/internal/types2/initorder.go`, lines 16–182 and 223–332](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/initorder.go#L16-L332)).
|
||
Source ties and calls are exercised by
|
||
[`go/types/api_test.go`, lines 1408–1619](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/api_test.go#L1408-L1619),
|
||
with cycle ordering in
|
||
[`internal/types/testdata/check/init0.go`, lines 22–89](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/init0.go#L22-L89).
|
||
- The compiler first attempts static initialization and serializes remaining
|
||
ordered assignments into a compiler-generated init function. It then emits
|
||
one package task whose dependency tasks are separate `R_INITORDER`
|
||
relocations and whose payload is an ordered function-pointer list
|
||
([`cmd/compile/internal/staticinit/sched.go`, lines 34–145](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/staticinit/sched.go#L34-L145),
|
||
[`cmd/compile/internal/noder/writer.go`, lines 2717–2773](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/writer.go#L2717-L2773),
|
||
[`cmd/compile/internal/noder/reader.go`, lines 3288–3345](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/reader.go#L3288-L3345),
|
||
[lines 3389–3416](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/reader.go#L3389-L3416),
|
||
[`cmd/compile/internal/pkginit/init.go`, lines 20–145](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/pkginit/init.go#L20-L145)).
|
||
The requested historical `cmd/compile/internal/walk/init.go` path does not
|
||
exist at this tag; the noder, `staticinit`, and `pkginit` files above are the
|
||
active implementation.
|
||
- The linker schedules ready tasks by canonical task symbol and emits each
|
||
exactly once, and the runtime executes those tasks before user main
|
||
([`cmd/link/internal/ld/inittask.go`, lines 19–39 and 104–180](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/inittask.go#L19-L180),
|
||
[`cmd/link/internal/ld/heap.go`, lines 56–99](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/heap.go#L56-L99),
|
||
[`runtime/proc.go`, lines 203–290](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/runtime/proc.go#L203-L290),
|
||
[lines 8049–8124](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/runtime/proc.go#L8049-L8124)).
|
||
The `issue31636` packages exercise imports written out of order, while the
|
||
linker queue above—not that fixture's stale comment—pins lexical ready-task
|
||
order
|
||
([`test/fixedbugs/issue31636.dir/main.go`, lines 7–17](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/fixedbugs/issue31636.dir/main.go#L7-L17)).
|
||
- `go/build` specifies sorted directory presentation; its default path obtains
|
||
byte-sorted names and then classifies production, internal-test, and
|
||
external-test files/imports separately
|
||
([`go/build/build.go`, lines 108–111 and 193–207](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L108-L207),
|
||
[`os/dir.go`, lines 109–125](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/os/dir.go#L109-L125),
|
||
[`go/build/build.go`, lines 948–1040](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L948-L1040),
|
||
[lines 1061–1063](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1061-L1063),
|
||
[lines 1512–1518](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1512-L1518)).
|
||
The test loader constructs and rewrites canonical internal, external, and
|
||
generated-main variants before work actions. In the internal variant it
|
||
presents the already-sorted production category first and the already-sorted
|
||
internal-test category second, rather than globally sorting the merge; its
|
||
effective-test-cycle rule is pinned by
|
||
[`cmd/go/internal/load/test.go`, lines 85–101, 175–293, and 421–550](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L85-L550)
|
||
and
|
||
[`cmd/go/testdata/script/list_test_cycle.txt`, lines 1–20](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/list_test_cycle.txt#L1-L20).
|
||
Compile/link action ownership remains canonical in
|
||
[`cmd/go/internal/work/action.go`, lines 437–455, 628–708, and 919–1068](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L437-L1068),
|
||
while `go test` rejects a bad test graph before creating those actions
|
||
([`cmd/go/internal/test/test.go`, lines 1185–1226](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1185-L1226)).
|
||
- Unified export data separates public objects from private bodies/init data;
|
||
a blank import declaration serializes no declaration, and import readers
|
||
consume the semantic package export independently of that local spelling
|
||
([`cmd/compile/internal/noder/unified.go`, lines 314–353](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/unified.go#L314-L353),
|
||
[lines 463–570](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/unified.go#L463-L570),
|
||
[`cmd/compile/internal/noder/writer.go`, lines 2742–2749](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/writer.go#L2742-L2749),
|
||
[`cmd/compile/internal/importer/ureader.go`, lines 41–62](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/importer/ureader.go#L41-L62)).
|
||
Together with the resolver's omission from package scope, that public/private
|
||
split is why another package cannot select `pkg.init`.
|
||
- Loader import checks, build-root action ownership, direct compiler import
|
||
inputs, and transitive linker inputs remain per canonical package rather
|
||
than per local import name
|
||
([`cmd/go/internal/load/pkg.go`, lines 787–805](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L787-L805),
|
||
[`cmd/go/internal/work/build.go`, lines 519–558](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L519-L558),
|
||
[`cmd/go/internal/work/exec.go`, lines 864–884](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L864-L884),
|
||
[lines 1592–1653](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L1592-L1653),
|
||
[`cmd/go/internal/work/gc.go`, lines 136–177](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/gc.go#L136-L177),
|
||
[lines 590–672](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/gc.go#L590-L672)).
|
||
|
||
#### Declaration and package-variable semantics
|
||
|
||
`fn init() void = { ... };` is a special initializer declaration. It must have
|
||
a body, no parameters, no result, no `export`, and no attribute. Multiple valid
|
||
declarations are accepted in one file and across files. No declaration of
|
||
another kind may claim `init`; a rejected non-function form is not inserted
|
||
into scope, so later references still fail lookup. A valid init retains its
|
||
file, source section, and position, but is never installed as a callable
|
||
declaration: `init()` and `pkg.init` fail lookup, it is absent from `.wwi`, and
|
||
it cannot affect canonical package identity.
|
||
|
||
Mutable package-level `let` is WW's Go-variable analogue. An initializer that
|
||
the existing static-data emitter can represent remains static. Every other
|
||
otherwise valid expression—including calls, allocation, and supported nested
|
||
array, struct, tuple, and slice values—is evaluated once by a hidden
|
||
package-owned helper and assigned to zero-backed package storage. Runtime slice
|
||
literals use canonical writable backing storage rather than escaping a helper
|
||
stack. `def` and `const` retain their existing compile-time/static rules and are
|
||
not broadened by this implementation.
|
||
|
||
The checker orders all initialized mutable lets by their checked declaration
|
||
dependencies. References through package functions are transparent edges.
|
||
Among remaining declarations, the one with the fewest unresolved dependencies
|
||
wins and original declaration order breaks ties. Files arrive byte-sorted
|
||
inside each loader category; a combined internal-test variant presents its
|
||
production category before its internal-test category, and declarations retain
|
||
source order inside each file. A cycle is
|
||
reported on the same deterministic walk as the pinned type checkers; removal
|
||
continues to expose later independent cycles, but any cycle suppresses all init
|
||
lowering and publication. Runtime variable assignments execute in that order,
|
||
then every special init function executes in owner-file/source order.
|
||
|
||
Each semantic package action owns one hidden task symbol:
|
||
|
||
```text
|
||
__ww..pkg.p.<canonical-path>.v<variant>.r<role>.init
|
||
```
|
||
|
||
The reversible empty-owner form is likewise variant/role qualified. Neither a
|
||
declared package name, default qualifier, explicit alias, blank spelling, path
|
||
leaf, physical directory, request ordinal, nor output name contributes to this
|
||
symbol. Compiler argv supplies it with
|
||
`--package-init-symbol <symbol>`. Only an executable command root or generated
|
||
test main additionally receives `--init-dispatch-symbol __ww..dispatch`, and
|
||
its compiler-generated entry calls that dispatcher before source `main` or the
|
||
generated test main body.
|
||
|
||
#### Product graph, variants, artifacts, and persistence
|
||
|
||
Before any producer, the driver forms the effective reachable graph for each
|
||
product, including internal-test replacement, and rejects a cycle introduced by
|
||
that replacement. It repeatedly chooses the byte-lexically smallest ready
|
||
canonical path, then variant and role, while blocking every importer on its
|
||
dependencies. The resulting root-owned dispatcher calls each effective package
|
||
task exactly once. Thus dependencies precede importers, a shared diamond task
|
||
runs once per product, independent ties ignore source import order and linker
|
||
argv order, and the root task completes before user main or tests.
|
||
|
||
An ordinary library object/archive contains its hidden task but building the
|
||
library does not execute it. An executable or generated-main root archive has
|
||
two deterministic members, `pkg.o/` followed by `init.o/`; the second member is
|
||
the root-owned dispatcher. Dependency archives remain ordinary `pkg.o/`
|
||
archives. Both driver stages stream member bytes through the same bounded
|
||
transfer buffer instead of retaining archive-sized allocations. Existing
|
||
linker archive fixpoint extraction pulls the dispatcher and
|
||
all referenced package tasks without a new linker format or free-floating
|
||
artifact. Logical linker argv is still the canonical root archive followed by
|
||
the reachable archive closure and runtime/native inputs; no `.wwi`, alias,
|
||
blank spelling, or dispatcher sidecar appears.
|
||
|
||
Production, production-plus-internal-test, external `_test`, test support, and
|
||
directory generated main retain separate action identities. One canonical
|
||
directory product replaces colocated production with `ptest` wherever internal
|
||
tests augment it, rewires `pxtest` self-import and affected transitive importers
|
||
to that action, and includes test-only blank edges/init declarations exactly
|
||
once. Support is an ordinary dependency task; the one generated main owns only
|
||
the final dispatcher call and cannot duplicate a tested task. Test-file-only
|
||
imports, runtime lets, and init functions never enter production. A blank
|
||
import cannot bypass imported-`main` rejection, including through vendor
|
||
expansion.
|
||
|
||
`.wwi` contains neither blank-only spelling, init declarations/bodies, hidden
|
||
variable helpers, slice backing symbols, package tasks, nor dispatcher facts.
|
||
It continues to encode only semantic exported declarations and their canonical
|
||
reachable type/constant facts. Consequently an init-body-only edit rebuilds the
|
||
owning object/archive and relinks affected products, while unchanged `.wwi`
|
||
bytes prevent importer recompilation. Adding or removing a blank edge rebuilds
|
||
the owning source action and changes exactly the affected reachable dispatcher;
|
||
a dispatcher-only change rebuilds the root `init.o/` member/archive without
|
||
recompiling an unchanged root source object. Reverse propagation stops at the
|
||
first regenerated byte-identical semantic export.
|
||
|
||
The owner source voucher remains `<action>.unit.ww`; a linked product root also
|
||
owns `<root>.init.unit.ww` for its dispatcher unit, `.init.s`, `.init.o`, and
|
||
two-member archive. Current persistent formats are build 18 and test 19. Warm
|
||
consumers select a dependency's staged `.wwi.new` or `.a.new` when that exact
|
||
action changed in the same request. All action artifacts, init artifacts, tool
|
||
identity copies, stamp, library/executable publications, and test statuses are
|
||
then one rollback-capable request transaction. No destination changes unless
|
||
every product stages successfully; a compiler, checker, init-order,
|
||
dispatcher, assembler, archiver, linker, allocation, status, or installation
|
||
failure removes remaining stages and restores the complete prior generation.
|
||
Before scratch acquisition or producer execution, `lstat`-style no-follow
|
||
checks reserve every action, tool, product, interface, status, and rollback
|
||
name; a dangling staging or backup symlink is an occupied structural conflict
|
||
and is never followed or removed. A committed dispatcher voucher must itself
|
||
be a regular file before it can authorize reuse. Compiler assembly and
|
||
interface bytes are first generated through anonymous files with checked full
|
||
writes and then published as their own rollback group. A non-regular compiler
|
||
destination is rejected before preservation, except that an already existing
|
||
character-device sink such as `/dev/null` receives a checked passthrough and is
|
||
never renamed or treated as a persistent artifact. Installation—not cleanup
|
||
of a recoverable old backup—is the commit point. Cold rejection removes the
|
||
exact request-owned scratch tree. Stale init code, stale closure metadata, and
|
||
mixed committed generations therefore cannot be reused.
|
||
|
||
#### Stage and observer ownership
|
||
|
||
The shared syntax AST, C parser, and WW parser own blank/init facts and source
|
||
positions. Both imports-only driver scans resolve the dotted path and retain
|
||
per-site legality; neither treats `_` as an alias. The C and WW checkers own
|
||
special-init validation, invisibility, mutable-let dependency ordering, cycle
|
||
diagnostics, and runtime lowering. The interface writers omit initialization
|
||
implementation; the code generators emit static storage, runtime helpers,
|
||
package tasks, canonical slice backings, and the entry dispatcher call. The two
|
||
drivers own task identity, effective test graphs, global dispatcher ordering,
|
||
exact direct compiler inputs, archive membership, link closure, persistence,
|
||
and the request transaction. The assemblers consume the dynamically sized
|
||
canonical symbols. Both linkers are unchanged and use their existing iterative
|
||
archive extraction. `internal/wwpackage` and `cmd/wwtest` retain package/test
|
||
classification and execution coordination; they do not parse imports, invent
|
||
tasks, or call init manually.
|
||
|
||
The focused native `test/sep/sepinit_test.ww` observer generates every source
|
||
tree temporarily and proves runtime let/init order, dependency chains,
|
||
diamonds, independent lexical ties, aggregate and allocation initialization,
|
||
multiple-cycle diagnostics, special-init rejection, test-variant isolation,
|
||
canonical task/dispatcher/archive bytes, init-only invalidation, and warm
|
||
invalid-init rollback across independent Cstage and WWstage roots. Direct and
|
||
recursive test legs compare the one directory dispatcher/archive and observable
|
||
dependency, `ptest`, `pxtest`, then `pmain` order; every production and
|
||
dependency task runs exactly once. Exact task counts include support and the
|
||
single generated main. Rejection rows compare complete normalized diagnostics and prove cold
|
||
scratch absence. The observer also uses a repository-built `setrlimit` launcher
|
||
to find one shared bounded-memory ceiling at which both drivers fail before a
|
||
producer, and proves no-follow atomic rejection of dangling driver staging and
|
||
compiler rollback names, non-regular compiler destinations, and compiler
|
||
output-write failures. The extended
|
||
`explicit_import_alias_binding_modes` observer owns repeated blank/default/
|
||
alias/file-scope combinations and no-binding/unused behavior. Existing
|
||
internal, vendor, imported-command, recursive, exact-argv, link-closure,
|
||
persistent-workdir, rejection-state, byte-identity, and bootstrap observers own
|
||
their unchanged broader boundaries. Grouped imports, quoted imports, and dot
|
||
imports remain deliberately unimplemented.
|
||
|
||
### 11.21 Implemented Go platform filename eligibility
|
||
|
||
Directory packages now apply Go 1.26.5's OS/architecture filename rule before
|
||
a source can enter WW's production or test graph. This closes a loader-wide
|
||
divergence rather than adding a syntax feature: WW remains a local,
|
||
manifest-free toolchain with unquoted dotted imports and one supported target,
|
||
`linux/amd64`.
|
||
|
||
#### Pinned Go evidence and pre-fix divergence
|
||
|
||
The reference is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `Context.matchFile` first rejects leading-dot/underscore names and unrelated
|
||
extensions, calls `goodOSArchFile`, and only then joins and opens the source
|
||
([`go/build/build.go`, lines 1438–1509](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1438-L1509)).
|
||
- `goodOSArchFile` cuts at the first dot, requires an underscore-prefixed
|
||
suffix, removes a final `test` token, gives a known OS/architecture pair
|
||
precedence over a final known single token, and treats every other suffix as
|
||
ordinary
|
||
([`go/build/build.go`, lines 1980–2027](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1980-L2027)).
|
||
Its match operation is against the selected `GOOS`/`GOARCH`, with only the
|
||
documented Android/Linux, illumos/Solaris, and iOS/Darwin aliases
|
||
([`go/build/build.go`, lines 1933–1977](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1933-L1977)).
|
||
- The exact past, present, and future filename-recognition sets are
|
||
`syslist.KnownOS` and `syslist.KnownArch`; they are intentionally broader than
|
||
currently supported targets and explicitly must not lose old names
|
||
([`internal/syslist/syslist.go`, lines 14–36 and 56–83](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/syslist/syslist.go#L14-L83)).
|
||
- `go/build` requires sorted directory presentation, its ordinary reader uses
|
||
byte-sorted names, and package classification consumes that order
|
||
([`go/build/build.go`, lines 108–111 and 193–207](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L108-L207),
|
||
[lines 859–914](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L859-L914),
|
||
[`os/dir.go`, lines 109–125](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/os/dir.go#L109-L125)).
|
||
- The official `TestMatchFile` table accepts `android.go`, `plan9.go`, and
|
||
`plan9_test.go` as whole-name ordinary files, accepts matching architecture
|
||
and Android/Linux aliases, and rejects a mismatching `foo_darwin.go`
|
||
([`go/build/build_test.go`, lines 381–425](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build_test.go#L381-L425)).
|
||
Command testdata independently proves that a selected Linux suffix contributes
|
||
its file and import on `linux/amd64` and both disappear on Darwin
|
||
([`cmd/go/testdata/script/list_constraints.txt`, lines 1–29 and 57–60](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/list_constraints.txt#L1-L60)).
|
||
An explicit package whose files are all excluded is rejected
|
||
([`build_no_go.txt`, lines 1–17 and 31–41](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/build_no_go.txt#L1-L41)).
|
||
|
||
Before this slice, both drivers accepted every visible `.ww` entry apart from
|
||
the production/test partition, and `internal/wwpackage` discovered every such
|
||
entry recursively. They opened and parsed candidates in raw filesystem order.
|
||
On Linux/amd64, a malformed `bad_windows.ww` therefore rejected the request;
|
||
an otherwise valid `platform_windows_arm64.ww` could add imports, actions,
|
||
direct `.wwi` inputs, archives, linker inputs, initialization, and runtime
|
||
behavior; wrong-target internal and external tests ran; a directory containing
|
||
only `only_windows.ww` was selected recursively; and editing an ineligible file
|
||
recompiled its owner. Cstage and WWstage agreed with each other but were both
|
||
wrong.
|
||
|
||
#### Final source and graph ownership
|
||
|
||
The basename predicate is exact and allocation-free. It examines the stem
|
||
before the first dot, removes final `_test` for suffix analysis, then recognizes
|
||
only the pinned Go `KnownOS`/`KnownArch` sets. A recognized pair must be
|
||
`linux_amd64`; a recognized final single must be `linux` or `amd64`. Unknown or
|
||
misplaced tokens remain ordinary. There is no alias-, declared-name-, path-leaf-,
|
||
physical-directory-, artifact-, or request-order input to this decision.
|
||
|
||
Both drivers first collect every visible `.ww` basename in checked dynamically
|
||
grown storage, byte-sort the names, then apply target and production/test
|
||
eligibility before source stat/open/parse and package validation. This removes
|
||
the former filesystem-order diagnostic race and adds no fixed file bound. The
|
||
shared coordinator already sorts directory entries; its source predicate now
|
||
removes a mismatching basename before it is appended to discovery or grouped
|
||
into a package/test product. A recursive pattern skips a directory with no
|
||
eligible sources. An explicit directory with no eligible production source
|
||
retains WW's stable `directory contains no WW package sources` rejection.
|
||
|
||
Eligibility owns whether a source occurrence exists. For a selected file, the
|
||
parser and checker retain its exact file-local imports, aliases, blank
|
||
occurrences, positions, and declarations, and the package graph deduplicates
|
||
their resolved canonical targets exactly as before. For an excluded file there
|
||
is no occurrence to resolve: missing, self, cycle, final-`internal`, vendor, and
|
||
imported-`main` validation do not run, and the file contributes no canonical
|
||
dependency or action. This is source/file ownership before package-graph
|
||
ownership, never another identity dimension.
|
||
|
||
#### Build, test, artifacts, and execution
|
||
|
||
Production sees all matching non-test sources. The internal-test variant sees
|
||
that production category followed by matching same-package `*_test.ww` files;
|
||
the external variant sees only matching external `*_test.ww` files. The suffix
|
||
rule therefore removes wrong-target test-only imports and initialization before
|
||
variant construction, support generation, or generated-main generation.
|
||
`plan9_test.ww` remains ordinary because the suffix has no nonempty prefix;
|
||
`x_plan9_test.ww` is excluded; first-dot and pair-precedence cases behave like
|
||
the pinned Go table.
|
||
|
||
No checker, interface writer, assembler, archiver, or linker protocol changed.
|
||
The drivers simply stop excluded bytes before those owners. Each selected
|
||
package unit still contains its category-ordered source files and exact import
|
||
occurrences. The compiler still receives one byte-sorted direct `.wwi` input per
|
||
canonical edge; `.wwi` still contains only semantic exports; archives still
|
||
contain only their canonical package action (plus the command root dispatcher
|
||
member where applicable); and the linker still receives the root plus reachable
|
||
archive-only closure. An import found only in an excluded file therefore
|
||
creates no `.wwi`, object, archive, init task, dispatcher edge, linker argument,
|
||
binary effect, or test execution.
|
||
|
||
#### Persistence, rejection, and stage responsibility
|
||
|
||
Persistent formats are build 18 and test 19 so a pre-slice workdir performs one
|
||
complete reachable-action refresh under the new membership contract. Thereafter
|
||
an excluded-file add, removal, or content edit changes no unit voucher, `.wwi`,
|
||
assembly, object, archive, dispatcher, test status, or reverse action. Existing
|
||
product policy may still relink an explicitly requested executable from its
|
||
unchanged archives. A selected private implementation edit rebuilds its owner;
|
||
if its `.wwi` is byte-identical, reverse compilation stops and only affected
|
||
products relink.
|
||
|
||
Wrong-target malformed sources and wrong-target structural import sites are
|
||
ignored without producers. Selected structural failures are reported in
|
||
byte-sorted filename order before producers. Any later selected-source compiler
|
||
failure remains inside the existing request transaction: staged dependency
|
||
changes are discarded, all prior actions/tool records/stamps/publications stay
|
||
byte-identical, no `.new` generation survives, and no mixed package or test
|
||
result is published.
|
||
|
||
`cmd/ww/main.c` and `selfhost/cmd/ww/main.ww` mechanically mirror direct
|
||
enumeration, sorting, target filtering, and checked allocation. The shared
|
||
`internal/wwpackage/package.ww` predicate owns recursive build/test discovery.
|
||
The compiler/checker/writer consume only selected units and require no special
|
||
case; `w6a` and `w6l` remain unchanged. The focused native
|
||
`platform_filename_source_selection` observer generates independent cold and
|
||
persistent Cstage/WWstage work roots and proves exact suffix edge cases,
|
||
sorted diagnostics, direct and recursive build/test selection, production/test
|
||
isolation, repeated-edge canonicalization, exact compiler/assembler/linker
|
||
argv, archive-only closure, artifact/assembly/binary equality, reversed-root
|
||
independence, runtime results, ignored-edit reuse, `.wwi`-stable reverse
|
||
propagation, and late-failure rollback. Existing dynamic-allocation,
|
||
no-follow, byte-identity, bootstrap, internal, vendor, and imported-command
|
||
observers retain their broader ownership.
|
||
|
||
Source-level `//go:build`/`+build` equivalents, arbitrary tags, cross-target
|
||
selection, grouped/quoted/dot imports, modules, manifests, registries, and a
|
||
programmable build language remain deliberately unsupported. Go's `UseAllFiles`
|
||
escape is also not exposed. Section 11.22 closes the formerly separate
|
||
directory test-product topology divergence without changing these filename
|
||
eligibility boundaries.
|
||
|
||
### 11.22 Implemented one canonical directory package-test product
|
||
|
||
`ww test` now owns one practical test product per canonical selected directory,
|
||
not one product per declared test package. Production, augmented internal test,
|
||
external test, support, recompiled dependency, and generated-main actions stay
|
||
separate compilation units; only their execution/publication ownership is
|
||
unified. This is the applicable Go 1.26.5 topology for WW's local, dotted,
|
||
manifest-free package model.
|
||
|
||
#### Pinned Go evidence and pre-fix divergence
|
||
|
||
The reference is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `TestPackagesFor` defines one `pmain` test binary running `ptest` and optional
|
||
`pxtest`, with `ptest` equal to production plus same-package test files
|
||
([`cmd/go/internal/load/test.go`, lines 85–101 and 175–226](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L85-L101)).
|
||
- External self-import is recognized before the external package is formed and
|
||
is rebound to `ptest`, not ordinary `p`
|
||
([lines 144–161 and 228–266](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L144-L161)).
|
||
- One `pmain` receives both applicable targets, one sorted import set, and then
|
||
`recompileForTest` copy-on-write rewires every affected transitive importer
|
||
from ordinary production to the augmented package
|
||
([lines 272–293, 342–376, and 421–490](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L272-L293)).
|
||
- The generated source scans both target classes into one function set and one
|
||
`testing.MainStart`/`Run`
|
||
([lines 595–638 and 790–860](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L595-L638)).
|
||
- A directory with no selected test files takes the early ordinary-production
|
||
compile path and creates no test support, generated main, link, executable,
|
||
or subprocess; its print action reports `[no test files]`
|
||
([`cmd/go/internal/test/test.go`, lines 1133–1170 and 1524–1557](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1133-L1170)).
|
||
- A real test package creates one generated source, one link action, and one
|
||
output-copy/install or run action, including `-c`/`-o`
|
||
([lines 1200–1364](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1200-L1364)).
|
||
- Go's action cache distinguishes cloned package objects even when their import
|
||
paths match, compiler inputs come from the selected action's direct
|
||
dependencies, and the link closure selects one archive per import path
|
||
([`cmd/go/internal/work/action.go`, lines 202–206, 437–447, and 628–658](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L202-L206),
|
||
[`exec.go`, lines 410–438 and 864–884](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L410-L438)).
|
||
- `go/build` classifies same-package and `_test` external files independently
|
||
and accepts directories containing only either class
|
||
([`go/build/build.go`, lines 948–953, 1005–1036, and 1076–1082](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L948-L953)).
|
||
|
||
Official command testdata closes the observable cases. `test_empty.txt` lines
|
||
3–24 and 30–53 accepts production-only, internal-only, external-only, combined,
|
||
test-only internal, test-only external, and mixed test-only directories
|
||
([source](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_empty.txt#L3-L24)).
|
||
`vendor_test_issue11864.txt` lines 8–9 and 64–80 proves an external test can use
|
||
an export declared only in an internal test source
|
||
([source](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/vendor_test_issue11864.txt#L64-L80)).
|
||
`list_test_imports.txt` lines 3–21 proves transitive rebuilding when a helper
|
||
imports the package under test
|
||
([source](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/list_test_imports.txt#L3-L21)).
|
||
`toolexec.txt` lines 27–50 observes distinct `ptest`, `pxtest`, and `pmain`
|
||
compiles but one main and linker call
|
||
([source](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/toolexec.txt#L27-L50)).
|
||
`test_no_tests.txt` lines 1–14 uses a panicking production initializer to prove
|
||
that no-test reporting does not execute a test process
|
||
([source](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_no_tests.txt#L1-L14)).
|
||
|
||
Before this slice WW constructed one generated main, link, binary, result, and
|
||
report for each declared same/external test package. A combined directory ran
|
||
two processes, initialized production state twice, hid internal-test exports
|
||
from the external package, and made `-c -o` fail as a multi-product request.
|
||
Even a directory with no selected tests manufactured support, a main, a link,
|
||
and a temporary executable merely to print `[no tests]`. Test-only external
|
||
directories were mislabeled, a valid mixed test-only directory was rejected,
|
||
and a transitive importer was compiled against ordinary production.
|
||
|
||
#### Final product and action topology
|
||
|
||
For canonical directory product `P`, the action graph is:
|
||
|
||
- `p`: ordinary production sources only;
|
||
- `ptest`: production plus same-package selected `*_test.ww` sources;
|
||
- `pxtest`: external-package selected `*_test.ww` sources only;
|
||
- product-scoped recompiled actions: unchanged source units whose direct target
|
||
set was rewritten by the `p -> ptest` substitution;
|
||
- support: one command-global production support action (or the reserved
|
||
`__wwtest` compiler binding when user `test` occupies that spelling);
|
||
- `pmain`: one directory-owned generated-main action importing every applicable
|
||
target and support.
|
||
|
||
The source shapes produce these reachable roots:
|
||
|
||
| Directory shape | Test closure and externally visible product |
|
||
| --- | --- |
|
||
| production, no selected tests | ordinary `p`; no support/main/link/run/output/result |
|
||
| production + internal | `ptest` + `pmain`; one binary/result |
|
||
| production + external | unaugmented `p` + `pxtest` + `pmain`; one binary/result |
|
||
| production + both | `ptest` + `pxtest -> ptest` + `pmain`; one binary/result |
|
||
| test-only same package | `ptest` + `pmain`; one binary/result |
|
||
| test-only external package | `pxtest` + `pmain`; one binary/result |
|
||
| test-only same + external | `ptest` + `pxtest -> ptest` + `pmain`; one binary/result |
|
||
|
||
A selected helper-only `*_test.ww` file is still a real test source: it is
|
||
loaded and may yield an empty harness. The no-real-run branch is specifically
|
||
the absence of selected test files after platform filtering. Ordinary
|
||
`ww build` excludes test filenames before reading even their package clauses,
|
||
so malformed test-only content and test-only imports cannot affect production.
|
||
|
||
The coordinator in `internal/wwpackage/package.ww` classifies all selected
|
||
files into one directory group. Classification is production-name-relative,
|
||
so a legitimate production package literally named `foo_test` has external
|
||
name `foo_test_test`; without production, a valid `p`/`p_test` pair is retained
|
||
as same/external rather than blindly stripping every suffix. The private driver
|
||
descriptor is an ordered directory record:
|
||
|
||
```
|
||
--ww-package-test KIND FAMILY PRODUCTION INTERNAL EXTERNAL DIR OUTPUT PUBLICATION STATUS
|
||
```
|
||
|
||
Missing action selectors and absent publication are `-`. `OUTPUT` is the
|
||
request-private runnable, while optional `PUBLICATION` is its caller-visible
|
||
retained copy. One descriptor owns at most one output, publication, and status.
|
||
Canonically duplicate products and pairwise output/publication/status/staging
|
||
collisions reject before producer execution. Declared names and output stems do
|
||
not identify products or actions.
|
||
|
||
The Cstage and WWstage drivers first load and validate the ordinary production
|
||
root. They form `ptest` and `pxtest` as separate source actions, bind external
|
||
self-import to `ptest`, seed `p -> ptest`, and copy/rewrite the affected
|
||
dependency closure. Both deduplicated dependency edges and every original
|
||
file-local import binding target are rewritten through action identity. The
|
||
strict closure validator rejects any leaked ordinary/augmented duplicate; no
|
||
initialization or archive-order fallback can hide an incomplete substitution.
|
||
|
||
`pmain` stores a checked, byte-sorted unique target action set. Its generated
|
||
unit imports each target once plus support. The compiler argv repeats
|
||
`--test-target-package` in that same order, followed by the exact byte-sorted
|
||
direct `--import PATH WWI` set. Thus a combined shape has the essential form:
|
||
|
||
```
|
||
w6c --test-package ... -I PTEST.wwi -o PTEST.s PTEST.unit.ww
|
||
w6c --test-package ... --import P PTEST.wwi ... -I PXTEST.wwi ...
|
||
w6c -T --entry --test-support-module test \
|
||
--test-target-package P --test-target-package P_test \
|
||
--import P PTEST.wwi --import P_test PXTEST.wwi --import test TEST.wwi \
|
||
-I PMAIN.wwi -o PMAIN.s PMAIN.unit.ww
|
||
```
|
||
|
||
Actual arguments also contain action-owned init and dispatcher symbols. The
|
||
assembler receives one source object per compiled action and exactly one
|
||
`pmain.init.s -> pmain.init.o` dispatcher. Test target archives contain only
|
||
their deterministic `pkg.o` member; the main archive contains `pkg.o` then
|
||
`init.o`. Link argv is root plus reachable archives only:
|
||
|
||
```
|
||
w6l -o OUTPUT.new PMAIN.a [PXTEST.a] [PTEST-or-P.a] ... TEST.a libwwrt.a
|
||
```
|
||
|
||
No `.wwi`, source filename, standalone semantic object, or linker-order choice
|
||
participates. Both native linkers already resolve archive members by symbols;
|
||
they required no topology-specific change.
|
||
|
||
#### Import, export, initialization, and execution ownership
|
||
|
||
Default, explicit-alias, and blank imports remain file-local source
|
||
occurrences. The package graph still uses one canonical edge per target and
|
||
preserves every occurrence for usage and legality diagnostics. Substitution
|
||
changes only the chosen canonical action. Consequently an external source
|
||
continues to spell `import P`, but its direct compiler export input is
|
||
`ptest.wwi`; an exported helper in an internal test source is ordinary augmented
|
||
package export data and needs no special reader format. Per-owner `@test`
|
||
metadata in `.wwi` remains sufficient. The writer/reader format did not change.
|
||
|
||
`cmd/w6c/main.c`, `cmd/wcc/ww.h`, and `cmd/wcc/check.c`, with their self-hosted
|
||
twins, changed singular generated-target state into a target set. Every target
|
||
import is marked used, and every imported `@test` declaration receives its
|
||
canonical target qualifier. The coordinator controls target order; the checker
|
||
does not resolve directories. `wwdump` passes an empty target set on its
|
||
non-test path.
|
||
|
||
One dependency-first dispatcher is generated from the substituted closure.
|
||
Each reachable canonical action contributes one initialization task; `pmain`
|
||
is the sole entry package that calls the dispatcher. A combined directory
|
||
therefore initializes dependencies, augmented production, external tests,
|
||
support, and main exactly once in one process. Filtering and listing operate on
|
||
the single deterministic enumeration containing both target sets; output has
|
||
one accounting block and one directory report. `ww test -c -o OUTPUT DIR`
|
||
publishes the one directory binary even when both target classes exist.
|
||
|
||
#### Artifacts, persistence, invalidation, and rejection
|
||
|
||
Semantic action artifacts remain separate: `.unit.ww`, `.wwi`, `.s`, `.o`, and
|
||
`.a` for each production/test/recompiled/main/support action, plus main init
|
||
unit/assembly/object. The directory product alone owns the binary, status, and
|
||
result. Test persistent-work format is `19`; semantic package storage is format
|
||
`3` and includes the product-scoped `for_test` identity for recompiled actions.
|
||
There is still no cache, CAS, manifest, registry, database, or result cache.
|
||
|
||
Warm reuse compares owner-unit bytes and exact direct export bytes. An internal
|
||
helper body edit with stable `.wwi` rebuilds only `ptest` and relinks; external
|
||
and reverse compilation stop. An external body-only edit rebuilds only
|
||
`pxtest`. Adding or changing an exported internal helper changes `ptest.wwi`,
|
||
then rebuilds exactly affected recompiled importers, `pxtest`, and `pmain`.
|
||
Adding or removing a target class changes only the owning directory product and
|
||
newly reachable actions. Request/root order and equivalent directory spelling
|
||
do not change action bytes, target order, output, or reuse.
|
||
|
||
Loader-owned source classification, import legality, canonical-product,
|
||
duplicate-closure, cycle, command-kind, and publication-path errors reject
|
||
before compiler, assembler, linker, support, or main work. Production failure
|
||
is diagnosed once even though an augmented action would contain the same
|
||
sources. Later compiler, assembler, generated-main, archive, link, staging, or
|
||
commit failure remains one request-wide transaction: no sibling product runs,
|
||
no status/result/binary or mixed generation is published, prior committed
|
||
bytes remain unchanged, and every staged `.new` is discarded. Both drivers use
|
||
checked dynamic allocation and transactional clone construction; allocation
|
||
failure cannot publish a partial action or leave cleanup to traverse
|
||
uninitialized storage.
|
||
|
||
The native proof is primarily
|
||
`directory_package_graph_variants`,
|
||
`multi_directory_shared_package_plan`,
|
||
`empty_and_invalid_package_classes`,
|
||
`dynamic_package_universe_crosses_former_boundary`,
|
||
`platform_filename_source_selection`,
|
||
`vendor_directory_import_resolution`, and
|
||
`test_variant_initialization`, with late transaction ownership in
|
||
`sibling_test_variant_failures_are_isolated`. Together they compare
|
||
cold/persistent Cstage and WWstage units, exports, assembly, objects, exact
|
||
archive members, mains, binaries, diagnostics, runtime order, literal and
|
||
normalized compiler/assembler/linker argv, both root orders in each stage,
|
||
precise body/export and target-removal/re-addition invalidation, combined-graph
|
||
allocation failure, repeated late internal/external/main/link rollback, and a
|
||
complete work-directory sweep for staged residue.
|
||
|
||
At completion of this earlier topology slice, deliberately unchanged or
|
||
unsupported behavior included the raw single-file compatibility path, the
|
||
then-current `[no tests]` presentation text, Go modules and build cache, network
|
||
resolution, manifests, coverage/vet/fuzz/benchmark generation, source-level
|
||
build expressions, quoted/grouped/dot imports, and targets other than the
|
||
separately specified fixed `linux/amd64` filename selection. Section 11.35
|
||
subsequently closes only that presentation-text gap. None is used to define
|
||
canonical package or directory-product identity.
|
||
|
||
### 11.23 Implemented case-fold collision preflight
|
||
|
||
This slice pins the collision semantics to Go 1.26.5, tag commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`. The official command loader uses
|
||
an exact import cache at `src/cmd/go/internal/load/pkg.go:633-636,757-775`,
|
||
performs contextual and vendor resolution before cache lookup at
|
||
`:840-911,974-1005`, owns one command-global folded import table at `:1725`,
|
||
and rejects a second fold-equivalent import spelling at `:1950-1959`. Its
|
||
selected-name collision is over `Package.AllFiles` (`:149-194`) and is applied
|
||
at `:1991-2000`. `src/cmd/go/internal/str/str.go:32-89` defines the pinned
|
||
`ToFold` and `FoldDup` algorithms; the direct, transitive, and filename
|
||
expectations are in
|
||
`src/cmd/go/testdata/script/list_case_collision.txt:1-41`. Filename discovery
|
||
and package/test classification are ordered by
|
||
`src/go/build/build.go:859-914,1005-1036,1076-1082,1450-1469`.
|
||
|
||
Before this slice, a Linux case-sensitive filesystem let distinct directories
|
||
such as `domain.Foo` and `domain.foo`, expanded vendor identities, and selected
|
||
files such as `File.ww` and `file.ww` build as unrelated packages or sources.
|
||
Both Cstage and WWstage did so byte-identically. A symlink making the two import
|
||
spellings reach one directory happened to trip the older exact
|
||
directory/identity check, but that host-physical consequence was neither the Go
|
||
diagnostic nor the required package-graph rule.
|
||
|
||
#### Exact identity and request-only folded keys
|
||
|
||
Canonical package identity remains the exact, case-sensitive effective dotted
|
||
identity. It is still the key used by action interning, source import maps,
|
||
`.wwi` ownership, mangled symbols, storage digests, archives, diagnostics, and
|
||
link closure. Default bindings, explicit aliases, blank imports, declared
|
||
package names, path leaves, artifacts, and physical directories do not replace
|
||
it. Exact repeated occurrences therefore continue to form one canonical edge
|
||
and one package action.
|
||
|
||
The loader graph additionally owns a checked, dynamically grown, request-only
|
||
table from a simple-fold key to the first exact package representative. Every
|
||
ordinary effective identity registers after contextual local/vendor expansion
|
||
and before exact action reuse or physical-directory conflict checks. Exact
|
||
reuse succeeds. A distinct spelling with the same key rejects as
|
||
`ww: case-insensitive import collision: "A" and "a"`; WW byte-sorts the two
|
||
exact spellings so root, request, import, and discovery order cannot select a
|
||
different diagnostic. It never stores, interns, looks up, or publishes the
|
||
folded spelling as package identity.
|
||
|
||
WW dotted import components are ASCII by construction: the C lexer/parser
|
||
accept them through `cmd/wcc/lex.c:53-63` and
|
||
`cmd/wcc/parse.c:1318-1353`, and the self-hosted syntax path mirrors that in
|
||
`lib/ww/syntax/lex.ww` and `lib/ww/syntax/decl.ww`. Context-derived identities
|
||
are revalidated, and arbitrary local filesystem bytes are escaped into ASCII.
|
||
The general Unicode fold routine is nevertheless shared with filename
|
||
preflight; for package identities its observable domain reduces exactly to
|
||
ASCII case folding.
|
||
|
||
Vendor imports register the fully expanded canonical identity, not the short
|
||
source spelling. Thus `lib.Foo` and `lib.foo` reached below one vendor owner
|
||
collide as, for example, `domain.app.vendor.lib.Foo` and
|
||
`domain.app.vendor.lib.foo`. Reaching one physical directory through two such
|
||
identities changes neither ownership nor the diagnostic. The physical
|
||
directory remains a resolution fact, never a substitute identity.
|
||
|
||
Production, same-package test (`ptest`), external test (`pxtest`), and
|
||
product-scoped recompiled actions share their one exact ordinary package
|
||
representative and do not re-register as different packages. External
|
||
compiler identity may still carry `_test`; that action path is not the folded
|
||
package key. Copy-on-write clones copy exact identity and do not register.
|
||
Generated main has no ordinary import identity and does not register. Ordinary
|
||
toolchain package `test` registers like any real package; only the reserved
|
||
synthetic `__wwtest` role stays outside the ordinary representative table.
|
||
|
||
#### Selected source basenames
|
||
|
||
Directory enumeration first excludes leading-dot, leading-underscore,
|
||
wrong-platform, and variant-ineligible files, validates the selected regular
|
||
sources, and byte-sorts their names. Before delegation, the coordinator performs
|
||
its required package-clause classification and parses selected production files
|
||
to reject `@test` declarations outside `*_test.ww`. The delegated driver then
|
||
registers each selected basename in a second request-only table scoped by
|
||
canonical physical directory. Repeated views of the exact same selected
|
||
basename across `p`, `ptest`, or `pxtest` are accepted. Distinct fold-equivalent
|
||
basenames reject as
|
||
`ww: case-insensitive file name collision: "File.ww" and "file.ww"` before the
|
||
driver's graph-import scan or any producer. The preflight is not an earlier
|
||
replacement for the coordinator-owned source validation parse.
|
||
|
||
One `ww test` request shares that directory scope across production,
|
||
same-package test, external test, same-only, external-only, and mixed test-only
|
||
actions while preserving their separate compilation units. This catches a
|
||
collision crossing classifications, such as production `X_TEST.ww` and test
|
||
`x_test.ww`. An ordinary `ww build` excludes `*_test.ww` before registration.
|
||
Hidden, underscore-prefixed, and wrong-platform files never register and
|
||
therefore create no collision or invalidation.
|
||
|
||
This last ordering is WW's explicit applicability boundary rather than a claim
|
||
that every upstream `AllFiles` member is selected here. Go includes test files
|
||
and some ignored Go files in `AllFiles`, so its ordinary build can diagnose a
|
||
broader set. WW intentionally follows its existing fixed-target source
|
||
eligibility and build/test isolation: files it does not load have no graph or
|
||
persistence effect.
|
||
|
||
Filesystem basenames are arbitrary non-NUL bytes, so their fold keys reproduce
|
||
the pinned Unicode 15.0 `unicode.SimpleFold` minimum-cycle behavior without
|
||
locale or normalization. Each malformed UTF-8 byte contributes one U+FFFD to
|
||
the temporary key, as Go string ranging does; diagnostics preserve the exact
|
||
original byte and quote it as `\xNN`. Printable Unicode remains UTF-8, other
|
||
nonprinting runes use Go-style `\u` or `\U` escapes, and composed/decomposed
|
||
Unicode spellings are not normalized.
|
||
|
||
#### Tool, artifact, transaction, and persistence ownership
|
||
|
||
The coordinator owns initial eligibility and production/test classification;
|
||
the delegated driver loader owns both fold checks. The language parser still
|
||
owns the exact import occurrence and qualifier. The driver owns per-site self,
|
||
internal, vendor, and imported-main structural legality, while the compiler
|
||
checker owns file-local binding, use, and visibility. The export writer/reader
|
||
owns exact canonical `.wwi` data. Compiler, assembler, archiver, and linker
|
||
protocols did not change. Successful neighboring units, `.wwi`, assembly,
|
||
objects, archives, generated mains, binaries, and exact tool argv therefore
|
||
remain byte-identical in Cstage and WWstage.
|
||
|
||
All root and reachable dependency loading, fold registration, and final exact
|
||
identity binding finish before scratch acquisition, support or generated-main
|
||
producer work, compilation, assembly, archive construction, or linking. A
|
||
collision invokes none of those tools and creates no unit, `.wwi`, assembly,
|
||
object, archive, main, binary, result, status, voucher, stamp, or `.new` stage.
|
||
Request-wide publication remains transactional: committed sibling and
|
||
dependency bytes survive a newly introduced collision, and removing the
|
||
colliding source restores precise warm reuse.
|
||
|
||
The fold tables live only for one command and are freed at graph teardown.
|
||
Entries become live only after every owned string and vector allocation
|
||
succeeds, so allocation failure cannot publish a partial table or make cleanup
|
||
traverse uninitialized entries. Successful action/unit/storage content did not
|
||
change; build workdir format stays `18`, test workdir format stays `19`, and
|
||
semantic storage stays `3`. A format bump would only discard valid exact-key
|
||
artifacts and is therefore not used.
|
||
|
||
Native proof extends `package_graph_diagnostics_are_stable`,
|
||
`platform_filename_source_selection`, and
|
||
`vendor_directory_import_resolution`, with command-global allocation failure
|
||
retained in `allocation_failure_is_command_global`. The matrix covers direct,
|
||
transitive, reversed, recursive, same-directory, and vendor-expanded imports;
|
||
exact-repeat acceptance; reversed vendor import and product order;
|
||
production/internal/external/test-only filenames; reversed creation and
|
||
direct/recursive collision-diagnostic parity; cross-classification, Unicode,
|
||
invalid UTF-8, ignored files, and absence of normalization; zero-tool
|
||
rejection; multi-product publication isolation; cold/warm add-remove reuse;
|
||
exact artifact preservation; and Cstage/WWstage diagnostic and byte identity.
|
||
|
||
### 11.24 Implemented package-source test execution directory
|
||
|
||
Every coordinator-executed directory-package test product now runs its one
|
||
generated binary from the canonical physical source directory of the selected
|
||
package. The child also receives the corresponding effective `PWD`. This is
|
||
runtime metadata for the directory product, not canonical package or action
|
||
identity.
|
||
|
||
#### Pinned Go evidence and pre-fix WW behavior
|
||
|
||
The authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `go test` documents that each listed package is tested by a separate binary,
|
||
that `testdata` is ignored by package discovery so it can hold ancillary
|
||
files, and that a command-run binary executes in the corresponding package
|
||
source directory
|
||
([`cmd/go/internal/test/test.go`, lines 64–75 and 411–440](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L411-L440)).
|
||
The same text says that a generated test binary invoked directly may require
|
||
the user to enter that directory first; the source directory is not embedded
|
||
in the executable.
|
||
- `runTestActor.Act` creates the command, assigns
|
||
`cmd.Dir = a.Package.Dir`, clips the original environment, appends `PATH`,
|
||
calls `base.AppendPWD(env, cmd.Dir)`, assigns the environment, attaches
|
||
output, and runs the command
|
||
([`test.go`, lines 1661–1697](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1661-L1697)).
|
||
The run action retains the original package rather than deriving a directory
|
||
from `ptest`, `pxtest`, or `pmain`.
|
||
- `AppendPWD` requires an absolute directory and appends `PWD=<dir>` without
|
||
replacing inherited entries
|
||
([`cmd/go/internal/base/env.go`, lines 15–27](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/base/env.go#L15-L27)).
|
||
Go's `os/exec` applies last-value-wins duplicate elimination to an explicit
|
||
environment by scanning backward, retaining the last key, and restoring the
|
||
surviving order
|
||
([`os/exec/exec.go`, lines 1246–1308](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/os/exec/exec.go#L1246-L1308)).
|
||
On the pinned Linux boundary, all inherited exact uppercase `PWD=` entries
|
||
are therefore superseded by the appended package value. Keys remain
|
||
case-sensitive; `pwd=` and malformed non-key entries are not `PWD`.
|
||
- Loader `Package.Dir` is the source directory and remains a separate field
|
||
from `ImportPath`; the command loader copies it from `go/build.Package.Dir`
|
||
([`cmd/go/internal/load/pkg.go`, lines 63–76 and 395–402](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L63-L76)).
|
||
`go/build` likewise owns source location separately from import identity
|
||
([`go/build/build.go`, lines 436–451, 521–525, and 612–624](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L436-L451)).
|
||
- Official scripts use files, directories, and executable fixtures relative to
|
||
the tested package and mutate ordinary data between test invocations
|
||
([`test_cache_inputs.txt`, lines 57–98 and 194–305](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_cache_inputs.txt#L57-L98));
|
||
exercise recursive discovery from a symlink root without following nested
|
||
directory symlinks
|
||
([`list_symlink_dotdotdot.txt`, lines 1–20](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/list_symlink_dotdotdot.txt#L1-L20));
|
||
and keep multi-package compile-only output separate from execution
|
||
([`test_compile_multi_pkg.txt`, lines 3–38](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_compile_multi_pkg.txt#L3-L38)).
|
||
|
||
Before this slice, both WW stages ran directory products from the coordinator's
|
||
invocation directory. With deliberately duplicated inherited entries,
|
||
`getcwd` returned that caller directory while WW's first-match `os.getenv`
|
||
returned the first unrelated `PWD`. `data.txt` and `testdata/input.txt` were
|
||
therefore read from the caller, and relative writes from parallel products
|
||
collided there. Production and test-only dependency initializers inherited the
|
||
same incorrect process context. Direct, recursive, redundant, absolute, and
|
||
root-symlink spellings already converged on one product but did not use its
|
||
stored directory for execution. Cstage and WWstage had identical pre-fix
|
||
output and binaries.
|
||
|
||
#### Directory-product ownership and identity separation
|
||
|
||
The package coordinator already canonicalizes each selected source directory
|
||
to one absolute, symlink-free physical spelling, rebuilds its selected source
|
||
paths below that directory, sorts and deduplicates them, and stores the result
|
||
as `pkggroup.dir`. Relative, absolute, redundant-component, direct, recursive,
|
||
reversed-root, filesystem-order, and root-symlink requests that reach one
|
||
package therefore retain the same physical product directory. WW's deliberate
|
||
applicability boundary differs from Go only where Go preserves a loader-owned
|
||
symlink spelling: WW uses its already specified canonical physical spelling.
|
||
|
||
That directory is an execution-context field. Exact case-sensitive dotted
|
||
package identity still owns graph interning, import bindings, mangled symbols,
|
||
`.wwi` ownership, action and storage keys, archives, diagnostics, and link
|
||
closure. Declared package name, source alias, path leaf, filename, artifact
|
||
basename, output path, test action name, and physical-directory equality do
|
||
not become canonical identity. No physical path was added to a unit, export,
|
||
symbol, archive, generated main, action digest, product name, status, voucher,
|
||
stamp, or persistence key.
|
||
|
||
One `pkggroup` owns the process for production plus internal tests,
|
||
production plus external tests, the combined shape, internal-only,
|
||
external-only, and mixed test-only directories. Production `p`, augmented
|
||
`ptest`, external `pxtest`, product-scoped recompiled actions, support, and
|
||
generated main remain separate actions and derive no independent cwd. The one
|
||
directory product supplies its `dir` to the one executed binary.
|
||
|
||
#### Child cwd, environment, and concurrency
|
||
|
||
Only `pkgstartrun` sets the existing `exec.command.dir` to `pkggroup.dir`.
|
||
`lib/os/exec` opens the absolute stdout/stderr captures in the parent, copies
|
||
argv and environment, forks, and calls `chdir` only in the child immediately
|
||
before `execve`. The executable, `argv[0]`, captures, product scratch, and
|
||
coordinator publication paths are absolute, so the child directory cannot
|
||
reinterpret them. No runtime coordinator-global `chdir` was added; its cwd and
|
||
`PWD` remain unchanged.
|
||
|
||
Each started product also receives a newly allocated run environment. Section
|
||
11.36 supersedes this slice's former test-process locale and temporary-directory
|
||
policy: the vector is now a Go-like original-environment snapshot. It keeps the
|
||
first occurrence of each normal case-sensitive key, omits later normal
|
||
duplicates and raw empty entries, preserves nonempty malformed entries, excludes
|
||
inherited uppercase `PATH` and `PWD`, and then appends the selected toolchain
|
||
`PATH` and `PWD=<pkggroup.dir>`. Caller `LC_ALL` and `TMPDIR` therefore reach the
|
||
user test; build-plan tools retain their separate pinned values.
|
||
|
||
The vector, normalization table, and generated strings are product-local,
|
||
dynamically sized, and published only after every checked allocation succeeds.
|
||
Partial failure frees only initialized owned storage and never frees borrowed
|
||
inherited strings. The normalization table is gone before launch. `exec.start`
|
||
synchronously deep-copies the command before returning, after which the
|
||
coordinator frees its run vector, generated `PATH`, generated `PWD`, generated
|
||
`-package` argument, and argv vector. Concurrent children therefore hold
|
||
independent fork snapshots; no shared environment vector or process-global
|
||
state is mutated.
|
||
|
||
All dependency initialization occurs inside that product process. A production
|
||
or test-only dependency reached by package `p` sees `p`'s directory. If the
|
||
dependency is separately selected as its own test product, that second process
|
||
sees the dependency's directory. Filters, no-match filters, and list mode use
|
||
the same binary and context whenever they execute. With multiple products and
|
||
`-j N`, each child independently observes its own directory and fixture names;
|
||
emission remains byte-sorted and identical to `-j 1`.
|
||
|
||
#### Nonexecution paths, tools, and direct binaries
|
||
|
||
`ww build` starts no test process. Directory `ww test -c`, including
|
||
`-c -o`, builds or publishes but never enters `pkgstartrun`; no execution cwd
|
||
or run environment is allocated. A published binary subsequently invoked by
|
||
the user bypasses the coordinator and inherits the user's cwd and environment.
|
||
The raw single-file test compatibility route retains its caller cwd, `PWD`,
|
||
stdin, and stream behavior, but section 11.32 applies the test-process `PATH`
|
||
rule at its driver-owned launch. A directory with no selected test source still
|
||
creates no support, generated main, link, run, result, or execution-context
|
||
state.
|
||
|
||
Build-plan commands retain `dir=""` and their existing tool environment.
|
||
Compiler, assembler, in-driver archiver, linker, support generation, and
|
||
generated-main construction therefore retain their exact prior cwd, argv, and
|
||
environment. The directory cwd rule required no `lib/os/exec`, compiler,
|
||
checker, writer, assembler, linker, or driver change; the later test-only PATH
|
||
rule is isolated at launch and changes neither build-plan environment nor those
|
||
tools.
|
||
Independent Cstage/WWstage compile-only products remain byte-identical, and
|
||
changing only `data.txt` or `testdata` changes no unit, `.wwi`, assembly,
|
||
object, archive, generated-main, or binary bytes.
|
||
|
||
#### Failure, cleanup, persistence, and proof
|
||
|
||
A missing product directory after a successful build fails the child's
|
||
`chdir`. The executor reports the positive errno through its setup marker as
|
||
`termination.ERROR`, distinct from a program exit 127. The coordinator emits
|
||
`FAIL DIR [package] (test harness error ERRNO)`, treats it as execution/setup
|
||
failure rather than loader failure, retains successful compilation, continues
|
||
independently schedulable siblings, and removes its owned captures and scratch
|
||
under the existing execution-failure contract. It never changes the parent or
|
||
a sibling's cwd/environment.
|
||
|
||
Execution cwd and `PWD` are request-time process metadata. There is no test
|
||
result cache, and runtime failure does not invalidate already committed build
|
||
artifacts. A warm persistent request still performs the established final
|
||
relink, but no compiler or assembler work; changing only fixture data causes no
|
||
additional producer work or persistent-byte change and the next always-run
|
||
test immediately observes the new data. Build workdir format remains `18`,
|
||
test workdir format remains `19`, and semantic storage remains `3`.
|
||
|
||
The focused native owner is
|
||
`directory_test_execution_working_directory` in
|
||
`test/package/package_test.ww`. It creates only disposable source trees and
|
||
compares Cstage and WWstage across duplicate and large environments; exact
|
||
`getcwd`, effective/count/position of `PWD`; absent, empty, nonempty, and
|
||
duplicate inherited `PATH`; ordinary data, `testdata`, and
|
||
relative writes; all production/internal/external/test-only shapes;
|
||
production and test-only dependency initialization; recompiled external
|
||
self-import; direct/recursive/redundant/absolute/symlink roots; reversed roots
|
||
and creation order; `-j 1`/parallel execution; filters/list/no-match; failure
|
||
and timeout; no-test and build paths; `-c`, `-c -o`, running retained tests,
|
||
direct binaries, and raw single files; original test variables and exact tool
|
||
cwd/argv/locale/TMPDIR/PATH; persistent data-only reuse and
|
||
artifact/binary identity; and a deterministic post-build directory removal
|
||
where the affected product reports `ENOENT` while its sibling succeeds.
|
||
Checked command-global allocation-failure parity remains owned by
|
||
`allocation_failure_is_command_global`; the focused observer additionally
|
||
crosses the former fixed environment-size boundary and verifies that no
|
||
partial execution environment or staged `.new` state is published.
|
||
|
||
### 11.25 Implemented null standard input for captured actions
|
||
|
||
Every process launched through WW's captured asynchronous executor now receives
|
||
an explicit fd 0. An empty `exec.command.stdinpath`, which is the production
|
||
default, opens the null device read-only; a nonempty value opens that exact path.
|
||
Consequently every coordinator-executed directory test product observes
|
||
immediate EOF instead of inheriting and consuming the invoking terminal, pipe,
|
||
or file. Captured directory build plans and the compiler, assembler, and linker
|
||
processes that inherit their stdio receive the same noninteractive boundary.
|
||
|
||
#### Pinned Go evidence and pre-fix WW behavior
|
||
|
||
The authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `runTestActor.Act` constructs an `exec.Cmd`, assigns its package directory,
|
||
environment, stdout, stderr, cancellation, and wait delay, and invokes
|
||
`Run` without assigning `Stdin`
|
||
([`cmd/go/internal/test/test.go`, lines 1661–1697](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1661-L1697)).
|
||
- `Cmd.Stdin` specifies that a nil value reads from `os.DevNull`;
|
||
`childStdin` opens that device and retains the file for the child; and
|
||
`Start` installs it as the first child file before process creation
|
||
([`os/exec/exec.go`, lines 193–206, 531–538, and 710–738](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/os/exec/exec.go#L193-L206)).
|
||
- The ordinary build-command path has the same default. `Shell.runOut` creates
|
||
an `exec.Cmd`, assigns output, directory, and environment, and runs it without
|
||
assigning `Stdin`
|
||
([`cmd/go/internal/work/shell.go`, lines 600–663](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/shell.go#L600-L663)).
|
||
- Official `os/exec` tests define a `cat` helper that copies stdin to EOF and
|
||
require that helper to terminate successfully when run with no `Stdin`
|
||
assignment
|
||
([`os/exec/exec_test.go`, lines 201–204 and 416–459](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/os/exec/exec_test.go#L416-L459)).
|
||
The command testdata separately exercises deliberately supplied stdin-pipe
|
||
lifetime and closure for orphaned test descendants
|
||
([`cmd/go/testdata/script/test_timeout_stdin.txt`, lines 1–21 and 39–88](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_timeout_stdin.txt#L1-L21));
|
||
that script is adjacent stream-lifetime evidence, while the default null-fd
|
||
conclusion comes directly from the implementation chain above.
|
||
|
||
Before this slice, `lib/os/exec.start` redirected only stdout and stderr. A
|
||
directory driver invoked with a nonempty stdin file passed the same open file
|
||
description through the top-level inherited-stdio handoff, the package
|
||
coordinator, its captured builder, and the generated product. Serial products
|
||
could consume caller data; parallel products raced on the shared file offset;
|
||
a test that waited for input could wait on an interactive caller. Direct
|
||
measurement with a one-byte pipe made the same directory `@test` fail under
|
||
both Cstage and WWstage because its first read returned that byte. The raw
|
||
single-file route also read the byte and failed, but that route intentionally
|
||
remains inherited-stdio compatibility behavior.
|
||
|
||
#### Descriptor ownership, action boundaries, and concurrency
|
||
|
||
`exec.start` validates `stdinpath`, selects `/dev/null` for the empty value, and
|
||
opens the input before creating either output capture. `safefd` moves all three
|
||
standard streams above fd 2 when a caller had closed a standard descriptor.
|
||
After fork, the child maps the owned input to fd 0 before mapping the captures
|
||
to fd 1 and fd 2; setup failures travel through the existing close-on-exec
|
||
marker. The parent closes its input copy immediately after fork. Every
|
||
pre-fork error path closes every successfully acquired descriptor.
|
||
|
||
The package coordinator does not read or mutate its own fd 0. Each captured
|
||
build or run child opens an independent null descriptor, so `-j N` products
|
||
share neither readable caller data nor an input offset. Production, internal,
|
||
external, recompiled-for-test, support, and generated-main actions still form
|
||
the same graph and the one directory product still owns one process. Package
|
||
and test-only dependency initialization observes EOF inside that process.
|
||
Filters, list mode, no-match execution, failure, and timeout use the same
|
||
boundary.
|
||
|
||
Standard input is request-time process metadata only. It does not enter
|
||
canonical dotted identity, declared-name binding, actions, units, exports,
|
||
symbols, archives, generated main, executable bytes, product names, storage
|
||
keys, or diagnostics. The source path accepted by `stdinpath` is an executor
|
||
resource, not a package or filesystem-identity input.
|
||
|
||
#### Inherited-stdio routes, failure, persistence, and proof
|
||
|
||
`exec.runstdio` remains unchanged. The top-level driver therefore preserves
|
||
inherited stdin for raw single-file tests and runs, and a published test binary
|
||
invoked directly receives its invoker's fd 0. Directory `ww test -c`, including
|
||
`-c -o`, starts no product; the compiled binary acquires no embedded stdin
|
||
policy. No-selected-test packages likewise start no product. Directory build
|
||
and compile-only plans are captured actions and therefore noninteractive, but
|
||
their output, cwd, environment, graph, and publication rules are unchanged.
|
||
|
||
Failure to open an explicit input path or the default null device is a
|
||
pre-fork `termination.ERROR` with positive errno. Because input opens first,
|
||
neither output capture exists. A child-side `dup2` or close failure is reported
|
||
through the setup marker, distinguished from exit 127, and follows the existing
|
||
process-group cleanup path. Test failures, timeouts, post-build directory
|
||
removal, sibling isolation, transaction rollback, and scratch removal retain
|
||
their prior contracts.
|
||
|
||
No test-result cache exists. Caller stdin bytes never affect source actions or
|
||
persistent artifacts, and changing only the explicit proof input causes no
|
||
compile or assemble work beyond the established warm final relink. Build
|
||
workdir format remains `18`, test workdir format remains `19`, and semantic
|
||
storage remains `3` because no persisted byte schema changed.
|
||
|
||
The focused native owner remains
|
||
`directory_test_execution_working_directory` in
|
||
`test/package/package_test.ww`. It now drives every relevant command with a
|
||
known nonempty input file and requires EOF across all directory action/test
|
||
variants, production and test-only dependency initialization, serial and
|
||
parallel products, filters/list/no-match, recursive and equivalent roots,
|
||
failure, timeout, persistent cold/warm/data-only runs, and post-build child
|
||
setup failure. Tool wrappers require EOF without changing cwd, argv, locale, or
|
||
`TMPDIR`. Direct published and raw single-file binaries must instead read the
|
||
supplied data. The observer also proves input-open failure creates no captures,
|
||
source-class rejection creates no persistent state, Cstage/WWstage diagnostics
|
||
and output match, compile-only binaries are equal, persisted artifact bytes do
|
||
not change, and no `.new` residue survives.
|
||
|
||
### 11.26 Implemented combined ordered test-product output
|
||
|
||
Every coordinator-executed directory-package test product now maps its standard
|
||
output and standard error to one product-local open capture. The coordinator
|
||
emits that capture on stdout after the product completes, preserving the order
|
||
in which writes from either descriptor reach the shared output. Runtime and
|
||
child-setup status lines are stdout product diagnostics. WW no longer drains
|
||
two captures and emits all stdout before all stderr.
|
||
|
||
#### Pinned Go evidence and pre-fix WW behavior
|
||
|
||
The authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `runTestActor.Act` selects one output writer for the test action: direct
|
||
stdout, JSON conversion, stdout plus a buffer, or a private buffer
|
||
([`cmd/go/internal/test/test.go`, lines 1436–1499](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1436-L1499)).
|
||
- It assigns that same writer to both `cmd.Stdout` and `cmd.Stderr`, then runs
|
||
the test binary
|
||
([`test.go`, lines 1661–1697](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1661-L1697)).
|
||
Success and runtime-failure status text is written through `cmd.Stdout`
|
||
([`test.go`, lines 1712–1769](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1712-L1769)).
|
||
- `os/exec.Cmd` documents its shared-writer rule; `childStderr` returns the
|
||
already prepared stdout child file when the writers compare equal; and
|
||
`Start` installs the returned files as descriptors 1 and 2
|
||
([`os/exec/exec.go`, lines 208–225, 565–606, and 710–738](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/os/exec/exec.go#L565-L606)).
|
||
- Official command testdata has test mains write only to `os.Stderr`, requires
|
||
those bytes on `go test` stdout in buffered and streaming forms, and requires
|
||
command stderr to remain empty
|
||
([`cmd/go/testdata/script/test_fail_newline.txt`, lines 3–35 and 42–65](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_fail_newline.txt#L3-L65)).
|
||
The adjacent orphan-I/O test forwards a descendant's stderr through the test
|
||
process and likewise requires the bytes on command stdout
|
||
([`test_timeout_stdin.txt`, lines 9–21 and 39–82](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_timeout_stdin.txt#L9-L82)).
|
||
|
||
The output destination is explicit in the pinned implementation and official
|
||
testdata. The ordering conclusion is source-derived: equal writers reuse one
|
||
child file or pipe instead of two independently drained pipes. No installed
|
||
host Go behavior is authority.
|
||
|
||
Before this slice, `pkgstartrun` supplied distinct `test.stdout` and
|
||
`test.stderr` paths. `exec.start` opened independent files, and
|
||
`pkgemitgroup` later emitted the entire stdout file followed by the entire
|
||
stderr file on different coordinator descriptors. A direct both-stage probe
|
||
that wrote `OUT-1`, `ERR-1`, `OUT-2`, `ERR-2` by alternating syscalls therefore
|
||
reported `OUT-1`, `OUT-2` on stdout and `ERR-1`, `ERR-2` on stderr. Cstage and
|
||
WWstage had byte-identical pre-fix behavior.
|
||
|
||
#### Descriptor and product ownership
|
||
|
||
The reusable captured executor owns only the descriptor mechanism. When
|
||
`stdoutpath` and `stderrpath` are byte-equal, it opens the path once with the
|
||
existing exclusive mode and obtains a close-on-exec duplicate from the same
|
||
open file description. The child maps those owned descriptors to fd 1 and fd 2.
|
||
Distinct paths retain independent exclusive opens and their prior behavior.
|
||
Path equality here selects an executor resource; it creates no filesystem,
|
||
package, import, action, symbol, artifact, or persistence identity.
|
||
|
||
The package coordinator owns the policy. One `pkggroup` now allocates one
|
||
`runoutput`, supplies it for both child paths, reads it once, and writes it to
|
||
coordinator stdout. Production, internal, external, recompiled-for-test,
|
||
support, generated-main, and test-only actions retain their exact topology and
|
||
one directory product still owns one process. Dependency initialization and
|
||
test bodies share the product descriptors naturally; no source rewriting or
|
||
manual stream forwarding exists.
|
||
|
||
Individual writes by one process retain syscall order. Descendants inheriting
|
||
the descriptors share the same open output, with ordinary kernel scheduling for
|
||
concurrent writers. Different products never share a capture. `-j N` may run
|
||
products concurrently, but the coordinator still waits for completion and
|
||
emits complete captures in canonical group order, so serial and parallel
|
||
command byte streams remain identical.
|
||
|
||
#### Diagnostics, nonexecution, and inherited routes
|
||
|
||
Successful and failing test-binary bytes, including bytes written to fd 2, are
|
||
emitted on stdout. A nonzero product, signal-classified test, timeout, or child
|
||
setup failure appends the existing `FAIL DIR [package] (test ...)` status on
|
||
stdout. Loader, source, compiler, assembler, linker, build-action, allocation,
|
||
capture-read, and cleanup diagnostics keep their established stderr channel;
|
||
captured build-plan stdout and stderr remain separate.
|
||
|
||
`ww build`, directory `ww test -c` (including `-c -o`), and a directory with no
|
||
selected test source start no product and allocate no run capture. A published
|
||
test binary invoked directly and the raw single-file compatibility route bypass
|
||
the coordinator, inherit fd 1 and fd 2 independently, and retain the caller's
|
||
stream destinations. `exec.runstdio` is unchanged. An arbitrary
|
||
`exec.command` with distinct output paths is also unchanged.
|
||
|
||
#### Failure, persistence, cleanup, and proof
|
||
|
||
Input still opens before any output. A merged output open failure creates no
|
||
child and no second capture. Duplicate, fork, descriptor-map, `chdir`, and
|
||
`execve` failures use the existing checked setup marker and close every owned
|
||
descriptor. Product failure does not erase successfully committed compilation;
|
||
sibling products retain independent output, process groups, and cleanup. The
|
||
coordinator removes its product captures with the existing temporary root, and
|
||
rejection or rollback publishes no partial result or `.new` state.
|
||
|
||
Output routing is request-time process metadata. It changes no unit, export,
|
||
assembly, object, archive, generated main, binary, action/storage key, tool
|
||
record, stamp, or persistent byte. There is still no test-result cache. Build
|
||
workdir format remains `18`, test workdir format remains `19`, and semantic
|
||
storage remains `3`.
|
||
|
||
The executor-level native proof in `test/wwfixture/process/main.ww` requires
|
||
distinct captures to stay distinct and equal paths to preserve alternating
|
||
fd-1/fd-2 bytes through one file in both compiler stages, including when the
|
||
caller closed stdout and stderr. The package owner
|
||
`directory_test_execution_working_directory` alternates real writes through
|
||
production and test-only dependency initialization; production/internal,
|
||
external, combined, recompiled, and test-only products; filters, list, and
|
||
no-match execution; success, assertion failure, signal, timeout, and post-build
|
||
`chdir` failure; serial/parallel and equivalent-root requests; cold/warm/data-
|
||
only persistence; and direct/raw boundaries. It requires Cstage/WWstage output
|
||
and diagnostics to match, failure/setup trailers to use stdout, successful
|
||
outer stderr to be empty, direct/raw stderr to remain separate, artifacts and
|
||
binaries to remain byte-identical, and every temporary or staged path to be
|
||
cleaned.
|
||
|
||
### 11.27 Implemented Go-like directory test-binary retention
|
||
|
||
Directory-package `ww test` now separates the request-private executable that
|
||
the coordinator may run from the optional caller-visible executable it retains.
|
||
`-c` means retain without running; `-o` means retain at the requested location
|
||
and still run unless `-c` is also present. Output naming, directory fan-out,
|
||
duplicate-name preflight, exact null-device discard, executable mode, and
|
||
no-test behavior follow the applicable Go 1.26.5 contract.
|
||
|
||
#### Pinned Go evidence and direct pre-fix measurements
|
||
|
||
The authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `CmdTest.Long` directly states that `-c` writes `pkg.test` in the current
|
||
directory and does not run it, while `-o` saves a copy and still runs unless
|
||
`-c` is present; a trailing slash or existing directory receives
|
||
`pkg.test`
|
||
([`cmd/go/internal/test/test.go`, lines 150–168](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L150-L168)).
|
||
- `testNeedBinary` makes nonempty `-o` an independent retention request
|
||
([`test.go`, lines 631–646](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L631-L646)).
|
||
`runTest` recognizes an existing directory or trailing separator, rejects a
|
||
multi-package non-directory output, and preflights every selected package
|
||
for duplicate test-binary names before builder execution, except when the
|
||
output is the null device
|
||
([`test.go`, lines 771–804](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L771-L804)).
|
||
- `builderTest` takes the ordinary production-only branch when no test files
|
||
exist, creating no test link or retained binary
|
||
([`test.go`, lines 1133–1169](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1133-L1169)).
|
||
A real test first links into its action object directory; `-c` or binary
|
||
retention adds an install action, only `-c` selects the no-op print action,
|
||
and the non-`-c` run action depends on the original build action rather than
|
||
the installed copy
|
||
([`test.go`, lines 1200–1313](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1200-L1313)).
|
||
- `testBinaryName` explicitly uses the final import-path element rather than
|
||
the declared package name; its command-line-files exception uses the source
|
||
package name
|
||
([`test.go`, lines 2287–2300](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L2287-L2300),
|
||
[`cmd/go/internal/load/pkg.go`, lines 1727–1769](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1727-L1769)).
|
||
- `BuildInstallFunc` creates parents and installs a linked executable with mode
|
||
`0777` filtered by the process umask
|
||
([`cmd/go/internal/work/exec.go`, lines 1904–2000](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L1904-L2000),
|
||
[`cmd/go/internal/work/shell.go`, lines 119–220 and 283–301](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/shell.go#L119-L220)).
|
||
On the pinned Unix target, only exact `/dev/null` is the null spelling
|
||
([`cmd/go/internal/base/path.go`, lines 81–92](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/base/path.go#L81-L92)).
|
||
- Official `test_compile_multi_pkg.txt` requires missing nested output
|
||
directory creation, default current-directory output, rejection of a
|
||
non-directory multi-output and duplicate names, `/dev/null` acceptance, and
|
||
`-o DIR` retention while tests still run
|
||
([lines 3–38](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_compile_multi_pkg.txt#L3-L38)).
|
||
|
||
The separation between saved and executed paths is a conclusion derived from
|
||
the pinned action dependencies: the run consumes the temporary link action,
|
||
not the install action. Duplicate names are likewise a materialization
|
||
collision, not package identity. Section 11.31 completes the later install
|
||
dependency: compile-only products retain the request transaction, while a
|
||
running retained product installs independently only after its successful run.
|
||
No installed host Go behavior was used as authority.
|
||
|
||
Before this slice, direct native measurements of both Cstage and WWstage showed
|
||
that single-package `-c -o FILE` retained and did not run, but `-o FILE`
|
||
without `-c` exited 2 with `-o needs -c for a package target`; multi-package
|
||
`-c -o FILE` exited 2 with the older unconditional fan-out rejection. Default
|
||
multi-package `-c` scattered `<declared-package>.test` binaries into their
|
||
source directories. Those measurements used the public driver route and
|
||
observed exits, diagnostics, files, executable behavior, and stage-equal bytes;
|
||
they were not conclusions drawn from WW source.
|
||
|
||
#### Coordinator policy and identity boundaries
|
||
|
||
`internal/wwpackage.packagecommand` is the sole owner of public output policy.
|
||
It resolves the invocation directory, computes each visible
|
||
`<import-leaf>.test` name, recognizes output-directory and `/dev/null` forms,
|
||
rejects non-directory fan-out and duplicate names, omits publication for
|
||
no-test products, and schedules execution according to `-c`. A contextual
|
||
dotted request uses its exact final component; a local path request uses its
|
||
directory leaf as the manifest-free presentation equivalent. Neither becomes
|
||
declared-name or physical-directory identity.
|
||
|
||
Every actual test product still links to `package.test` below its private plan
|
||
root. The private descriptor carries that `OUTPUT` plus an optional absolute
|
||
`PUBLICATION`. The Cstage and WWstage drivers implement only this symmetric
|
||
mechanism; they do not independently decide names or CLI policy. The
|
||
coordinator always executes `OUTPUT`, so `-o` cannot alter executable argv,
|
||
cwd, environment, null stdin, combined output, filters, action topology, or
|
||
test outcome.
|
||
|
||
Visible basename, publication path, private runnable path, declared family,
|
||
physical source directory, production/internal/external/recompiled/support/main
|
||
variants, symbols, `.wwi`, archives, action identity, and persistence keys
|
||
remain distinct. A duplicate basename rejects only the requested
|
||
materialization. It never merges, renames, folds, or rekeys either canonical
|
||
package. Compiler inputs, exported interfaces, generated main, archive order,
|
||
and linked bytes are otherwise unchanged.
|
||
|
||
#### Publication, execution, failure, and cleanup
|
||
|
||
Without explicit `-o`, `-c` retains each binary in the invocation directory.
|
||
An existing directory or a path ending in `/` receives one visible name per
|
||
selected package; missing parents are created with `0777` subject to umask. A
|
||
non-directory destination accepts exactly one selected package. Exact
|
||
`/dev/null` suppresses retained copies, permits duplicate visible names, and
|
||
does not suppress execution unless `-c` is also present. A no-test package
|
||
performs ordinary production validation, reports `[no test files]`, and creates
|
||
no binary or otherwise-unused output directory. Successful test-bearing
|
||
compile-only products are silent, matching Go's no-op print action.
|
||
|
||
For `-c`, the driver copies the private runnable bytes to a distinct `.new`
|
||
inode opened with executable mode `0777` subject to umask. Temporary runnable,
|
||
retained copy, statuses, changed persistent actions, tool records, and stamp
|
||
then enter the existing one-request transaction. All producers and linkers
|
||
complete before installation. Any load, compile, assemble, archive, link,
|
||
stage, or install failure preserves old retained binaries and persistent bytes,
|
||
discards all stages, removes cold scratch, and rolls back only output prefixes
|
||
created by that request. Occupied or dangling `.new` paths reject before tools
|
||
and are never overwritten.
|
||
|
||
For running `-o`, the build transaction commits only the private runnable,
|
||
status, and semantic actions. The coordinator executes that runnable and, on a
|
||
successful result, invokes the selected driver stage's public install action.
|
||
Assertion failure, signal, timeout, interruption, or child-setup failure skips
|
||
that action and preserves any prior binary. Successful parallel products
|
||
install independently after their runs; canonical result emission order stays
|
||
unchanged. Direct invocation of a retained binary continues to inherit caller
|
||
cwd, environment, and separate standard descriptors.
|
||
|
||
`-c` and `-o` can accompany `-w`: the workdir owns only semantic actions while
|
||
the invocation/output path owns only the retained copy. Unchanged actions are
|
||
reused, changed source invalidates the applicable test actions, and the
|
||
always-run link refreshes the private runnable and retained copy. Only `-c`
|
||
suppresses execution. This is build reuse, not a result cache.
|
||
|
||
No persisted byte schema changed. Build workdir format remains `18`, test
|
||
workdir format remains `19`, and semantic storage remains `3`.
|
||
|
||
The focused native owners are `compile_artifact_naming` and
|
||
`test_binary_publication_transaction` in `test/package/package_test.ww`. Their
|
||
Cstage/WWstage matrix covers single/default/directory/nested/multi/null output;
|
||
declared-name versus import-leaf naming; executable mode and direct execution;
|
||
temporary argv versus retained path; no-test omission; duplicate and
|
||
non-directory rejection; occupied stages; serial and parallel sibling
|
||
publication; injected late-link rollback over old files and newly created
|
||
parents; runtime-failure preservation; persistent cold/warm/invalidation
|
||
behavior; diagnostic equality; retained binary byte identity; and absence of
|
||
`.new` residue. Existing package tests continue to own all action/test variants,
|
||
graph identity, output ordering, cwd/environment/stdin, timeout, and broader
|
||
transaction behavior.
|
||
|
||
### 11.28 Implemented Go-like build-output permissions
|
||
|
||
Newly published build outputs now use Go 1.26.5's output-kind permission and
|
||
caller-umask contract. An ordinary linked command starts from `0777`; a
|
||
non-link archive starts from `0666`. The kernel filters either base permission
|
||
through the invoking process's umask when the request-private publication inode
|
||
is created. WW's required adjacent interface sidecar is data like its archive
|
||
and uses the same `0666` base. Assembly-only builds create neither kind of
|
||
public output.
|
||
|
||
#### Pinned Go evidence and direct pre-fix measurements
|
||
|
||
The authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `runBuild` routes explicit single and directory `-o` products through
|
||
`ModeInstall`, after deciding the caller-visible output path
|
||
([`cmd/go/internal/work/build.go`, lines 459–558](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L459-L558)).
|
||
- `BuildInstallFunc` begins with permission `0666`, changes it to `0777` for an
|
||
ordinary link action, creates the output parent, and gives that permission to
|
||
`moveOrCopyFile`
|
||
([`cmd/go/internal/work/exec.go`, lines 1904–2000](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L1904-L2000)).
|
||
- On its rename path, `moveOrCopyFile` creates a destination-adjacent dummy with
|
||
the requested permission, observes the caller-filtered mode, removes the
|
||
dummy, applies that mode to the linked source, and renames it. Its copy
|
||
fallback creates the destination with the requested permission and therefore
|
||
receives the same kernel filtering
|
||
([`cmd/go/internal/work/shell.go`, lines 119–220](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/shell.go#L119-L220)).
|
||
- Official `build_output.txt` asserts executable default, explicit-file,
|
||
nested-file, trailing-directory, and existing-directory command outputs
|
||
([lines 7–44](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/build_output.txt#L7-L44)).
|
||
`build_multi_main.txt` exercises directory fan-out for two main packages and
|
||
a local command-line package
|
||
([lines 1–16](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/build_multi_main.txt#L1-L16)).
|
||
|
||
The testdata anchors directly specify that the public command routes produce
|
||
executables. The exact `0777`/`0666` bases and caller filtering are implemented
|
||
by the pinned source. Therefore the resulting mode formula is source-derived;
|
||
it is not an observation of the installed host Go toolchain.
|
||
|
||
Before this slice, fresh public-driver measurements of one byte-identical
|
||
command gave mode `0755` from both stages under umask `000`. Under umask `077`,
|
||
Cstage still gave `0755` while WWstage gave `0700`. The C linker created through
|
||
`fopen` and unconditionally applied `chmod(0755)` after emission; the WW linker
|
||
created with base `0755`. Thus both discarded permitted group/other write bits,
|
||
and Cstage additionally reintroduced bits forbidden by a restrictive mask.
|
||
|
||
The non-link branch had a separate stage mismatch under the same official rule.
|
||
With umask `000`, Cstage published a byte-identical archive/interface pair as
|
||
`0666` while WWstage published it as `0644`; both became `0600` under umask
|
||
`077`. Cstage's fresh `fopen` data stage already had base `0666`, while
|
||
WWstage's data-copy stage explicitly used base `0644`.
|
||
|
||
#### Ownership, publication, and identity boundaries
|
||
|
||
The C and WW linkers now open every fresh linked output with base `0777`. The C
|
||
linker emits through the resulting descriptor instead of applying a fixed mode
|
||
afterward; the WW linker uses the same creation base. The WWstage driver's
|
||
archive/interface copy now uses `0666`, matching Cstage's existing data-file
|
||
creation. No driver independently reads or stores a umask.
|
||
|
||
For public build routes, the coordinator has already rejected an occupied or
|
||
dangling output `.new` before the selected linker or copy owner opens the
|
||
request-private stage. Creation therefore receives the current child process's
|
||
umask exactly once. The established transaction renames that same inode to the
|
||
caller-visible destination, so neither the final name nor replacement of an old
|
||
destination changes its mode. A failed compiler, assembler, archiver, linker,
|
||
stage, or installation preserves the old destination's bytes and mode and
|
||
removes all request stages. Directory fan-out gives each independent command
|
||
the same request-local rule; concurrent driver processes retain independent
|
||
umasks and publication paths.
|
||
|
||
Permission bits are presentation metadata, not semantic inputs. Package and
|
||
action identity, graph edges, declared names, physical directory metadata,
|
||
compiler/assembler/archive/link argv, `.wwi` contents, artifact bytes, and
|
||
persistence keys are unchanged. An unchanged warm request may reuse every
|
||
semantic action but still relinks or copies the requested public product so its
|
||
mode reflects the current invocation. Source invalidation changes the applicable
|
||
artifact bytes without changing the formula. Retained test-binary copying
|
||
remains a distinct output-policy path and already uses the same `0777` linked-
|
||
executable rule. No Go-style dummy is needed and no `-go-tmp-umask` residue is
|
||
created because WW links or copies directly into its already-private fresh
|
||
stage.
|
||
|
||
No persisted byte schema changed. Build workdir format remains `18`, test
|
||
workdir format remains `19`, and semantic storage remains `3`.
|
||
|
||
The WW-native owner `build_output_permissions_follow_umask` uses a test-only
|
||
exec launcher to arrange exact process umasks. It covers both Cstage and
|
||
WWstage; cold, warm, and invalidated persistent builds; explicit, default,
|
||
raw-file, and multi-command directory outputs; `0777`, `0700`, `0750`, and
|
||
`0770` command results; `0666` and `0600` archive/interface results;
|
||
assembly-only omission; retained test-binary non-regression; direct execution;
|
||
injected late-link request rollback over old files and modes; occupied-stage
|
||
rejection; simultaneous builds with different umasks; diagnostic parity;
|
||
artifact and binary byte identity; and absence of `.new` or umask-probe residue.
|
||
|
||
### 11.29 Implemented exact null-output discard for builds
|
||
|
||
Exact `ww build -o /dev/null` now removes output installation while preserving
|
||
the ordinary load and action graph. It is not a request to create an archive,
|
||
executable, interface, or scratch tree at the null-device pathname.
|
||
|
||
#### Pinned Go evidence and fact classification
|
||
|
||
The sole authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `runBuild` loads packages and reports load errors first, then recognizes the
|
||
null output and clears `BuildO` before any output-directory, multi-package,
|
||
or install-action branch. It finally constructs ordinary `ModeBuild` actions
|
||
for every selected package
|
||
([`cmd/go/internal/work/build.go`, lines 459–558](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L459-L558)).
|
||
- `AutoAction` maps a main package in that ordinary mode to a link action and a
|
||
non-main package to a compile action
|
||
([`cmd/go/internal/work/action.go`, lines 450–455](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L450-L455)).
|
||
- On the pinned Unix target, `IsNull` accepts exact `os.DevNull`, which is
|
||
`/dev/null`; its only additional spelling rule is the Windows-only
|
||
case-insensitive `NUL` exception
|
||
([`cmd/go/internal/base/path.go`, lines 81–92](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/base/path.go#L81-L92)).
|
||
- The test builder treats a nonempty `-o` as a binary-retention request, exempts
|
||
the null device from multi-package output rejection, and makes a null target
|
||
use the private build action instead of an install action
|
||
([`cmd/go/internal/test/test.go`, lines 631–646, 771–804, and 1259–1294](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1259-L1294)).
|
||
- Official `devnull.txt` requires `go test -c -o $devnull` and a non-main
|
||
package `go build -o $devnull` to succeed without changing the device
|
||
([lines 3–25](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/devnull.txt#L3-L25)).
|
||
`build_dash_o_dev_null.txt` requires a command-line source build to succeed
|
||
without its default executable
|
||
([lines 1–12](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/build_dash_o_dev_null.txt#L1-L12)).
|
||
`build_cache_link.txt` requires a cold null build to compile and link and an
|
||
unchanged warm null build to skip compilation but link again
|
||
([lines 4–22](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/build_cache_link.txt#L4-L22)).
|
||
`TestRemoveDevNull` requires cleanup never to remove the device
|
||
([`cmd/go/internal/work/build_test.go`, lines 22–35](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build_test.go#L22-L35)).
|
||
|
||
The load-before-output order, exact spelling, absence of installation, normal
|
||
command link, normal non-command compile, cold/warm link behavior, raw-source
|
||
behavior, and device preservation are directly implemented or asserted by the
|
||
pinned sources above. Acceptance of multiple mixed package roots and an empty
|
||
matched set is derived from clearing `BuildO` before the output-cardinality
|
||
branches and then iterating the ordinary package action list. That conclusion
|
||
applies to WW's manifest-free local package set without importing Go's module,
|
||
cache, or distribution model. No installed host Go behavior is authority.
|
||
|
||
#### Direct pre-fix measurements
|
||
|
||
Fresh public-driver probes measured both stages before production edits:
|
||
|
||
- raw source, one command directory, and one non-main library directory each
|
||
failed with exit 1 and `ww: cannot create scratch /dev/null.sepwork`;
|
||
- a two-command-plus-library request failed with exit 2 and
|
||
`wwtest package: cannot use -o with multiple packages`;
|
||
- a persistent command request reached the linker but failed through
|
||
`/dev/null.new`: Cstage reported `w6l: cannot open /dev/null.new`, WWstage
|
||
reported `w6l: cannot open output`, and both left the caller workdir empty;
|
||
- raw `ww test -c -o /dev/null FILE` and its running form failed at the same
|
||
adjacent-scratch acquisition, while directory `test -c` and running test
|
||
requests already built privately, discarded the retained copy, and preserved
|
||
their compile-only versus run distinction;
|
||
- a blank import of a missing package produced the same positioned
|
||
`cannot find package missing.pkg` diagnostic in Cstage and WWstage before
|
||
output setup; and
|
||
- `/dev/null` remained the same character device, mode, device/inode, and size
|
||
throughout the failed probes.
|
||
|
||
Those are directly measured WW facts. The externally observable gap was thus
|
||
the build/raw-driver interpretation of exact null as an artifact stem, plus the
|
||
coordinator's ordinary multi-output rejection, rather than a loader, compiler,
|
||
linker, or device-write defect.
|
||
|
||
#### Ownership, actions, publication, and identity
|
||
|
||
`internal/wwpackage.packagecommand` owns the shared package-request output
|
||
policy. After argument parsing and before output planning it records exact Unix
|
||
null discard. Loading, source classification, package/import validation,
|
||
canonical grouping, graph construction, and diagnostic precedence remain
|
||
unchanged. The coordinator suppresses default names, output-directory setup,
|
||
ordinary non-directory fan-out rejection, caller publication, and the
|
||
visibility-only `-S` workdir requirement, then gives every selected group a
|
||
request-private plan product. Commands still link; libraries still compile and
|
||
archive; mixed and repeated roots still use their canonical graph/action
|
||
deduplication. A recursive pattern matching no package emits its ordinary
|
||
warning and has no output-cardinality error.
|
||
|
||
The direct Cstage and WWstage drivers own raw or single-directory requests that
|
||
do not enter the coordinator. For exact null they allocate a private command
|
||
product, run the unchanged separate-compilation pipeline, and remove that
|
||
product and its scratch on every return. Their raw-test paths use the existing
|
||
unretained private test binary rather than setting `/dev/null` as output and
|
||
object stem. `-c` still suppresses execution; a running request still reports
|
||
ordinary pass, assertion, signal, and harness outcomes. Directory tests retain
|
||
their previously established private-runnable/null-publication behavior.
|
||
|
||
There is no caller-visible stage or destination to commit, occupy, replace, or
|
||
chmod. Producer failure or signal removes private plan state; persistent action
|
||
rollback preserves every prior unit, interface, assembly, object, archive,
|
||
tool record, and stamp. Successful persistent requests commit semantic actions
|
||
normally, unchanged actions are warm-reused, source changes invalidate their
|
||
owners, and command links still run for each request. Separate simultaneous
|
||
Cstage and WWstage requests own disjoint private products and workdirs. Exact
|
||
lookalikes remain normal caller-owned outputs and retain their existing
|
||
fan-out, `.sepwork`, permission, occupied-stage, transaction, and diagnostic
|
||
rules.
|
||
|
||
Output disposition remains request metadata. Dotted package identity, declared
|
||
name, physical source directory, import binding, graph edges, action/storage
|
||
keys, compiler/assembler/linker semantic argv, symbols, `.wwi`, unit and
|
||
artifact bytes, and persistent invalidation are unchanged. No persisted byte
|
||
contract changed: build workdir format remains `18`, test workdir format remains
|
||
`19`, and semantic storage remains `3`.
|
||
|
||
The WW-native owner `exact_null_output_discards_build_products` covers Cstage
|
||
and WWstage command, library, mixed-root, raw-build, assembly-only, and raw-test
|
||
routes; load/import precedence; empty-pattern warning; exact lookalike
|
||
rejection/publication; cold, warm, and invalidated persistence; normal link
|
||
actions and captured runnable bytes; injected linker failure and signal;
|
||
persistent rollback; concurrent stage isolation; device preservation; private
|
||
path and `.new` cleanup; semantic-artifact and captured-binary byte identity;
|
||
and diagnostic/output parity. Existing directory-test owners cover test-product
|
||
parallelism, timeout, child-setup failure, retained-output transactions, and
|
||
runtime cwd/environment/stdin. Build runtime behavior is inapplicable, and
|
||
caller-output rollback, occupied caller stages, and output permissions are
|
||
inapplicable to the exact discard branch because it creates no public inode.
|
||
|
||
### 11.30 Implemented single-root build output directories
|
||
|
||
An explicit `ww build -o OUT` now treats `OUT` as a directory when ordinary
|
||
`stat` reports an existing directory or the spelling ends in `/`. The rule is
|
||
independent of package count. A selected command directory publishes
|
||
`OUT/<requested-import-leaf>` (falling back to the selected local directory
|
||
leaf when no contextual identity exists); a raw command-line source publishes
|
||
`OUT/<source-basename-without-.ww>`. A missing trailing-slash hierarchy is
|
||
created from `0777`, filtered by caller umask, through the existing checked
|
||
directory ledger. All roots load first, but independently selected non-main
|
||
roots are omitted from the directory branch's action list. A selection
|
||
containing no command—including a raw non-main root—rejects as
|
||
`ww: no main packages to build` without running a producer or changing the
|
||
output directory. After a lone command's default basename is synthesized, an
|
||
existing directory at that
|
||
basename instead rejects as
|
||
`ww: build output "<name>" already exists and is a directory`; a non-main
|
||
package has no default public output and is unaffected.
|
||
|
||
#### Pinned Go evidence and fact classification
|
||
|
||
The sole authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `runBuild` completes package loading and package-error checking before output
|
||
handling at
|
||
[`cmd/go/internal/work/build.go`, lines 459–471](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L459-L471).
|
||
After synthesizing a lone `main` package's default output at lines 473–478,
|
||
its output branch classifies an existing directory through
|
||
`os.Stat`, or a spelling ending in `/` or the host path separator, at
|
||
[lines 508–518](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L508-L518).
|
||
It then creates install actions only for packages named `main`, targets each
|
||
at the output directory joined with `DefaultExecName`, rejects an empty
|
||
command action list as `no main packages to build`, and executes that graph
|
||
at
|
||
[lines 519–535](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L519-L535).
|
||
The non-directory single-output branch is separate at
|
||
[lines 537–548](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L537-L548).
|
||
- `DefaultExecName` uses the final import-path element for a directory package
|
||
and the source basename for command-line files
|
||
([`cmd/go/internal/load/pkg.go`, lines 1727–1769](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1727-L1769)).
|
||
- `BuildInstallFunc` creates the target parent before installation, and
|
||
`Shell.Mkdir` implements that operation as `os.MkdirAll(dir, 0777)`
|
||
([`cmd/go/internal/work/exec.go`, lines 1975–2000](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L1975-L2000),
|
||
[`cmd/go/internal/work/shell.go`, lines 283–301](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/shell.go#L283-L301)).
|
||
- Official
|
||
[`build_output.txt`, lines 10–29 and 41–45](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/build_output.txt#L10-L45)
|
||
asserts a raw source's default basename, a missing trailing-slash directory,
|
||
and an existing directory destination.
|
||
- Official
|
||
[`build_multi_main.txt`, lines 1–16](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/build_multi_main.txt#L1-L16)
|
||
asserts command fan-out beneath one directory, no-main rejection, the
|
||
implicit-default-existing-directory error, and raw command-line-source
|
||
placement beneath an existing output directory.
|
||
|
||
Load-before-output ordering, `stat`/separator classification, command-only
|
||
installation, import-leaf naming, destination joining, no-main rejection, and
|
||
the `0777` parent-creation request are directly implemented by the pinned
|
||
source. Raw-source basename and existing/missing directory behavior are
|
||
directly asserted by official testdata. The resulting parent mode after umask
|
||
is derived from the pinned `MkdirAll` call. Application to
|
||
exactly one directory package is derived from `runBuild`: the directory branch
|
||
tests output form, not package cardinality, while the cardinality check exists
|
||
only in the later non-directory branch. These facts apply to WW's local
|
||
manifest-free command and raw-source products without importing Go's module,
|
||
cache, registry, distribution, or network behavior. The installed host Go
|
||
version is not authority.
|
||
|
||
#### Direct pre-fix measurements
|
||
|
||
Fresh public Cstage (`out/bin/ww`) and WWstage (`out/bin/ww_ww`) probes measured
|
||
the same divergence before production edits:
|
||
|
||
- one command directory plus an existing output directory spelled without `/`
|
||
returned 0, renamed the caller's directory to a PID-bearing transaction
|
||
backup, installed a 4,268-byte ELF executable at the directory pathname, and
|
||
diagnosed failure to remove the nonempty backup;
|
||
- the same existing directory spelled with `/` returned 1 with
|
||
`ww: cannot preserve transaction destination .../`;
|
||
- a missing nested spelling ending in `/` returned 1 while trying to acquire
|
||
`<OUT>/.sepwork` before the hierarchy existed;
|
||
- a raw `main.ww` plus an existing trailing-slash destination failed through
|
||
the same transaction-destination path instead of producing `OUT/main`; and
|
||
- a non-main directory plus an existing directory spelled without `/` returned
|
||
0, replaced the directory pathname by an archive, wrote its `.wwi` beside
|
||
that pathname, and stranded the former directory as a transaction backup;
|
||
and
|
||
- for both a command directory and a raw command-line source, an existing
|
||
directory at the synthesized default basename was renamed to a transaction
|
||
backup and replaced by the executable; both stages returned 0 and diagnosed
|
||
inability to remove the deliberately nonempty backup.
|
||
|
||
Completion review measured four additional stage-identical pre-completion
|
||
behaviors before their production edits. A mixed command/non-main request
|
||
compiled the independent non-main root in both stages; a raw non-main root
|
||
returned 0 and published an archive plus `.wwi`; a contextual `alias` symlink
|
||
to physical directory `physical` published `OUT/physical`; and an exactly
|
||
arranged umask `000` produced newly created output parents with mode `0700`.
|
||
Pinned Go instead loads then omits the independent non-main action, rejects the
|
||
raw no-command selection, uses the requested import leaf, and requests parent
|
||
mode `0777`. The preserved traces and stat results are in the session evidence
|
||
ledger.
|
||
|
||
Final review then measured four stage-identical load-precedence leaks before
|
||
the completion edit. A non-main root with a missing import reported only
|
||
`no main packages`; a command with a missing import and an overlong derived
|
||
directory destination reported only the path error; two colliding command
|
||
basenames, one with a missing import, reported only the duplicate-destination
|
||
error; and a recursive command with a missing import plus an implicit default
|
||
directory collision reported only the collision. Pinned `runBuild` lines
|
||
470–471 load and check all selected packages before any output handling at
|
||
lines 473–548. Missing-package diagnostics therefore precede no-main,
|
||
derived-path, duplicate-destination, and implicit-default checks. Extending
|
||
that boundary to WW's transactional duplicate guard is derived from the pinned
|
||
ordering because the guard is WW-local output preflight. The exact probes and
|
||
outputs are preserved in the evidence ledger.
|
||
|
||
Those are directly measured WW facts. Both drivers interpreted every non-null
|
||
single-root `-o` as one file and object stem. The compiler, assembler, linker,
|
||
archive writer, and shared package coordinator were not the cause.
|
||
|
||
#### Ownership, actions, publication, and identity
|
||
|
||
`internal/wwpackage.packagecommand` remains the shared package-request output
|
||
owner. It classifies output directories, discovers and groups the complete
|
||
selection, and passes every selected root plus output-preflight metadata into
|
||
the shared separate-build executor. Only after that executor has loaded all
|
||
packages and imports does it retain command roots, derive their complete action
|
||
closure, and evaluate no-main, path-length, duplicate-destination, and
|
||
implicit-default checks. A separate presentation field carries the requested
|
||
import leaf (or local-path fallback) through collision preflight and
|
||
publication; canonical physical directory metadata remains loader metadata.
|
||
The coordinator commits the retained products through one request transaction.
|
||
The dispatch part of the gap belonged to the early single-root compatibility
|
||
choice in `cmd/ww.do_build` and `selfhost/cmd/ww.dobuild`; completion review
|
||
also closed the coordinator's independent-non-main action,
|
||
physical-leaf-presentation, and load-precedence leaks.
|
||
|
||
After ordinary argument parsing and root resolution, both drivers now apply the
|
||
same exact Unix classification. A directory root with a directory output enters
|
||
the existing package coordinator. An explicit logical root carries its
|
||
unchanged logical root identity while the corresponding argument is replaced
|
||
by the already-resolved loader route; a default invocation inserts exactly one
|
||
`.`; a literal directory remains literal. Thus the shared loader, grouping,
|
||
graph, action, output-preflight, and publication rules operate exactly as they
|
||
do for a larger request.
|
||
|
||
The raw-file compatibility route remains driver-owned. It derives the joined
|
||
command path, uses that path as the existing direct action's product and stem,
|
||
and passes the classified directory to the shared transaction's checked
|
||
creation ledger. A bounds failure is carried as preflight metadata so source
|
||
and import errors, and raw no-main rejection, retain pinned load-first
|
||
precedence before the path diagnostic. It does not manufacture a package
|
||
request or change raw-source graph identity. `stat` follows a symlinked output
|
||
directory; lexical publication remains beneath the requested symlink spelling.
|
||
Exact `/dev/null` is classified first by the completed discard rule and never
|
||
enters this directory branch.
|
||
|
||
For an implicit default, the drivers pass the existing-directory collision as
|
||
preflight metadata to the common separate-build executor. The executor waits
|
||
until package/import loading, contextual checks, and graph-cycle validation
|
||
have established the root action kind. It rejects a command before scratch,
|
||
workdir, tool, stage, or destination acquisition, but lets a non-main package
|
||
perform its unchanged no-public-output build. This keeps raw and directory
|
||
compatibility routes on the same diagnostic-precedence rule without deriving
|
||
kind from a path, filename, declared-name guess, or driver-side source scan.
|
||
|
||
Loading and source/import rejection precede every output-derived rejection,
|
||
including no-main, derived-path length, duplicate destination, and implicit
|
||
default collision; all precede output creation. A selection with no command
|
||
rejects after full package/import loading and graph validation but before
|
||
compiler, assembler, linker, or directory mutation. In a mixed request,
|
||
independently selected non-main roots have no action; a non-main package
|
||
reachable as a command dependency still performs its ordinary semantic action.
|
||
Repeated exact roots retain canonical graph/action deduplication. Successful
|
||
commands compile, assemble, archive, and link normally; `-S -w` remains
|
||
action-only and publishes no command. Directory form still selects only
|
||
commands and therefore retains no-main rejection, but destination length,
|
||
duplicate publication names, implicit destination collision, and output-parent
|
||
creation belong to the install action that `-S` never reaches. They are
|
||
inapplicable to that assembly-only request. An explicit external workdir
|
||
prevents an adjacent `<command>.sepwork`; without `-w`, that established WW
|
||
scratch tree remains an ordinary retained build artifact beneath the output
|
||
directory.
|
||
|
||
Existing destination contents and symlink targets survive successful
|
||
publication. Compiler failure, linker failure, or linker signal preserves the
|
||
prior command and every committed persistent artifact, removes `.new` and
|
||
transaction stages, and rolls back only directory prefixes created for the
|
||
failed request. Every caller-output prefix is requested as `0777` and filtered
|
||
once by the caller umask; persistent/private work directories keep their
|
||
separate modes. The raw route has the same missing-directory rollback through
|
||
the shared creation ledger. Independent Cstage and WWstage processes use
|
||
disjoint output, work, stage, and process ownership and may complete
|
||
concurrently. `ww build` itself has no runtime action; direct execution of the
|
||
published command verifies its ordinary program exit result, while runtime
|
||
failure/timeout policy remains owned by `ww run` and `ww test`.
|
||
|
||
This is output disposition and dispatch only. Dotted package/import identity,
|
||
declared package name, physical source directory metadata, file-local import
|
||
bindings, graph edges, action and storage keys, symbols, `.wwi`, compiler,
|
||
assembler, archive and linker semantic inputs, artifact bytes, invalidation,
|
||
and public-file output-mode formula are unchanged. Correcting caller-output
|
||
parent creation metadata does not enter any semantic identity. There is no
|
||
persisted-byte contract change: build workdir format remains `18`, test
|
||
workdir format remains `19`, and semantic storage remains `3`.
|
||
|
||
The WW-native owner `single_root_build_output_directory` covers literal,
|
||
logical, default-dot, symlinked, raw-file, explicit existing/missing, and
|
||
implicit-default existing-directory forms in both stages; basename selection
|
||
and directory-content preservation; logical alias versus physical-leaf
|
||
separation; command rejection, raw no-main rejection, non-main no-output
|
||
behavior, long raw-output and load-error precedence; mixed command-only and
|
||
repeated roots; skipped-root import rejection; and no-main, directory-derived
|
||
path, duplicate-destination, and recursive implicit-collision precedence with
|
||
zero tool activity; exact `0777` missing-parent creation under umask `000`;
|
||
the already-aligned retained-test control; `-S -w` command selection with no
|
||
install-only preflight or output-directory creation; cold, warm,
|
||
and invalidated persistence; exact compiler/assembler/linker action traces;
|
||
successful program exit results; compiler and linker failure; linker signal;
|
||
prior-state and newly-created-directory rollback; `.new` and transaction
|
||
cleanup; concurrent stage isolation; executable and semantic-artifact bytes;
|
||
and exact diagnostic parity. Existing owners continue to cover public-file
|
||
output umasks, occupied stages, generalized multi-product transactions, test
|
||
runtime failure and timeout, null discard, and broader package/import graph
|
||
matrices.
|
||
|
||
### 11.31 Implemented Go-like public-output overwrite safety
|
||
|
||
Every caller-visible build and retained-test install now protects an existing
|
||
destination at the same late boundary as Go 1.26.5. After applicable producers
|
||
finish, ordinary `stat` rejects a directory and rejects a nonempty regular file
|
||
whose leading bytes do not identify a toolchain output. Absent paths, empty
|
||
regular reservations, recognized outputs, and non-directory non-regular paths
|
||
remain replaceable. Exact `/dev/null` and assembly-only `-S` have no install
|
||
action and never enter this rule.
|
||
|
||
#### Pinned Go evidence and classification
|
||
|
||
The sole authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `Shell.moveOrCopyFile` and `Shell.CopyFile` call `checkDstOverwrite` before
|
||
replacing the destination
|
||
([`cmd/go/internal/work/shell.go`, lines 119–235](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/shell.go#L119-L235)).
|
||
`checkDstOverwrite` uses `os.Stat`, rejects a directory, and—unless forced—
|
||
rejects a nonempty regular file for which `isObject` is false
|
||
([lines 248–261](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/shell.go#L248-L261)).
|
||
- `BuildInstallFunc` creates the destination parent and reaches
|
||
`moveOrCopyFile(..., false)` only after its build producer
|
||
([`cmd/go/internal/work/exec.go`, lines 1904–2000](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L1904-L2000)).
|
||
`objectMagic` and `isObject` read the first 64 bytes and recognize archive,
|
||
ELF, Mach-O, PE, Plan 9, WASM, and XCOFF prefixes without consulting a file
|
||
extension
|
||
([lines 2118–2150](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L2118-L2150)).
|
||
- `runBuild` loads and checks every selected package before constructing the
|
||
output/install action
|
||
([`cmd/go/internal/work/build.go`, lines 459–558](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L459-L558)).
|
||
- `builderTest` makes `-c` depend directly on the install action. For a running
|
||
retained test, the run consumes the private build action and the install
|
||
action additionally depends on that run
|
||
([`cmd/go/internal/test/test.go`, lines 1257–1364](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1257-L1364)).
|
||
`Builder.Do` invokes an actor only when dependency failure has not propagated
|
||
(unless the action explicitly ignores failure), so a failed test run skips
|
||
`BuildInstallFunc`
|
||
([`cmd/go/internal/work/exec.go`, lines 72–207](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L72-L207)).
|
||
- Official `build_output_overwrite.txt` requires refusal to replace a
|
||
nonempty source file and preservation of its contents
|
||
([lines 1–20](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/build_output_overwrite.txt#L1-L20)).
|
||
Official `test_compile_tempfile.txt` requires an existing empty reservation
|
||
to be accepted and replaced
|
||
([lines 1–11](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_compile_tempfile.txt#L1-L11)).
|
||
Official `build_output.txt` separately pins executable command and archive
|
||
products
|
||
([lines 47–57 and 64–76](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/build_output.txt#L47-L76)).
|
||
|
||
The destination predicate, complete magic table, load-before-install ordering,
|
||
producer-before-check ordering, and run-before-install dependency are directly
|
||
implemented by the pinned source. Non-overwrite and empty-file acceptance are
|
||
directly asserted by official testdata. Applying ELF and archive recognition
|
||
to WW's byte-identical output forms is derived from that implementation. Go
|
||
has no WW interface sidecar; recognizing only the compiler-owned
|
||
`//ww:module ` prefix is the derived local application that permits ordinary
|
||
repeat publication without letting arbitrary sidecar text be overwritten. No
|
||
installed host Go behavior was used as authority.
|
||
|
||
#### Fresh four-axis audit and pre-fix measurements
|
||
|
||
The bounded audit selected this one gap on the build axis and the shared
|
||
retained-test install axis. The package control selected the same canonical
|
||
command root twice and measured one deduplicated command action plus one
|
||
dependency action, with byte-identical Cstage/WWstage units, interfaces, and
|
||
archives. The import control placed a used alias in one source file and an
|
||
unused alias for the same dependency in a sibling; both stages emitted the
|
||
same file-local unused-import diagnostic and committed no work. Those package
|
||
and import candidates were aligned and were not changed.
|
||
|
||
Fresh public Cstage and WWstage probes directly measured the same pre-fix
|
||
behavior. Explicit command, raw command, output-directory child, library
|
||
archive/interface, compile-only test, and running retained-test destinations
|
||
containing arbitrary nonempty text were replaced successfully. A nonempty
|
||
directory at a build or test child destination was renamed to a PID-bearing
|
||
transaction backup, replaced by the executable, and left stranded because
|
||
backup cleanup could not unlink the directory. Empty reservations were already
|
||
accepted. Missing-import rejection already preceded destination handling. All
|
||
measured successful executables, archives, interfaces, diagnostics, runtime
|
||
results, and semantic artifacts were stage-identical. Those are directly
|
||
measured WW facts, not source inferences.
|
||
|
||
#### Ownership, action order, rollback, and identity
|
||
|
||
The Cstage `sep_txn_commit` and WWstage `septxncommit` publishers own the byte
|
||
predicate. Each transaction entry now explicitly distinguishes a public
|
||
install from internal status, tool-identity, stamp, and persistent-action
|
||
state. Only command/archive output, retained-copy, and published `.wwi` entries
|
||
are checked. Producers still finish before transaction commit; a rejected
|
||
destination discards all staged outputs and preserves every prior public and
|
||
persistent byte. A library archive and interface remain one rollback group, so
|
||
arbitrary text in either destination changes neither.
|
||
|
||
`internal/wwpackage.packagecommand` continues to own directory-test naming and
|
||
scheduling. A running retained descriptor withholds its public destination
|
||
from the build child. After a successful private run, the coordinator invokes
|
||
a private action in the selected driver, which stages an executable copy and
|
||
re-enters the same guarded publisher. A failed, signalled, timed-out,
|
||
interrupted, or unstartable run never invokes that action. Successful products
|
||
in a multi-package running request install independently; compile-only products
|
||
retain the established request transaction. The driver-owned raw single-file
|
||
route applies the same private build, run, and guarded-install sequence.
|
||
|
||
Package-build descriptors use `build-public` only for caller-visible command or
|
||
archive products. Private package-build placeholders, test runnables, `ww run`,
|
||
workdir-owned test binaries, null-discard products, and assembly-only products
|
||
remain internal entries. Destination path, file kind, magic, declared name,
|
||
requested alias, import leaf, physical directory, and publication order do not
|
||
enter package/import identity, graph edges, action keys, symbols, artifacts,
|
||
`.wwi` contents, or persistence keys.
|
||
|
||
The guard follows symlinks for classification, matching `os.Stat`; the existing
|
||
transaction still replaces the destination directory entry itself. It permits
|
||
FIFO and other non-directory non-regular destinations because the pinned guard
|
||
does. Diagnostics are exactly
|
||
`ww: build output "PATH" already exists and is a directory` and
|
||
`ww: build output "PATH" already exists and is not an object file` in both
|
||
stages. No guard is preflighted during loading: package/import errors still win,
|
||
and compiler, assembler, archive, or linker failure prevents the install action
|
||
from being reached.
|
||
|
||
Build runtime is inapplicable because `ww build` starts no program. Test
|
||
runtime is applicable and owns the post-run dependency above. Producer failure,
|
||
linker interruption, output-parent rollback, concurrency, occupied stages,
|
||
prior-state preservation, and residue cleanup remain governed by the existing
|
||
request/private-action transactions; the new check adds no process-global
|
||
state. Public artifact bytes and modes are unchanged on accepted installs.
|
||
There is no persisted-byte contract change: build workdir format remains `18`,
|
||
test workdir format remains `19`, and semantic storage format remains `3`.
|
||
|
||
The WW-native `public_output_overwrite_safety` observer covers both stages:
|
||
direct, default, raw, package-output-directory, library, compile-only test, and
|
||
running-test routes; late linker activity and load precedence; absent/empty,
|
||
ELF, archive, interface, arbitrary regular, directory, symlink, and FIFO
|
||
destinations; cold, warm, and invalidated persistent rollback; run-before-check
|
||
and failed-run no-install behavior; exact null and assembly-only exclusions;
|
||
runtime results; modes; diagnostic identity; public and semantic artifact-byte
|
||
identity; and `.new`, install-stage, and transaction-backup cleanup.
|
||
`test_binary_publication_transaction` pins the changed failed-run behavior and
|
||
the existing linker failure, output-parent rollback, multi-product, persistent,
|
||
and retained-binary contracts. Existing request-transaction, timeout,
|
||
interruption, and concurrent-driver owners continue to cover those unchanged
|
||
dimensions.
|
||
|
||
### 11.32 Implemented selected toolchain first in test `PATH`
|
||
|
||
Every test binary actually started by `ww test` now receives one effective
|
||
uppercase `PATH` beginning with the canonical absolute directory of the
|
||
selected WW driver. An absent or empty inherited value produces only that
|
||
directory. A nonempty first effective inherited value follows it after `:`;
|
||
ordinary duplicate `PATH=` entries collapse to the one child value. This is
|
||
test-process metadata only: build tools and every request that starts no test
|
||
process retain their prior environment.
|
||
|
||
#### Pinned Go evidence and classification
|
||
|
||
The sole authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- The `go test` command documentation states that `$GOROOT/bin` is placed at
|
||
the beginning of the test process's `PATH`, so an executed test resolves the
|
||
`go` command from the invoking toolchain
|
||
([`cmd/go/internal/test/test.go`, lines 87–94](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L87-L94)).
|
||
- `(*runTestActor).Act` begins with `cfg.OrigEnv`, applies
|
||
`base.AppendPATH`, then `base.AppendPWD`, and assigns that environment to
|
||
each test command
|
||
([`cmd/go/internal/test/test.go`, lines 1661–1668](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1661-L1668)).
|
||
`AppendPATH` appends `PATH=$GOROOT/bin` for an empty effective inherited
|
||
value and `PATH=$GOROOT/bin:<old>` otherwise
|
||
([`cmd/go/internal/base/env.go`, lines 29–45](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/base/env.go#L29-L45)).
|
||
- `Cmd.environ` removes duplicate environment keys while preferring the later
|
||
entry, making the appended value effective
|
||
([`os/exec/exec.go`, lines 1231–1265](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/os/exec/exec.go#L1231-L1265)).
|
||
On the supported Unix model, initial environment lookup uses the first
|
||
inherited occurrence
|
||
([`syscall/env_unix.go`, lines 20–44 and 66–84](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/syscall/env_unix.go#L20-L84)).
|
||
- Official `test_goroot_PATH.txt` tests both an empty `PATH` and a nonempty
|
||
directory containing no executable; the test must find the `go` executable
|
||
in the current toolchain's `$GOROOT/bin`
|
||
([lines 1–41](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_goroot_PATH.txt#L1-L41)).
|
||
|
||
Those source rules and official assertions are behavior directly implemented
|
||
or asserted by pinned Go. Using the selected WW driver's sibling directory as
|
||
the local toolchain-bin analogue is derived from that implementation: WW has
|
||
no `GOROOT`, and that directory already supplies the driver's default compiler,
|
||
assembler, linker, and package-test coordinator. Applying the rule to WW's raw
|
||
single-file compatibility route is also derived; it is a local input extension,
|
||
but it executes the same observable test and initialization code. Canonical
|
||
absolute spelling is runtime metadata only and prevents a relative driver path
|
||
from leaking the coordinator's later package cwd into `PATH`.
|
||
|
||
#### Fresh four-axis audit and direct pre-fix measurements
|
||
|
||
The bounded audit considered all four permanent axes and selected only this
|
||
test-runtime gap:
|
||
|
||
- **Build:** pinned `runBuild` loads all roots and checks package errors before
|
||
output/action construction
|
||
([`cmd/go/internal/work/build.go`, lines 459–478](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L459-L478)); official
|
||
`build_json.txt` distinguishes load errors from compiler failures
|
||
([lines 15–26 and 39–45](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/build_json.txt#L15-L45)).
|
||
A direct missing-import probe made both WW stages exit `1` with the identical
|
||
source diagnostic and no producer or public output. This candidate was
|
||
aligned.
|
||
- **Test:** direct Cstage and WWstage directory probes, each invoked with
|
||
`PATH=/usr/bin:/bin`, both exited `0` while the test printed exactly that
|
||
unchanged value. `/home/kimchi/src/ww/out/bin` was absent. These are directly
|
||
measured pre-fix WW facts and establish the selected external difference.
|
||
- **Package:** pinned `types2.(*Checker).initFiles` rejects package name `_`
|
||
([`cmd/compile/internal/types2/check.go`, lines 311–355](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/check.go#L311-L355)),
|
||
with official anchors in
|
||
[`internal/types/testdata/check/blank.go`](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/blank.go#L1-L5)
|
||
and [`test/blank1.go`](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/blank1.go#L1-L10).
|
||
Direct production, imported, and test-only probes were rejected by both WW
|
||
stages, but only through the loader's generic `invalid or missing package
|
||
clause`; the direct compilers also produced different syntax-recovery
|
||
streams. Equal rejection was not semantic alignment. The gap was different
|
||
and is completed in section 11.56.
|
||
- **Import:** pinned `unusedImports` requires every nonblank import binding to
|
||
be used
|
||
([`cmd/compile/internal/types2/resolver.go`, lines 706–740](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L706-L740)); official
|
||
`importdecl0` covers default, alias, dot, and blank forms
|
||
([lines 5–31](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/importdecl0/importdecl0a.go#L5-L31)).
|
||
A direct unused default-import probe produced identical Cstage/WWstage
|
||
diagnostics and no committed work. This candidate was aligned.
|
||
|
||
The build, package, and import observations above are directly measured WW
|
||
behavior; the linked rules are behavior directly implemented or asserted by
|
||
pinned Go. The conclusion that this slice crosses those axes only when code in
|
||
a successfully loaded test variant or initialized dependency observes `PATH`
|
||
is derived from the pinned launch placement.
|
||
|
||
#### Ownership, launch behavior, and preserved boundaries
|
||
|
||
The environment is synthesized at the three true test-process launch owners:
|
||
`internal/wwpackage.pkgstartrun` for directory products, Cstage
|
||
`run_test_bin`, and WWstage `runsingletest` for raw single-file tests. Each
|
||
uses the selected driver directory's canonical absolute spelling. The first
|
||
effective uppercase inherited value is the suffix; absent and empty values
|
||
have no suffix; ordinary uppercase duplicates are removed. For directory
|
||
products, section 11.36 owns unrelated entries: a Go-like original-environment
|
||
snapshot retains caller locale and temporary-directory values, case-distinct
|
||
and nonempty malformed entries, and the final package `PWD`. Raw tests retain
|
||
caller cwd, `PWD`, other environment entries, stdin, and split streams.
|
||
|
||
The rule covers internal, external, and combined directory products;
|
||
dependency initialization; filters and list mode; running retained tests; and
|
||
raw single-file tests. It is independently materialized for each concurrent
|
||
product. `ww build`, `ww run`, compiler/assembler/linker and generated-main
|
||
commands, compile-only and assembly-only tests, no-test products, rejected
|
||
requests, and later direct execution of a retained binary receive no test
|
||
environment transformation.
|
||
|
||
Loading, graph construction, compilation, assembly, linking, action keys, and
|
||
artifact production are unchanged. A load, compile, or link failure starts no
|
||
test process, so runtime `PATH` is inapplicable and the existing diagnostic
|
||
precedence remains. A started test observes the new environment before normal
|
||
success, assertion failure, signal, timeout, or interruption. Existing process
|
||
groups, cancellation, output capture, and cleanup own those outcomes; the
|
||
environment adds no global mutable state. A running retained request remains
|
||
private build, private run, then guarded install, so any unsuccessful run
|
||
publishes nothing and preserves prior bytes. Parallel products receive separate
|
||
environment arrays and retain existing result isolation.
|
||
|
||
Canonical physical driver directories do not become package, import, graph,
|
||
action, artifact, symbol, `.wwi`, publication, or persistence identity.
|
||
Compiled units, interfaces, archives, executables, modes, diagnostics, and
|
||
public-output disposition are unchanged. No stored key or byte changed, so
|
||
build workdir format remains `18`, test workdir format remains `19`, and
|
||
semantic storage format remains `3`.
|
||
|
||
The extended WW-native `directory_test_execution_working_directory` observer
|
||
proves Cstage/WWstage equality for absent, empty, nonempty, and duplicate
|
||
caller `PATH`; all directory test shapes and dependency initialization;
|
||
filters, listing, raw single-file, and running retained tests; relative selected
|
||
driver canonicalization; build/no-test/compile-only/rejection exclusions;
|
||
unchanged compiler, assembler, and linker environments; concurrent products;
|
||
runtime failure with prior retained-byte rollback; artifact-byte identity; and
|
||
transaction, stage, workdir, and generated-file cleanup. Existing signal,
|
||
timeout, interruption, concurrent-driver, and public-output transaction owners
|
||
cover the unchanged mechanisms at those boundaries.
|
||
|
||
### 11.33 Implemented newline before directory test result trailers
|
||
|
||
When a directory-owned test product has emitted a nonempty combined capture
|
||
whose final byte is not newline, `ww test` now emits exactly one newline before
|
||
its existing `ok` or run-status `FAIL` trailer. Empty and already
|
||
newline-terminated captures gain no byte. The rule belongs only to the
|
||
coordinator boundary between completed test-process output and its result
|
||
trailer; it does not rewrite the capture or affect a route with no coordinator
|
||
trailer.
|
||
|
||
#### Pinned Go evidence and classification
|
||
|
||
The sole authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `(*runTestActor).Act` selects one output writer/buffer for a package test
|
||
([`cmd/go/internal/test/test.go`, lines 1436–1499](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1436-L1499)),
|
||
then assigns that same writer to the test command's stdout and stderr and
|
||
retains the resulting bytes as `out`
|
||
([lines 1661–1708](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1661-L1708)).
|
||
- On success, a nonempty `out` without a trailing newline receives one before
|
||
the `ok` record
|
||
([lines 1712–1732](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1712-L1732)).
|
||
On failure with partial output, the same check inserts one before `FAIL`
|
||
([lines 1733–1769](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1733-L1769)).
|
||
- Official `test_fail_newline.txt` asserts that buffered partial failure output
|
||
and `FAIL` begin on different lines, and that buffered verbose partial
|
||
success output and `ok` begin on different lines. It also records the
|
||
deliberate streaming-mode exception
|
||
([lines 3–35](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_fail_newline.txt#L3-L35)).
|
||
|
||
Those source rules and official script assertions are behavior directly
|
||
implemented or asserted by pinned Go. Applying the buffered-package boundary
|
||
to WW's directory-product capture is derived from that implementation: WW's
|
||
manifest-free directory coordinator likewise owns the completed combined bytes
|
||
and immediately appends a package result trailer. Excluding raw single-file
|
||
tests and later manual execution of retained binaries is also derived from the
|
||
pinned distinction: those WW routes have no coordinator-owned `ok` or `FAIL`
|
||
trailer to separate.
|
||
|
||
#### Fresh four-axis audit and direct pre-fix measurements
|
||
|
||
The bounded audit considered all four permanent axes and selected only this
|
||
test-output gap:
|
||
|
||
- **Go-like build:** pinned `(*ErrorReporter).errorUnresolved` gives an
|
||
undeclared main function its dedicated link error
|
||
([`cmd/link/internal/ld/errors.go`, lines 29–65](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/errors.go#L29-L65)).
|
||
`TestUndefinedRelocErrors` directly requires build failure and that message
|
||
([`cmd/link/internal/ld/ld_test.go`, lines 19–45](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/ld_test.go#L19-L45)),
|
||
using official `issue10978/main.go`, whose main function is absent
|
||
([lines 5–27](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/testdata/issue10978/main.go#L5-L27)).
|
||
Direct Cstage and WWstage `ww build -o /dev/null` probes of a selected WW
|
||
command package without `main` both exited `1`, produced the identical
|
||
`w6l: undefined reference to 'main'` then `ww: w6l failed` diagnostics, and
|
||
published nothing. This candidate was aligned.
|
||
- **Go-like test:** a selected external `*_test.ww` initializer wrote exactly
|
||
`partial-success` without newline and exited `0`. Both stages exited `0`,
|
||
wrote no stderr, and emitted 72 stdout bytes beginning
|
||
`partial-successok `. The corresponding initializer wrote exactly
|
||
`partial-failure` to stderr and exited `7`; both commands exited `1`, wrote
|
||
no coordinator stderr, and emitted 86 stdout bytes beginning
|
||
`partial-failureFAIL `. Full Cstage and WWstage captures were byte-identical.
|
||
These are directly measured pre-fix WW facts and establish the selected
|
||
externally observable difference.
|
||
- **Go-like package:** `MultiplePackageError` represents conflicting selected
|
||
package clauses and formats the two declarations
|
||
([`go/build/build.go`, lines 538–548](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L538-L548));
|
||
the scanner creates it when selected files disagree
|
||
([lines 930–967](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L930-L967)),
|
||
and `TestMultiplePackageImport` asserts the typed result and files
|
||
([`go/build/build_test.go`, lines 105–124](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build_test.go#L105-L124)).
|
||
Direct WW directories declaring `alpha` and `beta` were rejected before any
|
||
producer by both stages with the same positioned conflict diagnostic. This
|
||
candidate was aligned.
|
||
- **Go-like import:** `loadImport` rejects a package declared `main` when it is
|
||
imported from another directory
|
||
([`cmd/go/internal/load/pkg.go`, lines 787–805](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L787-L805));
|
||
official `import_main.txt` asserts the rule for builds and internal/external
|
||
tests
|
||
([lines 3–35](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/import_main.txt#L3-L35)).
|
||
Both WW stages rejected a direct dotted import of a package declared `main`
|
||
with the identical `ww: package cmdpkg is a program, not an importable
|
||
package` diagnostic. This candidate was aligned.
|
||
|
||
The direct Go source and official-test statements above are behavior directly
|
||
implemented or asserted by pinned Go. The WW command results are directly
|
||
measured behavior. The conclusion that the selected change is a runtime
|
||
presentation boundary, with no build, package, or import identity effect, is
|
||
derived from the pinned placement after command completion and before the
|
||
result record.
|
||
|
||
#### Ownership, final behavior, and preserved boundaries
|
||
|
||
`internal/wwpackage.pkgemitgroup` is the true owner because it alone has both
|
||
the completed product-local combined capture and knowledge that an existing
|
||
directory result trailer follows. It first emits the capture unchanged, then
|
||
emits one separator only when the capture is nonempty and its last byte is not
|
||
newline, then follows the established success or failure branch. The check is
|
||
shared by Cstage and WWstage and is independent for every canonically ordered
|
||
product, including internal, external, and combined variants; dependency
|
||
initialization; filters and list mode; concurrent products; and the private run
|
||
of a retained request.
|
||
|
||
Empty output does not acquire a leading blank line, and output already ending
|
||
in newline does not acquire a second one. A nonzero exit or signal retains its
|
||
existing process classification and `FAIL` text; only a preceding partial line
|
||
is terminated. Test-harness timeout and ordinary assertion output already end
|
||
in newline and therefore remain byte-identical. A child that cannot start has
|
||
no completed capture/trailer boundary in this function. Parent interruption,
|
||
producer failure, and load, compile, assemble, archive, link, or install
|
||
failure retain their existing diagnostics and precedence. Raw single-file
|
||
tests and later direct execution of retained binaries have no package
|
||
coordinator result trailer and retain their exact process bytes.
|
||
|
||
Loading, graph construction, action construction and scheduling, compiler,
|
||
assembler, archiver, linker, generated main, test executable, and retained
|
||
artifact bytes are unchanged. The separator is emitted after the private
|
||
process completes; it is not written into the capture, executable, interface,
|
||
archive, work record, or public destination. Running retention remains private
|
||
build, private run, then guarded install. Failed, signalled, interrupted, or
|
||
unstartable runs still publish nothing and preserve prior retained bytes.
|
||
Concurrent products retain separate capture files and canonical emission;
|
||
there is no shared mutable newline state. Existing process-group cleanup,
|
||
transaction rollback, temporary-root removal, and staged-file cleanup are
|
||
unchanged.
|
||
|
||
Physical source directories remain runtime/loader metadata only and do not
|
||
become package, import, graph, action, artifact, symbol, `.wwi`, publication,
|
||
or persistence identity. No persisted byte or key changes, so build workdir
|
||
format remains `18`, test workdir format remains `19`, and semantic storage
|
||
format remains `3`.
|
||
|
||
The WW-native `directory_test_trailer_starts_on_new_line` observer proves both
|
||
stages for unterminated stdout success, unterminated stderr failure,
|
||
unterminated signal output, already terminated output, and empty output. It
|
||
also covers concurrent products, a filter, list mode, running retained
|
||
publication, retained executable byte identity, and the unchanged raw/manual
|
||
routes; complete stdout and stderr from the concurrent Cstage and WWstage runs
|
||
must match exactly. Existing package execution, timeout, interruption,
|
||
transaction, persistence, byte-identity, and cleanup owners continue to prove
|
||
the mechanisms this slice does not alter.
|
||
|
||
### 11.34 Implemented final `FAIL` for explicit ordinary test failures
|
||
|
||
An ordinary `ww test` request with an explicit target now ends its ordered
|
||
standard output with exactly one command-owned `FAIL\n` when test setup, build,
|
||
or execution fails. The line follows every package result, including successful
|
||
packages ordered after an earlier failure. It applies to one or many explicit
|
||
directory, recursive, dotted-directory, or raw-file targets; filters and list
|
||
mode; and the private execution of a retained test. It does not apply to bare
|
||
implicit-current-directory `ww test`, `-c`, `-S`, `ww build`, command-line
|
||
usage/shape or output preflight rejection, publication-only failure,
|
||
capture-only failure, cleanup-only failure, allocation/systemic coordinator
|
||
failure, or later direct execution of a retained binary.
|
||
|
||
#### Pinned Go evidence and classification
|
||
|
||
The sole authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `runTest` reports setup errors, writes the per-package setup-failure result,
|
||
and sets the command exit status
|
||
([`cmd/go/internal/test/test.go`, lines 1010–1061](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1010-L1061)).
|
||
It then creates a root `go test` action owned by `printExitStatus`, orders all
|
||
package print actions, and executes that root
|
||
([lines 1099–1124](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1099-L1124)).
|
||
- `builderTest` constructs the ordinary build/run/clean/print chain and gives
|
||
the run and print boundaries the failure handling needed to reach ordered
|
||
output; its compile-only branch instead uses a dependency-sensitive nop
|
||
print action
|
||
([lines 1133–1169 and 1185–1366](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1133-L1366)).
|
||
- `(*runTestActor).Act` turns a dependency build failure into a package test
|
||
result and sets exit status 1
|
||
([lines 1436–1521](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1436-L1521)).
|
||
Every non-nil execution error, including nonzero exit or abnormal/start
|
||
failure, likewise sets the exit status and emits the package failure result
|
||
([lines 1644–1774](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1644-L1774)).
|
||
- `builderCleanTest` and `builderPrintTest` put cleanup and captured package
|
||
output before the root status action
|
||
([lines 2237–2259](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L2237-L2259)).
|
||
`printExitStatus` then prints exactly `FAIL\n` when at least one package
|
||
argument was explicit and the global exit status is nonzero
|
||
([lines 2262–2284](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L2262-L2284)).
|
||
- Official `test_status.txt` requires a failing package, a later successful
|
||
package, and a final standalone `FAIL\n`
|
||
([lines 3–6](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_status.txt#L3-L6)).
|
||
Official `test_syntax_error_says_fail.txt` requires `FAIL` for an explicit
|
||
test build/setup syntax failure
|
||
([lines 1–13](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_syntax_error_says_fail.txt#L1-L13)).
|
||
- `testFlags` records explicit file operands in `pkgArgs`
|
||
([`cmd/go/internal/test/testflag.go`, lines 219–290](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/testflag.go#L219-L290));
|
||
`PackagesAndErrors` turns those files into the command-line package
|
||
([`cmd/go/internal/load/pkg.go`, lines 2895–2918](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L2895-L2918)),
|
||
which `GoFilesPackage` constructs
|
||
([lines 3244–3315](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L3244-L3315)).
|
||
|
||
Those source rules and official assertions are behavior directly implemented
|
||
or asserted by pinned Go. The single-explicit-package and raw-file cases are
|
||
derived from `len(pkgArgs) != 0` and the explicit-file loading path. The bare
|
||
implicit exclusion is derived from empty `pkgArgs`. The compile-only and
|
||
publication-only exclusions are derived from their uncleared dependency
|
||
failure preventing the root actor under the pinned work executor
|
||
([`cmd/go/internal/work/exec.go`, lines 134–205](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/exec.go#L134-L205)).
|
||
|
||
#### Fresh four-axis audit and direct pre-fix measurements
|
||
|
||
The bounded audit considered all four permanent axes and selected only this
|
||
test-command status gap:
|
||
|
||
- **Go-like build:** pinned unresolved-symbol handling and its undeclared-main
|
||
case are owned by `(*ErrorReporter).errorUnresolved`
|
||
([`cmd/link/internal/ld/errors.go`, lines 29–65](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/errors.go#L29-L65)),
|
||
with official assertions in `TestUndefinedRelocErrors`
|
||
([`cmd/link/internal/ld/ld_test.go`, lines 19–45](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/ld_test.go#L19-L45))
|
||
and `issue10978/main.go`
|
||
([lines 5–27](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/testdata/issue10978/main.go#L5-L27)).
|
||
Direct Cstage and WWstage no-main builds both exited 1 with identical linker
|
||
diagnostics and no output. This candidate was aligned.
|
||
- **Go-like test:** an explicit failing directory made both stages exit 1 with
|
||
empty stderr and byte-identical 207-byte stdout (SHA-256
|
||
`3d0d44d5d9c4d4d95446382807ee092a611f19b43dc3013cf8df76f135cb5c46`),
|
||
ending at its package failure rather than a standalone marker. A failing then
|
||
successful `-j 2` request had byte-identical 384-byte stdout (SHA-256
|
||
`4623567924df78375fcca84ff797b7cb89d06d3fd5382704d8b9ebb79916b9d9`)
|
||
ending at the successful `ok` result. A raw-file failure had byte-identical
|
||
121-byte stdout (SHA-256
|
||
`8db356ffc5b3a6d9df3308bfba8301329c5c07ce30c5ccd5cc5ee22a6c43331c`)
|
||
ending at harness accounting. Explicit missing-import build failure likewise
|
||
lacked the final marker. These directly measured pre-fix WW facts establish
|
||
the selected external difference. Bare implicit and `-c` failures already
|
||
omitted the marker and were aligned exclusions.
|
||
- **Go-like package:** `MultiplePackageError` and package scanning implement
|
||
conflicting selected declarations
|
||
([`go/build/build.go`, lines 538–548 and 931–967](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L538-L548));
|
||
`TestMultiplePackageImport` asserts the rule
|
||
([`go/build/build_test.go`, lines 105–133](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build_test.go#L105-L133)).
|
||
Both WW stages rejected an `alpha`/`beta` directory identically before tools.
|
||
This candidate was aligned.
|
||
- **Go-like import:** `unusedImports` and `errorUnusedPkg` implement the unused
|
||
renamed-import diagnostic
|
||
([`cmd/compile/internal/types2/resolver.go`, lines 706–740](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L706-L740));
|
||
official `importdecl0` asserts ordinary and renamed forms
|
||
([lines 9–27](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/importdecl0/importdecl0a.go#L9-L27)).
|
||
After normalizing only PID-bearing scratch roots, both WW stages produced the
|
||
same unused-renamed-import diagnostic and no output. This candidate was
|
||
aligned.
|
||
|
||
The command results in that list are directly measured WW behavior; the linked
|
||
source and tests are behavior directly implemented or asserted by pinned Go.
|
||
The conclusion that only test presentation changes while build, package, and
|
||
import identity remain fixed is behavior derived from the pinned action and
|
||
final-status placement.
|
||
|
||
#### Ownership, final behavior, and preserved boundaries
|
||
|
||
The directory owner is `internal/wwpackage.packagecommand`: its private
|
||
explicit-target bit affects only final status, and `pkgemitplan`/`pkgemitgroup`
|
||
record attributable build/run failure while preserving canonical result order.
|
||
After all package captures, package results, install attempts, and temporary-root
|
||
cleanup, the coordinator emits one final line. Attributable setup/load rejection
|
||
uses the same status helper. The two public drivers own the raw-file equivalent:
|
||
they remember the producer or process result, finish their existing cleanup,
|
||
then emit the line. A successful run followed only by install or cleanup failure
|
||
does not acquire test-failure status.
|
||
|
||
Loading and source selection, canonical package and import identity, graph
|
||
nodes, action construction, scheduling, compiler/assembler/linker invocation,
|
||
generated main, child argv/environment/cwd/stdin, capture bytes, package
|
||
diagnostics, and diagnostic precedence are unchanged. Runtime nonzero exit,
|
||
signal, timeout, and executable-start failure keep their existing
|
||
classification; only the command status line follows. One command-global bit
|
||
is isolated from every product-local capture, so parallel completion order
|
||
cannot duplicate or reorder it. If the coordinator itself is interrupted before
|
||
final emission no post-termination output is promised; an observed child
|
||
interruption is an ordinary run failure.
|
||
|
||
Artifact construction and bytes are unchanged. A failing running-retained test
|
||
still preserves prior public bytes and creates no new executable; successful
|
||
products in a mixed request retain their existing independent install results.
|
||
Producer failure, publication rejection, transaction rollback, cleanup, and
|
||
residue ownership are unchanged, and the marker creates no file. Physical
|
||
directories and the private explicit-target signal do not enter package,
|
||
import, graph, action, artifact, symbol, `.wwi`, publication, or persistence
|
||
identity. No persisted byte or key changed, so build workdir format remains
|
||
`18`, test workdir format remains `19`, and semantic storage format remains `3`.
|
||
|
||
The WW-native `explicit_test_failure_has_final_status` observer covers both
|
||
stages for single and concurrent failing/succeeding packages, filters, list
|
||
mode, raw files, setup/build and runtime failure, success, bare implicit and
|
||
compile-only exclusions, running retained rollback, artifact-byte equality,
|
||
diagnostic equality, exact cardinality/order, and `.new`/transaction cleanup.
|
||
Existing directory execution observers cover signals, timeouts, child cleanup,
|
||
and canonical-order behavior with the new final line, while build-mode controls
|
||
prove that the other command axis remains silent.
|
||
|
||
### 11.35 Implemented Go-like no-test-files package result
|
||
|
||
A source-bearing directory test product with no selected `*_test.ww` file now
|
||
reports exactly `? <package> [no test files]\n` after ordinary production
|
||
validation. It continues to create no test-support action, generated main,
|
||
link, runnable, retained binary, captured runtime result, or process. The rule
|
||
is shared by explicit directories, implicit current-directory selection,
|
||
logical/dotted targets, recursive discovery, and compile-only or retained-output
|
||
requests. Platform-ineligible test filenames do not prevent the result. A
|
||
selected helper-only test file remains a real test product with an empty
|
||
harness; the raw single-file compatibility route remains outside the
|
||
directory-owned selected-test-file classification.
|
||
|
||
#### Pinned Go evidence and fact classification
|
||
|
||
The sole authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `builderTest` detects
|
||
`len(p.TestGoFiles)+len(p.XTestGoFiles) == 0`, keeps ordinary production as a
|
||
dependency, constructs output-preparation and print actions, and creates no
|
||
real test binary or run action
|
||
([`cmd/go/internal/test/test.go`, lines 1133–1169](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1133-L1169)).
|
||
- `(*runTestActor).Act` owns that print action and writes exactly
|
||
`? \t%s\t[no test files]\n` in the ordinary non-coverage case
|
||
([`cmd/go/internal/test/test.go`, lines 1524–1557, especially 1551–1552](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1524-L1557)).
|
||
- Official `test_no_tests.txt` invokes `go test testnorun`, requires the
|
||
`[no test files]` result, and gives production an initializer that panics if a
|
||
test binary is linked and executed
|
||
([`cmd/go/testdata/script/test_no_tests.txt`, lines 1–14](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_no_tests.txt#L1-L14)).
|
||
|
||
Those source rules and the script expectation are behavior directly implemented
|
||
or asserted by pinned Go. That the ordinary case compiles production, prints the
|
||
package result, and does not execute initialization is behavior derived from the
|
||
pinned action graph. Applying the bracketed status to WW's established local
|
||
package presentation is likewise derived: WW has no module import path, but its
|
||
directory product already owns the corresponding selected-test-file decision
|
||
and no-process action branch. This does not import Go's coverage behavior,
|
||
module loader, cache, manifest, registry, or network resolution.
|
||
|
||
#### Fresh four-axis audit and direct pre-fix measurements
|
||
|
||
The bounded audit considered all four permanent axes and selected only this
|
||
test-result wording gap:
|
||
|
||
- **Go-like build:** pinned unresolved-symbol handling and its special missing
|
||
`main` case are implemented by `(*ErrorReporter).errorUnresolved`
|
||
([`cmd/link/internal/ld/errors.go`, lines 29–67](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/errors.go#L29-L67))
|
||
and asserted by `TestUndefinedRelocErrors`
|
||
([`cmd/link/internal/ld/ld_test.go`, lines 19–45](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/ld_test.go#L19-L45))
|
||
using `issue10978/main.go`
|
||
([lines 5–27](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/testdata/issue10978/main.go#L5-L27)).
|
||
Both WW stages rejected a selected `package main` without `fn main`, emitted
|
||
identical 50-byte linker diagnostics, and created no output. This candidate
|
||
was aligned.
|
||
- **Go-like test:** a production directory with an aborting initializer and no
|
||
test file made both stages exit 0 with empty stderr and byte-identical 55-byte
|
||
stdout (SHA-256
|
||
`36adf30792e2900b60ec8cd02ba86e0387acebd41c4d9aab186af2c649ffe67c`):
|
||
`? /tmp/ww-go1265-four-axis.Wq8d8H/notest [no tests]\n`.
|
||
Bare implicit, logical `-I`, and `-c` forms produced the same bytes; `-c`
|
||
created no binary. A platform-excluded test file produced the same old status
|
||
class without observing its missing import or test body. These are directly
|
||
measured pre-fix WW facts and establish the selected external difference.
|
||
- **Go-like package:** `MultiplePackageError` and the package scan reject
|
||
conflicting selected declarations
|
||
([`go/build/build.go`, lines 538–548 and 931–967](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L538-L548));
|
||
`TestMultiplePackageImport` asserts the file/name pairs
|
||
([`go/build/build_test.go`, lines 105–133](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build_test.go#L105-L133)).
|
||
Both WW stages rejected an `alpha`/`beta` production directory identically
|
||
before tools. This candidate was aligned.
|
||
- **Go-like import:** `unusedImports` and `errorUnusedPkg` implement unused
|
||
ordinary and renamed-import diagnostics
|
||
([`cmd/compile/internal/types2/resolver.go`, lines 706–740](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L706-L740));
|
||
official `importdecl0` asserts both forms
|
||
([`internal/types/testdata/check/importdecl0/importdecl0a.go`, lines 9–27](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/importdecl0/importdecl0a.go#L9-L27)).
|
||
After normalizing only PID-bearing scratch roots, both WW stages rejected an
|
||
unused renamed dotted import with the same diagnostic and no output. This
|
||
candidate was aligned.
|
||
|
||
The command observations in that list are directly measured WW behavior. The
|
||
linked source and testdata are behavior directly implemented or asserted by
|
||
pinned Go. Selecting only the no-test-files presentation while keeping build,
|
||
package, and import semantics fixed is behavior derived from the pinned action
|
||
boundary and WW's already aligned no-process topology.
|
||
|
||
#### Ownership, final behavior, and preserved boundaries
|
||
|
||
`internal/wwpackage.pkgemitgroup` is the sole semantic owner of the directory
|
||
package result. The loader still sets `g.notests` only after exact filename and
|
||
platform eligibility have selected the source set. Product construction still
|
||
compiles ordinary production and omits support/main/link/output/status actions;
|
||
the scheduler still skips execution. The successful result literal changes
|
||
only after that work succeeds. Loading, import, package, graph, compiler,
|
||
assembler, archiver, linker, or publication failure therefore retains its prior
|
||
diagnostic and precedence and cannot be hidden by a no-test-files result.
|
||
|
||
Canonical dotted package/import identity, declared names, file-local import
|
||
bindings, graph nodes and edges, action keys, physical-directory metadata,
|
||
symbols, `.wwi`, source units, assembly, objects, archives, and executable bytes
|
||
are unchanged. There is no new artifact or publication destination. `-c` and
|
||
`-o` still omit a binary and do not create an otherwise-unused output hierarchy;
|
||
prior caller state and persistent generations are preserved on every producer
|
||
failure. Warm reuse and invalidation still concern production actions only.
|
||
|
||
Concurrent products retain canonical ordered emission because the text remains
|
||
inside the existing group emitter. Interruption before emission makes no new
|
||
promise; the branch starts no child that can be signalled or timed out. Cleanup
|
||
still removes only request-private plan state, creates no `.new` or `.install`
|
||
stage, and leaves no test-process residue. Cstage and WWstage use the same
|
||
coordinator owner and therefore emit byte-identical diagnostics and results.
|
||
|
||
The WW-native `empty_and_invalid_package_classes` observer now requires the
|
||
exact explicit and implicit result in both stages and uses an aborting production
|
||
initializer to prove no process starts. Existing package observers cover
|
||
logical and recursive selection, platform filtering, helper-only selected test
|
||
files, compile-only/output omission, persistent cold/warm/invalidation behavior,
|
||
large scheduling sets, failure rollback, stage parity, and artifact-byte
|
||
identity. No persisted-byte contract changed: build workdir format remains
|
||
`18`, test workdir format remains `19`, and semantic storage format remains `3`.
|
||
|
||
### 11.36 Implemented original environment for directory test processes
|
||
|
||
Every directory-owned test binary actually started by `ww test` now receives a
|
||
Go-like snapshot of the caller environment instead of the package build plan's
|
||
locale and temporary directory. On the supported Unix boundary, the snapshot
|
||
keeps the first occurrence of every normal case-sensitive `key=value`, omits
|
||
later normal duplicates and raw empty entries, and preserves nonempty malformed
|
||
entries in order. The existing selected-toolchain `PATH` and package-directory
|
||
`PWD` are then appended as the only test-command overrides. Caller `LC_ALL`,
|
||
`TMPDIR`, empty-valued variables, case-distinct keys, and arbitrary variables
|
||
therefore reach initialization and test code.
|
||
|
||
#### Pinned Go evidence and fact classification
|
||
|
||
The sole authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `invoke` initializes `cfg.OrigEnv` from
|
||
`toolchain.FilterEnv(os.Environ())` before command work
|
||
([`cmd/go/main.go`, lines 290–305](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/main.go#L290-L305)).
|
||
`FilterEnv` removes only Go's internal toolchain-switch count variable
|
||
([`cmd/go/internal/toolchain/select.go`, lines 50–59 and 74–85](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/toolchain/select.go#L50-L85));
|
||
WW has no corresponding switch state.
|
||
- `OrigEnv` is the startup environment and user binaries during `go test` use
|
||
it instead of build-tool `CmdEnv`
|
||
([`cmd/go/internal/cfg/cfg.go`, lines 328–333](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/cfg/cfg.go#L328-L333)).
|
||
- Unix `copyenv`, `Getenv`, and `Environ` retain the first occurrence of a
|
||
normal case-sensitive key, clear later duplicates, omit cleared or empty
|
||
entries from `Environ`, and leave nonempty malformed entries present
|
||
([`syscall/env_unix.go`, lines 20–50](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/syscall/env_unix.go#L20-L50),
|
||
[66–84](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/syscall/env_unix.go#L66-L84),
|
||
and [135–145](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/syscall/env_unix.go#L135-L145)).
|
||
- `(*runTestActor).Act` clips `cfg.OrigEnv`, applies `AppendPATH` and
|
||
`AppendPWD`, assigns the result to the package-directory command, and runs it
|
||
([`cmd/go/internal/test/test.go`, lines 1661–1697](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1661-L1697)).
|
||
The two appenders are defined at
|
||
[`cmd/go/internal/base/env.go`, lines 15–45](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/base/env.go#L15-L45),
|
||
and explicit-command duplicate removal prefers their later `PATH` and `PWD`
|
||
values
|
||
([`os/exec/exec.go`, lines 1231–1308](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/os/exec/exec.go#L1231-L1308)).
|
||
- Official `test_env_term.txt` passes an explicitly empty caller `TERM` to a
|
||
test and requires it to remain empty
|
||
([lines 1–14](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_env_term.txt#L1-L14)).
|
||
`test_cache_inputs.txt` changes caller `TESTKEY` and its `TestLookupEnv`
|
||
requires the arbitrary variable to be present
|
||
([lines 19–38](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_cache_inputs.txt#L19-L38)
|
||
and [269–280](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_cache_inputs.txt#L269-L280)).
|
||
|
||
Those source rules and official assertions are behavior directly implemented or
|
||
asserted by pinned Go. That an ordinary caller `LC_ALL`, `TMPDIR`, case-distinct
|
||
key, or other variable survives unchanged is behavior derived from the pinned
|
||
pipeline: none is removed or replaced after the original snapshot. First-value
|
||
normalization, malformed-entry retention, raw-empty omission, and the separation
|
||
from build-tool `CmdEnv` are directly implemented by the cited source.
|
||
|
||
#### Fresh four-axis audit and direct pre-fix measurements
|
||
|
||
The bounded audit considered all four permanent axes and selected only this
|
||
test-runtime difference:
|
||
|
||
- **Go-like build:** pinned unresolved relocation handling gives missing
|
||
`main.main` its dedicated link failure
|
||
([`cmd/link/internal/ld/errors.go`, lines 45–65](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/errors.go#L45-L65)),
|
||
asserted by `TestUndefinedRelocErrors`
|
||
([`cmd/link/internal/ld/ld_test.go`, lines 20–45](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/ld_test.go#L20-L45)).
|
||
Both WW stages rejected a selected `package main` without `fn main`, emitted
|
||
identical linker diagnostics, and created no output. This candidate was
|
||
aligned.
|
||
- **Go-like test:** a direct `execve` arranger supplied duplicate `LC_ALL`,
|
||
`TMPDIR`, arbitrary, and `PWD` variables; one empty-valued normal variable; a
|
||
case-distinct key; repeated nonempty malformed entries; and one raw empty
|
||
entry. Both stages exited `0` with empty stderr and byte-identical stdout
|
||
(SHA-256
|
||
`5b541239c8e9109c512b6ec7b8c59d4b18bf79391096fb14891d8de108786993`).
|
||
The test reported caller arbitrary/empty/case-distinct values, but reported
|
||
`LC_ALL` and `TMPDIR` as changed, two visible occurrences of the arbitrary
|
||
normal key, and the raw empty entry still present. These are directly measured
|
||
pre-fix WW facts and establish the selected difference.
|
||
- **Go-like package:** `MultiplePackageError` and the directory scan reject
|
||
conflicting selected declarations
|
||
([`go/build/build.go`, lines 538–549](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L538-L549)
|
||
and [939–967](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L939-L967));
|
||
`TestMultiplePackageImport` plus official `testdata/multi` asserts the result
|
||
([`go/build/build_test.go`, lines 105–124](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build_test.go#L105-L124)).
|
||
Both WW stages rejected an `alpha`/`beta` source directory with byte-identical
|
||
diagnostics and no output. This candidate was aligned.
|
||
- **Go-like import:** `unusedImports` and `errorUnusedPkg` require a nonblank
|
||
renamed import to be used
|
||
([`cmd/compile/internal/types2/resolver.go`, lines 706–740](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L706-L740));
|
||
official `importdecl0` asserts the alias case
|
||
([`internal/types/testdata/check/importdecl0/importdecl0a.go`, lines 5–31](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/importdecl0/importdecl0a.go#L5-L31)).
|
||
Both WW stages rejected an unused local alias for dotted import `fmt` with
|
||
the same semantic diagnostic and no output. This candidate was aligned.
|
||
|
||
The command observations above are directly measured WW behavior. The linked
|
||
rules are behavior directly implemented or asserted by pinned Go. Applying the
|
||
original-environment pipeline at WW's directory-product launcher while leaving
|
||
its raw single-file compatibility route intact is behavior derived from the
|
||
pinned launch boundary and WW's local input model.
|
||
|
||
#### Ownership, final behavior, and preserved boundaries
|
||
|
||
`internal/wwpackage.runenv`, called only by `pkgstartrun`, is the semantic owner.
|
||
It walks the coordinator's inherited vector in order, uses a bounded fallible
|
||
open-addressed key table to retain the first normal case-sensitive occurrence,
|
||
omits raw empty entries, retains nonempty malformed entries, and excludes exact
|
||
uppercase `PATH` and `PWD`. It then appends the existing canonical selected
|
||
driver `PATH` and `PWD=<pkggroup.dir>`. The table is freed before launch;
|
||
`exec.start` deep-copies the command, after which the product-local vector and
|
||
its two generated strings are freed. Concurrent products share no writable
|
||
environment storage and the coordinator process is never mutated.
|
||
|
||
`toolenv` remains the separate build-plan owner. Compiler, assembler, in-driver
|
||
archiver, linker, support generation, generated-main construction, request
|
||
scratch, cwd, argv, stdin, diagnostics, and failure precedence are unchanged;
|
||
those tools still receive their established `LC_ALL=C` and request-private
|
||
`TMPDIR`. The raw single-file route already preserved caller locale and
|
||
temporary-directory values and remains outside this directory-owned
|
||
normalization slice. A directly invoked retained binary still inherits its
|
||
invoker's concrete environment without coordinator policy.
|
||
|
||
Loading and platform source selection are unchanged. Production, internal-test,
|
||
external-test, recompiled-for-test, support, and generated-main graph/action
|
||
identity remain separate and unchanged. Canonical dotted package/import
|
||
identity, declared names, file import bindings, physical-directory metadata,
|
||
symbols, `.wwi`, source units, assembly, objects, archives, executables, modes,
|
||
and artifact bytes do not contain the run environment. Imported or dependency
|
||
initialization code observes the corrected values only inside the selected
|
||
product process; no physical path or environment value becomes package, import,
|
||
graph, action, artifact, publication, or persistence identity.
|
||
|
||
`ww build`, `ww run`, directory `ww test -c` or `-S`, no-test products, and
|
||
loading/compiler/linker rejection start no test process, allocate no run
|
||
environment, and retain their prior diagnostics and outputs. A started test
|
||
observes the corrected snapshot before success, assertion failure, signal,
|
||
timeout, interruption, or child-created descendants. Those outcomes continue
|
||
through the existing process-group, capture, ordered-result, cancellation, and
|
||
cleanup owners. For a running retained request, private build and run still
|
||
precede guarded installation: runtime failure publishes nothing and preserves
|
||
prior bytes, while success installs the same private executable bytes. Producer
|
||
failure, output guard failure, and cleanup-only failure retain their existing
|
||
rollback and diagnostic precedence.
|
||
|
||
Persistent work records and artifact invalidation are unchanged; test results
|
||
are never cached. Environment-only changes perform the established warm final
|
||
link and always run the private test, without changing committed action bytes.
|
||
No `.new`, `.install`, `.wwtxn.*`, capture, result, process, or request scratch
|
||
survives its existing cleanup boundary. This runtime-only metadata change alters
|
||
no persisted-byte contract, so build workdir format remains `18`, test workdir
|
||
format remains `19`, and semantic storage format remains `3`.
|
||
|
||
The expanded WW-native `directory_test_execution_working_directory` observer
|
||
proves both-stage equality for nonempty and empty-valued variables; caller
|
||
`LC_ALL` and `TMPDIR`; first-wins normal duplicates; case-distinct and repeated
|
||
malformed entries; raw-empty omission; package `PWD` and selected-toolchain
|
||
`PATH`; production and test-only dependency initialization; internal, external,
|
||
combined, and test-only products; filters/list/no-match; recursive/equivalent
|
||
selection; serial/parallel scheduling; failure, signal, timeout, and child setup
|
||
failure; retained success and rollback; cold/warm/data-only persistence;
|
||
unchanged artifact and binary bytes; build/no-test/compile-only/rejection
|
||
nonexecution; unchanged raw/direct compatibility; exact tool locale/TMPDIR; and
|
||
stage, transaction, capture, and workdir cleanup.
|
||
|
||
### 11.37 Implemented empty list-mode output
|
||
|
||
A valid directory-owned `ww test -list` request now emits one qualified test
|
||
name per selected descriptor and emits no harness list bytes when its filters
|
||
select zero tests. The test product still starts, package initialization still
|
||
runs, the harness returns success without accounting, and the coordinator still
|
||
emits the normal package `ok` result. Ordinary non-list execution with zero
|
||
selected tests remains distinct: it keeps its
|
||
discovered/selected/started/completed accounting and, as implemented later in
|
||
section 11.39, uses the pinned no-tests warning and package-result suffix.
|
||
|
||
#### Pinned Go evidence and fact classification
|
||
|
||
The sole authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `cmd/go` registers `-list` among the flags forwarded to the test binary
|
||
([`cmd/go/internal/test/testflag.go`, function `init`, lines 32–80](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/testflag.go#L32-L80)).
|
||
- `testing.(*M).Run` calls `listTests`, sets exit code 0, and returns before the
|
||
ordinary test execution and no-tests warning
|
||
([`testing/testing.go`, lines 2407–2411](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/testing/testing.go#L2407-L2411)
|
||
and [2440–2458](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/testing/testing.go#L2440-L2458)).
|
||
- `listTests` validates the pattern and prints only inside successful match
|
||
branches. It has no zero-match output branch
|
||
([`testing/testing.go`, function `listTests`, lines 2509–2535](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/testing/testing.go#L2509-L2535)).
|
||
- `testShowPass` retains successful list output, while the successful run actor
|
||
adds a no-tests suffix only if the captured bytes contain the ordinary
|
||
no-tests warning
|
||
([`cmd/go/internal/test/test.go`, function `testShowPass`, lines 649–652](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L649-L652)
|
||
and method `(*runTestActor).Act`, lines 1706–1732](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1706-L1732)).
|
||
- Official `list_test_simple.txt` asserts that list mode emits the matching Test,
|
||
Benchmark, and Example names
|
||
([`cmd/go/testdata/script/list_test_simple.txt`, lines 3–14](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/list_test_simple.txt#L3-L14)).
|
||
|
||
Those source branches and official positive assertions are behavior directly
|
||
implemented or asserted by pinned Go. That a zero-match `go test -list` run has
|
||
no list payload, avoids the ordinary no-tests warning, and may still receive the
|
||
command's normal successful package result is behavior derived from their
|
||
composition. WW retains its local `-list` plus `-run`/`-filter` syntax; only the
|
||
applicable selected-name and empty-result behavior is aligned.
|
||
|
||
#### Fresh four-axis audit and direct pre-fix measurements
|
||
|
||
The bounded audit examined all four permanent axes before selecting this test
|
||
runtime difference:
|
||
|
||
- **Go-like build:** pinned `(*ErrorReporter).errorUnresolved` gives a missing
|
||
`main.main` a dedicated failure
|
||
([`cmd/link/internal/ld/errors.go`, lines 29–67](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/errors.go#L29-L67)),
|
||
asserted by `TestUndefinedRelocErrors` and official `issue10978`
|
||
([`cmd/link/internal/ld/ld_test.go`, lines 19–45](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/ld_test.go#L19-L45),
|
||
[`testdata/issue10978/main.go`, lines 5–27](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/testdata/issue10978/main.go#L5-L27)).
|
||
Both WW stages rejected a selected command package without `fn main`, emitted
|
||
zero stdout and the same 50 stderr bytes (SHA-256
|
||
`9ed4d7684412c6d2e615041902072c81e9e09acb3970246d89a2c8bdddd2fcfa`),
|
||
and published no output. This audited applicable property was aligned.
|
||
- **Go-like test:** for a directory containing one `visible` test, both stages
|
||
ran `test -list -run no_such_test`, exited 0 with empty stderr, and emitted the
|
||
same 78 stdout bytes (SHA-256
|
||
`d59638ab03a27803ca8e3fd884f341bbb1535ec9604fb69bdff1de4f608a8da0`):
|
||
`[no matches]\n` followed by the normal package result. Positive list
|
||
selection printed `list_nomatch.visible` once in both stages. This synthetic
|
||
empty-result line was the selected difference.
|
||
- **Go-like package:** pinned `MultiplePackageError` and directory scanning
|
||
reject conflicting declarations
|
||
([`go/build/build.go`, lines 538–549](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L538-L549)
|
||
and [939–967](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L939-L967)),
|
||
asserted by `TestMultiplePackageImport` and official `testdata/multi`
|
||
([`go/build/build_test.go`, lines 105–133](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build_test.go#L105-L133),
|
||
[`testdata/multi/file.go`, lines 1–5](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/testdata/multi/file.go#L1-L5),
|
||
and [`file_appengine.go`, lines 1–5](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/testdata/multi/file_appengine.go#L1-L5)).
|
||
Both WW stages rejected an `alpha`/`beta` directory with zero stdout and the
|
||
same 159 stderr bytes (SHA-256
|
||
`eaaa0c91f41b5d3deac4caf4299d5c7c650a1330be9b43edd090b8bfea906076`).
|
||
This audited applicable property was aligned.
|
||
- **Go-like import:** pinned `unusedImports` and `errorUnusedPkg` reject a
|
||
nonblank unused alias
|
||
([`cmd/compile/internal/types2/resolver.go`, lines 706–740](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L706-L740)),
|
||
asserted by official `importdecl0`
|
||
([`internal/types/testdata/check/importdecl0/importdecl0a.go`, lines 9–26](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/importdecl0/importdecl0a.go#L9-L26)).
|
||
Both WW stages rejected an unused `spare` alias for dotted import `dep` with
|
||
zero stdout and the same diagnostic after only private scratch-PID
|
||
normalization (SHA-256
|
||
`a429b027e92d52de1c5ec581b1f45c860b0e85b459c3ac7347e2719900cec511`).
|
||
This audited applicable property was aligned without changing dotted import
|
||
identity.
|
||
|
||
The command observations and byte hashes are directly measured WW behavior.
|
||
The linked source branches and testdata assertions are behavior directly
|
||
implemented or asserted by pinned Go. Applying the empty-list rule to WW's one
|
||
local directory-owned test product while retaining its manifest-free input and
|
||
filter syntax is behavior derived from that pinned execution boundary.
|
||
|
||
Pre-fix `test -c` products were byte-identical between Cstage and WWstage:
|
||
112829 bytes, SHA-256
|
||
`d2994ef440d7ceb9be0a7caf53c90dd19d208e847e51ff41ecb89504f825c4c8`.
|
||
Directly running either retained product with the same nonmatching list filter
|
||
already emitted no stdout or stderr because it had no coordinator-supplied
|
||
package prefix. Explicit raw-file requests with package options remained a
|
||
separate rejected CLI shape in both stages.
|
||
|
||
#### Ownership, final behavior, and preserved boundaries
|
||
|
||
`lib/test.run` is the semantic owner. Its existing descriptor loop still
|
||
qualifies, filters, and prints every positive list match in order; its list
|
||
return now emits nothing extra when the selected count is zero. The package
|
||
coordinator does not recognize or strip a magic line, so identical bytes written
|
||
by package initialization or user code remain ordinary captured output.
|
||
|
||
Loading and platform source selection are unchanged. Production,
|
||
internal-test, external-test, recompiled-for-test, support, and generated-main
|
||
nodes and actions remain unchanged. Exact dotted import identity, declared
|
||
package names, aliases, variants, physical runtime directories, graph edges,
|
||
initialization order, symbols, and publication names keep their existing roles.
|
||
The product process and package initialization still run in list mode; no
|
||
per-test child starts. Positive matching, option diagnostics and precedence,
|
||
ordinary non-list no-match output, no-test-file results, and raw-file rejection
|
||
were unchanged by this list-only slice; section 11.39 subsequently changes only
|
||
the ordinary no-match warning and successful result annotation.
|
||
|
||
The shared support implementation change legitimately changes its object,
|
||
archive, and linked test-product bytes. Its exported signature and `.wwi` byte
|
||
contract do not change. Existing content invalidation rebuilds the affected
|
||
support/link actions; there is no test-result cache and no new graph identity.
|
||
Running `-o` still executes the private product before guarded publication, and
|
||
`-c`, destination safety, transaction rollback, prior-output preservation, and
|
||
artifact modes are unchanged.
|
||
|
||
Load, compile, assemble, archive, link, initialization, signal, timeout,
|
||
interruption, child-start, publication, and cleanup failure paths retain their
|
||
existing diagnostics and precedence. Parallel products keep independent
|
||
processes, captures, environments, working directories, input descriptors, and
|
||
ordered result slots. The changed runtime branch allocates and publishes no
|
||
file, and existing cleanup remains responsible for `.new`, `.install`,
|
||
`.wwtxn.*`, captures, process groups, and request scratch.
|
||
|
||
The WW-native `list_mode_with_no_matches_emits_no_sentinel` observer proves
|
||
both stages across concurrent combined and test-only products, package
|
||
initialization, cold and warm persistent work, absence of list/accounting
|
||
sentinels, positive deterministic selection, running `-o` retention, later
|
||
direct execution, stage stdout/stderr equality, retained executable byte
|
||
identity, and `.new` cleanup. The existing routing observer separately keeps
|
||
the section-11.37 baseline for ordinary non-list reporting; section 11.39
|
||
supersedes that private marker while retaining the accounting.
|
||
|
||
No persisted-byte contract changed: build workdir format remains `18`, test
|
||
workdir format remains `19`, and semantic storage format remains `3`.
|
||
|
||
### 11.38 Implemented declared-`main` function-kind semantics
|
||
|
||
A package whose **declared package name** is `main` now rejects every
|
||
package-scope non-function declaration named `main`. `let`, `const`, `def`, and
|
||
`type` forms receive `cannot declare main - must be func` from either compiler
|
||
checker and are not installed in package scope. The rule is deliberately
|
||
narrower than Go's complete source signature rule: WW retains its established
|
||
C/Hare-style program-entry ABI, including supported argument- and
|
||
result-bearing function declarations.
|
||
|
||
#### Pinned Go evidence and fact classification
|
||
|
||
The sole authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `types2.(*Checker).declarePkgObj` tests both identifier spelling `main` and
|
||
`check.pkg.name == "main"`, emits `cannot declare main - must be func`, and
|
||
returns without declaring the object
|
||
([`cmd/compile/internal/types2/resolver.go`, lines 90–110](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L90-L110)).
|
||
The public checker implements the same condition and return
|
||
([`go/types/resolver.go`, method `(*Checker).declarePkgObj`, lines 103–124](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L103-L124)).
|
||
- Official type-checker testdata rejects constant, type, and variable
|
||
declarations named `main` in package `main`
|
||
([`internal/types/testdata/check/decls5.go`, lines 5–10](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/decls5.go#L5-L10)).
|
||
The fixed-bug test also rejects `var main = func() {}`: a variable containing
|
||
a function is still not a function declaration
|
||
([`test/fixedbugs/issue21256.go`, lines 1–9](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/fixedbugs/issue21256.go#L1-L9)).
|
||
|
||
Those conditions, diagnostics, early returns, and testdata assertions are
|
||
**behavior directly implemented or asserted by pinned Go**. That the semantic
|
||
owner is package declaration checking; that a rejected object does not become
|
||
the entry binding; and that declared package name rather than canonical path,
|
||
path leaf, physical directory, or command selection owns the rule are
|
||
**behavior derived from the pinned implementation**.
|
||
|
||
Pinned Go separately requires a function `main` in package `main` to have no
|
||
arguments or results
|
||
([`cmd/compile/internal/types2/resolver.go`, method
|
||
`(*Checker).collectObjects`, lines 416–444](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L416-L444)),
|
||
asserted by official `mainsig.go`
|
||
([lines 7–13](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/mainsig.go#L7-L13)).
|
||
That is also **behavior directly implemented or asserted by pinned Go**, but it
|
||
does not honestly apply to WW's source ABI. Both baseline WW stages accepted
|
||
`fn main(x: i32) void` and `fn main() i32`, produced byte-identical
|
||
executables, and ran them successfully; WW's own self-hosted command tools use
|
||
`main(argc: i32, argv: **u8) i32`. Those observations are **directly measured
|
||
WW behavior**. Preserving those function forms while applying the independent
|
||
declaration-kind requirement is **behavior derived from the pinned
|
||
implementation within WW's applicable model boundary**.
|
||
|
||
#### Fresh four-axis audit and direct pre-fix measurements
|
||
|
||
The bounded audit examined all four permanent axes before this package slice
|
||
was selected:
|
||
|
||
- **Go-like build:** pinned `(*ErrorReporter).errorUnresolved` gives missing
|
||
`main.main` a dedicated error
|
||
([`cmd/link/internal/ld/errors.go`, lines 29–67](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/errors.go#L29-L67)),
|
||
asserted by `TestUndefinedRelocErrors`
|
||
([`cmd/link/internal/ld/ld_test.go`, lines 19–45](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/ld_test.go#L19-L45))
|
||
and official `testdata/issue10978/main.go` lines 5–27. Both WW stages
|
||
rejected a selected `main` package with no entry, emitted empty stdout and
|
||
the same 50 stderr bytes (SHA-256
|
||
`9ed4d7684412c6d2e615041902072c81e9e09acb3970246d89a2c8bdddd2fcfa`),
|
||
and published nothing. This applicable control was aligned.
|
||
- **Go-like test:** pinned `isTestFunc` and `checkTestFunc` define and reject a
|
||
wrong test function shape
|
||
([`cmd/go/internal/load/test.go`, lines 555–579 and 775–787](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L555-L579)),
|
||
with the official wrong-signature script anchor at
|
||
[`cmd/go/testdata/script/test_main.txt`, lines 11–13 and 30–40](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_main.txt#L11-L13).
|
||
Both WW stages rejected `@test fn bad(x: i32) void` before execution, emitted
|
||
the same semantic diagnostic, no accounting, and final `FAIL\n` stdout
|
||
(SHA-256
|
||
`4f8e9e45f8a9e1843b81eaf3bdf52a6b778d415d23bf985774a9d34a43f69bd5`).
|
||
This applicable control was aligned.
|
||
- **Go-like package:** baseline Cstage accepted `let main`, `const main`, and
|
||
`def main`, published mode-0755 executables, and those executables exited 139
|
||
with empty output. The `let`/`const` executable SHA-256 was
|
||
`edd3bad62be69701a373aa0567972bfb976690b0332b8c117891125254fc85b5`;
|
||
the `def` executable SHA-256 was
|
||
`9e56d6710395b287e18e85187eee86d846927c6f3ea91216858c6026f38ebdff`.
|
||
Cstage `type main` and every WWstage non-function form instead reached the
|
||
linker's missing-`main` failure. Neither stage emitted the pinned package
|
||
diagnostic. Both stages accepted a directory command package containing
|
||
`let main` plus a valid internal test, ran it, and reported package `ok` with
|
||
byte-identical 178-byte stdout (SHA-256
|
||
`a6e165fb558be62932e217ccd1d3175348f7490489bca8e9828872e28c01236f`).
|
||
This was the selected difference.
|
||
- **Go-like import:** pinned `unusedImports` and `errorUnusedPkg` reject a
|
||
nonblank unused alias
|
||
([`cmd/compile/internal/types2/resolver.go`, lines 706–740](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L706-L740)),
|
||
asserted by official `importdecl0a.go` lines 9–27. Both WW stages rejected
|
||
unused `import spare audit.dep;`, emitted empty stdout, and reported
|
||
`"audit.dep" imported as spare and not used`. This applicable control was
|
||
aligned.
|
||
|
||
The WW command results, output lengths, hashes, exit statuses, and runtime
|
||
signals are **directly measured WW behavior**. The linked source and testdata
|
||
facts are **behavior directly implemented or asserted by pinned Go**. Selecting
|
||
the declaration-kind rule while excluding the incompatible function-signature
|
||
rule is **behavior derived from the pinned implementation**.
|
||
|
||
As an identity control, both stages built `package utility; export let main:
|
||
i32 = 7` as byte-identical 924-byte archives (SHA-256
|
||
`10382e7812229d73c4acefdf8988a13372b6eb7a2981559b3adade524ed5a929`).
|
||
That is **directly measured WW behavior** and pins the required non-effect for
|
||
non-`main` declared packages.
|
||
|
||
#### Ownership, final behavior, and preserved boundaries
|
||
|
||
`reject_nonfunction_main_decls` in `cmd/wcc/check.c` and its self-hosted twin
|
||
`rejectnonfunctionmaindecls` in `selfhost/cmd/wcc/check.ww` are the semantic
|
||
owners. They run after parsing but before qualified-use discovery and package
|
||
name installation. Each walks selected top-level declarations, tests the
|
||
declaration-carried `pkgname`, reports the pinned diagnostic, and removes only
|
||
the rejected node from subsequent package-scope checking. This mirrors the
|
||
pinned resolver's return-before-declare behavior. No driver mode, entry flag,
|
||
canonical action key, directory classification, or linker-symbol heuristic is
|
||
consulted.
|
||
|
||
Direct post-fix calls to `w6c` and `w6c_ww` on the same invalid source now exit
|
||
1 with empty stdout, no assembly output, and byte-identical 102-byte stderr
|
||
(SHA-256
|
||
`39001ed88e2ab8b7675fcc51b4b794cf8ebc2a803e1f05de45d7d0ba1cd98a38`)
|
||
ending in `cannot declare main - must be func`. Directory builds of all four
|
||
forms fail through `ww: w6c failed for ...`, never reach `w6a` or `w6l`, publish
|
||
no output, and give byte-identical Cstage/WWstage diagnostics when the owned
|
||
output path is the same. Directory tests emit only the command-owned final
|
||
`FAIL\n` on stdout, report build failure on stderr, and emit no test body,
|
||
accounting, or package `ok` result.
|
||
|
||
Loading and Go-platform source eligibility are unchanged. Production and test
|
||
source selection still determines which declarations reach the checker; an
|
||
excluded source has no effect. Declared package name remains independent from
|
||
canonical dotted identity, aliases, path leaf, filename, physical directory,
|
||
requested root, output name, linker order, and artifact/storage locator. A
|
||
dependency physically and canonically ending in `main` but declared `utility`
|
||
continues to export `main`, bind through its declared qualifier, and produce
|
||
stage-byte-identical `.unit.ww`, `.wwi`, assembly, object, archive, and command
|
||
executable bytes. Valid `main(argc, argv) i32` and `main() i32` commands remain
|
||
accepted and byte-identical between stages.
|
||
|
||
Graph construction and action identities are unchanged for valid programs. An
|
||
invalid selected command or command-test variant reaches its normal compiler
|
||
action and fails there; assembler, archiver, linker, runtime, generated test
|
||
execution, and publication do not become alternative semantic owners. An
|
||
ordinary import of a declared-`main` package is still rejected earlier by the
|
||
loader as `ww: package PATH is a program, not an importable package`, even when
|
||
that command also contains the malformed declaration. This preserves import
|
||
diagnostic precedence and the toolchain-owned external-test exception.
|
||
|
||
Cold rejection creates no output or retained scratch. Warm rejection after a
|
||
successful command preserves the complete committed owner unit, interface,
|
||
assembly, object, archive, init unit/assembly/object, tool vouchers, workdir
|
||
stamp, and public executable byte for byte. It installs no staged generation;
|
||
exact source restoration reuses the committed action and reproduces the prior
|
||
binary. There is no test-result cache and no new reuse key. Producer failure,
|
||
rollback, existing-output preservation, concurrent action isolation,
|
||
interruption, process cleanup, and transaction cleanup continue through their
|
||
existing owners; the checker adds no process, descriptor, mutable global state,
|
||
or cleanup path. No active `.new`, `.install`, `.wwtxn.*`, adjacent rejection
|
||
scratch, test child, or capture survives the tested failure boundaries.
|
||
|
||
The WW-native `nonfunction_main_declarations_reject` observer proves all four
|
||
non-function kinds, exact direct-compiler stage parity, cold build rejection,
|
||
directory-test nonexecution, declared-name/dotted-import/physical-leaf
|
||
separation, supported entry ABI preservation, valid artifact-byte parity,
|
||
command-import precedence, complete warm work/publication rollback, restored
|
||
reuse, and residue absence. Existing interruption and concurrent-transaction
|
||
observers remain the owners of those unchanged mechanisms; this declaration
|
||
check introduces no independently interruptible or shared state.
|
||
|
||
No valid persisted-byte contract changed. Build workdir format remains `18`,
|
||
test workdir format remains `19`, and semantic storage format remains `3`.
|
||
|
||
### 11.39 Implemented ordinary zero-match test results
|
||
|
||
An ordinary successful directory `ww test` whose valid `-run`/`-filter`
|
||
selection starts no registered test now uses Go's externally visible no-tests
|
||
protocol. The shared test runtime writes exactly
|
||
`testing: warning: no tests to run\n` through standard error, retains WW's
|
||
discovered/selected/started/completed accounting, and returns success. The
|
||
directory coordinator recognizes that exact line at capture byte zero or after
|
||
a newline and appends ` [no tests to run]` to the corresponding successful
|
||
package `ok` result. WW's former `[no matches]` sentinel is no longer emitted.
|
||
|
||
This is deliberately distinct from the completed list-mode rule: list mode
|
||
returns before the warning/accounting branch and retains an unsuffixed package
|
||
result. A source-bearing directory without test files also retains its separate
|
||
`? <package> [no test files]` result and starts no runtime product.
|
||
|
||
#### Pinned Go evidence and fact classification
|
||
|
||
The sole semantic authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `testing.(*M).Run` returns directly from list mode at lines 2407–2411. In
|
||
ordinary execution it gathers whether tests, examples, or fuzz targets ran,
|
||
writes exactly `testing: warning: no tests to run` to stderr when none did,
|
||
and keeps the outcome successful when no independent failure occurred
|
||
([`testing/testing.go`, lines 2432–2485](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/testing/testing.go#L2432-L2485)).
|
||
- `cmd/go` defines the line-delimited `noTestsToRun` marker
|
||
([`cmd/go/internal/test/test.go`, line 1385](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1385))
|
||
and, after a successful test process, recognizes it at capture byte zero or
|
||
after a newline and appends ` [no tests to run]` to the package result
|
||
([method `(*runTestActor).Act`, lines 1706–1732](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1706-L1732)).
|
||
- Official script/testdata `test_match_no_tests.txt` runs one registered test
|
||
through a nonmatching filter and asserts the suffixed successful package
|
||
result
|
||
([lines 1–11](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_match_no_tests.txt#L1-L11)).
|
||
- Official precedence script/testdata `test_match_no_tests_build_failure.txt`
|
||
asserts that a build failure under a nonmatching filter produces `FAIL` and
|
||
does not acquire a successful no-tests result
|
||
([lines 1–18](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_match_no_tests_build_failure.txt#L1-L18)).
|
||
|
||
Those branches, exact bytes, success conditions, delimiter checks, result
|
||
suffix, and script assertions are **behavior directly implemented or asserted
|
||
by pinned Go**. That the runtime owns whether a test ran, the coordinator owns
|
||
the package-result annotation, a build failure precedes both, and an arbitrary
|
||
mid-line substring is not the marker are **behavior derived from the pinned
|
||
implementation**.
|
||
|
||
WW retains its fnmatch-based local `-run`/`-filter` language rather than
|
||
adopting Go regular expressions. WW also has an established always-visible
|
||
harness report rather than Go's quiet/`-v` presentation switch, so this slice
|
||
does not suppress every successful product capture or replace WW accounting
|
||
with Go's `PASS` line. Within that honest local presentation boundary, the
|
||
zero-execution warning, stream owner, success classification, marker delimiter,
|
||
and package annotation apply directly.
|
||
|
||
#### Fresh four-axis audit and direct pre-fix measurements
|
||
|
||
The bounded audit examined all four permanent axes before selecting this test
|
||
runtime/coordinator difference. Commands used Cstage `out/bin/ww` and WWstage
|
||
`out/bin/ww_ww` against identical sources:
|
||
|
||
- **Go-like build:** pinned linker method
|
||
`(*ErrorReporter).errorUnresolved` gives missing `main.main` a dedicated
|
||
failure ([`cmd/link/internal/ld/errors.go`, lines 29–67](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/errors.go#L29-L67)),
|
||
asserted by `TestUndefinedRelocErrors` and official `issue10978`
|
||
([`cmd/link/internal/ld/ld_test.go`, lines 19–45](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/ld_test.go#L19-L45),
|
||
[`testdata/issue10978/main.go`, lines 5–27](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/testdata/issue10978/main.go#L5-L27)).
|
||
Both WW stages rejected a declared-main package with no entry, emitted empty
|
||
stdout and the same 50 stderr bytes (SHA-256
|
||
`9ed4d7684412c6d2e615041902072c81e9e09acb3970246d89a2c8bdddd2fcfa`),
|
||
and published nothing. This applicable build property was aligned.
|
||
- **Go-like test:** with one registered test, both stages exited 0 for
|
||
`test -run no-such-*`, emitted empty stderr, and emitted the same 120 stdout
|
||
bytes (SHA-256
|
||
`ca12f88ebf1f94d3a2ca63ed1bc1e9b5a4811a660df3af4e70c7b9624ef97c40`):
|
||
`[no matches]`, zero-selection accounting, and an unsuffixed package `ok`.
|
||
This private marker and missing result annotation were the selected gap.
|
||
Empty list selection and positive ordinary selection were already aligned
|
||
controls and stayed outside the changed branch.
|
||
- **Go-like package:** pinned `MultiplePackageError` and directory scanning
|
||
reject conflicting declarations
|
||
([`go/build/build.go`, lines 538–549](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L538-L549)
|
||
and [939–967](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L939-L967)),
|
||
asserted by `TestMultiplePackageImport` and official `testdata/multi`
|
||
([`go/build/build_test.go`, lines 105–133](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build_test.go#L105-L133)).
|
||
Both WW stages rejected one `first`/`second` directory with empty stdout and
|
||
byte-identical 161-byte stderr (SHA-256
|
||
`a2d95681b8a97d55c26367084cd294632fa015882d1aa53b0df63f24bcf24ced`).
|
||
This applicable package property was aligned.
|
||
- **Go-like import:** pinned `unusedImports` and `errorUnusedPkg` reject every
|
||
nonblank unused import
|
||
([`cmd/compile/internal/types2/resolver.go`, lines 706–740](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L706-L740)),
|
||
asserted by official `importdecl0a.go`
|
||
([lines 9–26](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/importdecl0/importdecl0a.go#L9-L26)).
|
||
Both stages rejected an unused dotted `fmt` import with empty stdout and the
|
||
same semantic diagnostic;
|
||
raw stderr differed only in the deliberately stage-named private output path.
|
||
This applicable import property was aligned.
|
||
|
||
The WW statuses, streams, lengths, hashes, and diagnostics are **directly
|
||
measured WW behavior**. The linked official implementation and testdata are
|
||
**behavior directly implemented or asserted by pinned Go**. Applying the
|
||
runtime/coordinator split without changing WW's filter syntax or harness report
|
||
is **behavior derived from the pinned implementation**.
|
||
|
||
#### Ownership, final behavior, and preserved boundaries
|
||
|
||
`lib/test/run.ww` is the runtime owner. Its existing `selected == 0` branch now
|
||
writes the pinned warning through the same EINTR-safe fd writer used elsewhere,
|
||
targeting stderr, then writes the unchanged accounting to stdout and returns 0.
|
||
Its earlier list return is untouched. A directly invoked retained binary
|
||
therefore exposes the warning on stderr and accounting on stdout.
|
||
|
||
`internal/wwpackage/package.ww` is the directory result owner. It already gives
|
||
each product one combined stdout/stderr capture and emits that capture in
|
||
canonical group order. Its new predicate accepts only the exact warning at byte
|
||
zero or following `\n`; after `pkgrunok` succeeds, `pkgemitgroup` appends the
|
||
suffix to the result it already owns. Text embedded mid-line in a running test
|
||
does not match. A failed, signalled, timed-out, interrupted, or unstartable test
|
||
does not reach the successful result. A producer failure never starts the
|
||
runtime and cannot synthesize the warning or suffix.
|
||
|
||
Both selected driver stages compile the same `lib/test` code into test products
|
||
and delegate directory execution to the same WW-native coordinator, so no
|
||
C-only or self-host-only semantic fork was introduced. Direct post-fix probes
|
||
through both stages exited 0, emitted empty coordinator stderr, and emitted the
|
||
same 159 stdout bytes (SHA-256
|
||
`a67242ab79b9bd9bca1a32073c1fccbb9aa4fa9d8ad52ced667b25c54dc1be08`):
|
||
the warning, unchanged accounting, and suffixed package result.
|
||
|
||
Loading and Go-platform source selection are unchanged. Production,
|
||
internal-test, external-test, recompiled-for-test, support, and generated-main
|
||
graph nodes and actions are unchanged. Compilers, assemblers, archivers, and
|
||
linkers retain their diagnostics and scheduling. The support implementation
|
||
change legitimately changes its object/archive and linked test-product bytes,
|
||
but its exported signature and `.wwi` contract do not change; valid Cstage and
|
||
WWstage retained products remain byte-identical.
|
||
|
||
Declared package names and canonical dotted import identities remain separate.
|
||
The coordinator annotates an already-owned result; it derives no identity from
|
||
the warning, alias, declared name, path leaf, filename, physical directory,
|
||
output path, artifact name, or linker order. Physical directories remain test
|
||
cwd and result-label metadata only, never package/import/graph/action/artifact/
|
||
symbol/`.wwi`/publication/persistence identity.
|
||
|
||
Cold and warm persistent work produce identical result bytes and still run the
|
||
test product because there is no test-result cache. A successful retained run
|
||
publishes the privately tested executable through the existing guarded install.
|
||
A later producer failure preserves prior public bytes, and restored valid reuse
|
||
reproduces the same warning/suffix without rewriting an identical executable.
|
||
Publication rejection, rollback, existing-output preservation, concurrency,
|
||
interruption, process-group cancellation, capture separation, final `FAIL`, and
|
||
cleanup remain with their existing owners. No active `.new`, `.install`,
|
||
`.wwtxn.*`, adjacent `.sepwork`, process, or capture residue is introduced.
|
||
|
||
The WW-native `ordinary_no_match_uses_go_warning_and_result_suffix` observer
|
||
proves both stages; cold/warm reuse; concurrent reverse-requested packages and
|
||
ordered per-product markers; exact mid-line rejection; positive, list, and
|
||
no-test-files controls; retained publication and direct stderr ownership;
|
||
producer-failure precedence; cold/repeated failure; prior-output preservation;
|
||
restored reuse; normalized diagnostic parity; retained executable byte identity;
|
||
and transaction/output-scratch cleanup. Existing signal, timeout, interruption,
|
||
and process-group observers continue to prove those unchanged mechanisms.
|
||
|
||
This is runtime/coordinator presentation, not a persisted-byte contract. Build
|
||
workdir format remains `18`, test workdir format remains `19`, and semantic
|
||
storage format remains `3`.
|
||
|
||
### 11.40 Implemented current-directory default build names
|
||
|
||
An empty `ww build` package list selects the current directory just as an
|
||
explicit `.`, `./`, or equivalent sequence of single-dot components does. For
|
||
one command package and no explicit `-o`, the public executable is now named by
|
||
the selected directory's final component. The selector is loading syntax; it
|
||
is not the literal output pathname. Thus a command built while the current
|
||
directory is `tool` publishes `tool`, not `.`, and cold private build artifacts
|
||
use `tool.sepwork`, not `..sepwork`.
|
||
|
||
A non-main current-directory package uses the same corrected cold scratch stem,
|
||
but still has no link or public installation action. An explicit `-o`, exact
|
||
`-o /dev/null`, an ordinary non-current directory operand, and a contextual
|
||
dotted package request keep their established output rules.
|
||
|
||
#### Pinned Go evidence and fact classification
|
||
|
||
The sole semantic authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `search.CleanPatterns` turns an empty package-pattern list into exactly `.`;
|
||
`ImportPathsQuiet` then treats that local pattern as a directory selection
|
||
([`cmd/go/internal/search/search.go`, lines 441–480](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/search/search.go#L441-L480)).
|
||
- `work.runBuild` loads packages and checks load errors before output planning.
|
||
With exactly one loaded `main` package and no `-o`, it selects
|
||
`DefaultExecName`
|
||
([`cmd/go/internal/work/build.go`, lines 459–478](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L459-L478)).
|
||
- `load.(*Package).exeFromImportPath` takes the final loaded import-path
|
||
element, while `DefaultExecName` uses a source basename only for a
|
||
command-line-files package
|
||
([`cmd/go/internal/load/pkg.go`, lines 1727–1769](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L1727-L1769)).
|
||
- Official command testdata distinguishes module naming from the manifest-free
|
||
GOPATH case and requires bare `go build` to create the directory-named `src`
|
||
executable
|
||
([`clean_binary.txt`, lines 15–28](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/clean_binary.txt#L15-L28)).
|
||
A second manifest-free script changes to `m`, runs bare `go build`, and
|
||
requires executable `m`
|
||
([`gccgo_m.txt`, lines 4–14](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/gccgo_m.txt#L4-L14));
|
||
`build_static.txt` likewise builds and executes the default `hello`
|
||
([lines 11–14](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/build_static.txt#L11-L14)).
|
||
|
||
Those selection, loading, default-name branches and script assertions are
|
||
**behavior directly implemented or asserted by pinned Go**. WW has no module
|
||
or manifest identity for a literal root, so using the selected local directory
|
||
leaf as its already-specified presentation fallback is **behavior derived from
|
||
the pinned implementation**. The directory remains loader metadata and does
|
||
not become canonical package or import identity.
|
||
|
||
#### Fresh four-axis audit and direct pre-fix measurements
|
||
|
||
The bounded audit examined every permanent axis before choosing this build
|
||
presentation difference. Both public stages were measured at the same source
|
||
paths:
|
||
|
||
- **Go-like build:** multi-command directory selection without `-o` was already
|
||
aligned. For a valid command in directory `a`, however, bare `build`,
|
||
`build .`, and `build ./` each exited 1 in both stages with empty stdout and
|
||
the same 55 stderr bytes (SHA-256
|
||
`2e8030a9eeb7187fbc1cb4ee9d794c352f1c31c92c884f8ae09a57e39bfe86db`):
|
||
`ww: build output "." already exists and is a directory`. Explicit `-o`
|
||
succeeded and produced byte-identical runnable binaries, proving that only
|
||
default presentation was wrong. This was the selected gap.
|
||
- **Go-like test:** an ordinary valid zero-match directory run exited 0 in both
|
||
stages with identical warning, accounting, and `[no tests to run]` result
|
||
bytes. The selected build branch does not enter test product naming,
|
||
filtering, capture, execution, result annotation, or retained test output.
|
||
- **Go-like package:** a directory containing two selected declared package
|
||
names was rejected in both stages with identical diagnostics. The selected
|
||
change occurs after package loading and does not alter source eligibility,
|
||
declaration checks, package kind, graph nodes, or actions.
|
||
- **Go-like import:** a dotted `cyclea -> cycleb -> cyclea` graph was rejected
|
||
in both stages with identical cycle diagnostics. The selected change does
|
||
not alter spelling, search, visibility, resolution, canonical identity, or
|
||
graph edges.
|
||
|
||
The pre-fix statuses, streams, hashes, diagnostics, artifacts, and runtime
|
||
results are **directly measured WW behavior**. The cited implementation and
|
||
testdata are **behavior directly implemented or asserted by pinned Go**. The
|
||
cross-axis non-effects follow from the bounded post-load output branch and are
|
||
**behavior derived from the pinned implementation**.
|
||
|
||
#### Ownership, final behavior, and preserved boundaries
|
||
|
||
`cmd/ww.do_build` and `selfhost/cmd/ww.dobuild` are semantic twins and the sole
|
||
owners of this rule. Their current-directory predicate accepts only relative
|
||
paths whose components are all exactly `.`. Only in that branch do they
|
||
canonicalize the selected directory and take its final component for output and
|
||
cold scratch presentation. Ordinary literal directory operands retain their
|
||
lexical leaf, and contextual roots retain their dotted identity leaf.
|
||
|
||
Direct post-fix probes through both stages show that bare, dot, and dot-slash
|
||
builds exit 0 with empty stdout/stderr, publish mode-executable binaries named
|
||
`a`, and produce `a.sepwork` with no `..sepwork`. All six binaries are
|
||
byte-identical (SHA-256
|
||
`866c1eb875dad271d37572f43fb9d9b0eb6a2344d2e61646e655bb09f7909bf6`).
|
||
Their unit, interface, assembly, object, archive, and init artifacts are also
|
||
byte-identical between stages and spellings. Current-directory library builds
|
||
still publish nothing and link nothing; their unit, interface, assembly,
|
||
object, and archive bytes remain stage-identical under `libcurrent.sepwork`.
|
||
|
||
Loading and source selection precede this branch. A missing dotted import
|
||
therefore retains its byte-identical diagnostic and creates neither output nor
|
||
scratch. Graph and action construction, compiler/assembler/archiver/linker
|
||
semantics, runtime behavior, and artifact content are unchanged. A genuine
|
||
directory occupying the derived output still rejects before tools and names
|
||
the derived leaf in its diagnostic.
|
||
|
||
Cold and warm persistent builds retain their existing keys and reuse rules. A
|
||
source invalidation reruns producers; an injected compiler failure preserves
|
||
the prior executable and committed persistent generation, publishes no stage,
|
||
and leaves no `.new`, `.install`, or `.wwtxn.*` residue. Restoring producer
|
||
success installs the changed executable. Existing concurrency, interruption,
|
||
process-group, rollback, publication, and cleanup owners gain no shared state or
|
||
new process path.
|
||
|
||
The WW-native `current_directory_build_default_output` observer proves both
|
||
stages, all three current-directory spellings, executable mode/runtime/byte
|
||
parity, explicit and null output controls, non-main non-publication, corrected
|
||
cold scratch, missing-import precedence, cold/warm reuse, invalidation,
|
||
producer-failure rollback, prior-output preservation, genuine collision, and
|
||
residue absence. Existing package/import graph, byte-identity, concurrent
|
||
transaction, and interruption observers remain authoritative for mechanisms
|
||
this presentation rule does not change.
|
||
|
||
No persisted-byte contract changed. Build workdir format remains `18`, test
|
||
workdir format remains `19`, and semantic storage format remains `3`.
|
||
|
||
### 11.41 Implemented source-file import-section ordering
|
||
|
||
Every eligible WW source now has one contiguous import section immediately
|
||
after its package clause. Once an ordinary top-level declaration begins, the
|
||
first `import` in a later section is rejected as
|
||
`imports must appear before other declarations`. The parser continues for
|
||
recovery: consecutive imports in that late section do not repeat the ordering
|
||
diagnostic, while another ordinary declaration followed by another import
|
||
starts a separately diagnosed late section.
|
||
|
||
This is a source-file syntax rule, not a new import form. Existing unquoted
|
||
dotted default, explicit-alias, and blank imports are unchanged. Existing
|
||
aggregate module/reset boundaries and each constituent package clause begin a
|
||
new source section. The boundary bookkeeping remains parser metadata rather
|
||
than package, import, graph, action, artifact, symbol, `.wwi`, publication, or
|
||
persistence identity.
|
||
|
||
#### Pinned Go evidence and fact classification
|
||
|
||
The sole authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `syntax.(*parser).fileOrNil` states the source-file grammar as a package
|
||
clause, zero or more imports, and then zero or more top-level declarations.
|
||
Its recovery loop accepts a later import only to continue parsing and emits
|
||
exactly `imports must appear before other declarations` when the preceding
|
||
declaration was not an import
|
||
([`cmd/compile/internal/syntax/parser.go`, lines 397–428](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/parser.go#L397-L428)).
|
||
- The public parser first consumes the initial import section, then applies the
|
||
same predecessor check while parsing the rest of the file
|
||
([`go/parser/parser.go`, method `(*parser).parseFile`, lines 2887–2923](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/parser/parser.go#L2887-L2923)).
|
||
- Official types testdata requires one diagnostic for a late import followed by
|
||
contiguous imports, then another diagnostic when an ordinary declaration
|
||
separates a second late section
|
||
([`internal/types/testdata/fixedbugs/issue43190.go`, lines 5–30](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/fixedbugs/issue43190.go#L5-L30)).
|
||
|
||
Those grammar branches, diagnostic text, error-recovery behavior, and testdata
|
||
assertions are **behavior directly implemented or asserted by pinned Go**.
|
||
That the state belongs to one source parser, resets at WW's existing aggregate
|
||
source boundaries, and must reject before import-graph construction is
|
||
**behavior derived from the pinned implementation**.
|
||
|
||
The rule honestly applies to WW's model because it orders declaration classes
|
||
WW already implements. It requires no quoted, grouped, dot, or generalized
|
||
import syntax; module or manifest identity; registry, lock, cache, database,
|
||
CAS, or network resolution; or source-level build expression.
|
||
|
||
#### Fresh four-axis audit and direct pre-fix measurements
|
||
|
||
The bounded audit examined all four permanent axes against the pinned checkout
|
||
before selecting this import difference:
|
||
|
||
- **Go-like build:** pinned linker method
|
||
`(*ErrorReporter).errorUnresolved` gives unresolved `main.main` a dedicated
|
||
error
|
||
([`cmd/link/internal/ld/errors.go`, lines 29–67](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/errors.go#L29-L67)),
|
||
asserted by `TestUndefinedRelocErrors` and its source fixture
|
||
([`cmd/link/internal/ld/ld_test.go`, lines 19–45](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/ld_test.go#L19-L45),
|
||
[`testdata/issue10978/main.go`, lines 5–27](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/link/internal/ld/testdata/issue10978/main.go#L5-L27)).
|
||
Both WW stages rejected a selected declared-`main` package without an entry,
|
||
using empty stdout and the same linker/driver diagnostics. This applicable
|
||
control was aligned.
|
||
- **Go-like test:** pinned `testFlags` explicitly permits known test flags
|
||
before and after the package list and implements the transition between
|
||
package operands and flags
|
||
([`cmd/go/internal/test/testflag.go`, lines 219–345](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/testflag.go#L219-L345));
|
||
official `test_flag.txt` asserts both placements
|
||
([lines 1–4](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_flag.txt#L1-L4)).
|
||
In both WW stages, `-run selected` before or after a directory operand ran
|
||
exactly the same one of two registered tests and produced identical output.
|
||
This applicable control was aligned for WW's supported option set.
|
||
- **Go-like package:** pinned `MultiplePackageError` and directory scanning
|
||
reject two eligible declarations with different package names
|
||
([`go/build/build.go`, lines 538–549](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L538-L549)
|
||
and [lines 939–967](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L939-L967)),
|
||
asserted by `TestMultiplePackageImport`
|
||
([`go/build/build_test.go`, lines 105–133](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build_test.go#L105-L133)).
|
||
Both WW stages rejected a `first`/`second` directory before tools with the
|
||
identical positioned diagnostic. This applicable control was aligned.
|
||
- **Go-like import:** a command source declared a helper, then imported
|
||
`audit.dep`, then used that package from `main`. Both WW stages exited 0,
|
||
emitted empty build output, produced byte-identical executables (SHA-256
|
||
`f28892147ab0ae283dff5ceea7114dbc81142ed48cb9088ee7fb8294a5ce44cd`),
|
||
and those executables exited 42. Corresponding owner unit, interface,
|
||
assembly, object, archive, and initializer bytes were stage-identical. A
|
||
same-package test source with the same late-import shape ran successfully in
|
||
both stages with identical 251-byte stdout (SHA-256
|
||
`3c42fa9840f485fb21b5b5318a13b89abfe29e94b530db00779262368f4fbeba`)
|
||
and empty stderr. This acceptance was the selected difference.
|
||
|
||
The WW statuses, streams, runtime exits, and artifact hashes are **directly
|
||
measured WW behavior**. The cited implementation and testdata facts are
|
||
**behavior directly implemented or asserted by pinned Go**. Applying their
|
||
per-file ordering state to WW's existing dotted declarations is **behavior
|
||
derived from the pinned implementation**.
|
||
|
||
#### Ownership and final four-axis behavior
|
||
|
||
`parseimports` and `parsefile` in `cmd/wcc/parse.c`, with their semantic twins
|
||
in `lib/ww/syntax/parse.ww`, are the only production owners. Each keeps one
|
||
parser-local `previmport` bit. A normal import following a non-import reports
|
||
the pinned diagnostic, then sets the bit so adjacent imports remain one
|
||
recovery section. Any ordinary declaration clears it. The existing
|
||
module-path, module-reset, and package-clause boundaries set it for a new
|
||
source section.
|
||
|
||
The imports-only pass is used by public driver loading and therefore rejects a
|
||
selected or imported late source before graph and producer construction. The
|
||
full parser independently gives direct `w6c`/`w6c_ww` input and aggregate units
|
||
the same rule. The only tracked compatibility fixture that deliberately put a
|
||
declaration before its import was reordered; it still proves file-scoped import
|
||
binding and declaration installation order with byte-identical Cstage/WWstage
|
||
artifacts, without asserting the rejected syntax.
|
||
|
||
- **Go-like build:** selected and imported late sources now fail during parser
|
||
loading, before compiler, assembler, archiver, linker, output planning side
|
||
effects, or runtime. Missing-target resolution does not replace the earlier
|
||
syntax error. Valid import-first commands still build, publish, and run.
|
||
- **Go-like test:** late imports in production, same-package test,
|
||
external-test, and test-only sources fail before variant actions, generated
|
||
main, test binary, runtime, accounting, or retained publication. The
|
||
directory command emits its existing attributable final `FAIL\n`. A valid
|
||
import-first test retains and runs normally.
|
||
- **Go-like package:** source eligibility and package-clause classification
|
||
remain earlier owners. Wrong-platform sources produce no ordering error;
|
||
selected package-name conflicts retain their coordinator diagnostic.
|
||
Declared names and command/test family classification are unchanged.
|
||
- **Go-like import:** a file can no longer introduce a qualifier or side-effect
|
||
edge after ordinary declarations. Valid imports retain their exact source
|
||
spelling, declared-name qualifier, file scope, contextual/vendor resolution,
|
||
canonical identity, visibility checks, cycle checks, and initialization
|
||
edges.
|
||
|
||
Direct post-fix `w6c` and `w6c_ww`, and public `ww build`/`ww_ww build`, reject
|
||
the measured source with empty stdout and byte-identical 149-byte stderr
|
||
(SHA-256
|
||
`791ac87ab0aa2c91228f863ae80a8815aa83edf78c4996c5f11191193e3e4240`).
|
||
The diagnostic points to the late import at line 7, column 1. Directory tests
|
||
emit byte-identical `FAIL\n` stdout (SHA-256
|
||
`4f8e9e45f8a9e1843b81eaf3bdf52a6b778d415d23bf985774a9d34a43f69bd5`)
|
||
and byte-identical 314-byte stderr (SHA-256
|
||
`82ec52b26eaff053f475ce0773b7aee902e734cd87dc100848aee3772063f5b1`),
|
||
with no test body or accounting. A direct three-import recovery probe emits
|
||
exactly two stage-identical ordering diagnostics: one for the first of two
|
||
contiguous late imports and one after the intervening declaration.
|
||
|
||
Loading and fixed-target filename selection otherwise do not change. An
|
||
excluded `_windows.ww` or `_windows_test.ww` file contributes no parse,
|
||
package, import, graph, action, artifact, diagnostic, or invalidation state.
|
||
For valid files, graph nodes, action dependencies and scheduling, compiler and
|
||
linker arguments, initialization, runtime behavior, result ordering, and
|
||
publication remain unchanged. A package canonically named `domain.dep` may
|
||
still declare `renamed`; its importer uses `renamed.Name`, and its unit/export
|
||
remain owned by `domain.dep`.
|
||
|
||
Cold rejection creates no work artifact, output, capture, or adjacent scratch.
|
||
A warm source reordered into the invalid form preserves the complete committed
|
||
unit/interface/assembly/object/archive/initializer generation, tool vouchers,
|
||
stamp, and public executable byte for byte. Exact restoration reuses the
|
||
committed producers and republishes the same executable. Because rejection
|
||
occurs before a producer or test child, producer failure, runtime failure,
|
||
signals, timeout, interruption, and process-group cleanup acquire no new path;
|
||
their existing owners remain authoritative. Concurrent valid and invalid
|
||
requests use independent parser state, workdirs, captures, and outputs. No
|
||
`.new`, `.install`, `.wwtxn.*`, cold scratch, test process, or capture residue
|
||
survives the observed failure boundaries.
|
||
|
||
The WW-native `imports_precede_other_top_level_declarations` observer proves
|
||
direct compiler parity, exact recovery-section counts, selected and imported
|
||
build rejection, syntax-before-resolution precedence, all directory test
|
||
source variants, wrong-platform exclusion, valid runtime behavior, declared
|
||
name versus canonical identity, cold/warm persistence and rollback, restored
|
||
reuse, concurrent isolation, diagnostic equality, retained executable equality,
|
||
and intermediate artifact-byte equality. The C parser unit and the existing
|
||
`sepimport` observer separately pin the imports-only AST recovery and valid
|
||
file-scoped binding regression.
|
||
|
||
Rejected source creates no persisted byte contract, while valid source bytes
|
||
are unchanged. Build workdir format remains `18`, test workdir format remains
|
||
`19`, and semantic storage format remains `3`.
|
||
|
||
### 11.42 Implemented per-source UTF-8 BOM placement
|
||
|
||
Every eligible physical WW source may begin with one UTF-8-encoded U+FEFF byte
|
||
order mark (`EF BB BF`). That marker is ignored, and the following token keeps
|
||
its three-byte source position at line 1, column 4. U+FEFF at any later raw
|
||
source position is
|
||
rejected once as `invalid BOM in the middle of the file`, including inside a
|
||
line/block comment, string, or rune. Two leading markers therefore ignore the
|
||
first and reject the second. A truncated marker or another invalid UTF-8 byte
|
||
sequence retains the ordinary byte-error path; UTF-16 source is not introduced.
|
||
|
||
#### Pinned Go evidence and applicability
|
||
|
||
The sole authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- compiler reader `(*source).nextch` decodes UTF-8, skips U+FEFF at its first
|
||
source position, and reports `invalid BOM in the middle of the file`
|
||
elsewhere
|
||
([`cmd/compile/internal/syntax/source.go`, lines 113–165](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/source.go#L113-L165));
|
||
- public scanner `(*Scanner).next` rejects later U+FEFF and `(*Scanner).Init`
|
||
consumes the first one
|
||
([`go/scanner/scanner.go`, lines 58–100 and 128–164](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/scanner/scanner.go#L58-L164));
|
||
- scanner tests assert the ignored first marker and later markers between
|
||
tokens, in comments, runes, and strings
|
||
([`go/scanner/scanner_test.go`, lines 371–374 and 812–815](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/scanner/scanner_test.go#L371-L374),
|
||
[`go/scanner/scanner_test.go`, lines 812–815](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/scanner/scanner_test.go#L812-L815));
|
||
- compiler-scanner `TestScanErrors` asserts the positioned later-marker error
|
||
([`cmd/compile/internal/syntax/scanner_test.go`, lines 587–599](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/scanner_test.go#L587-L599)); and
|
||
- official command testdata places the marker before `package main` and loads
|
||
that source's imports and embedded file
|
||
([`cmd/go/testdata/script/build_ignore_leading_bom.txt`, lines 1–25](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/build_ignore_leading_bom.txt#L1-L25)).
|
||
|
||
Those source branches and assertions are **behavior directly implemented or
|
||
asserted by pinned Go**. Applying the first position independently to every WW
|
||
physical source before its existing synthetic aggregate boundary is **behavior
|
||
derived from the pinned implementation**. The pre-fix Cstage/WWstage failures
|
||
on leading markers and successes for markers in comments/strings were
|
||
**directly measured WW behavior**.
|
||
|
||
The behavior honestly applies inside WW's local, dotted-import, manifest-free
|
||
model: it is source representation before package and import interpretation.
|
||
It requires no module, manifest, registry, lock, cache, database, CAS, network
|
||
resolution, generalized import syntax, build expression, or normalized
|
||
identity.
|
||
|
||
#### Ownership and four-axis result
|
||
|
||
`lexinit`, `lpeek`, `lget`, and `lexnext` in `cmd/wcc/lex.c`, with their twins
|
||
in `lib/ww/syntax/lex.ww`, are the language owners. They skip the exact initial
|
||
marker while advancing the logical column by its encoded width, recognize a
|
||
later marker as one code point in every lexical context, and emit one
|
||
stage-identical diagnostic.
|
||
`sep_emit_body` in `cmd/ww/main.c` and `sepemitbody` in
|
||
`selfhost/cmd/ww/main.ww` replace the optional marker with three spaces in every
|
||
physical body placed after a synthetic `//ww:module-reset`, preserving columns;
|
||
direct and imports-only lexer input remains independently correct. The shared package
|
||
coordinator's `pkgclause` in `internal/wwpackage/package.ww` begins its
|
||
pre-discovery package-name scan after the same optional marker. It does not
|
||
replace the complete stage-driver scan.
|
||
|
||
- **Go-like build:** a selected command, library, or imported dependency may
|
||
use the marker in each eligible source. Multiple physical marked sources
|
||
compose normally, command publication succeeds, and the executable runs
|
||
normally. A later marker rejects during source loading before graph/action
|
||
construction or compiler, assembler, archiver, linker, install, or runtime
|
||
work. A source error keeps precedence over a missing import.
|
||
- **Go-like test:** production, same-package, external-package, and test-only
|
||
files each receive the offset-zero allowance. Valid variants build and run
|
||
through the ordinary single directory product. A later marker yields the
|
||
existing attributable `FAIL\n` result without a variant, generated main,
|
||
test process, accounting, or retained binary.
|
||
- **Go-like package:** package-clause recognition now begins at the pinned
|
||
logical source start in direct compilers, directory drivers, and the shared
|
||
coordinator. Declared names, source roles, package conflicts, command/test
|
||
family selection, and canonical identity do not change.
|
||
- **Go-like import:** imports following a legal marker and imports in a marked
|
||
dependency retain their exact source spelling, file scope, qualifier,
|
||
contextual local/vendor resolution, case-sensitive canonical dotted
|
||
identity, visibility, cycle, and initialization behavior. The marker never
|
||
becomes an edge or identity component.
|
||
|
||
Fixed-target filename selection remains earlier than parsing: an excluded
|
||
`_windows.ww` or `_windows_test.ww` contributes no marker diagnostic, package,
|
||
import, graph, action, artifact, or invalidation state. For valid inputs, graph
|
||
nodes, scheduling, producer arguments, initialization, runtime, result order,
|
||
and publication are unchanged. Legal marker bytes become three
|
||
position-preserving spaces only in the synthetic unit. Adding or removing the
|
||
marker therefore changes unit content and invalidates source-derived actions,
|
||
while semantic interface, assembly, object, archive, initializer, and
|
||
executable content remains the same; every form remains Cstage/WWstage
|
||
byte-identical.
|
||
|
||
Cold rejection leaves no product, work generation, adjacent scratch, capture,
|
||
`.new`, `.install`, or `.wwtxn.*`. A warm later-marker edit preserves the
|
||
entire committed generation, tool vouchers, stamp, and public executable.
|
||
Restoring the exact legal leading form recreates the same unit and reuses committed
|
||
compiler/assembler/archive work before the normal link/publication boundary.
|
||
Concurrent valid and invalid requests keep independent lexer/coordinator state,
|
||
workdirs, captures, diagnostics, and products. Because later-marker rejection
|
||
occurs before a producer or test child, producer/runtime failure, signals,
|
||
timeouts, interruption, and process-group cleanup gain no new branch; their
|
||
existing owners remain authoritative.
|
||
|
||
The C lexer unit, WW syntax unit, and WW-native
|
||
`utf8_bom_is_per_source_and_only_first` observer prove initial position,
|
||
later-marker lexical contexts, direct frontend diagnostics and assembly,
|
||
selected/imported multi-source build, wrong-target exclusion, every test source
|
||
role, test-only execution, syntax-before-resolution precedence, cold cleanup,
|
||
warm rollback and reuse, concurrent isolation, publication/runtime behavior,
|
||
and complete stage diagnostic/artifact parity.
|
||
|
||
No persisted format changes. Previously valid marker-free bytes are
|
||
unchanged; previously leading-marked requests could not commit a generation;
|
||
and diagnostic text is not a persisted-byte contract. Build workdir format
|
||
remains `18`, test workdir format remains `19`, and semantic storage format
|
||
remains `3`.
|
||
|
||
### 11.43 Implemented selected-source U+0000 rejection
|
||
|
||
Every selected physical `.ww` source rejects a raw byte `00` (U+0000) at its
|
||
physical line and byte column with exactly `invalid NUL character`. The rule is
|
||
source-wide: comments, interpreted-string text, rune text, and between-token
|
||
positions cannot turn a raw NUL into payload. An escape spelling such as
|
||
`\x00` remains a legal literal value because it is not byte `00` in
|
||
the source file. This section is only the raw-U+0000 rule: malformed UTF-8
|
||
and the independently implemented per-source BOM boundary in §11.42 are not
|
||
changed or broadened here.
|
||
|
||
#### Pinned evidence, applicability, and measured prior behavior
|
||
|
||
The sole authority is official Go 1.26.5 at
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`. Its compiler owner,
|
||
`(*source).nextch` in
|
||
[`cmd/compile/internal/syntax/source.go`, lines 113–165](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/source.go#L113-L165),
|
||
detects ASCII zero at lines 121–129, reports `invalid NUL character`, and
|
||
continues decoding. `TestScanErrors` pins the positioned diagnostic at
|
||
[`cmd/compile/internal/syntax/scanner_test.go`, lines 587–600](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/scanner_test.go#L587-L600),
|
||
and compiler testdata [`test/nul1.go`, lines 7–52](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/nul1.go#L7-L52)
|
||
requires NUL errors in strings, raw strings, line/block comments, and ordinary
|
||
source. Go's independent public scanner has the same rule in
|
||
[`go/scanner/scanner.go`, lines 63–108](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/scanner/scanner.go#L63-L108)
|
||
and its tests at lines 790–819. These are **behavior directly implemented or
|
||
asserted by pinned Go**.
|
||
|
||
Before this change, directly measured Cstage and WWstage package builds both
|
||
accepted a NUL in a line comment, wrote it into the committed synthetic unit,
|
||
published byte-identical archive/interface products, and allowed a dotted local
|
||
importer to link and run. The retained audit commands used `out/bin/ww` and
|
||
`out/bin/ww_ww` with `WW_SRCLIB=/home/kimchi/src/ww/lib` over
|
||
`/tmp/ww-pkgaudit.qtjcpO/src/nulcomment`; both exited zero with empty streams.
|
||
The same acceptance applied to raw NUL in strings and runes. Those observations
|
||
are **directly measured WW behavior**. Applying pinned Go's physical-source
|
||
rule independently to WW's selected files is **behavior derived from the
|
||
pinned implementation** and is applicable without importing Go's module,
|
||
manifest, registry, lock, cache, database, CAS, network, generalized-import,
|
||
or source-level build-expression model.
|
||
|
||
#### Ownership, timing, and four axes
|
||
|
||
The direct-frontend semantic owners are the logical source-decoder helpers in
|
||
`cmd/wcc/lex.c` and their exact twins in `lib/ww/syntax/lex.ww`: each raw zero
|
||
is consumed, reports the same positioned error, and is omitted before token
|
||
recovery. Filtered token spans preserve that decoder rule through identifiers,
|
||
numbers and suffixes, directives, escapes, operators, comments, and EOF. The
|
||
line-comment decoder consumes each body once before classifying an internal
|
||
module directive, so NUL filtering does not make generated path handling
|
||
superlinear. The
|
||
shared `internal/wwpackage/package.ww` coordinator owns public package/test
|
||
diagnostic precedence: its length-aware preflight reports every raw NUL in an
|
||
invalid physical source before its manual package-clause classifier. It is not
|
||
another identity policy. Driver source slurping and synthetic-unit composition
|
||
preserve byte lengths and are not semantic owners.
|
||
|
||
- **Go-like build:** after fixed-target filename selection, an invalid selected
|
||
root or dependency rejects during loading, before graph completion and before
|
||
compiler, assembler, archiver, linker, install, publication, or execution.
|
||
Source rejection in a root precedes resolution of that root's missing
|
||
imports. A wrong-target file is excluded before this rule and remains unread
|
||
by its semantic owners.
|
||
- **Go-like test:** selected production, same-package, external-package, and
|
||
test-only source each receive the rule before variant construction. Failure
|
||
emits the established attributable `FAIL\n` without a generated main, test
|
||
process, accounting, `ok` result, retained binary, or public test product.
|
||
- **Go-like package:** each selected physical file owns its diagnostic and
|
||
position. Declared package name, source role, package conflict handling,
|
||
command/test family, physical directory, and exact canonical dotted identity
|
||
are unchanged.
|
||
- **Go-like import:** invalid bytes create no import edge or graph node. Valid
|
||
import spelling, aliases, local/vendor/internal resolution, visibility,
|
||
cycle handling, and initialization order remain unchanged.
|
||
|
||
Thus raw NUL is never an input to manifest-free package identity, graph/action
|
||
keys, symbols, `.wwi`, archive naming, publication names, or persistence keys.
|
||
It neither changes local dotted-import boundaries nor introduces a manifest.
|
||
|
||
#### Failure, publication, persistence, and parity
|
||
|
||
Cold invalid requests create no unit, assembly, object, archive, executable,
|
||
capture, `.new`, `.install`, `.wwtxn.*`, or public output. A warm edit that
|
||
introduces NUL stops before a producer or install action, preserving the prior
|
||
committed unit/interface/assembly/object/archive generation, tool vouchers,
|
||
stamp, and public output byte for byte. Removing the NUL restores the ordinary
|
||
selected-source fingerprint; exact restoration may reuse the earlier generation.
|
||
Existing producer/runtime failure and transaction rollback remain their own
|
||
owners because this branch creates no new rollback mechanism.
|
||
|
||
Lexer and coordinator state are request/source-local. Concurrent valid and
|
||
invalid requests keep independent workdirs, captures, diagnostics, and
|
||
products; an invalid request cannot contaminate a valid sibling. The rule adds
|
||
no process, wait, or cancellation boundary, so signal, timeout, interruption,
|
||
process-group cleanup, and ordinary scratch cleanup retain their established
|
||
owners. Validation itself leaves no durable residue. Cstage and WWstage are
|
||
semantic twins: diagnostics match exactly, and valid unit/compiler/product
|
||
bytes retain their existing byte-identity contract.
|
||
|
||
`raw_nul_is_rejected_in_every_selected_source` in
|
||
`test/package/package_test.ww`, with focused C and WW lexer coverage, proves
|
||
literal and comment contexts plus adjacency recovery across escapes,
|
||
identifiers, numbers and typed suffixes, operators, comment delimiters, and
|
||
EOF; it also proves selected/imported builds, wrong-target exclusion, every
|
||
directory-test source role, precedence, cold cleanup, warm rollback and reuse,
|
||
concurrent isolation, valid escaped-NUL behavior, runtime/publication behavior,
|
||
and no-residue/parity observations.
|
||
|
||
No format bump. This changes invalid-source acceptance and diagnostics only;
|
||
valid source composition and valid `.wwi`, assembly, object, archive,
|
||
executable, and retained-test-product bytes are unchanged. Build workdir format
|
||
remains `18`, test workdir format remains `19`, and semantic storage format
|
||
remains `3`.
|
||
|
||
### 11.44 Implemented exact output-option name and value semantics
|
||
|
||
The `ww build` and `ww test` output option has the exact registered name `o`.
|
||
Its accepted forms are `-o VALUE`, `--o VALUE`, `-o=VALUE`, and
|
||
`--o=VALUE`. An equals form splits at the first `=` and preserves the complete
|
||
remaining value, including an empty value and additional `=` bytes. Repeated
|
||
occurrences are last-value-wins. A final empty value means no effective
|
||
explicit output: a single command uses its ordinary default, a multi-command
|
||
build performs its ordinary no-public-output build, a running test retains no
|
||
copy, and compile-only testing uses its ordinary default retained name.
|
||
Concatenated names such as `-oVALUE` and `--oVALUE` are unknown flags rather
|
||
than output requests. Build option parsing stops at the first root operand;
|
||
test parsing continues to recognize known test options, including exact `o`,
|
||
on either side of its package operands.
|
||
|
||
#### Pinned evidence and fact classification
|
||
|
||
The sole authority is official Go 1.26.5 at
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `init` registers exactly string flag name `o` for the build command in
|
||
[`cmd/go/internal/work/build.go`, lines 241–248](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L241-L248),
|
||
and `invoke` parses that flag set before passing only remaining operands to
|
||
`runBuild` in
|
||
[`cmd/go/main.go`, lines 290–322](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/main.go#L290-L322).
|
||
- `(*FlagSet).parseOne` accepts one or two leading dashes, splits the first
|
||
`=`, consumes the next argument only when there was no equals delimiter, and
|
||
rejects an unregistered concatenated name in
|
||
[`flag/flag.go`, lines 1074–1146](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/flag/flag.go#L1074-L1146).
|
||
`(*FlagSet).Parse` stops at the first non-flag operand at lines 1149–1176.
|
||
`stringValue.Set` and `(*FlagSet).Set` overwrite a repeated string value at
|
||
lines 240–250 and 494–528. `runBuild` derives effective explicit output from
|
||
the final value's nonzero length and otherwise selects its default behavior
|
||
in
|
||
[`cmd/go/internal/work/build.go`, lines 459–478](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L459-L478).
|
||
- Build command testdata uses an equals-delimited output successfully in
|
||
[`version_buildvcs_nested.txt`, line 57](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/version_buildvcs_nested.txt#L57).
|
||
`testParse` exercises exact names with two leading dashes and separate
|
||
values at
|
||
[`flag_test.go`, lines 164–215](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/flag/flag_test.go#L164-L215),
|
||
`TestUserDefined` asserts an equals-delimited string value at lines 251–267,
|
||
and `TestUsage` asserts unknown-flag failure at lines 153–161.
|
||
- Test command `init` registers exactly string flag name `o` in
|
||
[`cmd/go/internal/test/testflag.go`, lines 32–38](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/testflag.go#L32-L38).
|
||
`cmdflag.ParseOne` accepts one or two dashes, cuts the first `=`, preserves
|
||
empty and remaining-equals value bytes, and rejects unknown names in
|
||
[`cmd/go/internal/cmdflag/flag.go`, lines 53–118](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/cmdflag/flag.go#L53-L118).
|
||
`testFlags` recognizes known flags before and after the package list and
|
||
rejects an unknown flag with `-c` in
|
||
[`cmd/go/internal/test/testflag.go`, lines 219–349](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/testflag.go#L219-L349).
|
||
`testNeedBinary` and the output-classification branch treat final empty
|
||
`testO` as no explicit retained destination in
|
||
[`cmd/go/internal/test/test.go`, lines 631–646 and 771–781](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L631-L781).
|
||
- Official command testdata uses compile-only test output successfully in
|
||
[`devnull.txt`, lines 3–8](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/devnull.txt#L3-L8)
|
||
and
|
||
[`test_race_tag.txt`, lines 1–9](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_race_tag.txt#L1-L9).
|
||
[`test2json_interrupt.txt`, line 10](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test2json_interrupt.txt#L10)
|
||
places `-o` after a package operand, while
|
||
[`test_flag.txt`, lines 11–16](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/test_flag.txt#L11-L16)
|
||
asserts unknown-flag rejection with `-c` across supported placements.
|
||
|
||
Those registrations, parser branches, effective-output branches, and official
|
||
assertions are **behavior directly implemented or asserted by pinned Go**.
|
||
Applying their exact-name, first-equals, final-value, and command-placement
|
||
rules to WW's local command surface while retaining WW's diagnostic wording is
|
||
**behavior derived from the pinned implementation**. The measured WW matrix
|
||
below is **directly measured WW behavior**; no installed host Go result is used
|
||
as authority.
|
||
|
||
#### Direct pre-fix Cstage and WWstage matrix
|
||
|
||
Both stages had identical pre-fix behavior in every row:
|
||
|
||
| Route and spelling | Directly measured pre-fix result |
|
||
| --- | --- |
|
||
| single build, `-o=name` | exited 0 with empty streams, left `name` absent, and published executable `=name` |
|
||
| single build, `-oname` | exited 0 with empty streams and incorrectly accepted the concatenated name |
|
||
| single build, `--o name` or `--o=name` | exited 2 with empty stdout and byte-identical `ww build: unknown flag\n` stderr |
|
||
| single build, final `-o=` | exited 0 with empty streams and published literal file `=` rather than the default command name |
|
||
| build values containing `=` | retained an erroneous leading `=`; repeated separate forms were already last-value-wins |
|
||
| build option after the first root | remained package input rather than being reparsed, matching the required placement boundary |
|
||
| two-command coordinator, `-o=DIR/` | published both products beneath a literal leading-`=` directory |
|
||
| two-command coordinator, `-oDIR/` | incorrectly accepted the joined name and published beneath the requested directory |
|
||
| two-command coordinator, final `-o=` | exited 2 as `cannot use -o with multiple packages` instead of selecting no effective explicit output |
|
||
| compile-only directory test, `-o=name` | exited 0 with empty streams, left `name` absent, and published test binary `=name` |
|
||
| compile-only directory test, `-oname` | incorrectly accepted the concatenated name and published that retained binary |
|
||
| compile-only directory test, `--o=name` | exited 2 with empty stdout and byte-identical `ww test: unknown flag\n` stderr |
|
||
| compile-only directory test, final `-o=` or a value containing `=` | published literal `=` or an erroneous leading-`=` destination |
|
||
| test `-o` after its package operand | was already recognized, matching the required test placement boundary |
|
||
|
||
The wrong-path single-build executables were stage-byte-identical 4,268-byte
|
||
files with SHA-256
|
||
`866c1eb875dad271d37572f43fb9d9b0eb6a2344d2e61646e655bb09f7909bf6`.
|
||
The wrong-path retained test binaries were stage-byte-identical 112,829-byte
|
||
files with SHA-256
|
||
`5ea3ac9add844dc4cd98cc07fb64816415b5e3c03745dc4cc756ec093cf5cea7`.
|
||
The build and test unknown-flag diagnostics were respectively 23 and 22 bytes,
|
||
also byte-identical between Cstage and WWstage. These byte counts and hashes
|
||
describe only the direct pre-fix measurements.
|
||
|
||
#### Ownership and complete four-axis result
|
||
|
||
The Cstage command owners are `parse_build_flags` and `do_test` in
|
||
`cmd/ww/main.c`. Their WWstage semantic twins are `dobuild` and `dotest` in
|
||
`selfhost/cmd/ww/main.ww`. The shared multi-package owner is
|
||
`packagecommand` in `internal/wwpackage/package.ww`. Each recognizes exact
|
||
one-/two-dash separate/equals forms, replaces prior occurrences with the final
|
||
value, and derives effective explicit-output state from that final value's
|
||
non-emptiness. The build parser retains its first-root stop, while test and the
|
||
coordinator retain their established after-package recognition. `dorun` and
|
||
the shared `run` route are not changed. The compiler, assembler, archiver,
|
||
linker, runtime, package checker, and import resolver do not own this rule.
|
||
|
||
- **Go-like build:** exact accepted forms select the same established output
|
||
path as separate `-o VALUE`; a final empty value selects the existing
|
||
default/no-public-output branch. Invalid concatenated names reject before
|
||
loading, graph or action construction, producers, publication, or runtime.
|
||
- **Go-like test:** the same exact forms select retained destinations on both
|
||
sides of package operands. Final empty means no running-test retention or
|
||
the normal compile-only default. Discovery, variants, generated main,
|
||
filtering, execution, accounting, result annotation, and absence of a
|
||
test-result cache do not change.
|
||
- **Go-like package:** output bytes remain presentation metadata. Source
|
||
eligibility, package clauses, declared names, variants, command
|
||
classification, canonical package representatives, graph nodes, actions,
|
||
symbols, artifacts, and persistence keys are unchanged.
|
||
- **Go-like import:** output spelling creates no binding or edge and changes no
|
||
dotted import spelling, alias, search, local/vendor/internal rule,
|
||
visibility, cycle, initialization order, canonical identity, or `.wwi`
|
||
ownership.
|
||
|
||
#### Loading, lifecycle, parity, and proof
|
||
|
||
Accepted forms enter the same existing loading, graph, scheduling, compiler,
|
||
assembler, archiver, linker, runtime, publication, persistence, reuse, and
|
||
invalidation paths as `-o VALUE`. They add no action, process, transaction,
|
||
cache, key, artifact byte, or runtime state. Producer or runtime failure,
|
||
late output rejection, rollback, prior-state preservation, concurrent
|
||
publication, interruption, and process-group cleanup therefore retain their
|
||
established owners and results. Output installation keeps the existing
|
||
transaction, object-safety, mode, null-device, output-directory, and
|
||
running-retained-test guard rules.
|
||
|
||
Invalid concatenated names stop before all loading and work, create no
|
||
diagnostic competitor or product, and leave no unit, interface, assembly,
|
||
object, archive, executable, retained test binary, capture, output prefix,
|
||
`.new`, `.install`, `.wwtxn.*`, or scratch residue. A final empty value cannot
|
||
create literal `=`, `=.sepwork`, or transaction residue. Cold and warm
|
||
accepted requests use the ordinary publication and reuse paths; changing only
|
||
an accepted spelling does not rekey semantic work. Independent concurrent
|
||
requests own independent argument state, workdirs, stages, captures, and
|
||
outputs. Build starts no runtime; running tests keep their private executable
|
||
and publish only after successful execution.
|
||
|
||
The WW-native `output_flag_exact_name_and_value_semantics` observer is the
|
||
focused owner for both public stages and all three parser routes. It covers the
|
||
four accepted forms, extra and empty equals values, repetition, concatenated
|
||
name rejection, build/test placement controls, multi-command behavior,
|
||
diagnostic parity, runnable and retained artifact-byte parity, warm reuse, and
|
||
absence of literal-equals and transaction residue. Existing transaction,
|
||
producer/runtime failure, rollback, concurrency, interruption, output-mode,
|
||
and cleanup observers remain authoritative for the unchanged downstream
|
||
mechanisms. Post-fix byte counts and hashes are recorded only after direct
|
||
focused measurement; this section does not infer them from the implementation.
|
||
|
||
This is command parsing and output presentation only. No persisted-byte
|
||
contract changes: build workdir format remains `18`, test workdir format
|
||
remains `19`, and semantic storage format remains `3`.
|
||
|
||
### 11.45 Implemented selected-source malformed UTF-8 rejection
|
||
|
||
Every malformed UTF-8 byte in an eligible selected physical `.ww` source is
|
||
rejected at its 1-based physical line and raw-byte column with exactly
|
||
`invalid UTF-8 encoding`. The source decoder consumes that byte, omits it from
|
||
the logical character stream, and resumes. Consequently, a malformed
|
||
multi-byte spelling is diagnosed once for every byte that decodes as U+FFFD
|
||
with width one, while a correctly encoded U+FFFD remains valid. Validation is
|
||
source-wide: comment and literal contexts do not hide malformed bytes, and an
|
||
invalid byte cannot split an identifier, number or suffix, operator, escape,
|
||
comment delimiter, package keyword, or import spelling into a different token.
|
||
|
||
This section adds only malformed-UTF-8 validation. It does not reopen the
|
||
per-source leading-BOM contract in §11.42, raw-U+0000 rejection in §11.43, or
|
||
exact output-option parsing in §11.44. BOM, raw NUL, and malformed UTF-8 remain
|
||
independent positioned source conditions and are handled in raw-byte order.
|
||
|
||
#### Pinned evidence, applicability, and fact classification
|
||
|
||
The sole authority is official Go 1.26.5 at
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- compiler reader `(*source).init`, `(*source).pos`/`error`, and
|
||
`(*source).nextch` establish the 1-based byte-positioned decoding boundary in
|
||
[`cmd/compile/internal/syntax/source.go`, lines 60–88 and 113–165](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/source.go#L60-L165);
|
||
- `(*source).nextch` calls `utf8.DecodeRune` at lines 149–150, and a U+FFFD
|
||
result of width one reports exactly `invalid UTF-8 encoding`, consumes that
|
||
one byte, and resumes at lines 152–154;
|
||
- compiler-scanner `TestScanErrors` asserts the positioned malformed byte and
|
||
truncated-`EF` regression in
|
||
[`cmd/compile/internal/syntax/scanner_test.go`, lines 587–600 and 658](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/scanner_test.go#L587-L658);
|
||
- compiler testdata requires UTF-8 errors in interpreted and raw strings,
|
||
comments, identifiers, and ordinary source in
|
||
[`test/nul1.go`, lines 7–52](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/nul1.go#L7-L52);
|
||
- the independent public scanner corroborates width-one malformed decoding in
|
||
[`go/scanner/scanner.go`, lines 63–108](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/scanner/scanner.go#L63-L108)
|
||
and its literal test at
|
||
[`go/scanner/scanner_test.go`, lines 810–811](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/scanner/scanner_test.go#L810-L811);
|
||
- directory enumeration, filename eligibility, source reading, and test-role
|
||
classification are ordered by `Context.Import`, `Context.matchFile`, and
|
||
`Context.goodOSArchFile` in
|
||
[`go/build/build.go`, lines 859–953 and 1005–1036](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L859-L1036),
|
||
[`Context.matchFile`, lines 1438–1509](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1438-L1509),
|
||
and
|
||
[`Context.goodOSArchFile`, lines 1980–2027](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1980-L2027),
|
||
while internal/external test variants consume those selected lists in
|
||
[`cmd/go/internal/load/test.go`, `TestPackagesAndErrors`, lines 85–102 and 175–240](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L85-L240).
|
||
|
||
Those decoder branches, source-selection branches, and official assertions are
|
||
**behavior directly implemented or asserted by pinned Go**. Applying the same
|
||
per-selected-physical-source rule to `.ww` inputs, after WW's fixed-target
|
||
filename/test-role eligibility and before its package/import interpretation,
|
||
is **behavior derived from the pinned implementation**. It honestly applies to
|
||
WW's declared UTF-8 source without adding modules, manifests, registries, lock
|
||
files, caches, databases, CAS, network resolution, quoted/grouped/dot/general
|
||
imports, or a source-level build language.
|
||
|
||
Before this change, the following observations were **directly measured WW
|
||
behavior**:
|
||
|
||
- direct `w6c` and `w6c_ww` accepted comments containing stray continuation
|
||
`80`, lead `FF`, overlong `C0 80`, and surrogate `ED A0 80` bytes, exited
|
||
zero with empty streams, and emitted byte-identical 89-byte assembly with
|
||
SHA-256
|
||
`7385e3ce0107324edc94ee4377c5c2b0262c5b690939cb54f599ed09f9730db8`;
|
||
- both direct compilers accepted raw `FF` in a string and emitted
|
||
byte-identical 236-byte assembly with SHA-256
|
||
`4dbe79617badb56d541526ca276a9867d0d717ad9aa0c540f629882f87e3f3ad`,
|
||
while valid Korean and accented controls remained accepted and
|
||
stage-identical;
|
||
- both public build stages accepted malformed comments and literals, published
|
||
runnable binaries, and built and ran an imported dependency containing
|
||
malformed UTF-8; that dependency executable was 4,317 stage-identical bytes
|
||
with SHA-256
|
||
`f792da043743cc512c9d9a41deb4cb4af1e42d35e2716fcd5b57355fd7f566eb`;
|
||
- malformed production, same-package, external-package, and test-only selected
|
||
sources ran successfully in both stages; one same-package compile-only binary
|
||
was 112,829 stage-identical bytes with SHA-256
|
||
`108150d071a3ab4264d021d2c3fdc7a94ff71a00153fdf14bfe8e26520cc5da2`;
|
||
- a corrupted `pack<FF>age` produced a package-clause diagnostic plus
|
||
`unexpected character 0xff` in Cstage but a generic `unexpected character`
|
||
in WWstage, with 176-byte versus 171-byte stderr; corrupted imports reached
|
||
analogous fallback recovery rather than the pinned decoder diagnostic;
|
||
- malformed source before `import nowhere;` allowed missing-import resolution
|
||
to win, while a malformed same-package test keyword reached the
|
||
coordinator's unpositioned `invalid or missing package clause`; and
|
||
- malformed wrong-target and ordinary-build-excluded test files were ignored,
|
||
and reverse-created selected files were still diagnosed in byte-sorted name
|
||
order.
|
||
|
||
No installed host Go result supplies any authority or measurement above.
|
||
|
||
#### True ownership and complete four-axis result
|
||
|
||
The semantic owners are the source-decoder twins in `cmd/wcc/lex.c` and
|
||
`lib/ww/syntax/lex.ww`, plus the selected-physical-source preflight in
|
||
`internal/wwpackage/package.ww`. The decoders enforce bytewise recovery for
|
||
complete direct and composed compiler inputs. The shared coordinator enforces
|
||
the same validation before its textual package-clause classifier and import
|
||
discovery, so a coordinator fallback cannot outrank the physical-source error.
|
||
The Cstage/WWstage package-unit composers only transport already admitted
|
||
source bytes and are not additional owners.
|
||
|
||
- **Go-like build:** each eligible selected root, library, or dependency source
|
||
is validated before its imports complete the graph or any compiler,
|
||
assembler, archiver, linker, install, publication, or runtime action starts.
|
||
A source error in a selected root precedes missing, self, cycle, `internal`,
|
||
vendor, and imported-command resolution. Wrong-target and test-only files
|
||
excluded from ordinary build are not semantic inputs and are not decoded.
|
||
- **Go-like test:** production, same-package, external-package, and test-only
|
||
selected physical sources are validated before grouping or variant/product
|
||
construction. Rejection builds no support action or generated main, starts
|
||
no test process, emits no accounting or package `ok` line, and retains or
|
||
publishes no executable. An attributable explicit request keeps its existing
|
||
command-owned final `FAIL\n` presentation.
|
||
- **Go-like package:** each selected physical file owns its positioned errors;
|
||
selected filenames retain byte-sorted order. Correctly encoded non-ASCII
|
||
content remains legal in WW's permitted comment/literal contexts. Declared
|
||
package names, source roles, package conflicts, command/test classification,
|
||
and variant boundaries do not change.
|
||
- **Go-like import:** a malformed byte is filtered before it can manufacture,
|
||
split, or change an import occurrence, qualifier, or edge. Valid spelling,
|
||
aliases, file-scoped binding, local/vendor/internal resolution, visibility,
|
||
cycle detection, graph order, and initialization remain unchanged.
|
||
|
||
Canonical dotted package and import identity remains exact and
|
||
case-sensitive. Physical directory, declared name, alias, path leaf, filename,
|
||
source bytes, artifact name, output path, and linker order remain loader,
|
||
runtime, or presentation metadata only where already specified; none becomes
|
||
package, graph, action, symbol, `.wwi`, publication, or persistence identity.
|
||
|
||
#### Loading, graph, action, runtime, and diagnostics
|
||
|
||
Filename and test-role eligibility occurs first. The shared preflight then
|
||
scans eligible selected files in existing byte-sorted order, reporting every
|
||
malformed byte in the first invalid physical file in position order before
|
||
package-clause classification. Lines and columns advance by raw source bytes.
|
||
A legal leading BOM still advances three columns, raw NUL keeps its own exact
|
||
diagnostic, and the three source conditions interleave without one being
|
||
reclassified as another.
|
||
|
||
An invalid source completes no package node, import edge, test variant,
|
||
support action, or generated-main action. No compiler, assembler, archiver,
|
||
linker, installer, or runtime process is scheduled for that invalid request.
|
||
Independent valid siblings and requests keep the established command-global
|
||
planning and scheduling rules; validation adds no global state and cannot
|
||
cancel or mutate them. Valid loading, graph identity, action order,
|
||
initialization, runtime behavior, result order, and output selection are
|
||
explicit non-effects.
|
||
|
||
Diagnostics use exact text `invalid UTF-8 encoding` with path, 1-based line,
|
||
and 1-based raw-byte column. Each width-one malformed decode is consumed and
|
||
removed before token recovery, preventing a second stage-specific package,
|
||
import, identifier, literal, operator, escape, or EOF interpretation. Complete
|
||
direct frontend inputs report all malformed bytes. Public package/test loading
|
||
uses the same sequential physical-source preflight and therefore preserves
|
||
Cstage/WWstage diagnostic-byte parity and source-before-resolution precedence.
|
||
Existing valid-input, BOM, NUL, package, import, and output-option diagnostics
|
||
retain their owners and wording.
|
||
|
||
#### Publication, persistence, artifacts, and failure lifecycle
|
||
|
||
Cold malformed-source rejection creates no synthetic unit, `.wwi`, assembly,
|
||
object, archive, executable, retained test binary, result status, capture, or
|
||
published output. It leaves no `.new`, `.install`, `.wwtxn.*`, adjacent
|
||
`.sepwork`, tool-stage transaction, or scratch residue. Invalid input has no
|
||
artifact-byte comparison beyond identical absence.
|
||
|
||
Warm rejection commits no generation and preserves every prior unit,
|
||
interface, assembly, object, archive, tool record, stamp, executable, retained
|
||
binary, and public output byte for byte. Because staging has not begun, the
|
||
source branch requires no new rollback mechanism. Restoring the exact valid
|
||
source follows ordinary content comparison and may reuse the prior committed
|
||
generation. Valid Cstage and WWstage unit, interface, assembly, object,
|
||
archive, generated-main, executable, and retained-test bytes keep their
|
||
existing byte-identity contract.
|
||
|
||
Producer failure, runtime failure, publication-only failure, and cleanup-only
|
||
failure remain downstream owners and are not redefined; malformed-source
|
||
rejection makes those phases unreachable for the invalid request. Validation
|
||
state is source/request-local. Concurrent valid and invalid requests retain
|
||
independent workdirs, outputs, captures, diagnostics, processes, and
|
||
transactions. The change adds no process, wait, signal, timeout, cancellation,
|
||
or interruption boundary, so existing process-group ownership, interruption,
|
||
rollback, and cleanup remain unchanged. The recipe-owned fixed
|
||
`out/bootstrap` tree is not transaction residue.
|
||
|
||
#### Proof, twin parity, and formats
|
||
|
||
Focused C and WW lexer proofs cover valid encodings and encoded U+FFFD;
|
||
invalid leads and continuations; overlong, surrogate, out-of-range, truncated,
|
||
and repeated malformed spellings; token boundaries; and BOM/NUL interaction.
|
||
The WW-native `malformed_utf8_is_rejected_in_every_selected_source` observer
|
||
owns direct compiler, root/dependency build, source/import precedence, every
|
||
test source role, wrong-target selection, cold/warm rejection, exact
|
||
restoration and reuse, valid sibling concurrency, artifact absence, residue
|
||
cleanup, stage diagnostic parity, and valid-artifact byte parity. Concrete
|
||
post-change byte counts, hashes, and gate results are recorded only after
|
||
focused and full validation; they are not inferred from the implementation.
|
||
|
||
No format bump. This changes invalid-source acceptance and diagnostics only;
|
||
the valid persisted-byte contract is unchanged. Build workdir format remains
|
||
`18`, test workdir format remains `19`, and semantic storage format remains
|
||
`3`. No test-result cache is introduced.
|
||
|
||
### 11.46 Implemented effective-`init` import-binding recovery
|
||
|
||
An import whose effective file-local qualifier is `init` is rejected as
|
||
`cannot import package as init - init must be a func`. The rule covers an
|
||
explicit `init` alias and an unaliased dependency declared `package init`.
|
||
Every resolved rejected occurrence reports the core error at the first
|
||
import-spec token: the alias token when explicit, otherwise the first path
|
||
token. The occurrence creates no qualifier and takes no part in unused,
|
||
duplicate-binding, or declaration/import-collision recovery. A later
|
||
`init.Name` therefore recovers independently as undefined. Resolution retains
|
||
precedence, so a missing target fails without an additional effective-`init`
|
||
diagnostic.
|
||
|
||
Only the file-local binding is rejected. The resolved source occurrence and
|
||
its exact dotted dependency remain loader and graph provenance. Neither the
|
||
effective qualifier nor the dependency's declared package name becomes
|
||
canonical package, import, graph, action, symbol, `.wwi`, artifact,
|
||
publication, or persistence identity.
|
||
|
||
The paragraphs above state the normative implementation contract and are
|
||
**behavior derived from the pinned implementation**. The post-change results
|
||
recorded in the proof subsection below are **directly measured WW behavior**.
|
||
|
||
#### Pinned evidence and fact classification
|
||
|
||
The sole authority is official Go 1.26.5 at
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `(*Checker).collectObjects` resolves an import at lines 248–263, selects the
|
||
explicit alias or imported declared name at lines 264–274, rejects effective
|
||
name `init` and immediately continues at lines 275–278, before explicit
|
||
import recording, `PkgName` construction, used-import tracking, or file-scope
|
||
installation at lines 280–335 in
|
||
[`cmd/compile/internal/types2/resolver.go`, lines 223–335](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L223-L335);
|
||
- `(*Checker).unusedImports` examines only admitted imports at
|
||
[`cmd/compile/internal/types2/resolver.go`, lines 706–740](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L706-L740),
|
||
while package/file collision reconciliation is at lines 472–489 of that
|
||
file;
|
||
- the independent public checker implements the same effective-name rejection
|
||
and immediate continuation in
|
||
[`go/types/resolver.go`, lines 261–315, especially 290–293](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L261-L315);
|
||
- compiler-syntax `(*parser).importDecl` assigns the declaration position to
|
||
the first import-spec token in
|
||
[`cmd/compile/internal/syntax/parser.go`, lines 543–574](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/parser.go#L543-L574),
|
||
with node-position ownership in
|
||
[`cmd/compile/internal/syntax/nodes.go`, lines 10–31 and 56–64](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/nodes.go#L10-L64);
|
||
- public `ast.ImportSpec.Pos` independently chooses the alias position when
|
||
present and the path position otherwise in
|
||
[`go/ast/ast.go`, lines 908–915 and 939–946](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/ast/ast.go#L908-L946);
|
||
- compiler diagnostics are stably position-sorted in
|
||
[`cmd/compile/internal/base/print.go`, lines 70–92](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/base/print.go#L70-L92); and
|
||
- package loading and action construction remain separate from file binding in
|
||
[`cmd/go/internal/load/pkg.go`, lines 757–805](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L757-L805)
|
||
and
|
||
[`cmd/go/internal/load/pkg.go`, lines 2024–2047](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L2024-L2047),
|
||
[`cmd/go/internal/work/action.go`, lines 647–658](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L647-L658),
|
||
and test-variant construction in
|
||
[`cmd/go/internal/load/test.go`, lines 175–240](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L175-L240).
|
||
|
||
Official assertions are
|
||
[`internal/types/testdata/check/importdecl0/importdecl0a.go`, lines 9–17](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/importdecl0/importdecl0a.go#L9-L17),
|
||
which expects only the core error for an explicit `init` alias;
|
||
[`test/fixedbugs/issue4517d.go`, lines 7–9](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/fixedbugs/issue4517d.go#L7-L9),
|
||
which covers the explicit spelling; and
|
||
[`test/fixedbugs/issue43962.dir/a.go`, lines 1–5](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/fixedbugs/issue43962.dir/a.go#L1-L5)
|
||
with
|
||
[`b.go`, lines 1–7](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/fixedbugs/issue43962.dir/b.go#L1-L7),
|
||
which covers an imported package declared `init`.
|
||
|
||
Those resolver, syntax-position, loader/action branches and official
|
||
assertions are **behavior directly implemented or asserted by pinned Go**.
|
||
The immediate continuation proves that the rejected occurrence contributes no
|
||
unused, duplicate-binding, or declaration/import-collision recovery; every
|
||
rejected occurrence reports independently; a later selector sees no package
|
||
binding; and missing resolution wins before effective-name checking. The
|
||
separate loader/action path proves that rejecting the qualifier does not erase
|
||
the resolved dependency occurrence or change canonical identity. Those
|
||
conclusions are **behavior derived from the pinned implementation**. They
|
||
honestly apply to WW's local, unquoted dotted-import, manifest-free model
|
||
without adding modules, manifests, registries, lock files, caches, databases,
|
||
CAS, network resolution, quoted/grouped/dot/general imports, or a source-level
|
||
build language.
|
||
|
||
#### Fresh four-axis audit and direct pre-fix measurements
|
||
|
||
The fresh audit also reconfirmed two applicable but unselected differences:
|
||
multiple named source files remain different across build, test, package, and
|
||
import construction; shared test-process state and ordinary-abort behavior
|
||
remain different across test runtime and package/imported mutable state. They
|
||
remain genuine future candidates and were not reclassified as aligned or
|
||
inapplicable. Effective-`init` recovery was selected because the pinned
|
||
resolver supplies one exact, bounded semantic owner whose complete binding and
|
||
lifecycle effects can be closed without redefining either broader gap.
|
||
|
||
Before this slice, the following observations were **directly measured WW
|
||
behavior**. Every Cstage/WWstage pair had identical status, stdout bytes,
|
||
stderr bytes, and artifact state:
|
||
|
||
| Input | Status and stdout | Pre-fix stderr SHA-256 | Pre-fix recovery |
|
||
|---|---|---|---|
|
||
| explicit unused `init` alias | 1; empty | `5248382591e88562ba9c3c648af47523f617be0dcaf16586dc46a2517f76fe58` | bogus unused, then core |
|
||
| explicit alias used by `init.value()` | 1; empty | `a3189e9aeaf56d5cb8aa63aa1a4de07d5176af531555a5834315298e4e9105a8` | core, then undefined |
|
||
| implicit declared-name `init`, unused | 1; empty | `c77b3cf3b052727d90662c9b33ba85c10cba133d25b1d8b41dd53e32e1ab4978` | bogus unused, then core |
|
||
| implicit qualifier used by `init.value()` | 1; empty | `cf0cf83a83077736497cd54a801762912f97ced4684d6c878257edbc79958340` | core, then undefined |
|
||
| two rejected occurrences plus use | 1; empty | `9124e49408a710e1ed49a0b39b46b0967b9fe4c5f8bc67b21205d174bcfaebee` | bogus redeclaration/alternate and unused; two cores; undefined |
|
||
| rejected import plus top-level `let init` | 1; empty | `b5e48cfab10e95d581d64d59e28409c63c7f450fa09c8d2bd11d2bb1bf487c08` | bogus unused/collision/alternate plus correct declaration/core errors |
|
||
| missing target under alias `init` | 1; empty | `5c0fd415bb8bc8791bb87cf7211f69eea06b87ea63f264f5b8b526cbd8ac1fd9` | only missing-package error; aligned precedence |
|
||
| same-package test, unused alias | 1; exact `FAIL\n` | `9b40aac1b160743787b4782a967350b9c97a4bf414ea0c05ea9b926c85403f9e` | bogus unused, then core |
|
||
| external test, later use | 1; exact `FAIL\n` | `e3fcb66e8fe4eabaf2bbac0b510c370dd904fca90daab334ad4cd9b82ac914f3` | core, then undefined |
|
||
|
||
Representative pre-fix output placed both the bogus unused diagnostic and the
|
||
core error at generated-unit column 1, the `import` keyword:
|
||
|
||
```text
|
||
...unit.new:3:1: error: "pkg.normal" imported as init and not used
|
||
...unit.new:3:1: error: cannot import package as init - init must be a func
|
||
```
|
||
|
||
Repeated imports additionally reported `init redeclared in this block`; a
|
||
top-level declaration additionally reported
|
||
`init already declared through import of package init`. These were checker
|
||
recovery artifacts forbidden by the pinned immediate continuation. Pinned
|
||
position ownership maps WW's `import init ...` spelling to the alias at source
|
||
column 8.
|
||
|
||
Aligned controls succeeded in both stages with empty streams: blank
|
||
`import _ pkg.normal;` emitted a stage-byte-identical artifact with SHA-256
|
||
`20847ada6923ab0bfd1dff6a3c387e0c5adace74152b84e895bc420a2e4134e9`,
|
||
and used `import stable pkg.normal;` emitted a stage-byte-identical artifact
|
||
with SHA-256
|
||
`1a8fefbc12d5ea4a2bca938db6fbcdb66f3a14bbc0f7371756e4b5862ed8935c`.
|
||
Each rejected cold case created no new public artifact. A compiler wrapper
|
||
recorded exactly two calls per stage—dependency compilation followed by root
|
||
compilation with its canonical `.wwi`—and failure left the traced workdirs
|
||
empty with no `.new`, `.install`, or `.wwtxn.*` residue. Changing the warm
|
||
valid qualifier to `init` preserved the complete committed work-file manifest
|
||
and public product byte for byte in both stages, with no active transaction
|
||
residue.
|
||
|
||
The direct pre-fix four-axis result was:
|
||
|
||
- **Go-like build:** different diagnostic recovery and position; loading,
|
||
graph, producer order, failure, cold no-publication, warm rollback, and
|
||
cleanup were aligned;
|
||
- **Go-like test:** different for same-package and external-test sources for
|
||
the same checker reason; variant selection and final `FAIL\n` accounting
|
||
were aligned;
|
||
- **Go-like package:** different because a rejected qualifier spuriously
|
||
participated in package-declaration collision recovery; canonical package
|
||
identity was aligned; and
|
||
- **Go-like import:** the core rejection and missing-import precedence were
|
||
aligned, while binding admission, recovery exclusions, and diagnostic
|
||
position were different.
|
||
|
||
#### Ownership and complete four-axis contract
|
||
|
||
The semantic owners are the transient import-spec position plus checker-local
|
||
file-binding recovery:
|
||
|
||
- Cstage: `N_USE` in `cmd/wcc/ww.h:319-375`, import parsing in
|
||
`cmd/wcc/parse.c:1321-1359`, and binding/recovery in
|
||
`cmd/wcc/check.c:2911-2972,3987-4144`;
|
||
- WWstage: the `N_USE` twin in `lib/ww/syntax/ast.ww:108-158`, import parsing
|
||
in `lib/ww/syntax/decl.ww:9-50`, and binding/recovery in
|
||
`selfhost/cmd/wcc/check.ww:178-221,418-434,7531-7675,8601-8650`.
|
||
|
||
Both parsers retain the existing import-keyword node position for unrelated
|
||
structural diagnostics and record a transient first-spec-token position. Both
|
||
checkers identify a nonblank resolved occurrence whose effective qualifier is
|
||
exactly `init`, emit the core diagnostic in source order before qualifier-use,
|
||
duplicate, unused, collision, or installation recovery, exclude it from every
|
||
such table, and silently omit the rejected qualifier from file scope. The AST
|
||
occurrence itself remains intact.
|
||
|
||
Declared-name binding in `cmd/w6c/main.c:315-357` and
|
||
`selfhost/cmd/w6c/main.ww:410-458`, driver graph construction in
|
||
`cmd/ww/main.c:3396-3425,3630-3689` and its self-hosted twin, and all canonical
|
||
dotted identity rules remain unchanged.
|
||
|
||
- **Go-like build:** a resolved invalid root or dependency reaches the normal
|
||
dependency action, then the owning compiler action rejects once per
|
||
occurrence at the spec token without qualifier-recovery noise. Producer
|
||
failure still prevents new publication and preserves a prior committed
|
||
generation.
|
||
- **Go-like test:** the same checker rule applies after existing filename and
|
||
role selection to production-test, same-package-test, external-test, and
|
||
test-only sources. Failed products keep command-owned `FAIL\n` accounting and
|
||
are not installed; test runtime and process topology do not change.
|
||
- **Go-like package:** rejected qualifiers do not collide with package-scope
|
||
declarations. An imported declared name `init` remains the effective name
|
||
tested for an implicit import, but declared name, source role, package
|
||
identity, and package declaration semantics do not change.
|
||
- **Go-like import:** explicit and implicit effective-`init` bindings reject at
|
||
the alias/path spec token; every occurrence rejects; later `init.Name` is
|
||
undefined; missing resolution keeps precedence; and rejected bindings
|
||
create no unused, duplicate, or declaration-collision recovery.
|
||
|
||
#### Loading, lifecycle, parity, and formats
|
||
|
||
Filename/platform/test-role eligibility and selected-source UTF-8, BOM, NUL,
|
||
package-clause, and import-order validation remain earlier and unchanged.
|
||
Excluded and wrong-target files remain non-inputs. Existing dependencies load
|
||
normally; a missing dependency fails before checker binding recovery. Exact
|
||
canonical paths continue to own package nodes, sorted/deduplicated graph edges,
|
||
action keys, symbols, `.wwi` files, artifacts, publication, and invalidation.
|
||
Dependency compilation still precedes the rejecting root action; no action
|
||
ordering, scheduling, transaction, concurrency, or package-product topology
|
||
changes.
|
||
|
||
Only transient parser/checker state changes. No valid compiler output,
|
||
assembler, archiver, linker, initialization, runtime, test-runtime, or
|
||
publication path changes. Invalid root input cannot complete its assembly,
|
||
object, archive, link, retained-test, install, or runtime phases. Dependency or
|
||
root producer failures, runtime failures, publication-only failures, and
|
||
cleanup failures keep their existing owners and classifications.
|
||
|
||
Cold rejection creates no new public or retained root product and commits no
|
||
partial unit, `.wwi`, object, archive, executable, tool record, stamp, or
|
||
result. Warm rejection preserves the previous complete committed generation
|
||
and public product. Dependency reuse and ordinary source invalidation remain
|
||
unchanged, and a rejected generation never replaces root state. The rule adds
|
||
no process, signal, wait, timeout, cancellation, shared state, or lock, so
|
||
established request isolation, interruption rollback, descendant cleanup, and
|
||
concurrent valid/invalid request behavior remain unaffected. Failure leaves no
|
||
active `.new`, `.install`, `.wwtxn.*`, adjacent `.sepwork`, capture, scratch,
|
||
or tool-stage transaction residue; the fixed recipe-owned `out/bootstrap` tree
|
||
is not transaction residue.
|
||
|
||
The WW-native `effective_init_imports_never_enter_binding_recovery` observer
|
||
owns explicit and implicit bindings; unused, used, repeated,
|
||
declaration-collision, selector, and missing-target recovery; valid blank and
|
||
explicit-alias controls; ordinary and imported builds; applicable
|
||
production/same/external/test-only source roles; fixed-path stage
|
||
status/stdout/stderr parity; invalid binding rejection inside a dependency
|
||
reached through an imported root; cold empty-workdir rollback; warm
|
||
preservation; valid artifact-byte parity; and residue cleanup. Concrete
|
||
post-change statuses, diagnostic bytes and hashes, artifact hashes, and ordered
|
||
full-gate results are recorded only after focused and full validation; they are
|
||
not inferred from the implementation.
|
||
|
||
No persisted-byte contract changes. Import-spec coordinates and recovery
|
||
tables are transient compiler state. Build workdir format remains `18`, test
|
||
workdir format remains `19`, semantic storage format remains `3`, and no test
|
||
result cache is introduced.
|
||
|
||
#### Direct post-fix proof and ordered validation
|
||
|
||
The following results are **directly measured WW behavior**. Both rebuilt
|
||
stages reject explicit and implicit effective-`init` bindings at spec-token
|
||
column 8. Every occurrence produces one core error; rejected bindings produce
|
||
no unused, duplicate-binding, declaration/import-collision, or alternate-
|
||
location recovery. Independent invalid declarations and later undefined
|
||
selectors remain diagnosed, while missing-package resolution retains
|
||
precedence.
|
||
|
||
A fixed-path explicit-unused probe produced identical Cstage and WWstage
|
||
results: status 1, empty stdout, and 131-byte stderr with SHA-256
|
||
`615a06b827a41ce214b9e76049b402be94680a14ba5e3416455d7a628185c7d5`.
|
||
The valid blank-plus-explicit-alias control ran with status 41 and had identical
|
||
unit, `.wwi`, assembly, object, archive, generated-init, and executable bytes
|
||
across stages. Its 4,317-byte executable had SHA-256
|
||
`64a48e8b18f035b8598fbe39feedc5a0e6df45d256305cb0f32e8b27a0471b92`.
|
||
|
||
The WW-native observer passed for ordinary roots, a rejecting imported
|
||
dependency, production-test, same-package-test, external-test, and test-only
|
||
sources. It directly proved normalized diagnostic parity, cold empty-workdir
|
||
rollback and no publication, warm preservation and exact reuse of every
|
||
committed semantic file and public product, valid artifact-byte parity, and no
|
||
active transaction residue. `out/bin/test_300_check` passed 73/73 checks.
|
||
|
||
All ordered full gates then passed serially in the required order:
|
||
|
||
1. `make -j4 JOBS=4 test`
|
||
2. `make -j4 JOBS=4 test-commit`
|
||
3. `make -j4 JOBS=4 test-byteid`
|
||
4. `make -j1 JOBS=1 test-bootstrap`
|
||
5. `make -j1 JOBS=1 test-platform`
|
||
6. `make -j1 JOBS=1 test-all`
|
||
|
||
The first byte-identity invocation encountered one transient `roster` timeout
|
||
under four-way load. The exact isolated row passed, and the unchanged third
|
||
gate was rerun successfully: 161 language files and 1,421 data fixtures were
|
||
byte-identical with zero pinned divergences. Bootstrap reached the ww2/ww3/ww4
|
||
fixed point and round-tripped all five WWstage tools byte-identically; the
|
||
platform gate produced a byte-identical dynamic-link result. No production
|
||
code changed after the successful ordered sequence began.
|
||
|
||
### 11.47 Implemented empty-reason test skip classification
|
||
|
||
Pinned Go's applicable semantic rule is that a test may skip without supplying
|
||
a message, remains a successful skipped test, and does not prevent the next
|
||
selected test from running. Mapping that rule to WW's already representable
|
||
`test.skip("")` call is **behavior derived from the pinned implementation**.
|
||
|
||
WW realizes that rule by writing a structurally valid `TST_SKIPPED` control
|
||
frame with a zero-length payload and accepting it when the child otherwise exits
|
||
normally with status zero. Presentation remains
|
||
`qualified.name ... SKIP: ` followed immediately by newline. Skipped
|
||
accounting increases once; failure and harness-error accounting do not.
|
||
Nonempty reasons keep their existing behavior. A 4,094-byte reason remains an
|
||
invalid control result, and skip outside an active test still aborts. Those
|
||
WW-specific frame, presentation, bound, accounting, and outside-active details
|
||
are **directly measured WW behavior** in the post-change proof below; they are
|
||
not attributed to Go's implementation.
|
||
|
||
#### Pinned evidence and fact classification
|
||
|
||
The sole semantic authority is official Go 1.26.5 at
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- [`(*T).Skip` and `(*T).SkipNow` in `testing/testing.go`, lines
|
||
1231–1259](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/testing/testing.go#L1231-L1259)
|
||
show `Skip` accepting a variadic argument list and logging
|
||
`fmt.Sprintln(args...)` before calling zero-argument `SkipNow`; `SkipNow`
|
||
marks and stops that test and explicitly permits the next test to continue;
|
||
- [the package documentation in `testing/testing.go`, lines
|
||
273–293](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/testing/testing.go#L273-L293)
|
||
includes a zero-argument `t.Skip()`; and
|
||
- official assertions in
|
||
[`testing/sub_test.go`, lines
|
||
182–190](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/testing/sub_test.go#L182-L190),
|
||
[237–240](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/testing/sub_test.go#L237-L240),
|
||
and
|
||
[341–346](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/testing/sub_test.go#L341-L346)
|
||
mark message-less `SkipNow` and zero-argument `t.Skip()` cases successful.
|
||
|
||
Those methods, documentation, and official assertions are **behavior directly
|
||
implemented or asserted by pinned Go**: a message-less call is admitted and
|
||
successful, is classified skipped, and permits the next selected test to run.
|
||
That a suite containing this skip and otherwise passing selected tests has an
|
||
overall successful result is **behavior derived from the pinned
|
||
implementation**. The rule honestly applies within WW's local, dotted-import,
|
||
manifest-free model:
|
||
WW's public `test.skip` already takes a `str`, and that type already represents
|
||
the applicable empty-reason case without adding Go syntax, modules, manifests,
|
||
package-path conventions, regex filters, or a new build language.
|
||
|
||
#### Fresh four-axis audit and direct pre-fix measurements
|
||
|
||
The fresh audit classified multiple named source files, explicit
|
||
`*_test.ww` build operands, shared top-level test-process state and abort
|
||
boundaries, bare effective import bindings, and lexical import shadowing as
|
||
applicable differences that remain unselected. Leading-underscore explicit
|
||
source behavior retains a bounded applicability question, mixed declarations
|
||
are aligned, and grouped, quoted, dot, and generalized imports are inapplicable
|
||
to WW's import model. The exact explicitly named `*_test.go` build case lacks an
|
||
official pinned testdata assertion even though pinned source derives its
|
||
behavior, so it was not evidence-complete for this session. The empty-reason
|
||
skip was selected because its complete observable meaning has one bounded
|
||
shared-runtime owner and does not partially implement or redefine those broader
|
||
differences.
|
||
|
||
Before this slice, the following observations were **directly measured WW
|
||
behavior**. The fixed-path probe
|
||
`/tmp/ww-empty-skip-pre.Wkh1CW/pkg` defined production `marker()`, then test
|
||
`first`, which called `test.skip("")`, and passing test `second`. Both Cstage
|
||
and WWstage exited 1, wrote empty stderr, and emitted byte-identical 255-byte
|
||
stdout with SHA-256
|
||
`ed5015be2946b902cd42819d36ad102af34c229732b477441dc4b285ed612be3`:
|
||
|
||
```text
|
||
emptyskip.first ... HARNESS (malformed or contradictory result)
|
||
emptyskip.second ... ok
|
||
1 passed, 0 failed, 0 skipped, 1 harness errors
|
||
2 discovered, 2 selected, 2 started, 2 completed
|
||
FAIL /tmp/ww-empty-skip-pre.Wkh1CW/pkg [emptyskip] (test exit 1)
|
||
FAIL
|
||
```
|
||
|
||
Filtering to `first` failed with one harness error in both stages; filtering to
|
||
`second` succeeded; list mode succeeded and printed both names without
|
||
executing either body. `test -c -o` succeeded with empty streams and produced
|
||
stage-byte-identical 112,861-byte executables with SHA-256
|
||
`2d8f3a1adbd2f158ac605b4cecf9966a2b700ff0cc7f31aaa431bad3bc89e844`.
|
||
Direct execution of those binaries failed identically, with stdout SHA-256
|
||
`b83ef1368512dd3d2ee46c5e6d1c08369b40eb4b849eae70303aebaef80ee650`
|
||
and empty stderr. These are pre-fix measurements only.
|
||
|
||
For that fixed fixture, the directly measured pre-fix four-axis result was:
|
||
|
||
- **Go-like build:** both stages selected and built the production/test inputs
|
||
sufficiently to publish byte-identical retained test executables; this probe
|
||
did not independently trace graph/action topology;
|
||
- **Go-like test:** empty-reason classification, result presentation,
|
||
accounting, package status, and direct retained execution were different,
|
||
while filtering, list non-execution, and later-test execution were aligned;
|
||
- **Go-like package:** the production source and same-package test source formed
|
||
one runnable package result; this probe made no external/test-only-role claim;
|
||
and
|
||
- **Go-like import:** `import test` resolved and linked in both stages; this
|
||
probe made no separate qualifier, unused-import, or graph-provenance claim.
|
||
|
||
The broader unchanged role, identity, graph, persistence, and lifecycle items
|
||
below are implementation boundaries, not additional facts attributed to this
|
||
pre-fix fixture.
|
||
|
||
#### Ownership and complete four-axis contract
|
||
|
||
The true semantic owner is the shared in-binary test control-frame producer and
|
||
interpreter in `lib/test/run.ww`. Both stages link that one WW runtime; there is
|
||
no duplicate C/WW implementation. The producer rejects only a reason larger
|
||
than the control-frame payload limit and writes the empty `TST_SKIPPED` payload
|
||
normally. After the existing header and exact-length checks, the interpreter
|
||
accepts skipped code with payload length zero as well as positive length, while
|
||
retaining the requirement for normal status-zero child termination.
|
||
|
||
- **Go-like build:** ordinary source loading, graph/action construction and
|
||
scheduling, compiler, assembler, archiver, linker, naming, and output
|
||
publication semantics do not change. The source-content change invalidates
|
||
and relinks affected products through existing dependency rules. Ordinary
|
||
products that do not import `test` stay outside the changed source; an
|
||
ordinary product that explicitly imports `test` may rebuild with changed
|
||
artifact bytes, while its outside-active runtime abort remains unchanged.
|
||
- **Go-like test:** every shared-runtime descriptor accepts the empty reason as
|
||
one successful skip. This covers raw single-file, same-package,
|
||
external-test, honest test-only, filtered, coordinator-run retained, and
|
||
later direct retained-binary execution, including an active-test call reached
|
||
through production package code. Production source still contributes no test
|
||
descriptor. The result has no diagnostic or harness error, uses the existing
|
||
blank-after-colon skip line, increments only skipped accounting, and permits
|
||
later selected tests to continue.
|
||
- **Go-like package:** source roles, descriptor order, initialization, declared
|
||
names, and canonical package and variant identities do not change. A runtime
|
||
reason is result data, never identity.
|
||
- **Go-like import:** `import test`, exact dotted dependency resolution, graph
|
||
edges, initialization, qualifier binding, and unused-import behavior do not
|
||
change. No reason byte becomes import, graph, action, symbol, `.wwi`,
|
||
artifact, publication, or persistence identity.
|
||
|
||
#### Lifecycle, parity, proof, and formats
|
||
|
||
Filename and source eligibility, selected-file order, and test-role
|
||
classification are unchanged. An empty reason has no loader representation.
|
||
Graph nodes, edges, actions, ordering, product scheduling, generated
|
||
descriptors, compiler/assembler/archiver/linker operation, and private/public
|
||
output naming remain unchanged. Existing source-content invalidation rebuilds
|
||
affected runtime/test actions; there is no test-result cache.
|
||
|
||
At runtime, only the valid zero-length skip classification changes. Passes,
|
||
nonempty skips, assertion failures, signals, expected abort, premature clean
|
||
exit, ordinary abort, timeout ownership, process groups, descendant cleanup,
|
||
and the existing per-test process boundary retain their current owners and
|
||
behavior. An empty skip emits no diagnostic. Oversized reasons remain harness
|
||
errors, skip outside an active test still aborts, and all build, producer,
|
||
runtime, publication, and cleanup diagnostic channels and precedence remain
|
||
unchanged.
|
||
|
||
Affected private and retained test executables change because their shared
|
||
runtime changes; comparable Cstage and WWstage executables must remain
|
||
byte-identical. `-c`, running `-o`, guarded installation, destination modes and
|
||
names, exact null discard, private execution, and publication order are
|
||
unchanged. A successful empty skip reaches the existing success-publication
|
||
path. Producer, other runtime, and publication failures retain their existing
|
||
failure classification, cold no-partial-publication guarantee, and warm
|
||
preservation of committed generations and prior public bytes.
|
||
|
||
Persistence keys and schemas do not change. Existing content invalidation,
|
||
warm action reuse, relink, commit, rollback, parallel product isolation,
|
||
capture ownership, cancellation, interruption escalation, owned-child cleanup,
|
||
and transaction/scratch cleanup remain unchanged. No active `.new`,
|
||
`.install`, `.wwtxn.*`, adjacent `.sepwork`, capture, result, scratch, or
|
||
tool-stage transaction residue may remain outside an explicitly retained or
|
||
recipe-owned boundary.
|
||
|
||
After the change, both stages directly ran the fixed-path two-test probe with
|
||
status 0 and empty stderr. They emitted the same empty-reason skip line, ran the
|
||
later passing test, reported one pass, one skip, zero harness errors, complete
|
||
2/2 accounting, and the ordinary package `ok` result. Empty-only and pass-only
|
||
filters each succeeded, and list mode still printed both names without running
|
||
them. Both `test -c -o` invocations had empty streams and produced
|
||
byte-identical 112,861-byte mode-0755 executables with SHA-256
|
||
`257d05a99e920875e9d131ce18e7f11592179802fc6f864fc136ebf618d4a88c`.
|
||
Both retained executables then ran directly with status 0, identical empty
|
||
stderr, and identical skip/pass/accounting output.
|
||
|
||
The WW-native `empty_skip_reason_is_a_successful_skip` observer passed after
|
||
rebuilding `out/bin/test_package`. Its dynamic sources directly prove both-stage
|
||
status and stdout/stderr parity for raw single-file, same-package, external,
|
||
and honest test-only descriptors; an active-test call through production code;
|
||
later-test continuation; a nonempty-skip control; empty-only and pass-only
|
||
filters; list nonexecution; cold and warm work; compile-only and running
|
||
retention; byte-identical retained and ordinary `import test` executables;
|
||
direct retained execution; unchanged outside-active abort; the unchanged
|
||
4,094-byte oversized-reason harness error; and transaction/residue cleanup.
|
||
The complete focused `make -j1 JOBS=1 test-package` owner then passed all 53
|
||
observers with zero failures, skips, or harness errors. All ordered full gates
|
||
then passed serially after the final executable production and proof changes:
|
||
|
||
1. `make -j4 JOBS=4 test`
|
||
2. `make -j4 JOBS=4 test-commit`
|
||
3. `make -j4 JOBS=4 test-byteid`
|
||
4. `make -j1 JOBS=1 test-bootstrap`
|
||
5. `make -j1 JOBS=1 test-platform`
|
||
6. `make -j1 JOBS=1 test-all`
|
||
|
||
Every command exited zero. The byte-identity gates compared 161 language files
|
||
and 1,421 data fixtures with zero pinned-divergent fixtures; bootstrap retained
|
||
the `ww2 == ww3 == ww4` fixed point and five-tool WWstage round-trip byte
|
||
identity; and the platform dynamic-link artifact remained Cstage/WWstage
|
||
byte-identical at 8,464 bytes.
|
||
|
||
A final read-only review produced two wording-only corrections: the pinned
|
||
`Skip`/`SkipNow` description was split precisely, and the warm observer comment
|
||
was limited to persisted-work execution rather than claiming unmeasured action
|
||
reuse. With production and executable proof logic unchanged, the exact final
|
||
observer source then passed `make -j1 JOBS=1 test-package` again: all 53 tests
|
||
passed with zero failures, skips, or harness errors.
|
||
|
||
No format bump. Build workdir format remains `18`, test workdir format remains
|
||
`19`, semantic storage format remains `3`, and no test-result cache is
|
||
introduced.
|
||
|
||
### 11.48 Implemented selector-only effective import bindings
|
||
|
||
Pinned Go's applicable semantic rule is that an imported package's effective
|
||
name denotes a package-name object, not a value or type, and that object may be
|
||
used only to qualify a selector. A bare value occurrence is rejected as
|
||
`use of package BINDING not in selector`; a bare type occurrence is rejected as
|
||
`BINDING (package name) is not a type`. A bare occurrence does not mark the
|
||
import used, while a selector does. These rules and diagnostics are **behavior
|
||
directly implemented or asserted by pinned Go**.
|
||
|
||
The rule honestly applies within WW's local, dotted-import, manifest-free
|
||
model. WW already resolves every ordinary import to an effective default or
|
||
explicit file-local qualifier and already represents qualified value and type
|
||
selectors. Treating that existing qualifier as a package-name object closes a
|
||
checker hole without adding quoted, grouped, dot, generalized, network, module,
|
||
manifest, registry, or source-expression import machinery. Applying Go's
|
||
package-name-object rule to WW's already representable import binding is
|
||
**behavior derived from the pinned implementation**.
|
||
|
||
#### Pinned evidence and fact classification
|
||
|
||
The sole semantic authority is official Go 1.26.5 at
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- [`ident` in `cmd/compile/internal/types2/typexpr.go`, lines
|
||
18–60](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/typexpr.go#L18-L60)
|
||
resolves an identifier to its object and, in a type context, rejects an
|
||
object that is not a type name as `NAME (KIND) is not a type`;
|
||
- [the package-name value branch in that file, lines
|
||
89–92](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/typexpr.go#L89-L92)
|
||
rejects a package name outside a selector as
|
||
`use of package NAME not in selector`;
|
||
- [`objectKind` in `cmd/compile/internal/types2/object.go`, lines
|
||
675–680](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/object.go#L675-L680)
|
||
names a `PkgName` object's kind `package name`;
|
||
- [selector checking in `cmd/compile/internal/types2/call.go`, lines
|
||
672–735](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/call.go#L672-L735),
|
||
especially lines 681–691, admits a package name in the selector position and
|
||
marks that exact package-name object used;
|
||
- [import declaration in `cmd/compile/internal/types2/resolver.go`, lines
|
||
248–340](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L248-L340)
|
||
creates the `PkgName` in file scope, and
|
||
[`unusedImports`, lines
|
||
706–740](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L706-L740)
|
||
diagnoses each nonblank package-name object not marked by a selector;
|
||
- [compiler diagnostic sorting in `cmd/compile/internal/base/print.go`, lines
|
||
70–92](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/base/print.go#L70-L92)
|
||
preserves stable source-position ordering; and
|
||
- [binary-expression checking in `cmd/compile/internal/types2/expr.go`, lines
|
||
788–802](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/expr.go#L788-L802)
|
||
checks both operands before returning for either invalid result, so two bare
|
||
package-name operands retain two independently owned diagnostics.
|
||
|
||
Those source branches are **behavior directly implemented or asserted by
|
||
pinned Go**. Official assertions are
|
||
[`test/fixedbugs/issue11361.go`, lines
|
||
7–11](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/fixedbugs/issue11361.go#L7-L11),
|
||
which pairs an unused import with its bare package-value error;
|
||
[`src/internal/types/testdata/check/builtins0.go`, lines
|
||
613–617](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/builtins0.go#L613-L617),
|
||
which rejects a package name passed as a value; and
|
||
[`src/internal/types/testdata/check/decls1.go`, lines
|
||
45–73](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/decls1.go#L45-L73),
|
||
especially line 66, which asserts `math (package name) is not a type`.
|
||
|
||
From those pinned mechanisms it follows that a bare-only named import receives
|
||
both its unused-import diagnostic and its context-specific package-name
|
||
diagnostic; a legal selector removes only the unused diagnostic and never
|
||
excuses a distinct bare occurrence; an explicit alias supplies the displayed
|
||
name; and a sibling file without its own binding follows ordinary name lookup.
|
||
Those conclusions are **behavior derived from the pinned implementation**.
|
||
|
||
#### Fresh four-axis audit and direct pre-fix measurements
|
||
|
||
The fresh audit also confirmed multiple named source operands, explicit
|
||
`*_test.ww` build operands, shared top-level test-process state and fatal-abort
|
||
behavior, Go's regular-expression `-run` matching, and lexical shadowing of import
|
||
bindings as applicable but unselected differences. Ordinary directory
|
||
production selection was aligned. Grouped, quoted, and dot imports remain
|
||
inapplicable to WW's deliberately narrower syntax. Those classifications are
|
||
audit conclusions, not claims that this slice closes the unselected behavior.
|
||
|
||
Before this slice, the following observations were **directly measured WW
|
||
behavior**. With a dependency declared `package wire` and exporting a value and
|
||
type, both stages accepted legal `wire.Value` and `wire.Number` controls and
|
||
produced byte-identical 8,201-byte executables with SHA-256
|
||
`7fb0e95229aa22714d880070388ee5169697543076536267a8c709429cce0fcb`;
|
||
both ran with status 41. A bare-only value caused only the generated-unit
|
||
unused-import diagnostic in each stage. Once a legal selector marked the import
|
||
used, Cstage let a separate bare value reach the linker as
|
||
`undefined reference to 'wire'`, while WWstage let it reach code generation as
|
||
`cgident: unresolvable identifier (rule 7)`. An explicit alias reproduced the
|
||
same stage split using that alias. Reversing occurrence order or adding a
|
||
second bare occurrence did not restore checker ownership.
|
||
|
||
A bare type plus a legal selector was reported by both stages as
|
||
`unknown type 'wire'`, rather than the pinned package-name diagnostic. With no
|
||
selector, Cstage also retained the unused-import error, while WWstage emitted
|
||
only the unknown-type error. A sibling source that did not import `wire` let a
|
||
bare value reach the linker or code generator rather than following ordinary
|
||
undefined-name checking. Blank-import controls did follow ordinary undefined
|
||
lookup, missing targets retained missing-package precedence, and the valid
|
||
qualified/blank control retained artifact-byte and runtime parity. All cold
|
||
failed work directories examined were empty and no output was published.
|
||
|
||
The same checker escape was measured in same-package, external-test, honest
|
||
test-only, production-test, and imported-dependency paths: the test coordinator
|
||
reported `FAIL`, but Cstage failed in the linker while WWstage failed in code
|
||
generation. These status, stream, artifact, and cleanup results are **directly
|
||
measured WW behavior** from the pre-change Cstage/WWstage probes; they are not
|
||
attributed to Go.
|
||
|
||
The directly measured pre-fix result across the permanent axes was therefore:
|
||
|
||
- **Go-like build:** legal selector controls loaded, compiled, linked,
|
||
published, and ran byte-identically, but a bare package name escaped semantic
|
||
checking and failed at different backend phases;
|
||
- **Go-like test:** every applicable generated test source role reached the
|
||
ordinary package failure result, but its checker diagnostic and failure phase
|
||
differed between stages;
|
||
- **Go-like package:** effective qualifiers were already source-local during
|
||
legal selector resolution, but sibling and bare lookup could escape that
|
||
source-local package-name boundary; and
|
||
- **Go-like import:** unused accounting recognized some selector uses, but a
|
||
bare import binding was not consistently classified as a non-value,
|
||
non-type package-name object.
|
||
|
||
#### Ownership and complete four-axis contract
|
||
|
||
The true semantic owner is identifier and type-name resolution in the Cstage
|
||
and WWstage semantic checkers. The checker must distinguish a package-name
|
||
object belonging to the current source from ordinary lexical or package-scope
|
||
objects before generic undefined, type, code-generation, or link recovery. A
|
||
selector remains the only construct that consumes such an object and marks its
|
||
import used. A bare type name must not accidentally mark the import used. Both
|
||
implementations must produce the same normalized diagnostics at the same source
|
||
positions and retain ordinary undefined or unknown-type behavior when the
|
||
current file has no binding.
|
||
|
||
- **Go-like build:** every selected source is rejected during semantic checking
|
||
before compiler output, assembly, archive, link, or installation when it
|
||
contains a bare package-name object. Legal selectors retain the existing
|
||
build graph, actions, artifact bytes, runtime result, and publication rules.
|
||
- **Go-like test:** production, same-package, external-test, and honest
|
||
test-only sources use the same checker rule. Rejection precedes test-process
|
||
construction and execution; discovery, filters, descriptors, result
|
||
accounting, fatal/skip behavior, timeouts, and process cleanup do not change.
|
||
- **Go-like package:** the binding remains owned by exactly its source file.
|
||
Declared package names, canonical package and variant identity, selected
|
||
source membership, exported declarations, initialization, and symbol naming
|
||
do not change.
|
||
- **Go-like import:** default and explicit named bindings become consistently
|
||
selector-only package-name objects. Selectors alone satisfy unused-import
|
||
accounting. Blank imports create no binding, rejected effective `init`
|
||
imports install none, and missing-target resolution keeps precedence.
|
||
|
||
#### Lifecycle, parity, proof, and formats
|
||
|
||
Loading and source eligibility, filename ordering, package-clause validation,
|
||
canonical dotted resolution, contextual local/vendor expansion, source-role
|
||
classification, and graph-edge construction remain unchanged. The diagnostic
|
||
is a property of an already resolved file-local binding; physical directories
|
||
remain loader and presentation metadata and never acquire package, import,
|
||
graph, action, artifact, symbol, `.wwi`, publication, or persistence identity.
|
||
|
||
Semantic rejection occurs within the compiler action before code generation,
|
||
so no assembler, archiver, linker, test runtime, or installer may run for the
|
||
invalid action.
|
||
Diagnostic source order and precedence must remain stable: missing-package,
|
||
invalid effective-`init`, blank-no-binding, import collision, and ordinary
|
||
undefined-name paths keep their established owners; a valid binding receives
|
||
the exact package-name diagnostic and, unless a selector separately used it,
|
||
its independent unused-import diagnostic. Repeated invalid bare occurrences
|
||
are diagnosed independently.
|
||
|
||
Cold rejection must publish no executable, archive, interface, retained test
|
||
binary, or partial semantic action. Warm rejection must preserve the previous
|
||
public product and complete committed work generation byte-for-byte. A later
|
||
valid request must recover through existing invalidation and reuse rules.
|
||
Neither rejected source text nor its physical directory may create a new
|
||
identity or persistence key. Valid controls must retain comparable Cstage and
|
||
WWstage diagnostic and artifact-byte parity.
|
||
|
||
The invalid consumer's compiler action starts and rejects during semantic
|
||
checking, before its code-generation or downstream producer boundary. Already
|
||
valid dependency producers may also have completed before that rejection.
|
||
Assembler, archiver, linker, installer, test-runtime, and runtime-failure paths
|
||
for the invalid consumer are therefore unreachable. Existing producer/runtime
|
||
failure, rollback, publication transactions, parallel-product isolation,
|
||
concurrent-request locking, cancellation, interruption escalation, child
|
||
ownership, and descendant cleanup remain unchanged for other actions. Rejection
|
||
must remove request-owned stages and leave no active `.new`, `.install`,
|
||
`.wwtxn.*`, adjacent `.sepwork`, capture, result, scratch, or tool-stage
|
||
transaction residue.
|
||
|
||
The WW-native `bare_import_bindings_require_selectors` observer is required to
|
||
prove exact cross-stage status and normalized diagnostic parity for bare value
|
||
and type contexts, explicit aliases, selector order, repeated occurrences,
|
||
unused accounting, sibling-file isolation, blank/`init`/missing controls,
|
||
ordinary and imported builds, builtin-spelled package callees (`len`, `size`,
|
||
and `align`), nested value/type contexts, and every applicable test source role.
|
||
In particular, parser-shaped `size`/`align` type arguments must keep type
|
||
checking after the callee is classified as a package-name object and must never
|
||
escape through generic internal-expression recovery. The observer must also
|
||
prove valid artifact-byte/runtime parity, cold empty rollback, warm prior state
|
||
preservation, invalidation and recovery, and residue cleanup. Broader
|
||
producer/runtime failure, concurrency, interruption, and descendant-process
|
||
behavior retain their existing owners because this slice adds no such
|
||
boundary. These are proof requirements; validation and final post-change byte
|
||
measurements are recorded only after they are run.
|
||
|
||
No format bump. Build workdir format remains `18`, test workdir format remains
|
||
`19`, semantic storage format remains `3`, and no test-result cache is
|
||
introduced.
|
||
|
||
### 11.49 Implemented lexical shadowing of import bindings
|
||
|
||
An effective nonblank import qualifier is a file-local package-name object, not
|
||
a reserved spelling. An ordinary closer lexical binding may shadow it. Each
|
||
occurrence resolves to the nearest visible object: a selector before the local
|
||
declaration denotes the import and satisfies that import's use accounting; the
|
||
same spelling after a parameter, local, tuple-local, loop/range binder, or
|
||
match-arm binder denotes that closer binding. Leaving the nested scope restores
|
||
the import binding. A selector consumes an import only when its receiver
|
||
actually resolves to that import's package-name object. A selector whose
|
||
receiver is a local value neither consumes nor resurrects the same-spelled
|
||
import. This includes explicit aliases and qualifiers spelled like builtins.
|
||
|
||
This is lexical binding recovery, not a new import form or an identity rule.
|
||
Blank imports and rejected effective-`init` imports still install no binding;
|
||
an unresolved target still fails during resolution before checker binding
|
||
semantics. WW's existing `for ... else` behavior has no Go counterpart and is
|
||
unchanged.
|
||
|
||
#### Pinned Go evidence and fact classification
|
||
|
||
The sole semantic authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- the language specification defines imports as package objects with file-block
|
||
scope, and defines parameter/body/local declaration points, nested scopes,
|
||
and inner-declaration shadowing ([`doc/go_spec.html`, lines
|
||
2160–2174 and 2190–2233](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/doc/go_spec.html#L2160-L2233));
|
||
- `types2` constructs a file scope and `PkgName`, then resolves objects from
|
||
the innermost scope outwards
|
||
([`cmd/compile/internal/types2/resolver.go`, lines
|
||
223–335](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L223-L335),
|
||
[`check.go`, lines 73–94](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/check.go#L73-L94));
|
||
- parameter and local declaration timing is implemented in
|
||
[`signature.go`, lines 143–180](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/signature.go#L143-L180)
|
||
and [`assignments.go`, lines 525–602](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/assignments.go#L525-L602);
|
||
- selector checking marks an import used only after its receiver resolves to a
|
||
`PkgName`; bodies are processed before unused imports are diagnosed
|
||
([`call.go`, lines 672–692](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/call.go#L672-L692),
|
||
[`check.go`, lines 496–523](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/check.go#L496-L523),
|
||
[`resolver.go`, lines 706–740](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L706-L740)); and
|
||
- official fixtures compile a selector before a later local, retain that
|
||
declaration-point distinction, and show parameter shadowing
|
||
([`test/fixedbugs/bug129.go`, lines 8–13](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/fixedbugs/bug129.go#L8-L13),
|
||
[`issues0.go`, lines 16–23](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/issues0.go#L16-L23),
|
||
[`bug107.go`, lines 8–15](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/fixedbugs/bug107.go#L8-L15)).
|
||
|
||
Those specification, resolver, selector-use, declaration-point, and fixture
|
||
facts are **behavior directly implemented or asserted by pinned Go**. That a
|
||
WW occurrence before a local consumes the import, an occurrence after it sees
|
||
the local, a nested scope restores the import on exit, aliases and
|
||
builtin-spelled qualifiers follow the same rule, and a local selector does not
|
||
consume the import is **behavior derived from the pinned implementation**.
|
||
The behavior honestly applies to WW's existing file-local dotted bindings and
|
||
representable lexical scopes without introducing Go's modules, manifests,
|
||
quoted/grouped/dot imports, registry, cache, network resolution, or source
|
||
build expressions.
|
||
|
||
#### Fresh four-axis audit and direct pre-fix measurements
|
||
|
||
The fresh simultaneous audit classified multiple named source operands as a
|
||
different, applicable build/package slice; explicit `*_test.ww` build operands
|
||
as a different, applicable build/source-selection slice; shared top-level test
|
||
process state and fatal-abort topology as different, applicable test slices; and
|
||
Go-compatible regular-expression `-run` matching as a different, applicable
|
||
test slice. They remain open and unselected: each needs a wider true-owner
|
||
change. Grouped, quoted, and dot imports are inapplicable to WW's deliberately
|
||
narrow import grammar. No fresh pinned evidence reopened a completed section
|
||
through §11.48.
|
||
|
||
Before this slice, all following results were **directly measured WW behavior**:
|
||
|
||
- a directory build containing a real package selector followed by a legal
|
||
`let shadowmod` failed in both stages before publication; Cstage emitted
|
||
positioned 155-byte stderr (SHA-256
|
||
`13cfac9494a1f6c0ee958d3b74ecfe8b0efe2a685f31a8a1771fda3fa0af1b02`),
|
||
while WWstage emitted unpositioned 76-byte stderr (SHA-256
|
||
`298e4991ca9900ef32499762f8ae9abb8ace07c3e672dc66db1e911a8de62b75`).
|
||
Both had empty stdout, no output, and empty precreated workdirs;
|
||
- same-package and external test shadows failed before descriptor execution;
|
||
both emitted exactly `FAIL\n`, published/retained nothing, and left no work
|
||
entry. Cstage stderr was 277 bytes (SHA-256
|
||
`ac850802e5911f53c3e64be2ab55e1f3442438eadab35a40f63ddac869337e4e`),
|
||
WWstage was 186 bytes (SHA-256
|
||
`a1229bd19628e5dc909a0bcb848c30cc1dbdf9d370f21ed51e79489c06abcad0`);
|
||
- after a genuine selector, `let shadowmod: i32 = 1; return shadowmod.say()`
|
||
produced only the shadow prohibition in Cstage, but WWstage additionally
|
||
cascaded through `calling non-function` and `asserttyped: dot`; and
|
||
- an otherwise-unused import with only local `shadowmod.n` produced the shadow
|
||
prohibition rather than unused-import in both stages, proving the former
|
||
syntax-only use pass falsely consumed the import. Legal no-shadow controls
|
||
built, published byte-identical executables (SHA-256
|
||
`7b710cf0973821cec430878d1f90de64485438510512561263c1a16b367c3c78`),
|
||
and exited 42.
|
||
|
||
The direct probes also covered parameter, local, nested, explicit-alias,
|
||
selector-before/after, imported-dependency, same-package, external-test, and
|
||
honest test-only paths; both stages rejected every legal shadow. Thus the
|
||
pre-fix difference was legal-source rejection, false unused-import accounting,
|
||
and stage-divergent downstream recovery.
|
||
|
||
#### Ownership and complete four-axis behavior
|
||
|
||
The true owners are the Cstage semantic checker in `cmd/wcc/check.c`, its
|
||
self-hosted twin in `selfhost/cmd/wcc/check.ww`, and the latter's
|
||
`selfhost/cmd/wcc/cgenexpr.ww` local-versus-imported-enum fast path. They
|
||
remove the import-shadow prohibition; resolve use accounting through isolated
|
||
temporary lexical scopes rather than merely selector spelling; preserve
|
||
declaration timing; and gate dotted package/enum shortcuts on the visible
|
||
binding. The Cstage code generator already follows checker/local stamps and is
|
||
proved rather than redefined. Parsers, loader/source selection, drivers,
|
||
coordinator, canonical resolution, graph/action construction, assembler,
|
||
archiver, linker, runtime, publisher, and persistence records are not owners.
|
||
|
||
- **Go-like build:** raw, directory, and imported programs with legal shadowing
|
||
now pass checking, build through unchanged actions, publish normally, and run
|
||
the local value/field/function-pointer behavior. A genuinely invalid local
|
||
selector fails during checking before code generation or downstream tools.
|
||
- **Go-like test:** production called by test, same-package, external-test,
|
||
honest test-only, filtered, retained, and directly retained products use the
|
||
same rule before execution. Discovery, filters, descriptors, process state,
|
||
fatal/skip behavior, timeout, retention, and cleanup are unchanged.
|
||
- **Go-like package:** import binding remains file scoped; ordinary local scopes
|
||
nest within it, and sibling source files remain independent. Declared names,
|
||
source roles, package/variant identities, exported declarations,
|
||
initialization, symbols, and selected membership do not change.
|
||
- **Go-like import:** the nearest visible object wins. Only a selector whose
|
||
receiver is the visible package-name object satisfies unused-import accounting;
|
||
local field selectors do not. Default/explicit aliases, blank imports,
|
||
effective-`init`, missing-target precedence, canonical dotted identity,
|
||
contextual local/vendor mapping, visibility, cycles, and direct graph edges
|
||
retain their existing semantics.
|
||
|
||
#### Lifecycle, parity, proof, and formats
|
||
|
||
Filename/platform/test-role eligibility, byte-sorted source selection, package
|
||
clauses, source IDs, loading, and resolution remain earlier owners. Shadowing
|
||
does not add/remove an already-resolved direct import edge, rekey actions, or
|
||
change action order, variants, initialization dispatch, linker symbols,
|
||
`.wwi` ownership, artifacts, publication, or persistence identity. Physical
|
||
directories remain loader/runtime/presentation metadata, never canonical
|
||
package, import, graph, action, artifact, symbol, publication, or storage
|
||
identity.
|
||
|
||
The lexical-aware prepass keeps source-position diagnostic ordering. It removes
|
||
every `shadows imported module` diagnostic while preserving missing target,
|
||
invalid effective-`init`, blank/no-binding, collision/redeclaration, and
|
||
selector-only package-name diagnostics. An otherwise-unused import is reported
|
||
before a later invalid local selector according to source position; local
|
||
invalid dots reject with the same positioned recovery stamp in both stages and
|
||
cannot cascade into C/WW code generation, assembler, or linker diagnostics.
|
||
|
||
Valid shadowing reaches ordinary compiler, assembler, archiver, linker, and
|
||
runtime paths. The representative package matrix proves byte-identical
|
||
Cstage/WWstage unit, interface, assembly, object, archive, initializer, and
|
||
published executable artifacts; every test source role proves public binary
|
||
parity, and the retained case proves retained-binary parity. A cold invalid
|
||
action creates no public/retained/interface/archive/object/executable artifact
|
||
and no `.new`, `.install`, `.wwtxn.*`, adjacent `.sepwork`, capture, result, or
|
||
request scratch. A warm edit that
|
||
makes an import unused while also introducing an invalid local selector
|
||
preserves the prior committed generation and public product byte-for-byte;
|
||
exact restoration uses ordinary invalidation/reuse and cannot leave poisoned
|
||
state. Existing producer/runtime failure, late publication failure, rollback,
|
||
concurrency, interruption, process-group ownership, and cleanup remain their
|
||
existing owners because this checker slice adds no process, lock, transaction,
|
||
or shared runtime state.
|
||
|
||
The WW-native `lexical_import_bindings_shadow_normally` package observer and
|
||
the tool-suite `paramshadow_lexical_bindings` fixture matrix jointly prove
|
||
selector before local, self-shadowing initializer, parameter/let/tuple-let/
|
||
ordinary-for/range/match-arm declaration timing, all annotated tuple types
|
||
before any tuple binder, nested restoration, aliases and builtin-spelled
|
||
qualifiers, local struct/pseudo/function-pointer fields, imported-enum name
|
||
collisions, local dotted type/value rejection, unused accounting, and
|
||
sibling-file isolation. The package observer also covers raw and directory
|
||
builds, imported dependencies, every applicable test role, filtered and
|
||
retained/direct-retained execution, normalized diagnostic parity, valid
|
||
artifact/runtime parity, cold cleanup, warm preservation/restoration, and
|
||
residue absence. Blank/effective-`init`/missing-target behavior is unchanged
|
||
and remains proved by the immediately preceding focused observers.
|
||
|
||
Go has no range-loop `else` clause. That WW-only extension is therefore
|
||
inapplicable to this pinned-Go slice and was not redefined: the pre-existing
|
||
Cstage behavior keeps a range binder visible in `else`, whereas WWstage restores
|
||
the outer scope before `else`. Each stage's import-use prepass deliberately
|
||
matches its own live checker there; the cross-stage extension difference remains
|
||
open and is not presented as lexical-shadow parity proved by this slice.
|
||
|
||
No serialized format changes. This alters lexical resolution of source bytes
|
||
already present in the existing action vouchers and adds no action-key, graph,
|
||
artifact-layout, harness-protocol, cache, database, or publication field.
|
||
Build workdir format remains `18`, test workdir format remains `19`, semantic
|
||
storage format remains `3`, and no test-result cache is introduced.
|
||
|
||
### 11.50 Implemented named-source leading-dot/underscore eligibility
|
||
|
||
An explicitly named raw `.ww` source now observes the same unconditional
|
||
basename exclusion as a named `.go` source in Go 1.26.5. This closes the gap in
|
||
WW's existing single-source command route: a final requested basename beginning
|
||
`.` or `_` is not a package source, even though named sources otherwise bypass
|
||
directory-only target-suffix selection. Directory selection already enforced
|
||
this rule and remains unchanged.
|
||
|
||
#### Pinned Go evidence and applicability
|
||
|
||
The reference is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- `PackagesAndErrors` recognizes an existing `.go` operand and routes the
|
||
complete named list to `GoFilesPackage`
|
||
([`cmd/go/internal/load/pkg.go`, lines 2903–2918](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L2903-L2918)).
|
||
`GoFilesPackage` enables `UseAllFiles`, presents only the named `FileInfo`
|
||
entries through a synthetic directory, and loads one command-line package
|
||
([lines 3244–3315](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L3244-L3315)).
|
||
- `go/build.Import` passes each synthetic entry through `Context.matchFile`
|
||
([`go/build/build.go`, lines 886–914](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L886-L914)).
|
||
`matchFile` rejects a name beginning `_` or `.` before extension, target
|
||
suffix, open, imports, or build constraints; that branch precedes the
|
||
`UseAllFiles` condition
|
||
([lines 1438–1509](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1438-L1509)).
|
||
A package with no remaining source category returns `NoGoError`
|
||
([lines 1076–1082](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1076-L1082));
|
||
the command loader presents the case as `no Go files`
|
||
([`cmd/go/internal/load/pkg.go`, lines 250–270](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L250-L270)).
|
||
- Build reports load errors before installation/action construction
|
||
([`cmd/go/internal/work/build.go`, lines 697–728](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L697-L728)).
|
||
Test uses the same loader
|
||
([`cmd/go/internal/test/test.go`, lines 703–719](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L703-L719))
|
||
and turns its error into package setup failure before constructing a runnable
|
||
([lines 1015–1050](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/test/test.go#L1015-L1050)).
|
||
- Official command testdata explicitly records that `_cgo_yy.go` named on the
|
||
command line is ignored and permits the exact `no Go files` result
|
||
([`cgo_bad_directives.txt`, lines 11–23](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/cgo_bad_directives.txt#L11-L23)).
|
||
`import_ignore.txt` independently proves a dot file contributes no import
|
||
([lines 1–11](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/import_ignore.txt#L1-L11)).
|
||
|
||
The rule honestly applies to WW's local literal `.ww` operand. It adds no
|
||
module, manifest, registry, network, generalized import, or build-expression
|
||
surface. This section is deliberately bounded to the existing single raw
|
||
source target. Multiple named sources as one package and visible
|
||
`*_test.ww` exclusion from `ww build` remain separate open semantics; when a
|
||
future source-set loader admits multiple names, it must apply this same rule to
|
||
each requested basename.
|
||
|
||
#### Source, package, and import ownership
|
||
|
||
The twin public drivers own one allocation-free operand predicate after
|
||
existing CLI-shape checks and a successful requested-path `Stat`, but before
|
||
logical resolution or graph entry. It requires an original spelling ending
|
||
exactly `.ww`, then examines only the final requested basename. A hidden parent
|
||
containing visible `main.ww` does not
|
||
exclude the named source. A requested hidden symlink spelling is excluded even
|
||
when its target is visible or non-regular, while a visible requested spelling
|
||
remains eligible even when its target basename is hidden. This follows the
|
||
`FileInfo.Name` seen
|
||
by Go's synthetic named-file directory: Unix `Stat` follows the target but
|
||
fills `Name` from the requested path
|
||
([`os/stat_unix.go`, lines 28–38](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/os/stat_unix.go#L28-L38),
|
||
[`os/stat_linux.go`, lines 13–30](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/os/stat_linux.go#L13-L30)).
|
||
Physical target paths do not become identity.
|
||
|
||
Prefix exclusion precedes every later classifier. `_main_test.ww` and
|
||
`.main_test.ww` are absent before production/test partitioning. A hidden
|
||
`_main_windows.ww` is absent, but a visible `main_windows.ww` named directly
|
||
remains eligible because the named-file analogue uses `UseAllFiles`; directory
|
||
platform filtering is unchanged. Logical operands without a `.ww` suffix,
|
||
directory and recursive requests, imports, and `ww run` retain their existing
|
||
routes.
|
||
|
||
An excluded operand creates no package clause, declaration, production/test
|
||
variant, or top-level state. Its bytes are not decoded or parsed: malformed
|
||
UTF-8, NUL, BOM, missing/invalid package clauses, late imports, missing imports,
|
||
unused imports, cycles, `internal`/vendor rules, and checker diagnostics cannot
|
||
resurrect it or outrank selection. It contributes no qualifier, import-use
|
||
obligation, edge, canonical dotted identity, initializer, or link closure. The
|
||
lexical parent printed by the diagnostic is presentation metadata only and is
|
||
never package, import, graph, action, symbol, `.wwi`, artifact, publication, or
|
||
persistence identity.
|
||
|
||
#### Observable command and lifecycle behavior
|
||
|
||
`ww build HIDDEN.ww` exits 1 with empty standard output and
|
||
`ww: PARENT: directory contains no WW package sources` on standard error.
|
||
An ordinary explicit running `ww test HIDDEN.ww` adds its established exact
|
||
command-owned `FAIL` line on standard output; compile-only and assembly-only
|
||
test requests do not. With no slash, `PARENT` is `.`, a root child uses `/`,
|
||
and otherwise it is the requested lexical bytes before the final slash. CLI
|
||
flag/path-length errors and the existing raw-test directory-only package-option
|
||
shape keep their precedence. A failed requested-path `Stat` retains ordinary
|
||
target/logical resolution; for an existing non-directory raw operand,
|
||
no-source selection precedes logical resolution, output-destination preflight,
|
||
and all source, producer, publication, and runtime diagnostics. Exact
|
||
`/dev/null` does not suppress the load failure.
|
||
|
||
No root/dependency action, test support, generated main, compiler, assembler,
|
||
archiver, linker, harness, test child, or program process starts. Cold rejection
|
||
creates no default or explicit output, workdir, adjacent `.sepwork`, unit,
|
||
`.wwi`, assembly, object, archive, init artifact, binary, status, stage, capture,
|
||
result, transaction, or private temporary directory. Warm rejection starts no
|
||
transaction and preserves every prior work-artifact and public/retained byte.
|
||
It leaves no `.new`, `.install`, `.wwtxn.*`, or recovery residue. Producer,
|
||
runtime, publication-only, cleanup-only, signal, timeout, and descendant
|
||
semantics for visible inputs are unchanged.
|
||
|
||
The predicate is request-local and creates no shared state, process group,
|
||
lock, or interruption owner, so overlapping hidden and visible requests remain
|
||
isolated. Cstage and WWstage must agree byte-for-byte on status, stdout, stderr,
|
||
and complete artifact absence; representative visible named sources retain
|
||
binary and semantic-artifact identity. The focused native
|
||
`named_source_prefixes_are_ignored` observer owns both prefixes, build/test and
|
||
compile-only paths, prefix-before-test/platform precedence, requested symlink
|
||
spelling, hidden-parent/visible-basename and wrong-platform controls, unread
|
||
malformed/import bytes, cold cleanup, warm preservation/restoration, residue,
|
||
and stage parity.
|
||
|
||
No serialized format changes. Build workdir format remains `18`, test workdir
|
||
format remains `19`, semantic storage format remains `3`, and there is no test
|
||
result cache.
|
||
|
||
### 11.51 Implemented explicit named test-source build omission
|
||
|
||
A single existing raw `ww build` operand whose requested final basename ends
|
||
exactly `_test.ww` is now a test-only named source. WW syntax-observes only the
|
||
package clause and its initial contiguous import section, preserves any read/header
|
||
diagnostic, then omits the valid test-only root before logical resolution or
|
||
action construction. This is deliberately distinct from the leading-dot and
|
||
underscore rule in 11.50: `_test.ww` reaches that earlier exclusion, whereas a
|
||
visible `x_test.ww` reaches this test-only omission.
|
||
|
||
#### Pinned authority, tests, and applicability
|
||
|
||
- **behavior directly implemented or asserted by pinned Go** — official Go
|
||
1.26.5 commit `c19862e5f8415b4f24b189d065ed739517c548ba` recognizes an
|
||
existing non-directory named `.go` operand in `PackagesAndErrors`
|
||
([`cmd/go/internal/load/pkg.go`, lines 2903–2918](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L2903-L2918)),
|
||
builds its synthetic command-line package with `UseAllFiles`
|
||
([lines 3244–3315](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L3244-L3315)),
|
||
and classifies `_test.go` separately from `GoFiles`
|
||
([`go/build/build.go`, lines 930–1036](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L930-L1036)).
|
||
`UseAllFiles` bypasses ordinary target and build-expression rejection, but
|
||
not that test-file classification
|
||
([lines 1438–1509](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L1438-L1509)).
|
||
- **behavior directly implemented or asserted by pinned Go** — on a
|
||
successfully scanned header, `readGoInfo` reads the initial package/import
|
||
header and one stop byte, then removes that byte before parsing; on header
|
||
syntax recovery it deliberately drains the remaining source
|
||
([`go/build/read.go`, lines 265–315](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/read.go#L265-L315)).
|
||
Every raw NUL reached by its reader is a read error
|
||
([lines 71–89](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/read.go#L71-L89));
|
||
`parser.ImportsOnly` stops before ordinary declarations
|
||
([`go/parser/parser.go`, lines 2887–2923](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/parser/parser.go#L2887-L2923)).
|
||
Thus a package or initial-import header error precedes omission, while a
|
||
later declaration/body error does not become an ordinary-build error.
|
||
- **behavior directly implemented or asserted by pinned Go** — ordinary
|
||
initial loading does not recursively resolve test imports
|
||
([`cmd/go/internal/load/pkg.go`, lines 350–358](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L350-L358));
|
||
`go/build` records their metadata at `go/build/build.go:1037–1040`.
|
||
Build checks loader errors first and then omits a test-only root before
|
||
output/action construction
|
||
([`cmd/go/internal/work/build.go`, lines 459–559 and 731–745](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/build.go#L459-L559)).
|
||
- **behavior directly implemented or asserted by pinned Go** — related
|
||
official anchors are `go/build/build_test.go:382–421` (`TestMatchFile`),
|
||
`go/build/build_test.go:812–831` (`TestDirectives` and `XTestDirectives`),
|
||
`go/build/read_test.go:17–73,120–159,165–249` (header boundary, NUL, and
|
||
syntax recovery),
|
||
`cmd/go/testdata/script/test_relative_cmdline.txt:1–49`, and
|
||
`cmd/go/testdata/script/build_test_only.txt:1–18`. The pinned official
|
||
repository has no script that directly invokes `go build NAME_test.go`; the
|
||
exact named-build result below is derived from its pinned loader and action
|
||
ordering, not presented as an unanchored direct script assertion.
|
||
- **behavior derived from the pinned implementation** — one valid named test
|
||
source produces no build action. No effective `-o` and exact `/dev/null`
|
||
succeed silently; a non-directory output reports `ww: no packages to
|
||
build\n`; an existing or trailing-slash output directory reports
|
||
`ww: no main packages to build\n`. Header loading occurs before those
|
||
empty-selection branches.
|
||
- **behavior derived from the pinned implementation** — the pinned body
|
||
boundary is byte-sensitive: an ordinary non-`i` stop byte, a first malformed
|
||
UTF-8 byte, or a later BOM byte is excluded, while a reached NUL and an
|
||
unterminated comment remain load errors; a following byte `i` is attempted as
|
||
another import. WW applies the corresponding rule at its lexical `import`
|
||
boundary: it never lexes the first ordinary body token, but preserves NUL and
|
||
comment diagnostics encountered while skipping header trivia.
|
||
|
||
The rule honestly applies to WW's local, manifest-free literal `.ww` model:
|
||
`*_test.ww` already means test source for directory selection and `ww test`.
|
||
It introduces no module, manifest, registry, lock, network resolver, cache,
|
||
generalized import grammar, source build expression, or test-result cache.
|
||
|
||
#### Source and identity ownership
|
||
|
||
- **behavior directly implemented or asserted by pinned Go** — named-source
|
||
package construction presents `Stat`-derived file information through its
|
||
synthetic directory. The operand spelling remains the file name presented
|
||
to selection, even though `Stat` follows a symlink.
|
||
- **behavior derived from the pinned implementation** — the twin true owners
|
||
are `cmd/ww/main.c::do_build` and `selfhost/cmd/ww/main.ww::dobuild`, after
|
||
the existing hidden-prefix check and before `resolve_module` / `resolvemodule`.
|
||
A requested visible non-directory spelling ending `_test.ww` is classified
|
||
from that spelling; a symlink to a directory remains a directory request.
|
||
The finite-stream header reader is not a regular-file restriction: a supplied
|
||
finite FIFO is read as a source, while an unreadable entry reports its header
|
||
read failure. Physical parent directories and symlink targets remain loader
|
||
metadata, never canonical package or import identity.
|
||
- **behavior derived from the pinned implementation** — platform-looking
|
||
visible names such as `x_windows_test.ww` remain test-only named sources.
|
||
Multiple named sources, logical operands without `.ww`, directories,
|
||
recursive requests, `ww run`, and all visible non-test raw operands retain
|
||
their prior routes. In particular, this does not implement Go's multiple
|
||
named-source package collection.
|
||
- **behavior derived from the pinned implementation** — the header observation
|
||
is discarded after classification. It creates no canonical package,
|
||
command-line package representative, dotted import identity, qualifier,
|
||
symbol namespace, `.wwi`, action, archive, publication, or persistence key.
|
||
Initial import syntax is checked solely for load-error precedence; omitted
|
||
test-source imports are not resolved and create no graph edge or action.
|
||
|
||
#### Build, test, package, and import effects
|
||
|
||
- **behavior directly measured WW behavior** — before this change, both stages
|
||
compiled, linked, published, persisted, and ran a valid visible
|
||
`only_test.ww`; `ww build -w WORK -o OUT only_test.ww` exited 0 with empty
|
||
streams, a byte-identical mode-0755 executable, populated work state, and
|
||
runtime status 19. A missing test-only import likewise reached ordinary
|
||
import resolution.
|
||
- **behavior derived from the pinned implementation** — post-contract build
|
||
behavior is an empty production selection after a valid header: no compiler,
|
||
assembler, archiver, linker, generated main, test harness, test child, or
|
||
program process starts. `-S` follows the same no-action rule. No runtime
|
||
result can occur.
|
||
- **behavior derived from the pinned implementation** — package behavior is
|
||
confined to the transient header check; no production/test variant or
|
||
package action remains. Import behavior is likewise confined to syntax;
|
||
missing test-only dotted imports, late imports, body syntax/type errors, and
|
||
runtime faults cannot enter the production graph.
|
||
- **behavior derived from the pinned implementation** — test behavior is an
|
||
explicit non-effect. Raw `ww test`, `ww test -c`, and `ww test -S` continue
|
||
to select named test files. Directory and recursive `ww build` already
|
||
exclude selected test sources and remain unchanged.
|
||
|
||
#### Diagnostics, artifacts, and lifecycle
|
||
|
||
- **behavior derived from the pinned implementation** — CLI-shape and
|
||
multiple-operand delegation retain their prior precedence; 11.50 prefix
|
||
exclusion precedes this header reader. Header read/package/initial-import
|
||
diagnostics precede output policy. A first ordinary malformed UTF-8/BOM body
|
||
byte is excluded, while a reached NUL or unterminated header-trivia comment
|
||
is a header diagnostic. Once the header is valid, no unresolved import,
|
||
graph, producer, linker, or runtime diagnostic may surface. Both
|
||
stages use the same header boundary and must produce byte-identical status,
|
||
stdout, and stderr.
|
||
- **behavior derived from the pinned implementation** — cold no-action success
|
||
creates no default/explicit output, output directory, `.wwi`, unit, assembly,
|
||
object, archive, init product, `.sepwork`, workdir, stamp, transaction,
|
||
capture, result, or private build temporary. Output-policy diagnostics also
|
||
create none of those products.
|
||
- **behavior derived from the pinned implementation** — a warm request starts
|
||
no transaction, mutation, invalidation, reuse check, timestamp refresh, or
|
||
producer. Existing output, sidecar, workdir and artifacts remain
|
||
byte-identical on success and failure; no `.new`, `.install`, `.wwtxn.*`,
|
||
backup, or recovery residue remains. Restoring a visible non-test source
|
||
reuses prior valid warm state by the unchanged ordinary route.
|
||
- **behavior derived from the pinned implementation** — no action means no
|
||
publication, rollback work, producer/runtime failure path, shared lock, or
|
||
child process. Concurrent Cstage/WWstage no-action and header-diagnostic
|
||
requests are isolated. Interruption during header reading leaves no owned
|
||
persistent state; after a valid header there is no child or publication window
|
||
to clean up. Every reader closes its descriptor and releases request-local
|
||
storage before return.
|
||
- **behavior derived from the pinned implementation** — focused proof covers
|
||
valid, malformed-header, missing-test-import, wrong-platform, symlink and
|
||
finite-stream operands; default/file/directory/null/assembly output modes;
|
||
cold/warm preservation; trace-proven tool and runtime absence; rollback,
|
||
interruption, concurrency, cleanup, complete per-stage work preservation, and
|
||
Cstage/WWstage semantic-artifact parity. The complete per-stage snapshot
|
||
includes `.wwtool.ww`; cross-stage comparison excludes only that intentionally
|
||
different producer binary snapshot. Unaffected visible production controls
|
||
retain byte-identical outputs.
|
||
|
||
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:633–638`.
|
||
`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:2903–2932`, especially 2911–2918). Local
|
||
literals that do not enter that route are matched and directory-loaded by
|
||
`cmd/go/internal/modload/load.go:251–307,526–597` and
|
||
`cmd/go/internal/search/search.go:276–293`. `runBuild` uses that loader at
|
||
`cmd/go/internal/work/build.go:459–477`.
|
||
- **behavior directly implemented or asserted by pinned Go** — official
|
||
`cmd/go/testdata/script/list_ambiguous_path.txt:1–15,29–36` 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:1–9,11–17` directly asserts
|
||
that `dir.go -> dir` is not a source entry; `go/build/build.go:886–900`
|
||
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:95–112`
|
||
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:3274–3281`.
|
||
- **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 and preserve the prior public output and committed semantic
|
||
bytes, but leave the directly spawned compiler alive and exactly three
|
||
fixed-name `.new` files. A later persistent request rejects the existing
|
||
`.unit.new`. That independently verified supervision/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.
|
||
|
||
### 11.53 Implemented `.ww`-spelled directory run rejection
|
||
|
||
An existing target selected by `ww run` whose exact requested spelling ends
|
||
`.ww` is a named-source request when ordinary symlink-following `stat` reports
|
||
a directory. Run rejects that directory before package resolution or private
|
||
work creation. This is deliberately different from section 11.52's build/test
|
||
directory route: the command-specific front door, not the shared resolver,
|
||
owns the distinction.
|
||
|
||
#### Pinned authority and applicability
|
||
|
||
- **behavior directly implemented or asserted by pinned Go** — official Go
|
||
1.26.5 commit `c19862e5f8415b4f24b189d065ed739517c548ba`
|
||
scans leading `.go` operands at
|
||
`cmd/go/internal/run/run.go:73–112`, rejecting an `_test.go` spelling at
|
||
103–109 before passing the named set to `GoFilesPackage`.
|
||
`cmd/go/internal/load/pkg.go:3244–3289`, especially 3274–3281, follows
|
||
`Stat` and fatals when a named operand is a directory. Later checking,
|
||
action construction, linking, and execution at `run.go:141–173` are not
|
||
reached.
|
||
- **behavior directly implemented or asserted by pinned Go** — the exact Go
|
||
status, header-free diagnostic, and terminating newline follow
|
||
`cmd/go/internal/base/base.go:137–145,175–183`,
|
||
`cmd/go/main.go:98–100`, and `log/log.go:200–245`. Official
|
||
`cmd/go/testdata/script/run_hello.txt:1–10`, `run_dirs.txt:1–20`, and
|
||
`run_set_executable_name.txt:4–17` anchor the named-file run front and its
|
||
distinction from package-form run. Indirect official directory-kind anchors
|
||
are `list_ambiguous_path.txt:4–15,29–36`,
|
||
`mod_get_go_file.txt:47–58`, and `mod_symlink_dotgo.txt:4–9`. No official
|
||
end-to-end `go run` test asserts this directory diagnostic; the result is
|
||
implemented directly by the cited source.
|
||
- **behavior derived from the pinned implementation** — WW's `.ww`
|
||
named-source spelling and existing directory-package form meet at the same
|
||
practical boundary. The applicable adaptation uses `WW file` and
|
||
`*_test.ww` while preserving requested operand bytes. It requires no module,
|
||
manifest, registry, network lookup, generalized import grammar, cache,
|
||
database, CAS, or build expression.
|
||
|
||
#### Ownership, selection, and diagnostics
|
||
|
||
- **directly measured WW behavior** — before this change, Cstage followed a
|
||
direct `.ww` directory or visible `.ww`/`_test.ww` symlink into the ordinary
|
||
directory graph, invoked compiler, assemblers, linker, and user program, and
|
||
returned that program's status. WWstage instead entered raw-source loading,
|
||
returned status 1 with exact `ww: cannot read source\n`, and ran no producer
|
||
or program. Both removed the private work they had unnecessarily created.
|
||
- **behavior derived from the pinned implementation** — the true WW owners
|
||
are only `cmd/ww/main.c::do_run` and
|
||
`selfhost/cmd/ww/main.ww::dorun`, after their existing option/target parse
|
||
and requested `stat`, but before `resolve_module`/`resolvemodule` and run
|
||
scratch creation. Changing the shared resolver would wrongly change the
|
||
distinct build, test, logical, and dotted-package fronts.
|
||
- **directly measured WW behavior** — after the run-local classification,
|
||
both stages return status 1 with empty stdout. A requested spelling ending
|
||
`_test.ww` emits exactly
|
||
`ww: cannot run *_test.ww files (OPERAND)\n`; every other selected directory
|
||
ending `.ww` emits exactly
|
||
`OPERAND is a directory, should be a WW file\n`. The requested operand is
|
||
reproduced unchanged. `_test.ww` precedence applies before ordinary
|
||
directory rejection, including through a symlink.
|
||
- **directly measured WW behavior** — the rule includes direct and symlinked
|
||
`.ww` directories and hidden directory spellings `.hidden.ww` and
|
||
`_hidden.ww`. It also precedes malformed package clauses and missing imports
|
||
inside the directory because no member is selected or opened. Existing run
|
||
option errors and target determination retain their earlier precedence.
|
||
A trailing separator does not end `.ww`; non-`.ww` directories and dotted
|
||
logical requests retain the established package route.
|
||
|
||
#### Build, test, package, and import effects
|
||
|
||
- **directly measured WW behavior** — package/source selection is the primary
|
||
axis. The rejected request creates no raw or directory package, canonical
|
||
identity, declared-name instance, test variant, initializer, graph node, or
|
||
action. Requested spelling and followed target are diagnostic observations
|
||
only, never canonical package, action, symbol, artifact, `.wwi`,
|
||
publication, or persistence identity.
|
||
- **directly measured WW behavior** — build retains section 11.52's stat-first
|
||
rule for the same direct and symlink spellings. It still enumerates the
|
||
directory, discovers its dotted dependencies, constructs ordinary package
|
||
actions, and applies the established default, explicit, directory,
|
||
`/dev/null`, `-S`, publication, persistence, invalidation, and rollback
|
||
policies. Unaffected build controls retain stage-byte-identical public and
|
||
semantic artifacts.
|
||
- **directly measured WW behavior** — raw `ww test`, `ww test -c`, and
|
||
directory `ww test -S` retain their stat-first directory selection and
|
||
established diagnostics/artifact bytes. Test package variants, generated
|
||
main, process topology, filtering, capture, result ordering, retention, and
|
||
result non-caching are unchanged.
|
||
- **directly measured WW behavior** — imports are not scanned on the selected
|
||
run rejection and create no qualifier or edge. Dotted and non-`.ww` package
|
||
controls retain exact canonical import identity, dependency discovery, and
|
||
runtime behavior. No physical directory becomes canonical identity through
|
||
this rule.
|
||
|
||
#### Actions, lifecycle, parity, and scope
|
||
|
||
- **directly measured WW behavior** — selected rejection invokes no compiler,
|
||
assembler, archiver, linker, initializer, runtime, or owned child/process
|
||
group. A fixture-preoccupied exact `/tmp/ww_run_<pid>` plus sentinel remains
|
||
untouched, proving that the driver does not acquire or mutate its run-scratch
|
||
path; final cleanup leaves that path absent. It also creates no output,
|
||
`.sepwork`, unit, `.wwi`, assembly, object, archive, executable, capture,
|
||
result, transaction, stage, backup, or persistent record. Thus
|
||
producer/runtime failure, publication, reuse, invalidation, and rollback are
|
||
inapplicable on this preflight route; all prior caller and committed bytes
|
||
remain untouched.
|
||
- **directly measured WW behavior** — classification is request-local,
|
||
read-only, and isolated under concurrency. An interruption in this preflight
|
||
owns no child or filesystem resource. The general direct-driver interruption
|
||
gap from section 11.52 remains open: a different request interrupted after
|
||
transaction staging can still leave fixed-name `.new` files and poison
|
||
later persistent reuse. This slice neither reaches nor fixes that machinery.
|
||
- **directly measured WW behavior** — Cstage and WWstage match exactly on
|
||
status, stdout, stderr, diagnostic bytes, empty producer traces, artifact
|
||
absence, exact PID-path non-acquisition and final absence, concurrent
|
||
isolation, and cleanup for every selected row. Unaffected controls retain
|
||
diagnostic and public or semantic artifact-byte parity.
|
||
- **behavior derived from the pinned implementation** — this narrow
|
||
file-kind slice does not implement the complete suffix-first run front.
|
||
Regular or missing `_test.ww`, missing or logical `.ww`, multiple named
|
||
sources, finite FIFOs, and hidden regular sources retain their prior routes
|
||
and remain separately open where different. Recursive requests, ordinary
|
||
directory requests, and generalized imports are not changed.
|
||
|
||
The focused WW-native observer covers direct, symlinked, hidden, ordinary, and
|
||
`_test.ww` directory spellings; malformed-package and missing-import
|
||
precedence; exact requested diagnostics; empty tool/runtime traces; exact
|
||
PID-path non-acquisition and final absence; concurrency and cleanup;
|
||
trailing-separator,
|
||
non-`.ww`, regular-source, and dotted logical run controls; and unchanged
|
||
same-spelling build and raw/compile-only/assembly-only test 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.
|
||
|
||
### 11.54 Implemented wrong-suffix physical-source exclusion
|
||
|
||
One public operand is a local named source only when its exact requested
|
||
spelling ends `.ww` and the command's existing file-kind rule admits it. An
|
||
existing non-directory object with any other suffix does not become source and
|
||
does not preempt the same operand's ordinary dotted lookup. Thus a physical
|
||
`foo.bar` is ignored as a source while request `foo.bar` continues to
|
||
`foo/bar.ww` or `foo/bar/`. An existing directory, including a symlink whose
|
||
target is a directory, remains a stat-first directory package regardless of
|
||
suffix.
|
||
|
||
#### Pinned authority and applicability
|
||
|
||
- **behavior directly implemented or asserted by pinned Go** — official Go
|
||
1.26.5 commit `c19862e5f8415b4f24b189d065ed739517c548ba` enters named-file
|
||
mode in `cmd/go/internal/load/pkg.go:2887–2932`, especially 2903–2918,
|
||
only when a requested spelling ends `.go`, `Stat` succeeds, and the result
|
||
is not a directory. `GoFilesPackage` independently rejects every non-`.go`
|
||
member at `pkg.go:3244–3318` before constructing its synthetic package.
|
||
Build and test call that loader at
|
||
`cmd/go/internal/work/build.go:459–477` and
|
||
`cmd/go/internal/test/test.go:684–719`. Run independently consumes only
|
||
leading `.go` spellings at `cmd/go/internal/run/run.go:73–145`, especially
|
||
96–123.
|
||
- **behavior directly implemented or asserted by pinned Go** — official
|
||
`cmd/go/testdata/script/list_test_non_go_files.txt:1–13` directly tests a
|
||
mixed named-file list: after a `.go` member selects named-file mode,
|
||
`GoFilesPackage` rejects the non-`.go` member. Official `run_hello.txt:1–10`
|
||
and `run_set_executable_name.txt:4–17` anchor ordinary named-file and package
|
||
run fronts. None directly tests one existing wrong-suffix object colliding
|
||
with a package request, and the official tree contains no such singular
|
||
build/run/test script.
|
||
- **behavior derived from the pinned implementation** — the singular
|
||
collision result follows from the pinned suffix-before-`Stat` build/test
|
||
gate and run's suffix-only scan. WW's honest local adaptation applies the
|
||
same positive spelling decision to `.ww` named sources before its existing
|
||
dotted search. It requires no module, manifest, registry, network lookup,
|
||
generalized import syntax, cache, database, CAS, lock, or source expression.
|
||
|
||
#### Ownership, selection, and identity
|
||
|
||
- **directly measured WW behavior** — before this change, both stages adopted
|
||
an existing physical `foo.bar` as a raw source. Build and run therefore used
|
||
its package, imports, main, and runtime status instead of `foo/bar.ww`;
|
||
raw, compile-only, and assembly-only test used its test descriptors and
|
||
retained its semantic/public bytes. Removing only `foo.bar` selected the
|
||
logical provider and changed all of those observations.
|
||
- **behavior derived from the pinned implementation** — the true shared
|
||
owners are `cmd/ww/main.c::resolve_module` and
|
||
`selfhost/cmd/ww/main.ww::resolvemodule`. Their direct non-directory adoption
|
||
now requires the exact `.ww` requested spelling. The mirrored spelling
|
||
predicate also owns build/run requested-literal bookkeeping and raw test's
|
||
second-positional classifier plus main stat/resolution branch. These command
|
||
fronts distinguish direct directory, eligible direct source, and logical
|
||
resolution without moving the rule into the compiler, enumerator, graph,
|
||
coordinator, producer, or runtime.
|
||
- **directly measured WW behavior** — a resolved logical single-file provider
|
||
retains the established command-line-file root family `__root.*`; selection
|
||
by a dotted request does not invent a dotted storage identity. A resolved
|
||
logical directory retains its dotted package/import/action family such as
|
||
`foo.bar.*`. The ignored physical pathname, object kind, containing
|
||
directory, bytes, mode, and timestamp create no package member, qualifier,
|
||
graph node or edge, action, symbol, `.wwi`, initializer, artifact,
|
||
publication destination, or persistence key. The logical requested spelling
|
||
remains canonical request identity where the existing directory route uses
|
||
it.
|
||
- **directly measured WW behavior** — requested suffix, not a symlink target's
|
||
basename, owns the positive gate. A wrong-suffix symlink to a regular or
|
||
non-directory special object is ignored as source; a wrong-suffix symlink to
|
||
a directory follows ordinary directory routing. A visible `.ww` symlink to a
|
||
regular source remains eligible. Each stage retains its prior visible `.ww`
|
||
special-file kind handling; this slice does not make FIFO/device loading a
|
||
shared new contract.
|
||
|
||
#### Build, test, package, and import effects
|
||
|
||
- **directly measured WW behavior** — with a logical provider, build produces
|
||
the same source set, import closure, initializer graph, producer calls,
|
||
runtime result, public output, and persistent artifacts whether the
|
||
wrong-suffix object is absent or present. Run executes that same provider.
|
||
Raw/running test, the historical second-positional test-name filter,
|
||
`test -c`, and `test -S` select the same logical test package, descriptors,
|
||
support closure, binary, and assembly. Cstage and WWstage outputs and every
|
||
comparable semantic artifact are byte-identical.
|
||
- **directly measured WW behavior** — the ignored object's package clause,
|
||
imports, malformed bytes, checker failures, abort/nonzero behavior, and
|
||
timestamps are not source input and cannot displace logical-provider
|
||
diagnostics. Package membership and import edges are exactly those of the
|
||
provider. A logical directory retains its dotted identity and a logical file
|
||
retains `__root`; physical collision state supplies neither.
|
||
- **directly measured WW behavior** — when no logical provider exists, a
|
||
collision matches the absent-physical control. An ordinary build or run
|
||
emits its existing `cannot find module` diagnostic; raw test emits its
|
||
existing `cannot find` diagnostic plus `FAIL` only when running; `-c` and
|
||
`-S` omit that marker. A second positional deliberately retains the historic
|
||
package-coordinator route and its exact canonicalization or usage result,
|
||
rather than being silently redefined as a direct cannot-find path. Existing
|
||
flag, output, tree, package-option, hidden-source, named `_test.ww`, and
|
||
`.ww` run-directory precedence remains unchanged.
|
||
- **behavior derived from the pinned implementation** — all four permanent
|
||
axes meet at this one source-eligibility decision. Build no longer constructs
|
||
or publishes the wrong action; test no longer constructs or runs the wrong
|
||
test package; package membership is not stolen by an ineligible physical
|
||
filename; and import binding/initialization comes only from the logical
|
||
provider. No axis receives a compatibility bypass or new identity model.
|
||
|
||
#### Lifecycle, parity, formats, and scope
|
||
|
||
- **directly measured WW behavior** — changing the collision among absent and
|
||
stat-successful non-directory states does not invalidate semantic actions or
|
||
alter semantic bytes or producer inputs. An unchanged warm command still
|
||
performs the established final link and success publication, producing the
|
||
same public bytes while its inode and mtime may change. Replacing the
|
||
collision with a directory, or retargeting a symlink to a directory, leaves
|
||
this case and follows ordinary stat-first directory behavior; no new atomic
|
||
snapshot promise is made for a concurrent kind change.
|
||
- **directly measured WW behavior** — logical producer failure preserves the
|
||
prior public and semantic generation. A retained running-test runtime failure
|
||
occurs after the complete logical build generation commits: deferred public
|
||
installation is skipped, so prior retained public bytes survive while the
|
||
newly built semantic generation remains committed and reusable. Restoring the
|
||
prior source requires a later successful rebuild and commit, not rollback of
|
||
the runtime-failing generation. Normal completion and controlled failures
|
||
remove request-owned scratch and transaction fragments. The spelling gate is
|
||
request-local and allocates no state before logical action or coordinator
|
||
start; concurrent requests use separate destinations and the existing
|
||
logical-action synchronization.
|
||
- **directly measured WW behavior** — external signal interruption after an
|
||
action starts is unchanged. In particular, the verified direct-driver fixed
|
||
`.new` leakage and later persistent-request poisoning remain open. This
|
||
source classifier neither prevents nor recovers that residue and makes no
|
||
signal-cleanup claim.
|
||
- **behavior derived from the pinned implementation** — the rule does not
|
||
complete the remaining suffix-first run front, multiple named sources,
|
||
finite `.ww` FIFO capture, shared test-process state/failure topology,
|
||
or Go-compatible `-run` regular expressions. Exact `package documentation`
|
||
suppression was still open when section 11.54 closed and is completed in
|
||
section 11.55. Existing `.ww` directory slices, hidden-source exclusion,
|
||
named `_test.ww` build omission, recursive/multiple-root coordination,
|
||
package syntax, and import syntax remain intact.
|
||
|
||
Build workdir format remains `18`, test workdir format remains `19`, and
|
||
semantic storage format remains `3`. No schema, action descriptor, cache/result
|
||
record, manifest, transaction protocol, or lock changes.
|
||
|
||
### 11.55 Implemented exact `package documentation` source suppression
|
||
|
||
A selected source whose successfully parsed package name is exactly
|
||
`documentation` is a documentation source, not a semantic package source. It
|
||
is removed by loading before source-family folding, import-edge construction,
|
||
or any build, run, or test action. `documentation_test`, `documentationx`, and
|
||
every other package name remain ordinary.
|
||
|
||
#### Pinned authority, header boundary, and applicability
|
||
|
||
- **behavior directly implemented or asserted by pinned Go** — the sole
|
||
authority is official Go 1.26.5 commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`. Its `go/build` loader records a
|
||
package/import-header error before excluding an exact parsed package name
|
||
`documentation`, and does so before `_test.go` or package-family
|
||
classification. Named Go files pass through the same rule. Public Go command
|
||
help also reserves the name and says such files are ignored.
|
||
- **behavior directly implemented or asserted by pinned Go** — the pinned
|
||
loader reads the package clause and contiguous import section, not an
|
||
arbitrary body. A successful ordinary-body stop removes its one-byte
|
||
lookahead. It first probes a raw following `i` as a possible `import`,
|
||
however, so an `i` that does not form that exact keyword is a malformed
|
||
attempted import rather than a successful body boundary. Exact `import`
|
||
followed by malformed import syntax retains the ordinary import-parser
|
||
diagnostic.
|
||
- **behavior directly implemented or asserted by pinned Go** — official
|
||
`src/go/build/read_test.go` tests the ordinary-body stop and malformed-import
|
||
recovery, but no test or testdata in the pinned tree directly names
|
||
`package documentation`. `cmd/go/testdata/script/mod_doc.txt` concerns module
|
||
documentation and is not evidence for this rule. This absence is explicit;
|
||
host-Go observations do not fill it.
|
||
- **directly measured WW behavior** — before suppression, both driver stages
|
||
incorrectly treated documentation files as ordinary sources: doc-only roots
|
||
produced semantic artifacts, mixed roots conflicted, imported providers
|
||
created edges and actions, and test routes created test products. Valid
|
||
malformed bodies also exposed stage-specific recovery diagnostics, while
|
||
malformed package and contiguous-import headers already failed before an
|
||
action.
|
||
- **behavior derived from the pinned implementation** — the quiet candidate
|
||
recognizer admits one leading BOM, leading whitespace, comments, internal
|
||
line directives, and trivia around `package`, exact identifier
|
||
`documentation`, and `;`. It emits no diagnostic and sends only a plausible
|
||
exact candidate through the existing package/import-header parser, so
|
||
ordinary sources acquire no new early diagnostics. Malformed candidate
|
||
headers retain that parser's positioned errors.
|
||
- **behavior derived from the pinned implementation** — after a valid exact
|
||
header, a non-`i` first raw byte at the body boundary ends loading and every
|
||
later byte is ignored. If that first raw byte is `i` but does not form the
|
||
exact `import` token, both stage drivers and the shared coordinator emit
|
||
exactly `<FILE>:<LINE>:<COL>: error: expected top-level decl\n`, owned by
|
||
that byte. A malformed exact import retains its existing diagnostic. A
|
||
malformed package clause, malformed contiguous import, reached header NUL,
|
||
or unterminated header-trivia comment also remains an error. No no-source
|
||
diagnostic follows any such header error.
|
||
|
||
#### Selection, package identity, and imports
|
||
|
||
- **behavior derived from the pinned implementation** — existing CLI and
|
||
operand-shape errors, logical resolution and file-kind checks, and suffix,
|
||
hidden-prefix, target, and test-role eligibility retain precedence. The rule
|
||
then applies to selected directory members, literal and logical named roots,
|
||
raw tests, direct and recursive coordinator discovery, and every dotted
|
||
dependency resolving to a directory. Source imports remain directory-only;
|
||
a logical one-file provider is only a CLI-root compatibility route.
|
||
- **behavior derived from the pinned implementation** — named-file
|
||
documentation preflight is entered only after symlink-following `stat`
|
||
classifies the selected source as regular. A symlink to a regular file is
|
||
therefore included. The preflight owns one exact read buffer: a suppressed
|
||
documentation source is discarded from that buffer, while an ordinary source
|
||
carries the same bytes into graph loading instead of being reopened. FIFO and
|
||
other nonregular named-source routes retain their existing handling and are
|
||
neither classified nor otherwise changed by this preflight.
|
||
- **behavior derived from the pinned implementation** — coordinator directory
|
||
discovery collects metadata only. It canonicalizes and deduplicates selected
|
||
paths before reading source, classifies each unique source exactly once, and
|
||
passes the retained ordinary-source buffer to its existing source validation.
|
||
Direct-root errors and recursive pattern/group accounting are computed per
|
||
request from those classification results; a directory member is not
|
||
reclassified for each spelling or pattern that found it. The delegated stage
|
||
driver owns a separate request-graph observation: it enumerates each reached
|
||
canonical directory once, lazily opens only role-eligible files, and reuses
|
||
each observed path, classification, package-name/`@test` attestation, and byte
|
||
snapshot across production, same-package-test, external-test, and copied test
|
||
actions. A production-only request therefore still leaves `*_test.ww`
|
||
unopened. The coordinator and delegated driver are distinct existing process
|
||
boundaries; this slice does not add a cross-process atomic snapshot for a
|
||
source concurrently rewritten between those observations.
|
||
- **behavior derived from the pinned implementation** — the three test-source
|
||
routes remain distinct. A visible literal named `_test.ww` build first
|
||
validates its package/import header and then omits it by the already completed
|
||
test-only rule; documentation classification, including the raw-`i` check,
|
||
does not run. Directory production keeps eligible `*_test.ww` entries
|
||
unopened. Raw `ww test` and selected directory test variants do run the
|
||
documentation classifier. A logical request whose resolved file merely has
|
||
an `_test.ww` physical basename is not the literal named-build special case.
|
||
- **behavior derived from the pinned implementation** — an omitted source
|
||
contributes no package member, declared-family or test-family candidate,
|
||
import occurrence, binding or edge, qualifier, initializer, declaration,
|
||
symbol, graph action, unit, `.wwi`, or persistence identity. Its physical
|
||
pathname, parent, and symlink information remain loader observations only.
|
||
A logical one-file CLI source receives `__root` identity only when retained
|
||
as ordinary. A doc-only dotted directory provider has no package sources and
|
||
cannot satisfy an import; a same-named `.ww` file remains an import decoy
|
||
under the pre-existing directory-only import rule.
|
||
- **behavior derived from the pinned implementation** — a mixed directory
|
||
retains exactly the canonical local or dotted identity and source graph of
|
||
the same tree with the documentation file absent. Imports appearing in the
|
||
valid contiguous documentation header are checked only to establish the
|
||
header; they never become dependency edges. Imports, declarations,
|
||
initializers, tests, aborts, nonzero mains, missing dependencies, and syntax
|
||
after a successful non-`i` body boundary are unobserved.
|
||
|
||
#### Build, run, and test empty selections
|
||
|
||
- **behavior derived from the pinned implementation** — a direct
|
||
non-coordinator doc-only `ww build DIR` exits 1 with empty stdout and exact
|
||
stderr `ww: DIR: directory contains no WW package sources\n`. A selected
|
||
named or logical non-test source uses its physical containing directory in
|
||
the same diagnostic, and `-S`, output, and `/dev/null` modes do not displace
|
||
it. A direct root already routed through the coordinator, including an
|
||
output-directory request, instead uses exact stderr
|
||
`wwtest package: DIR: directory contains no WW package sources\n` with the
|
||
same status and stdout.
|
||
- **behavior derived from the pinned implementation** — the literal visible
|
||
named `_test.ww` build retains section 11.51's outcome even when its valid
|
||
declared name is `documentation`: no effective `-o` (including an
|
||
assembly-only request), or exact `/dev/null`, succeeds silently; a
|
||
non-directory output exits 1 with
|
||
`ww: no packages to build\n`; an output-directory request exits 1 with
|
||
`ww: no main packages to build\n`. Header errors still precede those
|
||
outcomes.
|
||
- **behavior derived from the pinned implementation** — `ww run` on a selected
|
||
doc-only physical or logical directory exits 1 with empty stdout and
|
||
`ww: DIR: directory contains no WW package sources\n`. The existing private
|
||
`/tmp/ww_run_<pid>` is acquired before directory enumeration and then
|
||
removed. A named or logical one-file run uses its physical parent's
|
||
no-source diagnostic before acquiring run scratch. The separately open
|
||
suffix-first run behavior may select a visible `_test.ww`; when it does, this
|
||
rule suppresses that source. A `.ww`-spelled directory keeps the earlier
|
||
stat-first run rejection.
|
||
- **behavior derived from the pinned implementation** — direct doc-only
|
||
`ww test DIR` exits 1 with stdout `FAIL\n` and the coordinator no-source
|
||
stderr; `ww test -c DIR` exits 1 with empty stdout and the same stderr.
|
||
Directory `test -S` without the required `-o` retains status 2 and exact
|
||
`ww test: -S needs -o\n`; after a valid `-o`, the directory retains status 2
|
||
and exact `ww test: -S needs a single test file\n`. Both checks precede
|
||
source classification. Named or logical raw `ww test FILE` exits 1 with
|
||
`FAIL\n` and the physical parent's driver no-source stderr; raw `-c` and
|
||
`-S` exit 1 with empty stdout and the same stderr. No requested output or
|
||
work state changes.
|
||
- **behavior derived from the pinned implementation** — a recursive build
|
||
pattern retaining only doc-only directories exits 0 with empty stdout and
|
||
one `ww: warning: "PATTERN" matched no packages\n`; recursive test exits 1
|
||
with empty stdout, that warning, then
|
||
`ww test: no packages to test\n`. A pattern also containing ordinary
|
||
directories builds or tests only those groups without warning. Multiple
|
||
patterns warn once for each no-match pattern. Any directly named doc-only
|
||
sibling root fails the complete request during discovery before any ordinary
|
||
group starts.
|
||
- **behavior derived from the pinned implementation** — the positioned raw-`i`
|
||
header error has empty stdout for build, run, `test -c`, and raw `test -S`.
|
||
An explicit running raw or directory/recursive test adds exactly `FAIL\n`.
|
||
Literal named `_test.ww` build and directory `test -S` retain their earlier
|
||
precedence and never reach this classifier.
|
||
|
||
#### Actions, lifecycle, parity, formats, and scope
|
||
|
||
- **behavior derived from the pinned implementation** — a doc-only source
|
||
causes no compiler, assembler, archiver, linker, generated test support/main,
|
||
test child, initializer, or program runtime. It creates no unit, `.wwi`,
|
||
assembly, object, archive, executable, output directory, sidecar, workdir
|
||
stamp, transaction, capture, or retained result. Mixed outputs and comparable
|
||
semantic artifacts are byte-identical to the source-absent control.
|
||
- **behavior derived from the pinned implementation** — a documentation source
|
||
has no publication destination or persistent key. Adding, removing, or
|
||
changing only an ignored documentation body does not invalidate, refresh,
|
||
replace, or become a reuse input for committed ordinary actions. Doc-only
|
||
cold failure publishes nothing; a warm no-source or header failure preserves
|
||
prior public and semantic bytes. Ordinary sibling publication, producer
|
||
failure, transaction rollback, and invalidation remain unchanged.
|
||
- **behavior derived from the pinned implementation** — classification state
|
||
is ephemeral and request-owned: the named-root preload is process-local and
|
||
cleared at the build boundary, while directory observations live only in the
|
||
request graph. Neither is persisted or shared across requests, and no lock,
|
||
schema, cache, or cross-request identity is added. Normal and controlled
|
||
failure use the existing reader and request-private cleanup. The verified
|
||
direct-SIGTERM fixed-`.new` poisoning gap remains open and is neither reached
|
||
nor repaired by this slice.
|
||
- **behavior derived from the pinned implementation** — Cstage and WWstage
|
||
must agree on selected status, stdout, stderr, source membership, graphs,
|
||
actions, semantic artifacts, and lifecycle. The producer-provenance
|
||
`.wwtool.ww` remains intentionally stage-specific. Build workdir format
|
||
remains `18`, test workdir format remains `19`, and semantic storage format
|
||
remains `3`; no action descriptor, cache/result record, transaction marker,
|
||
manifest, database, or lock is added.
|
||
|
||
### 11.56 Implemented blank declared package-name checking
|
||
|
||
The exact declared name in `package _;` is now valid package-clause syntax and
|
||
an invalid package name. Loaders retain the clause, its imports, and an
|
||
otherwise coherent source family long enough to construct the applicable
|
||
ordinary action; the compiler checker then reports exactly
|
||
`invalid package name _` at the underscore token and continues checking that
|
||
source. The underscore is accepted only in this package-name grammar slot. It
|
||
does not become an ordinary identifier, import alias, qualifier, canonical
|
||
package name, or successful exported identity.
|
||
|
||
#### Pinned authority, tests, and applicability
|
||
|
||
The sole authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- **behavior directly implemented or asserted by pinned Go** — the compiler
|
||
scanner admits `_` to identifier scanning, dispatches it through the name
|
||
path, and returns it as a name token; the parser accepts and stores that token
|
||
in the package-name position
|
||
([`cmd/compile/internal/syntax/scanner.go`, lines 88–107](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/scanner.go#L88-L107),
|
||
[368–394](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/scanner.go#L368-L394),
|
||
and
|
||
[437–439](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/scanner.go#L437-L439),
|
||
[`parser.go`, lines 397–420](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/parser.go#L397-L420)
|
||
and
|
||
[2751–2763](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/syntax/parser.go#L2751-L2763)).
|
||
The types2 checker rejects the retained node as `invalid package name _`
|
||
and continues file initialization
|
||
([`cmd/compile/internal/types2/check.go`, lines 336–355](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/check.go#L336-L355));
|
||
syntax errors prevent types2 from running
|
||
([`cmd/compile/internal/noder/noder.go`, lines 45–77](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/noder.go#L45-L77),
|
||
[`irgen.go`, lines 23–99](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/noder/irgen.go#L23-L99)).
|
||
- **behavior directly implemented or asserted by pinned Go** — `go/build`
|
||
reads `_` without declaration-error parsing, classifies production and test
|
||
roles, and records imports before cmd/go builds package actions
|
||
([`go/build/read.go`, lines 55–56](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/read.go#L55-L56),
|
||
[187–198](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/read.go#L187-L198),
|
||
and
|
||
[265–340](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/read.go#L265-L340),
|
||
[`go/build/build.go`, lines 931–1039](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/build/build.go#L931-L1039)).
|
||
Named files use one synthetic package loader
|
||
([`cmd/go/internal/load/pkg.go`, lines 3244–3315](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/pkg.go#L3244-L3315));
|
||
test synthesis augments production with internal-test files rather than
|
||
treating them as unrelated packages
|
||
([`cmd/go/internal/load/test.go`, lines 175–226](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/load/test.go#L175-L226)).
|
||
- **behavior directly implemented or asserted by pinned Go** —
|
||
[`test/blank1.go`, lines 1–31](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/test/blank1.go#L1-L31)
|
||
asserts the blank-name error plus later checker errors, directly proving
|
||
continued checking.
|
||
[`internal/types/testdata/check/blank.go`, lines 1–5](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/internal/types/testdata/check/blank.go#L1-L5)
|
||
separately asserts only the blank-name error. Official role controls
|
||
[`build_test_only.txt`, lines 1–18](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/build_test_only.txt#L1-L18)
|
||
and
|
||
[`build_no_go.txt`, lines 1–30](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/build_no_go.txt#L1-L30)
|
||
anchor the surrounding test-only selection rules. The pinned repository has
|
||
no official cmd/go test matrix for named, multiple, mixed,
|
||
test-only, artifact, rollback, concurrency, or interruption forms of
|
||
`package _`; those are WW-native proofs, not attributed to an absent Go
|
||
script.
|
||
- **behavior directly implemented or asserted by pinned Go** — after primary
|
||
syntax succeeds, types2 validates the imported package object's name before
|
||
consulting a local alias. Name `_` reports
|
||
`could not import PATH (invalid package name: "_")` at the import path;
|
||
an empty name instead quotes the actual empty value as
|
||
`invalid package name: ""`. The resolver
|
||
installs and caches a path-leaf-named fake package, marks the occurrence
|
||
used, and continues checking
|
||
([`cmd/compile/internal/types2/resolver.go`, lines 125–180 and 248–335](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/compile/internal/types2/resolver.go#L125-L180)).
|
||
The public checker twin implements the same rule
|
||
([`go/types/resolver.go`, lines 157–190 and 263–350](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/go/types/resolver.go#L157-L190)).
|
||
- No official pinned test directly supplies an imported `Package` whose name
|
||
is `_`. The two primary-source blank-name tests above do not assert this
|
||
importer-result validation. Its imported-interface matrix is therefore
|
||
WW-native proof grounded in the pinned resolver implementation, not a claim
|
||
about absent official testdata.
|
||
- **behavior derived from the pinned implementation** — the diagnostic owns
|
||
the underscore position, normally line 1 column 9, and belongs after source
|
||
loading, graph construction, complete-file syntax, and dependency-eligible
|
||
producer ordering. WW has the same explicit package clause, blank token,
|
||
syntax/check split, package families, imports, and package actions, so the
|
||
rule applies without adding modules, manifests, registries, generalized
|
||
imports, or a new identity model.
|
||
|
||
Before this slice, **directly measured WW behavior** was a generic positioned
|
||
`invalid or missing package clause` from both public stages before any
|
||
producer. Direct Cstage `w6c` emitted four package-clause recovery diagnostics
|
||
while WWstage `w6c_ww` emitted three. A visible named `_test.ww` ordinary build
|
||
was rejected at its header instead of being validated and omitted. These facts
|
||
were a real package/build/test/import difference despite stage-equal public
|
||
rejection. After the primary-source parser/checker repair and before the
|
||
imported-interface completion, **directly measured WW behavior** also accepted
|
||
an owner-matched hand-authored `.wwi` declaring `package _;`: default,
|
||
explicit, and blank controls accepted and published usable semantic facts, and
|
||
the explicit alias control produced successful byte-identical Cstage/WWstage
|
||
assembly and interface output. Ordinary producers could not create that
|
||
metadata, but direct `--import` and caller-owned persistent interfaces made the
|
||
gap externally observable.
|
||
|
||
#### Semantic ownership
|
||
|
||
Primary package-slot syntax and marker positions remain owned by the C/WW
|
||
parser twins `cmd/wcc/parse.c` and `lib/ww/syntax/parse.ww`; primary and
|
||
imported blank-name checker diagnostics and fake-package resolution are owned
|
||
by `cmd/wcc/check.c` and `selfhost/cmd/wcc/check.ww`. Imported export-data
|
||
materialization, four-state package metadata, primary-rooted reachability,
|
||
owner filtering, recovery qualifier assignment, and delayed concatenation are
|
||
owned by `cmd/w6c/main.c` and `selfhost/cmd/w6c/main.ww`. Exact import-path
|
||
token positions are private `N_USE` state owned by `cmd/wcc/ww.h`,
|
||
`lib/ww/syntax/ast.ww`, both parser twins, and
|
||
`lib/ww/syntax/decl.ww`.
|
||
|
||
The public drivers and package coordinator already supply canonical direct
|
||
interface arguments and inherit the validation without edits. No loader,
|
||
assembler, archiver, linker, runtime, package-identity, or import-syntax owner
|
||
changes in this completion. This complete ownership replaces the earlier
|
||
transitional assumption that the slice had only four syntax/checker owners.
|
||
|
||
#### Four-axis behavior and phase order
|
||
|
||
- **Build:** an eligible blank production source passes the loader, contributes
|
||
its ordinary package action and import closure, and fails in checker entry.
|
||
A visible literal named `_test.ww` still follows section 11.51: after its
|
||
header and contiguous imports are valid, ordinary build omits it before body
|
||
parsing or action construction, including when the declared name is `_`.
|
||
`ww run` retains its earlier MainOnly boundary: a blank root is not `main`,
|
||
so a successfully loaded root is rejected before any producer or compiler.
|
||
- **Test:** an all-blank production, internal-test, or honest test-only family
|
||
reaches its applicable test-package compiler action and fails there. A valid
|
||
production `p` plus blank test `_`, or blank production `_` plus unrelated
|
||
`p`/`p_test`, remains a coordinator family mismatch before tools. Existing
|
||
raw/directory `FAIL` placement, compile-only empty stdout, and directory
|
||
`-S` CLI-shape diagnostics are unchanged; no failed blank product runs.
|
||
- **Package:** `_` is retained only as a declared source-family observation.
|
||
It is not canonical identity. In an all-blank selected action, the checker
|
||
emits one positioned BlankPkgName diagnostic per retained source marker in
|
||
deterministic source-section order and continues later checking. Mixed
|
||
declared names retain loader conflict precedence.
|
||
- **Import:** a valid contiguous import in a blank source is a normal source
|
||
occurrence and graph edge. Missing or invalid recursive dependencies can
|
||
therefore fail before the parent checker. An ordinary blank source provider
|
||
cannot publish a successful interface or archive. A reached hand-authored or
|
||
corrupted `.wwi` that declares `_` is nevertheless parsed and defensively
|
||
rejected by the consuming compiler; an unused interface is inert. Default,
|
||
explicit, and blank aliases cannot mask the invalid provider name.
|
||
Visibility, vendor, cycle, and initialization rules do not change.
|
||
|
||
The complete observable phase order is: source eligibility and loader-visible
|
||
header/family checks; recursive import loading; MainOnly rejection for `run`;
|
||
eligible dependency producers for build/test or a run root that passed
|
||
MainOnly; the parent compiler's complete-file syntax; BlankPkgName checking;
|
||
reached imported-package validation; later checker diagnostics; then existing
|
||
driver/coordinator failure trailers.
|
||
Consequently malformed contiguous imports precede graph construction, a
|
||
missing dependency can suppress both a later body syntax error and
|
||
BlankPkgName, and full-file syntax suppresses checker diagnostics. A blank run
|
||
root never starts even valid dependency producers because MainOnly is earlier.
|
||
|
||
#### Test graph, actions, and identity boundaries
|
||
|
||
A production-only blank package under `ww test` has one ordinary production
|
||
compiler action. Production `_` plus a same-package `_test.ww` also declared
|
||
`_` forms one internal-test family: its augmented action owns both source sets,
|
||
and `sep_recompile_for_test` substitutes it throughout the product closure, so
|
||
the separate production node is not independently compiled for that product.
|
||
One compiler invocation reports one BlankPkgName per retained marker. A
|
||
test-only blank `_test.ww` forms one test-only internal action and reports once.
|
||
A blank production plus the actually related external name `__test` passes
|
||
family classification, but its blank production dependency fails before the
|
||
external action, generated main, link, or runtime can complete.
|
||
|
||
Direct raw files retain `__root.*`; dotted directories and providers retain
|
||
their canonical dotted package/import/action/artifact identities; production,
|
||
internal, external, recompiled, support, and generated-main actions retain
|
||
their existing distinctions. Physical paths, parents, source spellings, and
|
||
symlink targets remain loader or diagnostic observations. No successful
|
||
ordinary producer `.wwi` can advertise `_`; a supplied or corrupted `.wwi`
|
||
that does is invalid input, not an alternate symbol, publication, or
|
||
persistence identity.
|
||
|
||
#### Imported `.wwi` validation, reachability, and recovery
|
||
|
||
The rules in this subsection are **behavior derived from the pinned
|
||
implementation** for WW's supported source-like export-data channel. They do
|
||
not claim an official imported-blank fixture that does not exist.
|
||
|
||
Every sorted `--import CANONICAL FILE.wwi` is first read, owner-checked, and
|
||
syntax-parsed into its own standalone AST. Interface read, owner, syntax, and
|
||
structural import-map errors keep their existing precedence. The compiler then
|
||
syntax-parses the primary input. Any primary syntax error returns before
|
||
imported-package semantic validation, so it is never accompanied by the
|
||
broken-import diagnostic.
|
||
|
||
After successful primary parsing and import-map application, compiler test
|
||
mode materializes any required support `N_USE` before resolution. The node has
|
||
the primary owner/source ID, is marked used, uses visible name `test` or the
|
||
collision-safe reserved `__wwtest`, and is positioned at the generated primary
|
||
root because no source path token exists. An existing equivalent primary
|
||
occurrence prevents duplication. When no support interface is supplied, the
|
||
node retains the established raw external-support fallback; a supplied
|
||
blank-named support interface is validated like every source import. Reserved
|
||
`__wwtest` preserves its compiler-selected visible spelling after valid
|
||
resolution but cannot skip provider-name validation. Existing
|
||
`--test-target-package` roots already require a primary occurrence and add no
|
||
second node.
|
||
|
||
A metadata-only pass classifies each represented canonical package as valid,
|
||
missing, conflicting, or invalid; invalid means its one nonconflicting real
|
||
declared name is exactly `_`. Compiler-private placeholder packages remain
|
||
valid recovery metadata. Reachability is seeded only by canonical primary and
|
||
compiler-required `N_USE.usepath` occurrences, then reaches a fixed point over
|
||
standalone interface lists. An imported use contributes an edge only when its
|
||
owning canonical package is already reached and valid. Interface containers,
|
||
arbitrary embedded origins, and invalid, missing, conflicting, or unreachable
|
||
owners are never roots or traversal sources.
|
||
|
||
Before binding or concatenation, each standalone list is filtered to nodes
|
||
whose canonical owner is both reached and valid. Invalid-owner, unreachable,
|
||
and ownerless hand-authored facts are discarded. Thus an unused invalid
|
||
interface is wholly inert even when it contains an embedded valid-origin
|
||
section that imports the invalid path: it emits no diagnostic, installs no
|
||
declaration or scope, contributes no output or serialized fact, and leaves an
|
||
otherwise valid primary byte-equivalent to the no-interface control. If the
|
||
primary independently reaches that valid origin, its retained import can then
|
||
reach and diagnose the invalid provider. Binding runs on those filtered lists
|
||
and the primary list before the lists are concatenated, so unreachable
|
||
internal uses cannot manufacture missing, conflict, or invalid effects.
|
||
|
||
Every retained occurrence resolving to an invalid provider is marked used and
|
||
records declared provider name `_`. A nonblank occurrence receives a recovery
|
||
package binding using its explicit alias or, by default, the final component of
|
||
the canonical dotted path; a blank occurrence installs no visible binding.
|
||
The fake package has an empty scope. Qualified value, call, and type gateways
|
||
therefore recover as the error type without missing-member,
|
||
unknown-type/export, or calling-nonfunction cascades, while a lexically closer
|
||
value binding still shadows the recovery qualifier normally.
|
||
|
||
At checker entry, immediately after primary BlankPkgName diagnostics, the
|
||
first retained invalid occurrence of each canonical path emits exactly
|
||
`could not import PATH (invalid package name: "_")`; later occurrences of the
|
||
same path are deduplicated, while distinct paths diagnose in retained
|
||
occurrence order. Independent checker diagnostics continue afterward.
|
||
Deduplication uses canonical dotted path because WW has no Go source-directory
|
||
import-key component. Default, explicit, and blank alias forms all position
|
||
this diagnostic at the path's first identifier, never at an explicit alias.
|
||
The existing alias-or-path first-spec position remains unchanged for every
|
||
other binding diagnostic. Full parsing, imports-only parsing, and named-source
|
||
header parsing all retain both position families.
|
||
|
||
Public persistent build and test actions consume the same supported interface
|
||
channel. If a reached caller-owned committed `.wwi` is corrupted to declare
|
||
`package _;`, the consumer compiler fails after primary syntax and resolution;
|
||
that action's assembler and downstream archive, link, retention, or runtime do
|
||
not complete. A package-action failure prevents generated main; a generated-main
|
||
action that is itself the consumer performs the same validation before its own
|
||
assembly. Raw, production, internal, external, test-only, generated-main, `-c`,
|
||
and applicable `-S` consumer actions use the same rule. A same-named `.ww` file
|
||
remains an import decoy rather than a provider. An
|
||
unreferenced corrupt interface remains inert and does not invalidate or alter
|
||
the consumer. A failing direct compiler returns status 1 with empty stdout;
|
||
public test presentation retains its existing running `FAIL` and
|
||
package-trailer rules, while compile-only and assembly-only forms retain empty
|
||
stdout.
|
||
|
||
#### Artifacts, rollback, concurrency, parity, and formats
|
||
|
||
The failed primary blank action and a consumer rejecting a reached blank-named
|
||
interface emit neither compiler assembly nor `.wwi`, so their downstream
|
||
assembler, archiver, linker, test harness, and user runtime do not run. Valid
|
||
dependencies or test support that precede either failure may execute their
|
||
ordinary producers, but request rollback removes every request-owned stage and
|
||
commits no failed generation, public product, retained test binary, unit,
|
||
interface, assembly, object, archive, executable, stamp, or status. Direct
|
||
named `-o`/`-I` outputs, public outputs, retained tests, and committed semantic
|
||
bytes remain byte-identical. Restoring the exact valid source or `.wwi` bytes
|
||
uses the existing content-identity reuse path; invalid bytes never publish a
|
||
replacement consumer generation. Reached interface bytes already participate
|
||
through the existing compiler input and invalidation rules; semantic validation
|
||
adds no graph, action, or persistence key. A build-omitted named `_test.ww`
|
||
contributes no action or invalidation key.
|
||
|
||
Blank-package state, imported metadata, reachability sets, deduplication, and
|
||
fake bindings are compiler/checker-process-local. Independent concurrent
|
||
requests cannot share diagnostics, graph state, staging, or cleanup. Normal
|
||
failure is waited and rolled back through the existing transaction owner and
|
||
leaves no anonymous descriptor, `.new`, `.old`, `.install`, `.wwtxn.*`,
|
||
capture, result, request scratch, or child.
|
||
Direct `w6c` and `w6c_ww`, and public `ww` and `ww_ww`, agree on status,
|
||
stdout, exact path-token positions and diagnostic order, fake recovery,
|
||
output absence, prior-byte preservation, and every comparable semantic
|
||
dependency artifact. Producer provenance remains the established intentional
|
||
stage difference.
|
||
|
||
No signal-supervision behavior changed. Direct external `SIGTERM` during a
|
||
blocked persistent compilation still preserves prior committed/public bytes
|
||
but can leave the spawned compiler and fixed-name `.new` staging that poisons a
|
||
later request. That independently verified gap remains open and is not claimed
|
||
fixed by normal BlankPkgName rollback.
|
||
|
||
No serialized representation changed. The full parser changes only the
|
||
in-memory position of a blank package marker to the underscore token; outer
|
||
file/header/import-only markers and valid package markers keep their former
|
||
positions. Each twin's private in-memory `Node` gains only
|
||
`usepathfile/usepathline/usepathcol`; AST enum values, AST printing, `.wwi`
|
||
schema, build workdir format `18`, test workdir format `19`, and semantic
|
||
storage format `3` remain unchanged. No cache, result record, manifest, action
|
||
descriptor, transaction marker, database, or lock is added. This closes one
|
||
coherent semantic slice across all four axes;
|
||
it does not complete the remaining suffix-first run front, multiple named
|
||
source packages, shared test-process state and failure topology, RE2-compatible
|
||
flat `-run`, finite special-source handling, or external-driver interruption
|
||
recovery.
|
||
|
||
### 11.57 Implemented post-target `ww run` argument boundary
|
||
|
||
After one explicit `ww run` target has been selected, every later operand is
|
||
now program input. Neither driver reparses that suffix as build options. Known
|
||
and unknown option spellings, would-be option values, a lone `--`, empty
|
||
strings, later ordinary operands, and later `.ww` spellings retain their exact
|
||
bytes and order in the child vector. WW still supports only one selected run
|
||
target: this boundary does not turn a later `.ww` spelling into a second source
|
||
file.
|
||
|
||
#### Pinned authority, official tests, and applicability
|
||
|
||
The sole semantic authority is official Go 1.26.5 at commit
|
||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||
|
||
- **behavior directly implemented or asserted by pinned Go** — the Go command
|
||
parses a run command's registered flags before entering `runRun` and passes
|
||
only `Flag.Args()` to it
|
||
([`cmd/go/main.go`, lines 312–322](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/main.go#L312-L322)).
|
||
The standard flag parser stops at the first non-flag positional; it consumes
|
||
`--` only when that spelling occurs before the positional boundary
|
||
([`flag/flag.go`, lines 1074–1089 and 1149–1176](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/flag/flag.go#L1074-L1089)).
|
||
- **behavior directly implemented or asserted by pinned Go** — `runRun`
|
||
consumes either the contiguous named-file prefix or one selected package,
|
||
leaves the suffix as `cmdArgs`, and attaches those exact arguments to the run
|
||
action
|
||
([`cmd/go/internal/run/run.go`, lines 96–140 and 170–173](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/run/run.go#L96-L140)).
|
||
- **behavior directly implemented or asserted by pinned Go** — official
|
||
regression test
|
||
[`cmd/go/testdata/script/mod_run_flags_issue64738.txt`, lines 1–4](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/mod_run_flags_issue64738.txt#L1-L4)
|
||
asserts that `-p ignored` after a requested package is program input, not a
|
||
`cmd/go` flag. Official
|
||
[`cmd/go/testdata/script/run_dirs.txt`, lines 1–20](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/run_dirs.txt#L1-L20)
|
||
separately anchors Go's contiguous multi-file prefix; that source-set rule
|
||
remains open in WW.
|
||
- **behavior directly implemented or asserted by pinned Go** — Go deliberately
|
||
does not preserve the compiled program's exact nonzero exit status
|
||
([`cmd/go/internal/run/run.go`, lines 56 and 198–210](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/run/run.go#L198-L210));
|
||
command error accounting owns the resulting Go-command status
|
||
([`cmd/go/internal/base/base.go`, lines 218–246](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/base/base.go#L218-L246)).
|
||
That independent exit-status difference is not credited to this slice.
|
||
- **behavior derived from the pinned implementation** — WW's one explicit
|
||
local run target supplies the same honest semantic boundary without modules,
|
||
manifests, registries, network resolution, generalized imports, or source
|
||
build expressions. WW's implicit default-current-directory extension has no
|
||
explicit target token, so this slice leaves its leading option parsing
|
||
unchanged. A leading or pre-target `--` therefore retains WW's existing
|
||
exact unknown-flag rejection and is not claimed as Go `FlagSet` terminator
|
||
parity.
|
||
|
||
Before this slice, **directly measured WW behavior** was identical in Cstage
|
||
and WWstage but differed from the pinned boundary. Immediately target-following
|
||
`-p ignored` and `-- -p ignored` returned status 2, empty stdout, and exact
|
||
stderr `ww run: unknown flag\n`; `-o sentinel` and `-I path` were consumed by
|
||
the driver; and only a suffix after a second nonflag was passed unchanged.
|
||
Named-source and directory-package probes agreed on status, stdout, stderr,
|
||
and diagnostic order. Accepted runs loaded one target and its ordinary import
|
||
closure, constructed the private run action, compiled, assembled, archived,
|
||
linked, executed, propagated WW's established child status, and removed the
|
||
private executable and `.sepwork`. Rejected flag rows stopped before target
|
||
resolution, graph/action construction, tools, runtime, or scratch creation.
|
||
|
||
#### Ownership, source selection, and the four permanent axes
|
||
|
||
- **directly measured WW behavior** — Cstage owns the boundary in
|
||
`parse_build_flags` and its `do_run` consumer; WWstage owns the semantic twin
|
||
in its `dorun` parser and executor. No loader, package coordinator, compiler,
|
||
assembler, archiver, linker, test coordinator, checker, import binder, or
|
||
runtime library can repair a driver option that was already consumed.
|
||
- **behavior derived from the pinned implementation** — the primary axis is
|
||
build/run execution semantics. Driver options are recognized before the
|
||
first explicit target. That target alone controls resolution; the complete
|
||
later suffix controls only child invocation.
|
||
- **behavior derived from the pinned implementation** — the test axis is an
|
||
explicit non-effect. `ww test` option parsing, target discovery, filters,
|
||
source variants, generated harness, retained products, execution topology,
|
||
and result accounting do not use this run boundary.
|
||
- **behavior derived from the pinned implementation** — the package axis is an
|
||
explicit non-effect. The suffix is never searched, statted, opened, or
|
||
classified as source. Declared-name validation, source membership, command
|
||
classification, initializer topology, and canonical package identity remain
|
||
those of the one selected target.
|
||
- **behavior derived from the pinned implementation** — the import axis is an
|
||
explicit non-effect. Dotted spelling, aliases, local/vendor search, binding,
|
||
visibility, cycles, graph edges, interface ownership, and initialization
|
||
order are determined only by the selected source closure. Runtime argv is
|
||
never package, import, graph, action, symbol, artifact, `.wwi`, publication,
|
||
or persistence identity.
|
||
|
||
Direct roots retain `__root.*`; dotted directories retain dotted package,
|
||
import, action, symbol, artifact, and semantic identities. Physical target
|
||
spellings and paths remain loader or presentation observations. Post-target
|
||
arguments add no root, edge, action, source, or invalidation input and cannot
|
||
change compilation or comparable artifact bytes.
|
||
|
||
#### Phase order, diagnostics, and lifecycle
|
||
|
||
- **behavior derived from the pinned implementation** — target resolution,
|
||
loading, import closure, graph construction, compilation, assembly,
|
||
in-process archiving, and linking retain their existing order and inputs.
|
||
After a successful private link, the child vector is the private executable
|
||
at index 0 followed by the exact post-target suffix. The suffix reaches no
|
||
earlier phase.
|
||
- **directly measured WW behavior** — `os.args()` exposes that complete vector,
|
||
including the PID-bearing private executable path at index 0. WW currently
|
||
propagates an ordinary child's exact exit code. The argument repair changes
|
||
only indices 1 onward; PID presentation and exact child-status propagation
|
||
are preserved, including their independent difference from pinned Go.
|
||
- **behavior derived from the pinned implementation** — known, unknown,
|
||
incomplete, or `--` option spellings before the target retain their existing
|
||
driver diagnostics and status. No spelling after the target can emit a
|
||
driver-option diagnostic. Missing, invalid, non-main, or producer-failing
|
||
targets diagnose before runtime; a valid target starts and thereafter owns
|
||
output and failure caused by its arguments.
|
||
- **behavior derived from the pinned implementation** — run products remain
|
||
request-private. No public executable, retained test product, semantic fact,
|
||
work record, transaction, result, or cache entry is published. Post-target
|
||
argv enters no unit, interface, assembly, object, archive, initializer,
|
||
executable, stamp, or persistence byte and creates no reuse or invalidation
|
||
key. Ordinary build and every test route are byte-for-byte non-effects.
|
||
- **behavior derived from the pinned implementation** — target or producer
|
||
failure starts no program and follows ordinary rollback. Runtime nonzero
|
||
follows the established WW status mapping after successful private linking.
|
||
Existing unrelated public and committed semantic bytes remain untouched.
|
||
Normal success, producer failure, runtime failure, and concurrent runs remove
|
||
each request's owned private executable, `.sepwork`, stage, transaction,
|
||
capture, result, request, descriptor, and child. Parser state and argv are
|
||
invocation-local, so overlapping suffixes cannot cross between requests.
|
||
- **behavior derived from the pinned implementation** — Cstage and WWstage
|
||
must select the same boundary and retain exact status, stdout, stderr,
|
||
diagnostic order, runtime argv, normal cleanup, and comparable build-artifact
|
||
byte identity. The existing PID-bearing private path difference outside
|
||
stable comparisons is not reclassified by this slice.
|
||
|
||
The WW-native observer `run_post_target_arguments_are_program_argv` covers both
|
||
driver stages with literal named-source and directory-package targets. It
|
||
checks known separate and joined option spellings, unknown options, would-be
|
||
values, singleton value-taking spellings, `--`, later nonflags and `.ww`, an
|
||
empty string, pre-target controls, no-operand default-dot selection, diagnostic
|
||
precedence, exact child status and output, concurrent isolation, build/test
|
||
controls, artifact-byte parity, and normal residue cleanup.
|
||
|
||
No signal or process-supervision owner changes. Direct external SIGTERM during
|
||
blocked persistent compilation still can leave the owned compiler alive and
|
||
exactly three fixed `.new` stages, poisoning the next request while preserving
|
||
prior public and committed semantic bytes. That verified interruption gap
|
||
remains open; blind stage deletion is not this argument-boundary repair.
|
||
|
||
No serialized representation changes. Build workdir format remains `18`, test
|
||
workdir format remains `19`, and semantic storage format remains `3`; AST and
|
||
`.wwi` schemas, action descriptors, request protocols, transaction markers,
|
||
and stored facts are unchanged. This closes only the post-target argv slice.
|
||
Regular or missing `_test.ww`, missing `.ww`, hidden named sources, multiple
|
||
leading sources and their source-set boundary, shared test-package state,
|
||
panic/exit/Fatal/FailNow topology, RE2-compatible flat `-run`, literal
|
||
nonregular named-source behavior, three-way no-buildable-source diagnostics,
|
||
Go-like run exit-status mapping, and external-driver interruption recovery
|
||
remain open where applicable.
|
||
|
||
## 12. Candidate architectures and hard-gate decision
|
||
|
||
Five candidates were developed as coherent systems, not as feature bins.
|
||
|
||
### 12.1 Candidate A: Go-like integrated language command
|
||
|
||
One `ww` command would infer directory packages/imports, compile/cache/test them,
|
||
and add a small module/lock layer. Native inputs would remain compiler flags or
|
||
toolchain conventions. This preserves the strongest part of Go: explicit imports,
|
||
fast direct export data, and a short ordinary command
|
||
([Go command design](https://go.dev/doc/articles/go_command)). A WW-specific lock
|
||
and no-network build could improve on modern Go module behavior.
|
||
|
||
It still fails as an end-to-end native design. A source-only graph cannot name
|
||
host generators, C header trees, archive order, linker scripts, CRT, SDK, or
|
||
sysroot. Ambient compiler-driver and `pkg-config` behavior would remain outside
|
||
the key, and the build/host/target triad would be incomplete. Adding typed native
|
||
actions, complete toolchains, and content records turns it into Candidate E.
|
||
|
||
### 12.2 Candidate B: Hare/Odin-style local source plus an outer build tool
|
||
|
||
WW would use search roots and directory modules, with source vendored or supplied
|
||
by an OS package manager; Make-like orchestration would own native work. This is
|
||
small locally and avoids a language-owned network resolver. Hare 0.26.0 (released
|
||
2026-02-13) is a useful reference: directory modules, direct textual export data,
|
||
`HAREPATH`, explicit system-library flags, and cross-architecture tooling are
|
||
documented in its official manuals
|
||
([modules](https://harelang.org/documentation/usage/modules.html),
|
||
[project structure](https://harelang.org/documentation/usage/project-structure.html),
|
||
[system libraries](https://harelang.org/documentation/usage/system-libraries.html),
|
||
[cross compilation](https://harelang.org/documentation/usage/cross.html)). Odin's
|
||
named collections are a related local-source convention
|
||
([Odin overview](https://odin-lang.org/docs/overview/)).
|
||
|
||
As a complete WW system it fails: ordered search roots are selection policy
|
||
without locked source identity; ordinary outer recipes expose ambient tools,
|
||
environment, and mtimes; language and native graphs/caches cannot jointly explain
|
||
invalidation; and cross sysroots/ABI providers remain project conventions. Making
|
||
the outer tool hermetic and content-addressed yields Candidate C, not this model.
|
||
|
||
### 12.3 Candidate C: two-layer Plan 9-style builder and orchestrator
|
||
|
||
A strict package builder would compile an import graph. A separate small
|
||
declarative DAG tool would own generators, C/assembly, images, archives, and
|
||
links. With content records, pinned tools, sandboxing, and an exact handoff this
|
||
can pass every hard gate. It reflects `mk`'s valuable complete-graph/parallel-tool
|
||
shape without copying its mtime and ambient-environment assumptions.
|
||
|
||
It loses after the gates because the boundary creates two graph protocols, two
|
||
selection UIs, two explanation namespaces, and either duplicate scheduling/cache
|
||
logic or a coarse “build all packages” action. Ordinary native projects must know
|
||
when to invoke each layer. If both front ends lower into one shared scheduler and
|
||
cache, and `ww` owns the ordinary invocation, the result is the smaller Candidate
|
||
E. Keeping the second production tool after that offers no remaining orthogonal
|
||
concept.
|
||
|
||
### 12.4 Candidate D: Zig/Cargo-like programmable integrated project
|
||
|
||
A manifest would define artifacts and dependencies while a host-executed program
|
||
constructs a flexible native graph. This handles more native cases than a
|
||
language-only command. Zig 0.16.0, pinned here to its 2026-04-13 release metadata,
|
||
provides explicit target/native concepts, hashed package sources, local
|
||
dependency overrides, and generated-file graph edges
|
||
([download metadata](https://ziglang.org/download/index.json),
|
||
[0.16.0 reference](https://ziglang.org/documentation/0.16.0/),
|
||
[build system](https://ziglang.org/learn/build-system/)). Cargo 1.97.1, shipped
|
||
with Rust 1.97.1 on 2026-07-16, provides exact package IDs, workspaces, lock
|
||
checksums, resolver rules, and native `links` collision handling
|
||
([Cargo reference](https://doc.rust-lang.org/1.97.1/cargo/reference/),
|
||
[resolver](https://doc.rust-lang.org/1.97.1/cargo/reference/resolver.html)).
|
||
|
||
Zig's build program and Cargo's `build.rs` execute to decide or report build
|
||
behavior; Cargo explicitly
|
||
documents build-script inputs/outputs and its fingerprint cache
|
||
([build scripts](https://doc.rust-lang.org/1.97.1/cargo/reference/build-scripts.html),
|
||
[build cache](https://doc.rust-lang.org/1.97.1/cargo/reference/build-cache.html)). Those
|
||
reference systems as shipped do not meet WW's complete native/toolchain hard
|
||
gates.
|
||
|
||
The strongest coherent D is not left as a straw man: it content-identifies the
|
||
graph program and host compiler/runtime, declares its whole readable source/tool
|
||
closure, runs it in the denied-by-default sandbox with no network, and requires
|
||
it to emit a closed typed graph before artifact execution. That hardened model
|
||
can pass every gate. It still loses afterward: WW must permanently ship/secure/
|
||
bootstrap an evaluator API and host build-program toolchain, users debug both
|
||
program execution and its emitted graph, dependencies expose framework APIs, and
|
||
routine exceptions accumulate as library features. Finite records buy the same
|
||
WW requirements with less user and implementation machinery.
|
||
|
||
### 12.5 Candidate E: hermetic integrated action build — selected
|
||
|
||
Candidate E retains the Go-like ordinary UX and import-derived language graph,
|
||
then adds only the native/action facts that imports cannot express. Both lower
|
||
to one typed graph and content cache. It borrows declared tools/inputs and action
|
||
results from Bazel's hermetic/remote-execution model, and transparent
|
||
content-derived build records from Nix derivations, without adopting either
|
||
framework, evaluator, daemon topology, or user interface
|
||
([Bazel hermeticity](https://bazel.build/versions/9.2.0/basics/hermeticity),
|
||
[Bazel remote caching](https://bazel.build/remote/caching),
|
||
[remote execution protocol](https://github.com/bazelbuild/remote-apis/blob/master/build/bazel/remote/execution/v2/remote_execution.proto),
|
||
[Nix derivations](https://nix.dev/manual/nix/2.35/store/derivation/)).
|
||
|
||
It passes every hard gate and is selected. Its concepts are exactly package,
|
||
module/source selection, product/action, toolchain/target, artifact/digest, and
|
||
native provider/link plan. There is one graph, one scheduler, one cache key, one
|
||
explanation path, and one ordinary command.
|
||
|
||
### 12.6 Hard-gate matrix
|
||
|
||
Legend: **pass** means the strongest coherent form has a credible end-to-end
|
||
invariant; **fail** means it does not. D denotes the hardened evaluator above,
|
||
not unmodified Zig/Cargo behavior.
|
||
|
||
| Hard gate | A: Go-like | B: local + outer | C: two layer | D: programmable | E: action build |
|
||
|---|---|---|---|---|---|
|
||
| complete inspectable dependency DAG | fail for native work | fail across tools | pass | pass after sandboxed evaluation | **pass** |
|
||
| loud cycles/identity collisions | pass for packages; native incomplete | search shadowing fails identity | pass | pass | **pass** |
|
||
| frozen offline source closure | pass with proposed lock | vendoring can pass | pass | pass | **pass** |
|
||
| correct cache invalidation | fail for native/tool defaults | fail across mtime/outer recipes | pass | pass | **pass** |
|
||
| compiler/linker/runtime/toolchain identity | requires the E native layer | fail | pass | pass | **pass** |
|
||
| explicit B/H/T | fail | fail | pass | pass | **pass** |
|
||
| correct native dependency/link modeling | fail | fail | pass | pass | **pass** |
|
||
| deterministic package selection | pass | fail under search roots | pass | pass with lock | **pass** |
|
||
| reproducible artifacts/boundary | fail for native closure | fail | pass | pass with evaluator certification | **pass** |
|
||
| bounded bootstrap | pass with a seed | pass with enumerated seed/tools | pass | pass, larger evaluator TCB | **pass** |
|
||
| explain cache miss/rebuild | fail | fail | pass across two namespaces | pass across evaluation + graph | **pass** |
|
||
| one simple ordinary path | pass | two commands/configurations | two production layers | pass by convention | **pass** |
|
||
| no build/test network or mutation | pass if changed from Go defaults | outer recipes cannot guarantee | pass | pass | **pass** |
|
||
|
||
C, hardened D, and E survive the gates. E wins the requested post-gate
|
||
comparison:
|
||
|
||
| Criterion | C: two layer | D: hardened evaluator | E: selected |
|
||
|---|---|---|---|
|
||
| conceptual simplicity | two graph/handoff models | evaluator language/API plus emitted graph | one graph protocol; two finite descriptions |
|
||
| daily usability | user chooses builder/orchestrator | ordinary defaults can hide evaluator, exceptions cannot | `ww build/test/run` always |
|
||
| clean speed | parallel orchestration can match | evaluation overhead, then parallel graph | direct complete template plus parallel actions |
|
||
| incremental speed | cross-tool handoff may be coarse | evaluator must rerun/cache its own dependencies | direct exports, lazy content keys, cached link |
|
||
| rebuild blast radius | good only with API digests across handoff | can be good after evaluation | public-output digest propagation is intrinsic |
|
||
| cross-compilation | orchestrator can model it | rich API can model it | roles are built into every typed record |
|
||
| FFI/native honesty | outer layer owns it separately | API can express it | same provider/link records as package objects |
|
||
| implementation maintenance | two adapters/engines or coarse boundary | evaluator, SDK compatibility, sandbox, graph engine | one scheduler/store/adapter set |
|
||
| supply-chain security | two policy surfaces | dependency host code remains an evaluator input | one lock/source/action trust model |
|
||
| ecosystem scalability | two tool ecosystems | framework/API accumulation pressure | closed schemas version only for demonstrated facts |
|
||
| debugging/observability | two explanation namespaces | debug program, evaluator cache, then graph | one causal graph/record diff |
|
||
| bootstrap longevity | small outer interpreter possible | compiler/runtime/evaluator enter seed chain | fixed seed plan; no production evaluator |
|
||
|
||
### 12.7 Why each subsystem is in or out of the core
|
||
|
||
Package parsing/resolution and export data belong in the core because only the
|
||
compiler can state the true language graph and public ABI. Module selection and
|
||
lock verification belong beside it because an import identity must resolve to
|
||
one deterministic source before compilation. The typed action engine, target
|
||
descriptors, native providers, and toolchain closure belong in the core because
|
||
they share invalidation and link correctness with package objects. Test/doc/
|
||
install are thin product selections/materializations over that same graph.
|
||
|
||
Network transport remains a separate operation, though exposed by `ww`, because
|
||
fetching is not building. Credential policy, OS package installation, registry
|
||
hosting, signing authority, remote execution, deployment, and general release
|
||
automation stay outside. The finite `generate` action is the boundary: it lets
|
||
outer domain tools transform declared artifacts without turning WW into their
|
||
framework.
|
||
|
||
## 13. Migration plan
|
||
|
||
Migration cost does not affect the decision. It is nevertheless material: the
|
||
current directly implicated scaffolding is at least 7,969 lines across the
|
||
Makefile, two drivers, two interface writers, package coordinator, and test
|
||
wrapper, plus 4,728 lines in the focused separate-build/package/byte-identity/
|
||
driver tests counted for this audit. Compiler export/import logic, new native
|
||
adapters, and bootstrap work add new scope not represented by those deletion
|
||
counts.
|
||
|
||
The planning estimate is **15–22 engineer-months** for the first production
|
||
Linux/amd64 toolchain, including tests, migration, and deletion, plus **1–2
|
||
engineer-months per materially different additional official target/sysroot**.
|
||
This is an estimate for staffing and sequencing, not a reason to retain a weaker
|
||
architecture.
|
||
|
||
Every phase below ends in a bisect-clean commit. Experimental components are not
|
||
installed as a second user-facing build path. Until the point of no return, the
|
||
old command remains the only production path; after it, the new command is the
|
||
only path.
|
||
|
||
### Phase 0 — conformance corpus and protocol freeze
|
||
|
||
- Land the compact checked-in `protocol/schema/` modules for WWAR framing,
|
||
record/enum/union/default/kind assignments, wrappers, and finite digest byte
|
||
formulas. Freeze the exact schema-file digests. Preserve representation-only
|
||
preimage records without embedding the algorithms that construct them.
|
||
- Generate data-only codec tables deterministically. Keep one schema-aware
|
||
reference codec and a second independent oracle limited to raw WWAR framing,
|
||
hashing, and record identity; neither may implement future compiler or build
|
||
behavior.
|
||
- Gate: strict duplicate-key UTF-8/NFC schema loading, byte-identical generation
|
||
in separate fresh directories, compact valid/invalid vectors, all assignment
|
||
coverage, stable malformed-length precedence, domain separation, action-key
|
||
vectors, and record-kind substitution rejection. No production behavior
|
||
changes beyond adding this conformance gate.
|
||
- Package/API, graph/cache, native B/H/T, and bootstrap measurements remain useful
|
||
fixtures, but become tests in Phases 1, 2, 4, and 6 respectively. They are not
|
||
Phase 0 semantic answer tables.
|
||
|
||
### Phase 1 — compiler export and package protocol
|
||
|
||
- Implement deterministic `.wwe`/`.wwlm` writing and direct-interface reading in
|
||
Cstage and self-hosted compiler paths behind test-only entry points.
|
||
- Add package identity/alias syntax, strict directory enumeration, compiler
|
||
import extraction, target suffix selection, cycle/collision/internal checks,
|
||
and protocol compatibility diagnostics.
|
||
- Construct and test the deep public type closure and public type/ABI digest
|
||
preimages in compiler code with existing standard-library graphs. Reject
|
||
`.wwi` input in the experimental path; do not translate it.
|
||
- Gate: Cstage/WWstage emit byte-identical vectors, importers open only direct
|
||
export files, and API propagation stops on unchanged middle exports.
|
||
|
||
### Phase 2 — one action engine and local CAS
|
||
|
||
- Integrate the frozen WWAR codec into production code and implement typed pure
|
||
action-record/key functions, the action graph, lazy keys, scheduler, atomic
|
||
CAS/results, project index, corruption quarantine, graph JSON, environment and
|
||
sandbox policy, deterministic failure behavior, and causal explanation.
|
||
- Add deterministic package/archive/link adapters using the existing compiler,
|
||
assembler, and linker as explicitly hashed tools. This is a temporary adapter,
|
||
not a compatibility promise.
|
||
- Keep the engine under an internal test binary; the installed `ww` still follows
|
||
the old production path.
|
||
- Gate: all action-input mutation and failure-injection tests pass; identical warm
|
||
builds execute no compiler, assembler, archiver, or linker.
|
||
|
||
### Phase 3 — module, lock, source, and workspace layer
|
||
|
||
- Implement the manifest, lock, work, and vendor text parsers as ordinary typed
|
||
parser code, then implement the closed grammar, monotonic selector, canonical
|
||
lock,
|
||
HTTPS source-index/archive protocol, immutable source store, signatures,
|
||
explicit add/update/lock/fetch, overlays, vendor index, and canonical
|
||
source-tree construction. The schema fixes only the resulting record bytes and
|
||
source-tree digest formula.
|
||
- Build/test/doc/install remain network-denied from their first experimental use.
|
||
- Gate: frozen offline builds work from project source + complete locked source
|
||
closure + lock + installed named toolchain; collision/downgrade/hash/
|
||
path-normalization attacks fail loudly.
|
||
|
||
### Phase 4 — native, target, and external toolchain closure
|
||
|
||
- Implement full target descriptors, B/H/T lowering, C/assembly/native-provider
|
||
records, recursive provider selection/expansion, generated actions/sandbox,
|
||
object sidecars, exact link-plan construction, sysroot,
|
||
libc/CRT/loader/SDK/runtime, shared-library installation, and freestanding
|
||
products.
|
||
- Package supported assembler/linker/archive/C tools as immutable external
|
||
closures. Implement an external-assembler-compatible textual emission backend,
|
||
then have the pinned assembler produce `package.o` inside `ww.package`; port all WW/Plan-9-dialect
|
||
runtime and user assembly to a declared supported external dialect, and pass
|
||
object/link parity. An argv adapter alone cannot consume current `w6a` syntax.
|
||
Stop relying on WW-owned `w6a`/`w6l` before the experimental gate passes.
|
||
- Gate: native conflict, archive group/order, linker-script include, host leak,
|
||
freestanding, shared loader, and at least one real cross-target suite pass.
|
||
|
||
### Phase 5 — repository and consumer conversion rehearsal
|
||
|
||
- Define the final identity/layout conversion in a one-shot checker/rewriter under
|
||
`tools/migrate-build/`: folded files become directory packages; aliases,
|
||
manifests, native providers, products, generated inputs, and locks are emitted.
|
||
It is not an import resolver or runtime compatibility layer.
|
||
- Until cutover, CI applies that tool to a fresh ignored shadow tree. Tracked
|
||
production source stays in old syntax, so the old command remains its only
|
||
production path; the shadow is regenerated, never a second maintained source
|
||
tree or shipped interface.
|
||
- Dogfood the internal engine on the converted shadow of the standard library,
|
||
compiler tools, tests, examples, install layout, CI/package inputs, and sample
|
||
downstream consumers. Compare semantics, diagnostics, performance, artifacts
|
||
where protocols permit, and complete graph explanations.
|
||
- Gate: the regenerated full shadow, distribution/frozen-offline build,
|
||
self-contained installed toolchain outside the build tree, downstream samples,
|
||
and bootstrap inputs pass without an old-format edge.
|
||
|
||
### Phase 6 — new bootstrap and reproducible release
|
||
|
||
- Implement/gate the portable C recovery backend and snapshot generator, then
|
||
generate/check in `bootstrap/ww0.c` and the fixed plan. Produce stages 1/2/3/4,
|
||
rebuild stages with the executable engine, compare the actual bytes of every
|
||
declared output directly, and produce fixed-point and diverse-seed-compilation
|
||
reports, signed toolchain bundles, and recovery documentation on a clean
|
||
machine with no WW compiler.
|
||
- Gate: stage 2 equals stage 3 and stage 3 equals stage 4 by explicit
|
||
byte-for-byte comparison, including raw action/result records, in two
|
||
roots/concurrency levels; project plus complete
|
||
locked source closure and published named tool closure reproduce every release
|
||
artifact.
|
||
|
||
### Phase 7 — point of no return and deletion
|
||
|
||
In one atomic, bisect-clean cutover commit:
|
||
|
||
1. install the new engine as `ww` and make it the sole build/test/bootstrap path;
|
||
2. switch repository imports, manifests, locks, toolchains, CI, installation,
|
||
and release jobs to their final forms;
|
||
3. delete both old drivers, both `.wwi` writers, driver-side `.wwi` concatenation,
|
||
composed-unit/module-wrapper logic, generic C/self-hosted lexer/parser/checker/
|
||
symbol/codegen support for module directives, `-w`,
|
||
old import search/file folding, separate test coordinator,
|
||
duplicated production Make dependency graph, current Cstage bootstrap, and
|
||
retired owned assembler/linker path; and
|
||
4. delete the migration rewriter after all supported consumers have used its
|
||
released standalone copy; keep only a format-error guide.
|
||
|
||
The commit does not accept old `.wwi`, dotted/file imports, `-I`, `-w`, raw
|
||
library searches, or old work directories. No alias, warning period inside the
|
||
compiler, environment switch, or fallback subprocess retains a dual system.
|
||
|
||
### Phase 8 — consolidation
|
||
|
||
- Remove temporary parity fixtures that test deleted artifact bytes while
|
||
retaining semantic, action-key, reproducibility, and bootstrap regression
|
||
tests.
|
||
- Publish migration statistics and archive the old documentation as historical
|
||
release material outside the live manual.
|
||
- Gate: repository search and executable tracing show one graph constructor, one
|
||
package resolver, one cache, one test route, and one bootstrap route.
|
||
|
||
## 14. Validation plan and release gates
|
||
|
||
### 14.1 Unit and format tests
|
||
|
||
- Phase 0 has golden and adversarial vectors only for WWAR representation,
|
||
source-tree digest bytes, action-key/record identity formulas, typed record
|
||
assignments, wrappers, and canonical schema JSON.
|
||
- Phase 0 tests UTF-8/NFC, duplicate schema keys, unknown wire type/schema field,
|
||
oversized declarations, truncation, exact-length mismatch, union shape, and
|
||
record-kind substitution. Case-fold collision, traversal, symlink/device,
|
||
cache collision/corruption, and semantic record tests land with their owning
|
||
executable phases.
|
||
- Phases 1–4 add behavior tests for CAS tree/result objects, `.wwe`, `.wwlm`,
|
||
manifest/lock/work/vendor parsing, and target/toolchain/native processing;
|
||
these are not encoded as Phase 0 vector outcomes.
|
||
- Resolver vectors for minimum selection, incompatible-major identities,
|
||
workspace identity preservation, source origin independence, vendor matching,
|
||
internal packages, aliases, nested module/root-versus-parent-subpackage
|
||
identity collisions (including `/vN`), cycles, and target source specificity.
|
||
|
||
### 14.2 Package/interface tests
|
||
|
||
- One- and multi-file directory membership, file-scoped import use, same/external
|
||
tests, test-only packages, examples/docs, and generated fragments with import/
|
||
package rejection.
|
||
- Direct dependency interface-open counts equal package-graph indegree, never
|
||
transitive closure size.
|
||
- Private dependency edits preserve importer keys; exported but unused additions
|
||
rebuild direct importers; unchanged middle `.wwe` stops propagation; layout,
|
||
calling-convention, runtime ABI, compiler, target, and profile changes rebuild
|
||
the exact affected cone.
|
||
- Parameter renames, comments, private declaration ordering, and absolute source
|
||
paths do not change `.wwe`; semantic/ABI changes do.
|
||
|
||
### 14.3 Native and link tests
|
||
|
||
- C scalar/aggregate/variadic/callback/TLS/unwind ABI probes against an
|
||
independently compiled C harness for every official target.
|
||
- Binding generation changes on header tree, macro map, preprocessor, tool, C
|
||
ABI, and target; undeclared include access is denied.
|
||
- Assembly dialect/CPU mismatch, wrong-format objects, PIC/shared rules, archive
|
||
extraction order, repeated libraries, groups, whole archive, weak/strong
|
||
symbols, version scripts, linker-script includes, and deterministic archives.
|
||
- Exactly-one libc/runtime/provider enforcement; identical coalescing; duplicate
|
||
native ABI/symbol conflict; shared SONAME/loader/runtime installation closure;
|
||
freestanding entry/script with proof that no libc/CRT/loader appears.
|
||
|
||
### 14.4 Cross and sandbox tests
|
||
|
||
- Matrix with `B != H`, compiler product `H != T`, and all three distinct where
|
||
infrastructure permits. A B generator emits an H input; an H binary is never
|
||
executed during build; T objects never enter the H link.
|
||
- Poison host `PATH`, includes, libraries, SDK, locale, time, home, current
|
||
directory, and environment. Every attempted undeclared read/write/network/
|
||
process/tool access fails with its action identity.
|
||
- Cross tests build without a runner, run only with an exact declared runner,
|
||
and fail under `--require-run` when none exists.
|
||
|
||
### 14.5 Cache and failure injection
|
||
|
||
- Change each field in section 6.2 individually and require a key change; change
|
||
each expressly non-semantic observation and require no key change.
|
||
- Bit-flip blobs, trees, results, action mappings, tools, export data, objects,
|
||
and partial files at every publication boundary. Require quarantine/rebuild,
|
||
never acceptance or broad deletion.
|
||
- Concurrent identical publishers, killed compiler/linker, disk full, rename
|
||
failure, read-only output, interrupted materialization, stale project index,
|
||
malicious remote mapping, bad cache signature, and remote outage.
|
||
- Clean, local-hit, explicit remote-import, and no-cache builds must yield the
|
||
same result digests. Test executions still run.
|
||
|
||
### 14.6 Reproducibility and bootstrap
|
||
|
||
- Compare every artifact/action record across two absolute checkouts, source/
|
||
cache/output roots, usernames, locales, time zones, umasks, concurrency levels,
|
||
filesystem enumeration orders, and cold/warm caches.
|
||
- Verify debug/release, static/shared, hosted/freestanding, generated/native, and
|
||
signed/unsigned products. Impure profiles must state exactly why they are
|
||
outside the byte promise and must never enter shared cache.
|
||
- Build `ww0` with each supported host C toolchain, reach stages 2/3/4, run the
|
||
semantic then raw-record fixed point and diverse seed compilation, corrupt each stage input, and recover on a host
|
||
with no WW installation.
|
||
|
||
### 14.7 Performance and migration gates
|
||
|
||
On the audit's fixed eight-CPU reference host, the first release MUST:
|
||
|
||
- run package compilation in parallel and complete the full clean toolchain
|
||
build no slower than the measured 15.515 s `make -j8` baseline;
|
||
- perform a warm 15-package build with no compiler, assembler, archiver, or
|
||
linker process and no slower than the measured 0.053 s driver baseline;
|
||
- read only direct exports and avoid composed-unit duplication;
|
||
- store one CAS copy of duplicate tool/package content across all products;
|
||
- produce fully path-independent official artifacts, including host-side tools;
|
||
and
|
||
- provide a typed explanation for every deliberately induced rebuild.
|
||
|
||
Before cutover, every tracked current package/test/install/bootstrap consumer has
|
||
an assigned new identity and a passing converted test. The cutover gate includes
|
||
a repository-wide search for old forms and executable traces proving no old
|
||
driver, interface, workdir, library search, or test-coordinator path executes.
|
||
|
||
## 15. Evidence appendix
|
||
|
||
### 15.1 Research method and version pins
|
||
|
||
Research used official documentation, standards/manuals, release metadata, and
|
||
current upstream source—not comparison articles or community summaries. The
|
||
evolving-system snapshot was taken 2026-08-09:
|
||
|
||
| System | Pinned snapshot used |
|
||
|---|---|
|
||
| Plan 9 | live official `9p.io` Volume 2 documents, accessed 2026-08-09; pages are not versioned/dated editions |
|
||
| Go | online docs accessed 2026-08-09; Go 1.26.5 `go1.26.5` source tag |
|
||
| Hare | online docs accessed 2026-08-09; Hare 0.26.0 source, released 2026-02-13 |
|
||
| Odin | online docs accessed 2026-08-09; `dev-2026-07a`, commit `819fdc7a80667498b8b365999f1475a66c358640` |
|
||
| Zig | Zig 0.16.0, official metadata release date 2026-04-13; source archive SHA-256 `43186959edc87d5c7a1be7b7d2a25efffd22ce5807c7af99067f86f99641bfdf` |
|
||
| Rust/Cargo | Rust/Cargo 1.97.1, released 2026-07-16; Cargo `0.98.0` commit `c980f4866141969fab6254a680546a277789d6f0` |
|
||
| Bazel | Bazel 9.2.0 documentation/source |
|
||
| Nix | Nix 2.35.2 manual/source |
|
||
|
||
Zig's separate bootstrap-source archive inspected for this decision had SHA-256
|
||
`2a8266a4205772ef40838c8cbdf14875855a515ff3adf89b49c2d2ae93613d10`.
|
||
These pins matter because programmable-build and package behavior changes between
|
||
releases; this document does not generalize an old Zig/Cargo observation to an
|
||
unidentified current version.
|
||
|
||
### 15.2 Primary-source findings
|
||
|
||
**Pike, Plan 9, and early Go.** Pike's sources support explicit computable
|
||
imports, cycle rejection, direct compiled export information, fast compilation,
|
||
and orthogonal concepts. The collective Plan 9 papers add system-wide placement
|
||
of complexity and transparent encodings. Plan 9's namespace papers demonstrate
|
||
contextual filesystem composition; this document infers that contextual location
|
||
must not serve as WW's versioned distribution identity. `mk` shows complete graph scheduling while still relying
|
||
on timestamps, recipes, and environment. The architecture borrows the former
|
||
principles and replaces the latter ambient assumptions.
|
||
|
||
- [The Go Programming Language, 2009](https://go.dev/talks/2009/go_talk-20091030.pdf)
|
||
- [Go at Google: Language Design in the Service of Software Engineering, 2012](https://go.dev/talks/2012/splash.article)
|
||
- [Simplicity is Complicated, 2015](https://go.dev/talks/2015/simplicity-is-complicated.slide)
|
||
- [Go in Go, 2015](https://go.dev/talks/2015/gogo.slide)
|
||
- [Plan 9 overview](https://9p.io/sys/doc/9.html)
|
||
- [The Use of Name Spaces in Plan 9](https://9p.io/sys/doc/names.html)
|
||
- [Maintaining Files on Plan 9 with Mk](https://9p.io/sys/doc/mk.html)
|
||
- [Plan 9 Mkfiles](https://9p.io/sys/doc/mkfiles.html)
|
||
- [Plan 9 compiler suite](https://9p.io/sys/doc/comp.html)
|
||
|
||
**Later Go.** The original Go command demonstrates source-derived package DAGs,
|
||
directory conventions, and compiler-owned dependency work. The modern module
|
||
reference documents module identity, Minimal Version Selection, major-version
|
||
paths, checksums, and commands that may resolve/download modules. Current command
|
||
and source-install documents also separate build cache/toolchain/bootstrap
|
||
behavior. These are evidence, not automatic WW defaults; in particular WW uses
|
||
an exact lock and forbids implicit build-time acquisition.
|
||
|
||
- [About the Go command](https://go.dev/doc/articles/go_command)
|
||
- [Go module reference](https://go.dev/ref/mod)
|
||
- [`go` command reference](https://go.dev/cmd/go/)
|
||
- [Go toolchain selection](https://go.dev/doc/toolchain)
|
||
- [Installing Go from source](https://go.dev/doc/install/source)
|
||
- [Perfectly Reproducible, Verified Go Toolchains](https://go.dev/blog/rebuild)
|
||
- [Go's supply-chain security](https://go.dev/blog/supply-chain)
|
||
- [`go1.26.5` source](https://go.googlesource.com/go/+/refs/tags/go1.26.5/)
|
||
|
||
**Local-source systems.** Hare demonstrates how far a disciplined directory
|
||
module/search-root system can go with little package machinery; its documented
|
||
system-library and cross interfaces also expose why raw host paths and tool
|
||
defaults are insufficient for WW's hard gates. Odin's collections reinforce the
|
||
local namespace option but do not add a locked whole native closure.
|
||
|
||
- [Hare modules](https://harelang.org/documentation/usage/modules.html)
|
||
- [Hare project structure](https://harelang.org/documentation/usage/project-structure.html)
|
||
- [Hare system libraries](https://harelang.org/documentation/usage/system-libraries.html)
|
||
- [Hare cross compilation](https://harelang.org/documentation/usage/cross.html)
|
||
- [Hare 0.26.0 source](https://git.sr.ht/~sircmpwn/hare/tree/0.26.0)
|
||
- [Odin overview](https://odin-lang.org/docs/overview/)
|
||
- [Odin pinned source](https://github.com/odin-lang/Odin/tree/819fdc7a80667498b8b365999f1475a66c358640)
|
||
|
||
**Integrated project systems.** Zig supplies useful target/native vocabulary,
|
||
source hashes, local aliases, declared generated-file edges, and cross-building.
|
||
Cargo supplies package IDs, exact lock checksums, workspace behavior, resolver
|
||
documentation, and a native `links` uniqueness rule. Their programmable build
|
||
program/script model is deliberately rejected; a dependency host program is a
|
||
larger and less inspectable abstraction than WW's finite action record.
|
||
|
||
- [Zig build system](https://ziglang.org/learn/build-system/)
|
||
- [Zig overview](https://ziglang.org/learn/overview/)
|
||
- [Zig 0.16.0 language reference](https://ziglang.org/documentation/0.16.0/)
|
||
- [Zig release metadata](https://ziglang.org/download/index.json)
|
||
- [Zig 0.16.0 source](https://github.com/ziglang/zig/tree/0.16.0)
|
||
- [Cargo 1.97.1 reference](https://doc.rust-lang.org/1.97.1/cargo/reference/)
|
||
- [Cargo current reference entry](https://doc.rust-lang.org/cargo/reference/)
|
||
- [Cargo 1.97.1 resolver](https://doc.rust-lang.org/1.97.1/cargo/reference/resolver.html)
|
||
- [Cargo current resolver entry](https://doc.rust-lang.org/cargo/reference/resolver.html)
|
||
- [Cargo 1.97.1 build scripts](https://doc.rust-lang.org/1.97.1/cargo/reference/build-scripts.html)
|
||
- [Cargo current build-script entry](https://doc.rust-lang.org/cargo/reference/build-scripts.html)
|
||
- [Cargo 1.97.1 build cache](https://doc.rust-lang.org/1.97.1/cargo/reference/build-cache.html)
|
||
- [Cargo current build-cache entry](https://doc.rust-lang.org/cargo/reference/build-cache.html)
|
||
- [Cargo pinned source](https://github.com/rust-lang/cargo/tree/c980f4866141969fab6254a680546a277789d6f0)
|
||
|
||
**Hermetic invariants.** Bazel defines useful distinctions between declared
|
||
actions, execution platforms, action results, and content-addressed remote data.
|
||
Nix derivations demonstrate an inspectable build record whose output depends on
|
||
declared inputs. WW borrows those invariants only. It rejects Bazel's general
|
||
rule/ecosystem machinery and Nix's evaluator/store-as-package-manager as excess
|
||
for one language toolchain.
|
||
|
||
- [Bazel current hermeticity entry](https://bazel.build/concepts/hermeticity)
|
||
- [Bazel 9.2.0 hermeticity](https://bazel.build/versions/9.2.0/basics/hermeticity)
|
||
- [Bazel remote caching](https://bazel.build/remote/caching)
|
||
- [Remote Execution API](https://github.com/bazelbuild/remote-apis/blob/master/build/bazel/remote/execution/v2/remote_execution.proto)
|
||
- [Bazel 9.2.0 source](https://github.com/bazelbuild/bazel/tree/9.2.0)
|
||
- [Nix current derivation entry](https://nix.dev/manual/nix/latest/store/derivation/)
|
||
- [Nix 2.35 derivations](https://nix.dev/manual/nix/2.35/store/derivation/)
|
||
- [Nix build process](https://nix.dev/manual/nix/2.35/store/building.html)
|
||
- [Nix 2.35.2 source](https://github.com/NixOS/nix/tree/2.35.2)
|
||
|
||
**Native and reproducible toolchains.** LLVM and Clang define data-layout and
|
||
cross/toolchain choices that must be explicit for ABI-correct code. GNU manuals
|
||
document build/host/target vocabulary and semantic linker/archive/script
|
||
behavior. The reproducible-builds definition supplies the correct boundary:
|
||
same source, environment, instructions, and dependencies—not merely “same
|
||
compiler source.”
|
||
|
||
- [LLVM language-reference data layout](https://llvm.org/docs/LangRef.html#data-layout)
|
||
- [Clang cross compilation](https://clang.llvm.org/docs/CrossCompilation.html)
|
||
- [Clang toolchain](https://clang.llvm.org/docs/Toolchain.html)
|
||
- [Autoconf target triplets](https://www.gnu.org/software/autoconf/manual/autoconf-2.71/html_node/Specifying-Target-Triplets.html)
|
||
- [GCC language standards/runtime implications](https://gcc.gnu.org/onlinedocs/gcc/Standards.html)
|
||
- [GCC link options](https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html)
|
||
- [GNU linker](https://sourceware.org/binutils/docs/ld.html) and [linker scripts](https://sourceware.org/binutils/docs/ld/Scripts.html)
|
||
- [Reproducible Builds definition](https://reproducible-builds.org/docs/definition/)
|
||
|
||
### 15.3 Repository and empirical evidence record
|
||
|
||
The source audit covered the Makefile; C and self-hosted drivers; compiler entry
|
||
and both interface writers; package/test coordinator; language and test specs;
|
||
bootstrap documents/recipes; and package, separate-compilation, incremental,
|
||
byte-identity, and bootstrap tests. The audit found documentation drift as well
|
||
as code defects: the root instructions count five unit suites while Make lists
|
||
six, and the test-system document describes three pinned data byte divergences
|
||
while the current Make divergence list is empty. Neither drift item influences
|
||
the architecture, but both require cleanup during migration.
|
||
|
||
Raw commands, timings, traces, hashes, fixture logs, environment capture, and
|
||
interpretation for section 11.4 are retained in the session checkpoint under
|
||
`empirical/RESULTS.md` and `empirical/raw/`. The experiments were deliberately
|
||
small and answered only material uncertainties: actual process scheduling,
|
||
direct versus transitive interface consumption, private/public/link-only blast
|
||
radius, nonzero corruption, path identity, Cstage/WWstage symmetry, duplicate
|
||
storage, and hidden-host execution. No toy result is treated as proof that the
|
||
new architecture is complete; sections 13–14 turn each inference into a gate.
|
||
|
||
### 15.4 Assumptions
|
||
|
||
- Breaking import syntax, package layout, compiler flags, cache/workdir format,
|
||
bootstrap artifacts, and consumer builds is authorized.
|
||
- WW can add explicit C ABI/representation annotations and change its compiler
|
||
export protocol without preserving `.wwi` compatibility.
|
||
- Official releases can distribute or name legally usable immutable tool,
|
||
sysroot, runtime, and SDK closures for each supported target.
|
||
- SHA-256 is the version-1 content primitive; every format is domain-separated
|
||
and versioned so a future digest transition can be explicit.
|
||
- A first release may support fewer frozen targets than impure development
|
||
targets; it may not call an impure target “hermetic.”
|
||
- Byte reproducibility covers build artifacts, not identical behavior of an
|
||
external kernel, firmware, network service, or hardware.
|
||
|
||
### 15.5 Remaining risks and bounded experiments
|
||
|
||
These experiments are implementation gates inside the selected architecture;
|
||
they do not reopen its package identity, no-script, one-graph, lock/network,
|
||
direct-export, content-key, native-provider, or stage-zero choices.
|
||
|
||
1. **Deep `.wwe` closure.** Prototype the real standard-library type graph and
|
||
prove that one direct export file contains every transitive layout/type fact
|
||
required without leaking non-semantic source data. Adjust record layout, not
|
||
direct-dependency semantics.
|
||
2. **Generated C seed.** Measure generated `ww0.c` size, C99 portability, host-C
|
||
variance, and fixed-point convergence on at least three unrelated C
|
||
implementations. Restrict/repair the recovery emitter rather than introducing
|
||
a second maintained compiler or opaque-permanent binary seed.
|
||
3. **External linker/tool bundles.** Certify deterministic debug info, build ID,
|
||
archives, scripts, shared-loader metadata, redistribution rights, and resource
|
||
closure. Change tool adapters/bundle membership if needed; do not restore
|
||
ambient driver defaults.
|
||
4. **Sandbox portability.** Implement denial conformance on every official B
|
||
platform, including process children, filesystem race/symlink attacks, clock,
|
||
randomness, and network namespaces. A platform that cannot enforce it remains
|
||
non-frozen rather than gaining an undeclared exception.
|
||
5. **Native-provider coverage.** Exercise ELF first, then Mach-O frameworks/SDKs,
|
||
PE/COFF import libraries, symbol versioning, and kernel image builders. Extend
|
||
the closed typed schema by version where genuinely required; do not add raw
|
||
search or a general build language.
|
||
6. **Registry/private-source protocol.** Test mirror failover, redirects,
|
||
credential isolation, key rotation, provenance, yanked releases, and malicious
|
||
archives. Vendored/exact-origin operation remains the deterministic fallback.
|
||
7. **Performance.** Validate compiler worker strategy and CAS hashing against the
|
||
measured 15-package/full-toolchain budgets. Process topology may change while
|
||
action boundaries and keys remain fixed.
|
||
|
||
### 15.6 Final decision trace
|
||
|
||
The documented Pike evidence shapes the design: computable direct dependencies,
|
||
fast compilation, cycle rejection, package boundaries, and orthogonal concepts;
|
||
the collective Plan 9 papers add transparent encodings and system-wide placement
|
||
of complexity. Later Go work demonstrates one possible module/cache/toolchain
|
||
evolution but does not decide WW's answer. This document then applies those
|
||
principles to requirements early Go's package/build model did not expose
|
||
completely: foreign ABI contracts, C headers, external assembly and objects,
|
||
archive/link ordering, linker scripts, CRT/libc/sysroot identity, host generators,
|
||
and explicit build/host/target closures.
|
||
|
||
The resulting binding conclusion is singular: **replace the current system with
|
||
WW Action Build exactly as specified above**. Do not preserve the old path, and
|
||
do not substitute a programmable project framework or a source-only package
|
||
command during implementation.
|