driver: implement post-target run argv semantics
This commit is contained in:
@@ -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 312–322](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/main.go#L312-L322)).
|
||||
The standard flag parser stops at the first non-flag positional; it consumes
|
||||
`--` only when that spelling occurs before the positional boundary
|
||||
([`flag/flag.go`, lines 1074–1089 and 1149–1176](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/flag/flag.go#L1074-L1089)).
|
||||
- **behavior directly implemented or asserted by pinned Go** — `runRun`
|
||||
consumes either the contiguous named-file prefix or one selected package,
|
||||
leaves the suffix as `cmdArgs`, and attaches those exact arguments to the run
|
||||
action
|
||||
([`cmd/go/internal/run/run.go`, lines 96–140 and 170–173](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/run/run.go#L96-L140)).
|
||||
- **behavior directly implemented or asserted by pinned Go** — official
|
||||
regression test
|
||||
[`cmd/go/testdata/script/mod_run_flags_issue64738.txt`, lines 1–4](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/mod_run_flags_issue64738.txt#L1-L4)
|
||||
asserts that `-p ignored` after a requested package is program input, not a
|
||||
`cmd/go` flag. Official
|
||||
[`cmd/go/testdata/script/run_dirs.txt`, lines 1–20](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/testdata/script/run_dirs.txt#L1-L20)
|
||||
separately anchors Go's contiguous multi-file prefix; that source-set rule
|
||||
remains open in WW.
|
||||
- **behavior directly implemented or asserted by pinned Go** — Go deliberately
|
||||
does not preserve the compiled program's exact nonzero exit status
|
||||
([`cmd/go/internal/run/run.go`, lines 56 and 198–210](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/run/run.go#L198-L210));
|
||||
command error accounting owns the resulting Go-command status
|
||||
([`cmd/go/internal/base/base.go`, lines 218–246](https://github.com/golang/go/blob/c19862e5f8415b4f24b189d065ed739517c548ba/src/cmd/go/internal/base/base.go#L218-L246)).
|
||||
That independent exit-status difference is not credited to this slice.
|
||||
- **behavior derived from the pinned implementation** — WW's one explicit
|
||||
local run target supplies the same honest semantic boundary without modules,
|
||||
manifests, registries, network resolution, generalized imports, or source
|
||||
build expressions. WW's implicit default-current-directory extension has no
|
||||
explicit target token, so this slice leaves its leading option parsing
|
||||
unchanged. A leading or pre-target `--` therefore retains WW's existing
|
||||
exact unknown-flag rejection and is not claimed as Go `FlagSet` terminator
|
||||
parity.
|
||||
|
||||
Before this slice, **directly measured WW behavior** was identical in Cstage
|
||||
and WWstage but differed from the pinned boundary. Immediately target-following
|
||||
`-p ignored` and `-- -p ignored` returned status 2, empty stdout, and exact
|
||||
stderr `ww run: unknown flag\n`; `-o sentinel` and `-I path` were consumed by
|
||||
the driver; and only a suffix after a second nonflag was passed unchanged.
|
||||
Named-source and directory-package probes agreed on status, stdout, stderr,
|
||||
and diagnostic order. Accepted runs loaded one target and its ordinary import
|
||||
closure, constructed the private run action, compiled, assembled, archived,
|
||||
linked, executed, propagated WW's established child status, and removed the
|
||||
private executable and `.sepwork`. Rejected flag rows stopped before target
|
||||
resolution, graph/action construction, tools, runtime, or scratch creation.
|
||||
|
||||
#### Ownership, source selection, and the four permanent axes
|
||||
|
||||
- **directly measured WW behavior** — Cstage owns the boundary in
|
||||
`parse_build_flags` and its `do_run` consumer; WWstage owns the semantic twin
|
||||
in its `dorun` parser and executor. No loader, package coordinator, compiler,
|
||||
assembler, archiver, linker, test coordinator, checker, import binder, or
|
||||
runtime library can repair a driver option that was already consumed.
|
||||
- **behavior derived from the pinned implementation** — the primary axis is
|
||||
build/run execution semantics. Driver options are recognized before the
|
||||
first explicit target. That target alone controls resolution; the complete
|
||||
later suffix controls only child invocation.
|
||||
- **behavior derived from the pinned implementation** — the test axis is an
|
||||
explicit non-effect. `ww test` option parsing, target discovery, filters,
|
||||
source variants, generated harness, retained products, execution topology,
|
||||
and result accounting do not use this run boundary.
|
||||
- **behavior derived from the pinned implementation** — the package axis is an
|
||||
explicit non-effect. The suffix is never searched, statted, opened, or
|
||||
classified as source. Declared-name validation, source membership, command
|
||||
classification, initializer topology, and canonical package identity remain
|
||||
those of the one selected target.
|
||||
- **behavior derived from the pinned implementation** — the import axis is an
|
||||
explicit non-effect. Dotted spelling, aliases, local/vendor search, binding,
|
||||
visibility, cycles, graph edges, interface ownership, and initialization
|
||||
order are determined only by the selected source closure. Runtime argv is
|
||||
never package, import, graph, action, symbol, artifact, `.wwi`, publication,
|
||||
or persistence identity.
|
||||
|
||||
Direct roots retain `__root.*`; dotted directories retain dotted package,
|
||||
import, action, symbol, artifact, and semantic identities. Physical target
|
||||
spellings and paths remain loader or presentation observations. Post-target
|
||||
arguments add no root, edge, action, source, or invalidation input and cannot
|
||||
change compilation or comparable artifact bytes.
|
||||
|
||||
#### Phase order, diagnostics, and lifecycle
|
||||
|
||||
- **behavior derived from the pinned implementation** — target resolution,
|
||||
loading, import closure, graph construction, compilation, assembly,
|
||||
in-process archiving, and linking retain their existing order and inputs.
|
||||
After a successful private link, the child vector is the private executable
|
||||
at index 0 followed by the exact post-target suffix. The suffix reaches no
|
||||
earlier phase.
|
||||
- **directly measured WW behavior** — `os.args()` exposes that complete vector,
|
||||
including the PID-bearing private executable path at index 0. WW currently
|
||||
propagates an ordinary child's exact exit code. The argument repair changes
|
||||
only indices 1 onward; PID presentation and exact child-status propagation
|
||||
are preserved, including their independent difference from pinned Go.
|
||||
- **behavior derived from the pinned implementation** — known, unknown,
|
||||
incomplete, or `--` option spellings before the target retain their existing
|
||||
driver diagnostics and status. No spelling after the target can emit a
|
||||
driver-option diagnostic. Missing, invalid, non-main, or producer-failing
|
||||
targets diagnose before runtime; a valid target starts and thereafter owns
|
||||
output and failure caused by its arguments.
|
||||
- **behavior derived from the pinned implementation** — run products remain
|
||||
request-private. No public executable, retained test product, semantic fact,
|
||||
work record, transaction, result, or cache entry is published. Post-target
|
||||
argv enters no unit, interface, assembly, object, archive, initializer,
|
||||
executable, stamp, or persistence byte and creates no reuse or invalidation
|
||||
key. Ordinary build and every test route are byte-for-byte non-effects.
|
||||
- **behavior derived from the pinned implementation** — target or producer
|
||||
failure starts no program and follows ordinary rollback. Runtime nonzero
|
||||
follows the established WW status mapping after successful private linking.
|
||||
Existing unrelated public and committed semantic bytes remain untouched.
|
||||
Normal success, producer failure, runtime failure, and concurrent runs remove
|
||||
each request's owned private executable, `.sepwork`, stage, transaction,
|
||||
capture, result, request, descriptor, and child. Parser state and argv are
|
||||
invocation-local, so overlapping suffixes cannot cross between requests.
|
||||
- **behavior derived from the pinned implementation** — Cstage and WWstage
|
||||
must select the same boundary and retain exact status, stdout, stderr,
|
||||
diagnostic order, runtime argv, normal cleanup, and comparable build-artifact
|
||||
byte identity. The existing PID-bearing private path difference outside
|
||||
stable comparisons is not reclassified by this slice.
|
||||
|
||||
The WW-native observer `run_post_target_arguments_are_program_argv` covers both
|
||||
driver stages with literal named-source and directory-package targets. It
|
||||
checks known separate and joined option spellings, unknown options, would-be
|
||||
values, singleton value-taking spellings, `--`, later nonflags and `.ww`, an
|
||||
empty string, pre-target controls, no-operand default-dot selection, diagnostic
|
||||
precedence, exact child status and output, concurrent isolation, build/test
|
||||
controls, artifact-byte parity, and normal residue cleanup.
|
||||
|
||||
No signal or process-supervision owner changes. Direct external SIGTERM during
|
||||
blocked persistent compilation still can leave the owned compiler alive and
|
||||
exactly three fixed `.new` stages, poisoning the next request while preserving
|
||||
prior public and committed semantic bytes. That verified interruption gap
|
||||
remains open; blind stage deletion is not this argument-boundary repair.
|
||||
|
||||
No serialized representation changes. Build workdir format remains `18`, test
|
||||
workdir format remains `19`, and semantic storage format remains `3`; AST and
|
||||
`.wwi` schemas, action descriptors, request protocols, transaction markers,
|
||||
and stored facts are unchanged. This closes only the post-target argv slice.
|
||||
Regular or missing `_test.ww`, missing `.ww`, hidden named sources, multiple
|
||||
leading sources and their source-set boundary, shared test-package state,
|
||||
panic/exit/Fatal/FailNow topology, RE2-compatible flat `-run`, literal
|
||||
nonregular named-source behavior, three-way no-buildable-source diagnostics,
|
||||
Go-like run exit-status mapping, and external-driver interruption recovery
|
||||
remain open where applicable.
|
||||
|
||||
## 12. Candidate architectures and hard-gate decision
|
||||
|
||||
Five candidates were developed as coherent systems, not as feature bins.
|
||||
|
||||
26
docs/spec.md
26
docs/spec.md
@@ -703,6 +703,32 @@ ImportPath = ident { "." ident } .
|
||||
arguments and result; this rule does not adopt Go's source signature. An
|
||||
ordinary import of a package declared `main` is rejected, except for the
|
||||
toolchain's colocated external-test wiring.
|
||||
- For `ww run`, the first explicit non-option operand selects the one run
|
||||
target. Every later operand is program input and is passed unchanged and in
|
||||
order after the private executable's `argv[0]`; it is not reparsed as a
|
||||
driver option. This includes known or unknown option spellings, would-be
|
||||
option values, a lone `--`, empty arguments, ordinary nonflags, and later
|
||||
`.ww` spellings. A later `.ww` is therefore argv, not another source in a
|
||||
command-line package; multiple named sources remain unsupported. Registered
|
||||
driver options before the target retain their established spelling, value,
|
||||
repetition, and diagnostic rules. A leading or otherwise pre-target `--`
|
||||
retains WW's exact unknown-flag rejection rather than acting as a general
|
||||
terminator. With no explicit target, `ww run` retains its implicit current-
|
||||
directory selection and has no post-target suffix.
|
||||
Only the selected target and pre-target driver options affect resolution,
|
||||
source loading, package/import identity, graph construction, compiler,
|
||||
assembler, archiver, linker, private executable bytes, reuse, or
|
||||
invalidation. A missing, invalid, non-main, or producer-failing target
|
||||
diagnoses before runtime and no suffix spelling can mask that result. A
|
||||
successful private link executes with the exact suffix and retains WW's
|
||||
existing stdout, stderr, and exact child-status propagation. The private run
|
||||
product is removed normally and publishes no executable or persistent
|
||||
semantic state. `ww build`, every `ww test` route, package membership, and
|
||||
dotted import semantics are unchanged. Direct roots remain `__root.*`,
|
||||
dotted directories retain dotted identity, and argv never becomes package,
|
||||
import, action, symbol, artifact, `.wwi`, publication, or persistence
|
||||
identity. Build workdir format remains 18, test workdir format remains 19,
|
||||
and semantic storage format remains 3.
|
||||
- For `ww build`, the output-option name is exactly `o`. The accepted forms are
|
||||
`-o VALUE`, `--o VALUE`, `-o=VALUE`, and `--o=VALUE`. An equals form splits
|
||||
at its first `=` and preserves every later byte, including further `=`
|
||||
|
||||
@@ -479,6 +479,82 @@ supervision is unchanged: the known orphan compiler, fixed `.new` staging, and
|
||||
later persistent-request poisoning remain open and are not credited to this
|
||||
slice.
|
||||
|
||||
The run front has one separate post-target argument contract. The sole
|
||||
authority is official Go 1.26.5 at commit
|
||||
`c19862e5f8415b4f24b189d065ed739517c548ba`:
|
||||
|
||||
- **behavior directly implemented or asserted by pinned Go** — command flag
|
||||
parsing supplies only its positional suffix to `runRun`
|
||||
(`cmd/go/main.go:312–322`; `flag/flag.go:1074–1089,1149–1176`), and
|
||||
`runRun` consumes the named-file prefix or one package before attaching the
|
||||
untouched suffix to the run action
|
||||
(`cmd/go/internal/run/run.go:96–140,170–173`).
|
||||
- **behavior directly implemented or asserted by pinned Go** — official
|
||||
`cmd/go/testdata/script/mod_run_flags_issue64738.txt:1–4` proves that
|
||||
target-following `-p ignored` is program input rather than a Go-command
|
||||
option. `cmd/go/testdata/script/run_dirs.txt:1–20` anchors the independent
|
||||
contiguous named-file prefix, which WW does not claim here.
|
||||
- **behavior derived from the pinned implementation** — after WW's one
|
||||
explicit local run target, every remaining operand is runtime argv. The
|
||||
rule honestly applies without importing Go modules or manifests. WW's
|
||||
default-dot extension has no explicit target boundary, and leading or
|
||||
pre-target `--` remains its existing unknown flag rather than gaining
|
||||
general Go flag-terminator semantics.
|
||||
|
||||
Before the repair, **directly measured WW behavior** was stage-equal but
|
||||
different: both drivers rejected immediately target-following `-p ignored` and
|
||||
`-- -p ignored` at status 2 with empty stdout and exact unknown-flag stderr,
|
||||
consumed target-following `-o` and `-I` values as driver configuration, and
|
||||
passed the ordered suffix only after a second nonflag. Accepted controls loaded
|
||||
one target and its ordinary import closure and completed the private compiler,
|
||||
assembler, archiver, linker, and runtime route; rejected rows stopped before
|
||||
loading, actions, tools, runtime, or scratch.
|
||||
|
||||
The focused `run_post_target_arguments_are_program_argv` observer owns the
|
||||
completed boundary in `test/package/package_test.ww`. Across Cstage and WWstage
|
||||
it uses both a literal named source and a directory package and requires exact
|
||||
ordered delivery for separate and joined known-option spellings, unknown
|
||||
options, would-be values, a singleton value-taking spelling, `--`, later
|
||||
nonflags and `.ww`, and an empty string. It separately requires pre-target
|
||||
options and their missing/unknown diagnostics to remain driver-owned, leading
|
||||
`--` to keep its current rejection, no-operand run to keep default-dot
|
||||
selection, and target load/producer diagnostics to precede inert suffix bytes.
|
||||
Valid programs expose the private executable at `os.args()[0]`, receive the
|
||||
exact suffix at indices 1 onward, and retain WW's existing stdout, stderr, and
|
||||
exact child-status mapping. Pinned Go's distinct command-level nonzero status
|
||||
mapping (`cmd/go/internal/run/run.go:56,198–210` and
|
||||
`cmd/go/internal/base/base.go:218–246`) remains an open difference.
|
||||
|
||||
The observer also treats all four permanent axes as one contract. The build/run
|
||||
axis changes only the parser-to-child boundary. Build and test controls retain
|
||||
their status, streams, action inputs, and comparable artifact bytes. Package
|
||||
membership and command classification still come only from the selected
|
||||
target, while dotted-import resolution, edges, interfaces, visibility, and
|
||||
initialization still come only from that target's closure. Direct actions
|
||||
remain `__root.*`; dotted directories retain dotted identity; argv creates no
|
||||
package, import, graph, action, symbol, artifact, `.wwi`, publication,
|
||||
persistence, reuse, or invalidation identity.
|
||||
|
||||
Post-target bytes therefore cannot change compiler, assembler, archiver,
|
||||
linker, initializer, or private executable bytes. Run publishes no public
|
||||
product or semantic state. Normal success, target/producer failure, runtime
|
||||
nonzero, and overlapping requests must keep suffixes isolated and remove each
|
||||
owned private executable, `.sepwork`, stage, transaction, capture, result,
|
||||
request, descriptor, and child. Cstage and WWstage must agree on stable status,
|
||||
stdout, stderr, diagnostic order, runtime argv, cleanup, and comparable
|
||||
artifact bytes. No AST, interface, descriptor, request, transaction, or
|
||||
persistent schema changes; build workdir format remains 18, test workdir format
|
||||
remains 19, semantic storage format remains 3, and no test-result cache is
|
||||
introduced.
|
||||
|
||||
The observer makes no claim for regular or missing `_test.ww`, missing `.ww`,
|
||||
hidden named sources, multiple leading source operands and source-set
|
||||
boundaries, literal nonregular named sources, shared test-package state,
|
||||
panic/exit/Fatal/FailNow topology, Go-compatible RE2 `-run`, three-way
|
||||
no-buildable-source causes, or Go-like run exit-status mapping. External-driver
|
||||
SIGTERM supervision is also unchanged: the verified orphan compiler, three
|
||||
fixed `.new` stages, and later persistent-request poisoning remain open.
|
||||
|
||||
An existing local directory whose requested build basename ends `.ww`
|
||||
(including a visible `_test.ww` symlink to a directory) remains a directory
|
||||
package, not a raw named test source. WWstage `ww build` now uses the same
|
||||
|
||||
Reference in New Issue
Block a user