test: prove canonical directory test products

This commit is contained in:
2026-08-15 02:50:00 +09:00
parent 8dad2755b3
commit 7d73d31b38
6 changed files with 2935 additions and 1806 deletions

View File

@@ -2829,7 +2829,8 @@ and every component of the canonical import path. A selected command directory
declares `package main` while retaining its complete canonical import identity. declares `package main` while retaining its complete canonical import identity.
A source import of a command package from a A source import of a command package from a
different directory is rejected; the one same-directory exception is an different directory is rejected; the one same-directory exception is an
external `main_test` variant's canonical import of its production action. Two external `main_test` variant's canonical import of its effective augmented
test action. Two
ordinary logical identities for one physical directory are rejected rather ordinary logical identities for one physical directory are rejected rather
than compiled twice; section 11.16 records the deliberate exception for than compiled twice; section 11.16 records the deliberate exception for
distinct expanded vendor routes that converge through symlinks. distinct expanded vendor routes that converge through symlinks.
@@ -2948,54 +2949,57 @@ supported manifest-free forms include `ww build DIR...`, `ww build DIR/...`,
`ww test DIR...`, and `ww test DIR/...`, with overlapping direct and recursive `ww test DIR...`, and `ww test DIR/...`, with overlapping direct and recursive
roots. Test retains its existing `-run`, `-filter`, `-list`, `-timeout-ms`, 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 `-j`, `-c`, and `-w` forms. `ww test -c -o test.bin DIR` names the result when
the selected directory has one test variant; the coordinator rejects one output the request selects one canonical directory, including a directory with both
name for a multi-variant or recursive test request. Explicit `ww test FILE` same-package and external-package test sources. The coordinator rejects one
retains its compatibility path. 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, enumerates the The test coordinator still discovers requested directories, classifies the
test package names, selects variants, executes independent binaries, and emits selected test package names, executes one binary per test-bearing canonical
captured results in byte-sorted package order. It no longer concatenates a 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 generated production/test root, resolves imports, or starts one package graph
per binary or directory. Instead it sends one ordered build request containing per declared test package. Instead it sends one ordered build request containing
every selected directory/variant root to the Cstage or WWstage command. Its one product descriptor per selected directory, with optional production,
semantic selections are only the directory and selected variant/package same-package, and external-package selectors, to the Cstage or WWstage command.
identities; it also carries output destinations, coordinator-private completion It also carries output destinations, coordinator-private completion paths,
paths, import search roots, and the optional command-scoped work-directory import search roots, and the optional command-scoped work-directory policy.
policy. The command owns source selection, package loading, compiler inputs, The command owns source selection, package loading, substitution, compiler
archive construction, generated-main construction, and linking for every inputs, archive construction, the single generated main, and linking:
package variant:
- The ordinary production action selects the directory's byte-sorted non-test - The ordinary production action selects the directory's byte-sorted non-test
files. A no-test requested product uses this action directly, and every files. A no-test request uses this action directly. Ordinary builds and
ordinary, internal-test, or external-test import of that package reuses it. dependencies outside a tested closure continue to use it.
- The internal production-plus-test variant selects the byte-sorted production - The internal production-plus-test variant selects the byte-sorted production
files followed by byte-sorted matching `package p` test files. It is distinct files followed by byte-sorted matching `package p` test files. It is distinct
from production so its private production declarations and test declarations from production, exports declarations contributed by internal test files, and
remain isolated to that test product. replaces the ordinary action throughout the applicable tested closure.
- When production sources establish `p`, the external variant selects only - When production sources establish `p`, the external variant selects only
matching `package p_test` files, where `p` is the production declaration 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 rather than an import-path leaf. A test-only directory may establish its own
one consistent test package name, matching pinned `go/build` classification. `p`, `p_test`, or valid `p`/`p_test` pair, matching pinned `go/build`
A real source import of the production package uses its canonical import classification. The external action's import of the package under test binds
path and is a direct edge to the same ordinary production action used by to the augmented internal action when it exists. Importers affected by that
ordinary products and transitive imports; there is no external-production replacement are copied and rewired transitively; an ordinary and augmented
role or artifact. instance of one canonical package never coexist in the linked test closure.
- Generated main is a separate package action whose owner-only generated unit - Generated main is a separate package action whose owner-only generated unit
declares `package main` and imports exactly the selected variant and test declares `package main` and imports every applicable internal/external target
support. It consumes those direct `.wwi` files, emits its own `.wwi/.o/.a`, plus test support. It consumes those direct `.wwi` files, emits its own
and alone receives compiler `-T --entry`. Its target edge also receives the `.wwi/.o/.a`, and alone receives compiler `-T --entry`. Repeated byte-sorted
compiler-private `--test-target-package <canonical-path>` binding. That `--test-target-package <canonical-path>` arguments identify the target set.
private canonical-path qualifier prevents a tested command declared `main` Those compiler-private canonical qualifiers prevent declared-name collisions;
from colliding with generated main; it is not user alias syntax. they are not user alias syntax.
The authoritative directory-action identity is the triple **(canonical The coordinator groups one test product by canonical directory, but physical
filesystem directory, canonical ordinary import path, semantic variant)**. location is not a compiler/package identity. The authoritative action key uses
The semantic variants are production, internal production-plus-test, and the finalized canonical dotted import identity, semantic variant, role, and,
external `_test`; generated main and the reserved test-support alias are for a copy made by recompile-for-test, the owning canonical directory product's
explicit non-directory action classes. The declared package name is stored stable test identity. The semantic variants are production,
separately and is not part of canonical directory/path interning. Requested-root production-plus-same-package-test, external `_test`, directory generated main,
state, discovery role, product ordinal, output path, persistent artifact key, and recompiled-for-test. The declared package name, local import binding,
and discovery order never enter the triple. 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 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 is known. It is provisionally interned by canonical directory and variant, and
@@ -3059,19 +3063,19 @@ introduces a package registry.
Artifact publication follows the semantic action instead of product order: Artifact publication follows the semantic action instead of product order:
production uses the full finalized ordinary identity, internal appends production uses the full finalized ordinary identity, internal appends
`-internal-test`, external appends `_test-external-test`, and their generated `-internal-test`, external appends `_test-external-test`, and the one
mains append `-main`. Generated package identities are likewise derived from directory-owned generated main appends `-test-main`. Its package identity is
the full variant identity, for example `__wwtestmain.a.foo.internal.main` and `__wwtestmain.<canonical-directory-product-base>.main`, independent of either
`__wwtestmain.b.foo_test.external.main`. Equivalent products therefore reuse an declared test name. Equivalent roots therefore converge on one directory
already-interned directory action and generated-main action and publish through product and reuse already interned actions and persistent-workdir slots
the same persistent-workdir slots regardless of discovery or product order. regardless of discovery or request order.
The narrow raw single-file compatibility path alone retains `__root`. The narrow raw single-file compatibility path alone retains `__root`.
A deterministic dependency-first traversal of the complete command union A deterministic dependency-first traversal of the complete command union
invokes the compiler, assembler, and in-driver deterministic archiver once per invokes the compiler, assembler, and in-driver deterministic archiver once per
interned action. This is compile-time interning, not linker-argument interned action. This is compile-time interning, not linker-argument
deduplication. Each product is then linked separately from its generated-main deduplication. Each canonical directory product is linked once from its single
or executable root archive and the complete reachable archive closure. The generated-main root archive and the complete reachable archive closure. The
shared plan remains package-test-specific; it is not a generalized scheduler, shared plan remains package-test-specific; it is not a generalized scheduler,
action schema, cache, or protocol. action schema, cache, or protocol.
@@ -3095,15 +3099,19 @@ a rejected union build. After one successful union build, the completed test
products share the coordinator's existing `-j` process bound; captured output products share the coordinator's existing `-j` process bound; captured output
is still emitted only in byte-sorted directory/package order. is still emitted only in byte-sorted directory/package order.
Every source-imported dependency is a production variant, so dependency Ordinary production loading never selects dependency `*_test.ww` files.
`*_test.ww` files never enter the graph. Imports that occur only in selected Imports that occur only in selected test files add edges only to the applicable
test files add edges only to that internal or external variant. Each compiler internal or external action. Recompile-for-test may create a product-scoped copy
unit contains only its action's owned source set, while its invocation receives of an ordinary transitive importer, but that copy retains the importer's
only the byte-sorted direct dependency `.wwi` artifacts as separate inputs. 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 Variant compiles receive `--test-package`, which validates and retains private
`@test` declarations as compiler-only export metadata without synthesizing an `@test` declarations as compiler-only export metadata without synthesizing an
entry point. The distinct generated-main action consumes that metadata from its entry point. The distinct directory generated-main action consumes that
direct variant export and synthesizes the dispatcher with `-T`. metadata from every direct target export and synthesizes one dispatcher with
`-T`.
The generated-main action, rather than the tested variant, owns the implicit The generated-main action, rather than the tested variant, owns the implicit
direct test-runtime support edge. The command-scoped plan compiles the common direct test-runtime support edge. The command-scoped plan compiles the common
@@ -3125,22 +3133,23 @@ 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 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 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 section 11.16 is canonical source-tree identity, not a role alias. All ordinary
production actions, including an external test's colocated production and test actions use canonical action identity and the global bidirectional
dependency, use canonical directory identity and the global bidirectional import-path checks above. External self-import substitution changes the target
import-path checks above. There is no role-based tolerance for duplicate action, never the source spelling or file-local binding. There is no role-based
ordinary import identities and no late product-closure ambiguity to resolve. tolerance for duplicate ordinary import identities and no late product-closure
ambiguity to resolve.
The selected internal/external variants and a production action reached by Production, internal, and external actions may select source from one physical
their imports or test-runtime closure are the sanctioned graph nodes that may directory, but the final directory test closure is strict: wherever the
share a physical directory. This also lets a toolchain package's own tests augmented internal action substitutes for production, every affected direct and
coexist with the production action required by the test runtime. An internal transitive edge is rewired before tools. A closure containing both ordinary
variant already defines those production symbols, so the colocated production `p` and its augmented `ptest` is rejected rather than hidden by initialization
archive is omitted from that product's final link while the production action's or linker filtering. The external action therefore sees internal-test exports
dependency archives remain in the closure. The external product includes the through `ptest`, and the one linked process owns exactly one package state.
production archive. Variant-only archives are never linked into another Variant-only archives never leak into an unrelated directory product. All
product. All ordinary logical and physical package-identity collision checks ordinary logical and physical package-identity collision checks remain
remain unchanged; only distinct expanded vendor routes receive the section unchanged; only distinct expanded vendor routes receive the section 11.16
11.16 symlink-convergence exception. symlink-convergence exception.
Both stage linkers receive the generated-main archive first, followed by the Both stage linkers receive the generated-main archive first, followed by the
complete reverse-topological reachable package-archive closure, runtime, and complete reverse-topological reachable package-archive closure, runtime, and
@@ -3155,10 +3164,13 @@ one stable escape of the canonical discovery directory names the persistent
command work directory. It contains neither a declared package leaf nor a command work directory. It contains neither a declared package leaf nor a
product ordinal, so equivalent path spellings and reordered products select the product ordinal, so equivalent path spellings and reordered products select the
same request state. same request state.
Every `*_test.ww` package variant is built even when a file only Every selected `*_test.ww` package variant is built even when its files only
declares helpers and contains no `@test`, so its package clause and imports are declare helpers and contain no `@test`, so its package clause and imports are
still checked by the shared loader. Every built variant is run, and a successful still checked; that is a real zero-test package and runs one empty combined
compiler-owned dispatcher with empty output is reported as `[no tests]`. 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 tests]` report.
Persistent workdirs keep a global driver/compiler/assembler/stamp identity and Persistent workdirs keep a global driver/compiler/assembler/stamp identity and
per-action committed units. When that global identity is stale, the command per-action committed units. When that global identity is stale, the command
@@ -3175,12 +3187,9 @@ stops as soon as a regenerated importer export is byte-identical. Stable
semantic artifact keys make that behavior independent of which ordinary or semantic artifact keys make that behavior independent of which ordinary or
test product first discovered the action. test product first discovered the action.
This ownership split follows the pinned Go 1.26.5 implementation cited in The completed topology and its pinned Go 1.26.5 evidence are specified in
section 11.12: its loader reuses canonical cached package objects, its work section 11.22. WW borrows that command-global action boundary without adding
builder interns actions by mode and package, and its test loader reuses ordinary Go's build cache, import-configuration format, or module system.
production while constructing only the required internal, external, and
generated-main variants. WW borrows that command-global ownership boundary
without adding Go's build cache, import configuration format, or module system.
### 11.8 Implemented exact package-tool invocation slice ### 11.8 Implemented exact package-tool invocation slice
@@ -3389,7 +3398,8 @@ imports use their explicit compiler-owned bindings. Executable linking
independently walks the full reachable package independently walks the full reachable package
closure and passes archives, never interfaces. The same path handles an closure and passes archives, never interfaces. The same path handles an
ordinary package, the production-plus-internal-test variant, the external test ordinary package, the production-plus-internal-test variant, the external test
package and its reused production package, compiler-generated test main, and 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 the reserved test-support package. Persistent workdirs compare a newly emitted
export with its committed predecessor before allowing a direct importer to export with its committed predecessor before allowing a direct importer to
reuse owner-identical artifacts, retaining correctness without a new cache reuse owner-identical artifacts, retaining correctness without a new cache
@@ -3411,8 +3421,9 @@ its non-`main` canonical identity in the unit, export, archive, compiler argv,
and linker argv; the bootstrap self-rebuild independently proves the same rule 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 for the real `w6a` and `w6l` command directories. A focused command-test row
proves distinct production, internal, external, and generated-main actions, proves distinct production, internal, external, and generated-main actions,
colocated external-production reuse, parser-only command markers, stage-equal colocated external-to-augmented substitution, parser-only command markers,
unit/export/archive bytes, both test binaries' runtime behavior, and pre-tool 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. rejection when another directory tries to import the command.
The exact-argv regression uses the real diamond The exact-argv regression uses the real diamond
@@ -3424,9 +3435,9 @@ and byte-identical units, exports, archives, executables, and tool argument
vectors across two clean vectors across two clean
Cstage builds and two clean WWstage builds. The existing directory-package Cstage builds and two clean WWstage builds. The existing directory-package
variant regression checks separate production, internal, external, and variant regression checks separate production, internal, external, and
generated-main actions, exact generated-main direct variant/support exports, directory-generated-main actions, exact generated-main direct target/support
canonical production reuse across ordinary and test products, and archive-only exports, canonical recompile-for-test substitution, and one archive-only link
link closures. It also reverses equivalent product descriptors and compares closure. It also reverses equivalent product descriptors and compares
exact compiler and linker trace bytes, then changes a shared direct export in exact compiler and linker trace bytes, then changes a shared direct export in
persistent workdirs to prove propagation through direct importers stops at the persistent workdirs to prove propagation through direct importers stops at the
first byte-identical regenerated export. Both stages compile and run those first byte-identical regenerated export. Both stages compile and run those
@@ -3661,9 +3672,10 @@ over 255 bytes. They inspect the complete owner in units and exports, exact
direct sorted/deduplicated `.wwi` compiler inputs, long mangled assembler direct sorted/deduplicated `.wwi` compiler inputs, long mangled assembler
symbols, complete archive-only link closures, runtime results, and independent symbols, complete archive-only link closures, runtime results, and independent
Cstage/WWstage artifact bytes. Two deep outside-root directories declaring Cstage/WWstage artifact bytes. Two deep outside-root directories declaring
the same leaf coexist under distinct reversible identities. A long command the same leaf coexist under distinct reversible identities. A long command
package and its production, internal, external, and two generated-main actions package's internal, external, and one directory generated-main actions remain
remain distinct. Logical and literal roots, dependency-first and root-first 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 discovery, equivalent and symlink spellings, reordered products, and warm
requests reuse the same production action and persistent slot. The persistent requests reuse the same production action and persistent slot. The persistent
diamond observer also changes a shared dependency export, proves rebuilding of diamond observer also changes a shared dependency export, proves rebuilding of
@@ -3757,7 +3769,7 @@ lazily zero-extended `contextstate: []u8`.
Products, load frames, and topological frames use typed dynamically allocated Products, load frames, and topological frames use typed dynamically allocated
slices. `internal/wwpackage` continues to construct one union command for all slices. `internal/wwpackage` continues to construct one union command for all
selected directory-test groups, but now checks the complete selected directory-test groups, but now checks the complete
`12 + 6*products + 2*includes` builder argument count before allocating or `12 + 9*products + 2*includes` builder argument count before allocating or
starting the driver. starting the driver.
All graph and product growth starts at capacity 8 and doubles until it covers All graph and product growth starts at capacity 8 and doubles until it covers
@@ -3819,30 +3831,26 @@ byte-identical export. Closing the chain at `p299 -> p000` produces the complete
stage-identical 300-node cycle diagnostic with empty compiler, assembler, and stage-identical 300-node cycle diagnostic with empty compiler, assembler, and
linker traces. linker traces.
`dynamic_package_universe_crosses_former_boundary` first selects 309 package-test `dynamic_package_universe_crosses_former_boundary` selects 257 canonical
products through 257 directory spellings in one direct request per stage. directory products in one direct request per stage. Fifty-two directories have
Fifty-two real directories each produce ordinary production, internal combined same/external tests and each produces `ptest`, `pxtest`, and one
production-plus-test, external `_test`, and two generated-main actions; the directory `pmain`; 205 production-only directories take the no-test path. The
shared support closure brings that command-global universe to 270 actions. Two shared support closure brings the command-global universe to exactly 370
hundred five explicit symlink spellings of `p000` add distinct valid products compile actions and 422 assembler invocations, with 52 generated dispatchers,
and resolution contexts while reusing its one canonical internal action. The links, binaries, and results. The 205 no-test products have only ordinary
observer reverses product and variant order between stages, proves one compile production actions and statuses: no support-owned target, main, link, binary,
per action, checks all 309 binaries exist, runs boundary products, validates or result. The observer reverses all directory descriptors between stages,
variant-owned units, and compares every action artifact plus representative proves one compile per action, runs a boundary combined binary, validates
binaries byte-for-byte. variant-owned units and external self substitution, and compares representative
action artifacts, normalized traces, and binaries byte-for-byte.
The same observer then exercises the public `ww test <tree>/...` coordinator The same observer exercises the public `ww test <tree>/...` coordinator path
path. The generated tree has 257 real directories: the 52 test-bearing against that persistent action store. The coordinator passes exactly 257
directories above plus 205 production-only directories. The coordinator forms directory descriptors in one driver request, prints 52 combined `ok` reports
and passes 309 products and 258 contexts (including support) in one driver and 205 no-test `?` reports, and performs no new compilation. An unchanged warm
request. Reusing the direct request's persistent semantic-action store preserves all 270 request again invokes no compiler or assembler; the 52 real products follow the
existing actions and adds exactly 410 production/generated-main actions, for 680 existing explicit-output relink convention while no-test products still create
distinct actions. Both stages run every product, produce byte-identical ordered no linker work. Existing focused observers continue to prove
coordinator output and all 680 action artifacts, and perform no compilation on a
second equivalent public request. It checks all 104 test-bearing result labels
and all 205 no-test result labels, while a builder-boundary observer records
exactly one invocation containing all 309 descriptors for each cold and warm
public request. Existing focused observers continue to prove
dependency-first/root-first canonical reuse, root-only/combined artifact dependency-first/root-first canonical reuse, root-only/combined artifact
identity, exact reordered-product trace bytes, and request-shape-independent identity, exact reordered-product trace bytes, and request-shape-independent
persistent action reuse. persistent action reuse.
@@ -4351,8 +4359,9 @@ selected test-only directory remains an unusable build root and fails. Build
creates one production product per remaining directory. Test retains test-only creates one production product per remaining directory. Test retains test-only
directories and, after selection, constructs the already specified isolated directories and, after selection, constructs the already specified isolated
production/no-test, internal production-plus-test, external `_test`, support, production/no-test, internal production-plus-test, external `_test`, support,
and generated-main actions. Pattern expansion does not create those variants recompiled-for-test, and one directory-generated-main action. Pattern expansion
and cannot make one variant visible to another. 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 Vendor selection remains distinct from vendor import resolution. Selecting a
directory below `vendor`, literally or through an explicitly vendor-rooted directory below `vendor`, literally or through an explicitly vendor-rooted
@@ -4592,14 +4601,14 @@ directory may establish one consistent package name from its test files, as in
pinned `go/build`. External action identity remains the canonical production pinned `go/build`. External action identity remains the canonical production
identity plus the existing external variant suffix where that production identity plus the existing external variant suffix where that production
exists. Imports found only in internal or external test files belong only to exists. Imports found only in internal or external test files belong only to
that variant. Support and generated-main actions retain their isolated that action. Support and the directory generated-main retain isolated action
identities and archive closures. A generated dispatcher privately binds its identities and archive closures. A generated dispatcher privately binds its
tested target through tested targets through repeated, byte-sorted
`--test-target-package <canonical-path>` so a command variant declared `main` `--test-target-package <canonical-path>` arguments so a command variant declared `main`
does not collide with the dispatcher's own synthesized `main`; this is does not collide with the dispatcher's own synthesized `main`; this is
compiler-generated wiring distinct from ordinary source aliases. Zero-test compiler-generated wiring distinct from ordinary source aliases. A real
dispatchers mark their compiler-owned target/support metadata imports consumed. zero-test directory product marks all compiler-owned target/support metadata
That private binding is installed or marked consumed only in the generated 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 dispatcher's source section; an import from an earlier test-file section
neither supplies nor satisfies it. neither supplies nor satisfies it.
@@ -5117,14 +5126,15 @@ the reachable archive closure and runtime/native inputs; no `.wwi`, alias,
blank spelling, or dispatcher sidecar appears. blank spelling, or dispatcher sidecar appears.
Production, production-plus-internal-test, external `_test`, test support, and Production, production-plus-internal-test, external `_test`, test support, and
generated main retain separate action identities. An internal product replaces directory generated main retain separate action identities. One canonical
the colocated production task with its combined variant and includes test-only directory product replaces colocated production with `ptest` wherever internal
blank edges/init declarations exactly once. An external product initializes tests augment it, rewires `pxtest` self-import and affected transitive importers
ordinary production and its production dependencies before the external task. to that action, and includes test-only blank edges/init declarations exactly
Support is an ordinary dependency task; generated main owns only the final once. Support is an ordinary dependency task; the one generated main owns only
dispatcher call and cannot duplicate a tested task. Test-file-only imports, the final dispatcher call and cannot duplicate a tested task. Test-file-only
runtime lets, and init functions never enter production. A blank import cannot imports, runtime lets, and init functions never enter production. A blank
bypass imported-`main` rejection, including through vendor expansion. import cannot bypass imported-`main` rejection, including through vendor
expansion.
`.wwi` contains neither blank-only spelling, init declarations/bodies, hidden `.wwi` contains neither blank-only spelling, init declarations/bodies, hidden
variable helpers, slice backing symbols, package tasks, nor dispatcher facts. variable helpers, slice backing symbols, package tasks, nor dispatcher facts.
@@ -5139,7 +5149,7 @@ first regenerated byte-identical semantic export.
The owner source voucher remains `<action>.unit.ww`; a linked product root also 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 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 17. Warm 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 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 action changed in the same request. All action artifacts, init artifacts, tool
identity copies, stamp, library/executable publications, and test statuses are identity copies, stamp, library/executable publications, and test statuses are
@@ -5184,9 +5194,10 @@ diamonds, independent lexical ties, aggregate and allocation initialization,
multiple-cycle diagnostics, special-init rejection, test-variant isolation, multiple-cycle diagnostics, special-init rejection, test-variant isolation,
canonical task/dispatcher/archive bytes, init-only invalidation, and warm canonical task/dispatcher/archive bytes, init-only invalidation, and warm
invalid-init rollback across independent Cstage and WWstage roots. Direct and invalid-init rollback across independent Cstage and WWstage roots. Direct and
recursive test legs compare variant dispatcher/archive bytes and observable recursive test legs compare the one directory dispatcher/archive and observable
production-dependency order; exact task counts include support and generated dependency, `ptest`, `pxtest`, then `pmain` order; every production and
main. Rejection rows compare complete normalized diagnostics and prove cold 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 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 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 producer, and proves no-follow atomic rejection of dangling driver staging and
@@ -5305,7 +5316,7 @@ binary effect, or test execution.
#### Persistence, rejection, and stage responsibility #### Persistence, rejection, and stage responsibility
Persistent formats are build 18 and test 17 so a pre-slice workdir performs one 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 complete reachable-action refresh under the new membership contract. Thereafter
an excluded-file add, removal, or content edit changes no unit voucher, `.wwi`, an excluded-file add, removal, or content edit changes no unit voucher, `.wwi`,
assembly, object, archive, dispatcher, test status, or reverse action. Existing assembly, object, archive, dispatcher, test status, or reverse action. Existing
@@ -5340,9 +5351,242 @@ observers retain their broader ownership.
Source-level `//go:build`/`+build` equivalents, arbitrary tags, cross-target Source-level `//go:build`/`+build` equivalents, arbitrary tags, cross-target
selection, grouped/quoted/dot imports, modules, manifests, registries, and a selection, grouped/quoted/dot imports, modules, manifests, registries, and a
programmable build language remain deliberately unsupported. Go's `UseAllFiles` programmable build language remain deliberately unsupported. Go's `UseAllFiles`
escape is also not exposed. The separate remaining Go test-product topology escape is also not exposed. Section 11.22 closes the formerly separate
divergence—one generated main for combined internal and external variants—is directory test-product topology divergence without changing these filename
not hidden or changed by this slice. 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 85101 and 175226](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 144161 and 228266](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 272293, 342376, and 421490](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 595638 and 790860](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 11331170 and 15241557](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 12001364](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 202206, 437447, and 628658](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/work/action.go#L202-L206),
[`exec.go`, lines 410438 and 864884](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 948953, 10051036, and 10761082](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
324 and 3053 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 89 and 6480 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 321 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 2750 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 114 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 STATUS
```
Missing action selectors are `-`. One descriptor owns at most one output and
one status. Canonically duplicate products and pairwise output/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.
Deliberately unchanged or unsupported behavior includes the raw single-file
compatibility path, WW's `[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. None is
used to define canonical package or directory-product identity.
## 12. Candidate architectures and hard-gate decision ## 12. Candidate architectures and hard-gate decision

View File

@@ -251,10 +251,12 @@ ImportName = ident .
ImportPath = ident { "." ident } . ImportPath = ident { "." ident } .
``` ```
- Every source file begins with a package clause. A directory of eligible - Every source file begins with a package clause. Within one semantic source
`.ww` files sharing one declared package name compiles as one package. The action, eligible `.ww` files share one declared package name. Ordinary
declared name need not equal the directory name or the final component of its production and same-package test sources use `p`; external test sources may
canonical import identity. use the related `p_test`, and the actions remain separate even though one
canonical directory owns their test product. The declared name need not equal
the directory name or the final component of its canonical import identity.
- Directory source eligibility uses Go 1.26.5 filename suffix semantics for - Directory source eligibility uses Go 1.26.5 filename suffix semantics for
WW's fixed `linux/amd64` target. In the basename stem before the first dot, a WW's fixed `linux/amd64` target. In the basename stem before the first dot, a
final `_test` token is ignored for platform matching. A final known OS or final `_test` token is ignored for platform matching. A final known OS or
@@ -286,10 +288,12 @@ ImportPath = ident { "." ident } .
initialization. Repeated blank occurrences and blank plus default/explicit initialization. Repeated blank occurrences and blank plus default/explicit
named occurrences of one path are valid; every named occurrence remains named occurrences of one path are valid; every named occurrence remains
independently subject to duplicate-binding and unused checks. independently subject to duplicate-binding and unused checks.
The package dependency graph is the sorted, deduplicated union of the real Each semantic action's package dependency graph is the sorted, deduplicated
imports in all eligible files. Occurrences retain their owning file and union of real imports in that action's eligible source set. Occurrences retain
position, but equal canonical targets create one graph edge/package action. their owning file and position, but equal canonical targets create one graph
Self-import is rejected. edge. Test-only occurrences never enter ordinary production. Self-import is
rejected, except that toolchain-owned external-test self wiring is rebound to
the effective augmented package action after ordinary per-site validation.
- An executable package is one declared `package main` and containing a - An executable package is one declared `package main` and containing a
`fn main`; path and directory spelling do not classify commands. An ordinary `fn main`; path and directory spelling do not classify commands. An ordinary
import of a package declared `main` is rejected, except for the toolchain's import of a package declared `main` is rejected, except for the toolchain's
@@ -606,13 +610,21 @@ the program. Two placements, following the Go `foo` / `foo_test` model:
``` ```
Production, production-plus-white-box-test, external black-box-test, test Production, production-plus-white-box-test, external black-box-test, test
support, and generated test main are distinct package actions. Before a test support, recompiled-for-test dependencies, and generated test main are distinct
function runs, the generated test product initializes its exact reachable package actions. One canonical selected directory owns one test product and one
variant graph dependency-first and once per canonical action. A white-box generated main, which imports every applicable same-package and external target
variant replaces the colocated production task rather than initializing both; and produces one binary/result. The external action's import of the package
an external variant depends on ordinary production. Imports, runtime lets, and under test binds to the augmented white-box action when it exists; affected
init declarations found only in `*_test.ww` never enter an ordinary production transitive importers are copied and rewired so ordinary and augmented package
build. state do not coexist in the linked closure.
Before a test function runs, the one generated product initializes its exact
effective graph dependency-first and once per canonical action. Imports,
runtime lets, and init declarations found only in `*_test.ww` never enter an
ordinary production build. Test-only same-package, external-package, and valid
mixed directories are accepted from their selected test files. A directory
with no selected test file validates ordinary production but creates no test
support, generated main, link, binary, result, or process.
--- ---

View File

@@ -193,8 +193,9 @@ and nonempty-version-constant assertions.
`ww test` delegates directory package requests to the native package `ww test` delegates directory package requests to the native package
coordinator. The coordinator owns request-pattern expansion, package grouping, coordinator. The coordinator owns request-pattern expansion, package grouping,
same-package and external-package variant selection, filtering, result same-package and external-package action selection, one canonical
aggregation, and its internal temporary workspace. Test sources are exclusively directory-owned product, filtering, result aggregation, and its internal
temporary workspace. Test sources are exclusively
`*_test.ww` (Go's `_test.go` contract): a line-leading `@test` declaration in `*_test.ww` (Go's `_test.go` contract): a line-leading `@test` declaration in
any other source is rejected loudly — by both driver stages at directory any other source is rejected loudly — by both driver stages at directory
enumeration and by the coordinator at source classification. A local spelling enumeration and by the coordinator at source classification. A local spelling
@@ -204,8 +205,11 @@ directory prefix before the first wildcard. Recursive children beginning `.`
or `_` and exact `testdata` subtrees are pruned; child directory symlinks are or `_` and exact `testdata` subtrees are pruned; child directory symlinks are
not followed. A wildcard cannot consume a non-terminal exact `vendor` element, not followed. A wildcard cannot consume a non-terminal exact `vendor` element,
while an explicitly vendor-rooted pattern remains legal. Every selected while an explicitly vendor-rooted pattern remains legal. Every selected
test-bearing directory becomes one package run, and selected source-bearing test-bearing directory becomes exactly one package run, binary, and result even
directories without tests report the usual `?` line. The coordinator first when both internal and external actions exist. Selected source-bearing
directories without selected test files report the usual `?` line after
ordinary production validation, with no support, generated main, link, binary,
result, or process. The coordinator first
launches one driver plan for the complete command-global package/action union. launches one driver plan for the complete command-global package/action union.
After that shared build completes, `-j N` schedules up to N successful selected After that shared build completes, `-j N` schedules up to N successful selected
test binaries concurrently under `os.exec` start/poll supervision (no threads); test binaries concurrently under `os.exec` start/poll supervision (no threads);
@@ -213,10 +217,11 @@ emission stays strictly in group order, so the byte stream is identical at
every `-j` level, and `-j 1` — the default — matches the former sequential every `-j` level, and `-j 1` — the default — matches the former sequential
run loop exactly. Measured on the 31-package `lib/...` walk: run loop exactly. Measured on the 31-package `lib/...` walk:
7.0s sequential, 2.4s at `-j 4`. With `-c`, it publishes each exact 7.0s sequential, 2.4s at `-j 4`. With `-c`, it publishes each exact
`<package>.test` binary in the package directory; the first output owns the one `<package>.test` directory binary; the first output owns the one
shared cold sepwork containing the command-global action universe. Those become shared cold sepwork containing the command-global action universe. Those become
caller-owned artifacts. `-c -o <name>` caller-owned artifacts. `-c -o <name>`
names that artifact instead of the fixed stem, for exactly one package: names that artifact instead of the fixed stem for exactly one directory,
including a combined internal/external directory:
the coordinator rejects a multi-package fan-out ("cannot use -o with the coordinator rejects a multi-package fan-out ("cannot use -o with
multiple packages", Go's `go test -o` rule), and `-o` without `-c` is multiple packages", Go's `go test -o` rule), and `-o` without `-c` is
rejected at the driver ("needs -c for a package target") because a plain rejected at the driver ("needs -c for a package target") because a plain
@@ -256,8 +261,10 @@ archive/action ownership, one canonical direct edge for repeated occurrences,
stage-equal diagnostics and binaries, and clean rejection state. stage-equal diagnostics and binaries, and clean rejection state.
The declared-name observer proves imports are file-scoped while dependency The declared-name observer proves imports are file-scoped while dependency
edges are the package-wide sorted union; command and edges are the package-wide sorted union; command and
production/internal/external/generated-main variants retain canonical action production/internal/external/directory-main actions retain canonical action
ownership; vendor expansion changes identity but not the effective qualifier; ownership while one canonical directory owns their product; external
self-imports bind the augmented internal action; vendor expansion changes
identity but not the effective qualifier;
compiler argv contains only direct `.wwi` inputs; and its named rejected compiler argv contains only direct `.wwi` inputs; and its named rejected
actions leave neither committed nor staged action artifacts or a published actions leave neither committed nor staged action artifacts or a published
binary. It also forces a request transaction to reject after dependency work binary. It also forces a request transaction to reject after dependency work
@@ -277,9 +284,15 @@ normalized compiler/assembler/linker argv, units, `.wwi`, assembly, objects,
archives, generated-main archives, binaries, runtime/test output, direct and archives, generated-main archives, binaries, runtime/test output, direct and
recursive behavior, reversed roots, ignored-edit reuse, selected private-change recursive behavior, reversed roots, ignored-edit reuse, selected private-change
propagation, and request rollback after a dependency has staged and the root propagation, and request rollback after a dependency has staged and the root
compiler fails. The existing bounded-memory package-initialization observer compiler fails. Wrong-target test files cannot add a target to the directory
continues to own allocation-failure parity for the shared dynamically grown main or create one for an otherwise no-test directory. The bounded-memory
action universe. package-initialization observer now pressures the combined directory topology
itself: production, augmented internal test, external self-import, a transitive
recompile-for-test clone, support, and the two-target generated main. Each stage
searches its own bounded address-space ceiling, while the accepted failure must
have the same `ww: out of memory` diagnostic, invoke no compiler, assembler, or
linker, and leave an empty caller work directory with no output, status, or
staging path.
`test/sep/sepinit_test.ww` is the single focused package-initialization owner. `test/sep/sepinit_test.ww` is the single focused package-initialization owner.
It generates all source trees temporarily and runs independent cold/persistent It generates all source trees temporarily and runs independent cold/persistent
@@ -287,15 +300,18 @@ Cstage and WWstage legs. Its matrix covers blank-only reachability; dependency,
diamond, and independent ready-task order; runtime call/allocation and aggregate diamond, and independent ready-task order; runtime call/allocation and aggregate
package lets; multiple init declarations and invalid forms; direct/qualified package lets; multiple init declarations and invalid forms; direct/qualified
init invisibility; initialization cycles and diagnostic order; command, init invisibility; initialization cycles and diagnostic order; command,
internal-test, external-test, support, and generated-main ownership; canonical internal-test, external-test, support, and one directory-generated-main
ownership; canonical
task and dispatcher symbols; deterministic one- and two-member archives; task and dispatcher symbols; deterministic one- and two-member archives;
`.wwi` exclusion; byte-identical artifacts/binaries; init-only invalidation; `.wwi` exclusion; byte-identical artifacts/binaries; init-only invalidation;
warm invalid-init rollback; direct/recursive variant equivalence; exact warm invalid-init rollback; direct/recursive variant equivalence; exact
production, support, and generated-main task ordering; complete normalized production, support, ptest-before-pxtest-before-main task ordering, exactly-once
package/dependency initialization in one dispatcher; complete normalized
rejection diagnostics; dangling staging/rollback no-follow rejection; and rejection diagnostics; dangling staging/rollback no-follow rejection; and
checked compiler-output failure/non-regular-destination rollback; and checked compiler-output failure/non-regular-destination rollback; and
bounded-memory allocation-failure parity under one shared ceiling supplied by bounded-memory Cstage/WWstage allocation-failure parity across the complete
the repository-built `sep-limitexec` helper. combined package-test graph, under independently discovered ceilings supplied
by the repository-built `sep-limitexec` helper.
`ww build`, an explicit single-file `ww test -o <stem>`, and each successful `ww build`, an explicit single-file `ww test -o <stem>`, and each successful
directory-package `ww test -c` build publish `<stem>.sepwork` as a caller-owned directory-package `ww test -c` build publish `<stem>.sepwork` as a caller-owned
@@ -330,9 +346,11 @@ create false reuse or a mixed generation; a successful executable link still
reruns when required. One workdir serves one invocation at a time and may hold reruns when required. One workdir serves one invocation at a time and may hold
the complete command-global action universe for all selected roots and isolated the complete command-global action universe for all selected roots and isolated
variants; semantic identity, rather than request shape, controls reuse. Both variants; semantic identity, rather than request shape, controls reuse. Both
driver stages implement the identical contract. This is build staleness in the driver stages implement the identical contract. Test-mode persistent workdirs
use format 19. This is build staleness in the
Make/mk/Go sense, not a result cache: Make/mk/Go sense, not a result cache:
tests always run, and the byte-identity and bootstrap gates keep building on real directory test products always run, while no-selected-test directories do
not create a process. The byte-identity and bootstrap gates keep building on
fresh scratch. `make clean` reclaims every workdir under `out/`. fresh scratch. `make clean` reclaims every workdir under `out/`.
On a package or tree target, `ww build/test -w DIR` forwards that exact caller On a package or tree target, `ww build/test -w DIR` forwards that exact caller

View File

@@ -3,7 +3,7 @@ package pass_test;
import test; import test;
@test fn alpha_pass() void = { @test fn alpha_pass() void = {
assert(test.current() == "pass_test.alpha_pass"); assert(test.current() == "pass.alpha_pass");
}; };
@test fn beta_skip() void = { @test fn beta_skip() void = {

File diff suppressed because it is too large Load Diff

View File

@@ -736,7 +736,11 @@ fn rejectrow(td: str, label: str, src: str, expected: str) void = {
let td: str = testenv.fresh(); let td: str = testenv.fresh();
let tree: str = strings.concat(td, "/tree"); let tree: str = strings.concat(td, "/tree");
assert(os.mkdir(tree, 493) == 0); assert(os.mkdir(tree, 493) == 0);
let body: str = "package main;\n"; let target: str = strings.concat(tree, "/target");
let bridge: str = strings.concat(tree, "/bridge");
assert(os.mkdir(target, 493) == 0);
assert(os.mkdir(bridge, 493) == 0);
let body: str = "package target;\n";
let i: i32 = 0; let i: i32 = 0;
for (i < 600) { for (i < 600) {
let name: str = allocpkgname(i); let name: str = allocpkgname(i);
@@ -747,63 +751,98 @@ fn rejectrow(td: str, label: str, src: str, expected: str) void = {
body = strings.concat(body, "import _ ", name, ";\n"); body = strings.concat(body, "import _ ", name, ";\n");
i += 1; i += 1;
}; };
body = strings.concat(body, "fn main() i32 = { return 0; };\n"); body = strings.concat(body,
let src: str = strings.concat(td, "/main.ww"); "export fn value() i32 = { return 41; };\n");
testenv.writefile(src, body); testenv.writefile(strings.concat(target, "/target.ww"), body);
let wrapper: str = strings.concat(td, "/w6c-trace.sh"); testenv.writefile(strings.concat(target, "/same_test.ww"), strings.concat(
"package target;\n",
"export fn internal_helper() i32 = { return value(); };\n",
"@test fn internal_runs() void = { assert(value() == 41); };\n"));
testenv.writefile(strings.concat(bridge, "/bridge.ww"), strings.concat(
"package bridge;\nimport target;\n",
"export fn helper() i32 = { return target.internal_helper(); };\n"));
testenv.writefile(strings.concat(target, "/external_test.ww"),
strings.concat("package target_test;\nimport bridge;\nimport target;\n",
"@test fn external_runs() void = {\n",
" assert(target.internal_helper() == 41);\n",
" assert(bridge.helper() == 41);\n};\n"));
let wrapper: str = strings.concat(td, "/tool-trace.sh");
testenv.writeexecutable(wrapper, strings.concat("#!/bin/sh\n", testenv.writeexecutable(wrapper, strings.concat("#!/bin/sh\n",
"printf x >> \"$WW_SEPINIT_W6C_TRACE\"\nexit 99\n")); "printf x >> \"$WW_SEPINIT_TOOL_TRACE\"\nexit 99\n"));
let stages: []str = ["ww", "ww_ww"]; let stages: []str = ["ww", "ww_ww"];
let compilers: []str = ["w6c", "w6c_ww"];
let launcher: str = testenv.driver("sep-limitexec"); let launcher: str = testenv.driver("sep-limitexec");
let found: bool = false; let accepted: [2]str;
let last: str = ""; let stagei: i32 = 0;
let limit: i64 = 2621440i64; // Address-space layouts differ, so each implementation searches its own
let li: i32 = 0; // bounded ceiling. The accepted point must fail while constructing the
// Both implementations must reject under the same address-space ceiling. // combined p/ptest/pxtest/pmain and transitive-clone graph, before any tool.
// Search a bounded same-limit ladder because loader mappings differ across for (stagei < stages.len) {
// supported hosts; the 600-action graph makes the driver-allocation window let found: bool = false;
// broad, while the compiler trace pins failure before the first tool. let last: str = "";
for (limit <= 16777216i64 && !found) { let limit: i64 = 2621440i64;
let limitstr: str = strconv.i64tos(limit, strconv.base.DEC); let li: i32 = 0;
let good: [2]bool; for (limit <= 33554432i64 && !found) {
let diags: [2]str;
i = 0;
for (i < stages.len) {
let tag: str = allocpkgname(li); let tag: str = allocpkgname(li);
let trace: str = strings.concat(td, "/alloc-", stages[i], "-", let trace: str = strings.concat(td, "/alloc-", stages[stagei], "-",
tag, ".trace"); tag, ".trace");
let work: str = strings.concat(td, "/alloc-work-", stages[stagei],
"-", tag);
let output: str = strings.concat(td, "/alloc-output-",
stages[stagei], "-", tag);
let status: str = strings.concat(td, "/alloc-status-",
stages[stagei], "-", tag);
testenv.writefile(trace, ""); testenv.writefile(trace, "");
let env: []str = compilertraceenv(wrapper, assert(os.mkdir(work, 493) == 0);
testenv.driver(compilers[i]), trace); let base: []str = os.getenvs();
let output: str = strings.concat(td, "/alloc-", stages[i], "-", let env: []str = alloc([], (base.len + 4): u64)!;
tag); i = 0;
let av: []str = [launcher, limitstr, testenv.driver(stages[i]), for (i < base.len) {
"build", "-I", tree, "-o", output, src]; if (!strings.hasprefix(base[i], "WW_W6C=")
&& !strings.hasprefix(base[i], "WW_W6A=")
&& !strings.hasprefix(base[i], "WW_W6L=")
&& !strings.hasprefix(base[i],
"WW_SEPINIT_TOOL_TRACE=")) {
append(env, base[i]);
};
i += 1;
};
append(env, strings.concat("WW_W6C=", wrapper));
append(env, strings.concat("WW_W6A=", wrapper));
append(env, strings.concat("WW_W6L=", wrapper));
append(env, strings.concat("WW_SEPINIT_TOOL_TRACE=", trace));
let limitstr: str = strconv.i64tos(limit, strconv.base.DEC);
let av: []str = [launcher, limitstr, testenv.driver(stages[stagei]),
"test", "-c", "-w", work, "-I", tree,
"--ww-package-test", "test", "target", "target", "target",
"target_test", target, output, status, target];
let out: testenv.commandout; let out: testenv.commandout;
runenv(td, strings.concat("allocation-", stages[i], "-", tag), runenv(td, strings.concat("allocation-", stages[stagei], "-", tag),
av, env, &out); av, env, &out);
last = strings.dup(out.stderr); last = strings.dup(out.stderr);
good[i] = exitcode(&out) == 1 && testenv.same(out.stderr, if (testenv.listdir(work).len != 0
"ww: out of memory\n") || nofollowexists(output)
&& testenv.readfile(trace).len == 0; || nofollowexists(strings.concat(output, ".new"))
diags[i] = strings.dup(out.stderr); || nofollowexists(strings.concat(output, ".sepwork"))
if (testenv.exists(output) || testenv.exists(strings.concat(output, || nofollowexists(status)
".sepwork"))) { || nofollowexists(strings.concat(status, ".new"))) {
fail("allocation", "failed pressure leg published state"); fail("allocation", "failed pressure leg published state");
}; };
i += 1; if (exitcode(&out) == 1 && out.stdout.len == 0
}; && testenv.same(out.stderr, "ww: out of memory\n")
if (good[0] && good[1]) { && testenv.readfile(trace).len == 0) {
if (!testenv.same(diags[0], diags[1])) { accepted[stagei] = strings.dup(out.stderr);
fail("allocation", "C/WW allocation diagnostic mismatch"); found = true;
}; };
found = true; testenv.clean(work);
limit += 131072i64;
li += 1;
}; };
limit += 131072i64; if (!found) { fail("allocation", last); };
li += 1; stagei += 1;
};
if (!testenv.same(accepted[0], accepted[1])) {
fail("allocation", "C/WW allocation diagnostic mismatch");
}; };
if (!found) { fail("allocation", last); };
testenv.clean(td); testenv.clean(td);
}; };
@@ -932,16 +971,12 @@ fn rejectrow(td: str, label: str, src: str, expected: str) void = {
let tags: []str = ["c", "ww"]; let tags: []str = ["c", "ww"];
let reference: str = ""; let reference: str = "";
let variantnames: []str = [ let variantnames: []str = [
"widget-internal-test-main.init.unit.ww", "widget-test-main.init.unit.ww",
"widget-internal-test-main.init.s", "widget-test-main.init.s",
"widget-internal-test-main.init.o", "widget-test-main.init.o",
"widget-internal-test-main.a", "widget-test-main.a",
"widget_test-external-test-main.init.unit.ww",
"widget_test-external-test-main.init.s",
"widget_test-external-test-main.init.o",
"widget_test-external-test-main.a",
]; ];
let variantrefs: []str = ["", "", "", "", "", "", "", ""]; let variantrefs: []str = ["", "", "", ""];
let i: i32 = 0; let i: i32 = 0;
for (i < 2) { for (i < 2) {
let work: str = strings.concat(td, "/test-work-", tags[i]); let work: str = strings.concat(td, "/test-work-", tags[i]);
@@ -967,61 +1002,45 @@ fn rejectrow(td: str, label: str, src: str, expected: str) void = {
let rr: i32 = testenv.pos(out.stdout, "<R>"); let rr: i32 = testenv.pos(out.stdout, "<R>");
let ii: i32 = testenv.pos(out.stdout, "<I>"); let ii: i32 = testenv.pos(out.stdout, "<I>");
let tt: i32 = testenv.pos(out.stdout, "<T>"); let tt: i32 = testenv.pos(out.stdout, "<T>");
let tail: str = ""; let w: i32 = testenv.pos(out.stdout, "<W>");
if (tt >= 0) { tail = strings.sub(out.stdout, tt + 3, out.stdout.len); }; let e: i32 = testenv.pos(out.stdout, "<E>");
let de: i32 = testenv.pos(tail, "<D>"); let x: i32 = testenv.pos(out.stdout, "<X>");
let pe: i32 = testenv.pos(tail, "<P>"); if (!(d >= 0 && d < q && q < rr && rr < p && p < ii && ii < w
let w: i32 = testenv.pos(tail, "<W>"); && w < e && e < tt && tt < x)) {
let e: i32 = testenv.pos(tail, "<E>");
let x: i32 = testenv.pos(tail, "<X>");
if (!(d >= 0 && d < q && q < rr && rr < p && p < ii && ii < tt
&& de >= 0 && de < pe && pe < w && w < e && e < x)) {
fail("variants", strings.concat("test init order: ", out.stdout)); fail("variants", strings.concat("test init order: ", out.stdout));
}; };
if (testenv.occurrences(out.stdout, "<Q>") != 1 if (testenv.occurrences(out.stdout, "<Q>") != 1
|| testenv.occurrences(out.stdout, "<D>") != 2 || testenv.occurrences(out.stdout, "<D>") != 1
|| testenv.occurrences(out.stdout, "<R>") != 1 || testenv.occurrences(out.stdout, "<R>") != 1
|| testenv.occurrences(out.stdout, "<W>") != 1 || testenv.occurrences(out.stdout, "<W>") != 1
|| testenv.occurrences(out.stdout, "<I>") != 1 || testenv.occurrences(out.stdout, "<I>") != 1
|| testenv.occurrences(out.stdout, "<E>") != 1 || testenv.occurrences(out.stdout, "<E>") != 1
|| testenv.occurrences(out.stdout, "<P>") != 2) { || testenv.occurrences(out.stdout, "<P>") != 1) {
fail("variants", "variant initialization count"); fail("variants", "variant initialization count");
}; };
let internal: str = testenv.readfile(strings.concat(work, let dispatcher: str = testenv.readfile(strings.concat(work,
"/widget-internal-test-main.init.unit.ww")); "/widget-test-main.init.unit.ww"));
if (testenv.occurrences(internal, if (testenv.occurrences(dispatcher,
"__ww..pkg.p.testside.v0.r0.init") != 1 "__ww..pkg.p.testside.v0.r0.init") != 1
|| testenv.occurrences(internal, || testenv.occurrences(dispatcher,
"__ww..pkg.p.prodside.v0.r0.init") != 1 "__ww..pkg.p.prodside.v0.r0.init") != 1
|| testenv.occurrences(internal, || testenv.occurrences(dispatcher,
"__ww..pkg.p.widget.v1.r0.init") != 1 "__ww..pkg.p.widget.v1.r0.init") != 1
|| testenv.occurrences(internal, || testenv.occurrences(dispatcher,
"__ww..pkg.p.test.v0.r0.init") != 1
|| testenv.occurrences(internal,
"//ww:init-call __ww..pkg.p.__wwtestmain.widget.internal.main.v3.r2.init") != 1
|| testenv.pos(internal, "__ww..pkg.p.test.v0.r0.init")
>= testenv.pos(internal,
"//ww:init-call __ww..pkg.p.__wwtestmain.widget.internal.main.v3.r2.init")
|| testenv.has(internal, "__ww..pkg.p.widget.v0.r0.init")) {
fail("variants", "internal variant dispatcher ownership");
};
let external: str = testenv.readfile(strings.concat(work,
"/widget_test-external-test-main.init.unit.ww"));
if (testenv.occurrences(external,
"__ww..pkg.p.widget.v0.r0.init") != 1
|| testenv.occurrences(external,
"__ww..pkg.p.prodside.v0.r0.init") != 1
|| testenv.occurrences(external,
"__ww..pkg.p.widget_test.v2.r0.init") != 1 "__ww..pkg.p.widget_test.v2.r0.init") != 1
|| testenv.occurrences(external, || testenv.occurrences(dispatcher,
"__ww..pkg.p.test.v0.r0.init") != 1 "__ww..pkg.p.test.v0.r0.init") != 1
|| testenv.occurrences(external, || testenv.occurrences(dispatcher,
"//ww:init-call __ww..pkg.p.__wwtestmain.widget_test.external.main.v3.r2.init") != 1 "//ww:init-call __ww..pkg.p.__wwtestmain.widget.main.v3.r2.init") != 1
|| testenv.pos(external, "__ww..pkg.p.test.v0.r0.init") || testenv.pos(dispatcher, "__ww..pkg.p.widget.v1.r0.init")
>= testenv.pos(external, >= testenv.pos(dispatcher,
"//ww:init-call __ww..pkg.p.__wwtestmain.widget_test.external.main.v3.r2.init") "__ww..pkg.p.widget_test.v2.r0.init")
|| testenv.has(external, "testside")) { || testenv.pos(dispatcher,
fail("variants", "external variant dispatcher ownership"); "__ww..pkg.p.widget_test.v2.r0.init")
>= testenv.pos(dispatcher,
"//ww:init-call __ww..pkg.p.__wwtestmain.widget.main.v3.r2.init")
|| testenv.has(dispatcher, "__ww..pkg.p.widget.v0.r0.init")) {
fail("variants", "directory test dispatcher ownership");
}; };
let directstdout: str = strings.dup(out.stdout); let directstdout: str = strings.dup(out.stdout);
let recursivework: str = strings.concat(td, "/test-recursive-work-", let recursivework: str = strings.concat(td, "/test-recursive-work-",
@@ -1100,7 +1119,7 @@ fn rejectrow(td: str, label: str, src: str, expected: str) void = {
av, env, tmo(), &out); av, env, tmo(), &out);
if (exitcode(&out) == 0 if (exitcode(&out) == 0
|| !testenv.has(out.stderr, || !testenv.has(out.stderr,
"ww: dependency cycle in initialization closure") "ww: dependency cycle: p -> q -> r -> p")
|| testenv.readfile(trace).len != 0 || testenv.readfile(trace).len != 0
|| testenv.listdir(work).len != 0) { || testenv.listdir(work).len != 0) {
fail("test-cycle", out.stderr); fail("test-cycle", out.stderr);