driver: implement post-target run argv semantics

This commit is contained in:
2026-08-23 17:33:31 +09:00
parent 0b24b11d65
commit 29122f2a48
6 changed files with 579 additions and 17 deletions

View File

@@ -2300,7 +2300,7 @@ The default workflow is deliberately short:
```sh
ww init example.org/hello
ww build
ww run -- argument
ww run . argument
ww test .
```
@@ -2313,8 +2313,9 @@ 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`; arguments after `--` are never
interpreted by the build.
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
@@ -11168,6 +11169,165 @@ 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 312322](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 10741089 and 11491176](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 96140 and 170173](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 14](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 120](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 198210](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 218246](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.