run: reject .ww directories as named sources

This commit is contained in:
2026-08-23 01:07:07 +09:00
parent ca0e533c13
commit 59fc76964c
6 changed files with 612 additions and 20 deletions

View File

@@ -10376,6 +10376,141 @@ test/run command boundaries. No serialized representation changes: build
workdir format remains `18`, test workdir format remains `19`, semantic storage
format remains `3`, and no cache or result record is added.
### 11.53 Implemented `.ww`-spelled directory run rejection
An existing target selected by `ww run` whose exact requested spelling ends
`.ww` is a named-source request when ordinary symlink-following `stat` reports
a directory. Run rejects that directory before package resolution or private
work creation. This is deliberately different from section 11.52's build/test
directory route: the command-specific front door, not the shared resolver,
owns the distinction.
#### Pinned authority and applicability
- **behavior directly implemented or asserted by pinned Go** — official Go
1.26.5 commit `c19862e5f8415b4f24b189d065ed739517c548ba`
scans leading `.go` operands at
`cmd/go/internal/run/run.go:73112`, rejecting an `_test.go` spelling at
103109 before passing the named set to `GoFilesPackage`.
`cmd/go/internal/load/pkg.go:32443289`, especially 32743281, follows
`Stat` and fatals when a named operand is a directory. Later checking,
action construction, linking, and execution at `run.go:141173` are not
reached.
- **behavior directly implemented or asserted by pinned Go** — the exact Go
status, header-free diagnostic, and terminating newline follow
`cmd/go/internal/base/base.go:137145,175183`,
`cmd/go/main.go:98100`, and `log/log.go:200245`. Official
`cmd/go/testdata/script/run_hello.txt:110`, `run_dirs.txt:120`, and
`run_set_executable_name.txt:417` anchor the named-file run front and its
distinction from package-form run. Indirect official directory-kind anchors
are `list_ambiguous_path.txt:415,2936`,
`mod_get_go_file.txt:4758`, and `mod_symlink_dotgo.txt:49`. No official
end-to-end `go run` test asserts this directory diagnostic; the result is
implemented directly by the cited source.
- **behavior derived from the pinned implementation** — WW's `.ww`
named-source spelling and existing directory-package form meet at the same
practical boundary. The applicable adaptation uses `WW file` and
`*_test.ww` while preserving requested operand bytes. It requires no module,
manifest, registry, network lookup, generalized import grammar, cache,
database, CAS, or build expression.
#### Ownership, selection, and diagnostics
- **directly measured WW behavior** — before this change, Cstage followed a
direct `.ww` directory or visible `.ww`/`_test.ww` symlink into the ordinary
directory graph, invoked compiler, assemblers, linker, and user program, and
returned that program's status. WWstage instead entered raw-source loading,
returned status 1 with exact `ww: cannot read source\n`, and ran no producer
or program. Both removed the private work they had unnecessarily created.
- **behavior derived from the pinned implementation** — the true WW owners
are only `cmd/ww/main.c::do_run` and
`selfhost/cmd/ww/main.ww::dorun`, after their existing option/target parse
and requested `stat`, but before `resolve_module`/`resolvemodule` and run
scratch creation. Changing the shared resolver would wrongly change the
distinct build, test, logical, and dotted-package fronts.
- **directly measured WW behavior** — after the run-local classification,
both stages return status 1 with empty stdout. A requested spelling ending
`_test.ww` emits exactly
`ww: cannot run *_test.ww files (OPERAND)\n`; every other selected directory
ending `.ww` emits exactly
`OPERAND is a directory, should be a WW file\n`. The requested operand is
reproduced unchanged. `_test.ww` precedence applies before ordinary
directory rejection, including through a symlink.
- **directly measured WW behavior** — the rule includes direct and symlinked
`.ww` directories and hidden directory spellings `.hidden.ww` and
`_hidden.ww`. It also precedes malformed package clauses and missing imports
inside the directory because no member is selected or opened. Existing run
option errors and target determination retain their earlier precedence.
A trailing separator does not end `.ww`; non-`.ww` directories and dotted
logical requests retain the established package route.
#### Build, test, package, and import effects
- **directly measured WW behavior** — package/source selection is the primary
axis. The rejected request creates no raw or directory package, canonical
identity, declared-name instance, test variant, initializer, graph node, or
action. Requested spelling and followed target are diagnostic observations
only, never canonical package, action, symbol, artifact, `.wwi`,
publication, or persistence identity.
- **directly measured WW behavior** — build retains section 11.52's stat-first
rule for the same direct and symlink spellings. It still enumerates the
directory, discovers its dotted dependencies, constructs ordinary package
actions, and applies the established default, explicit, directory,
`/dev/null`, `-S`, publication, persistence, invalidation, and rollback
policies. Unaffected build controls retain stage-byte-identical public and
semantic artifacts.
- **directly measured WW behavior** — raw `ww test`, `ww test -c`, and
directory `ww test -S` retain their stat-first directory selection and
established diagnostics/artifact bytes. Test package variants, generated
main, process topology, filtering, capture, result ordering, retention, and
result non-caching are unchanged.
- **directly measured WW behavior** — imports are not scanned on the selected
run rejection and create no qualifier or edge. Dotted and non-`.ww` package
controls retain exact canonical import identity, dependency discovery, and
runtime behavior. No physical directory becomes canonical identity through
this rule.
#### Actions, lifecycle, parity, and scope
- **directly measured WW behavior** — selected rejection invokes no compiler,
assembler, archiver, linker, initializer, runtime, or owned child/process
group. A fixture-preoccupied exact `/tmp/ww_run_<pid>` plus sentinel remains
untouched, proving that the driver does not acquire or mutate its run-scratch
path; final cleanup leaves that path absent. It also creates no output,
`.sepwork`, unit, `.wwi`, assembly, object, archive, executable, capture,
result, transaction, stage, backup, or persistent record. Thus
producer/runtime failure, publication, reuse, invalidation, and rollback are
inapplicable on this preflight route; all prior caller and committed bytes
remain untouched.
- **directly measured WW behavior** — classification is request-local,
read-only, and isolated under concurrency. An interruption in this preflight
owns no child or filesystem resource. The general direct-driver interruption
gap from section 11.52 remains open: a different request interrupted after
transaction staging can still leave fixed-name `.new` files and poison
later persistent reuse. This slice neither reaches nor fixes that machinery.
- **directly measured WW behavior** — Cstage and WWstage match exactly on
status, stdout, stderr, diagnostic bytes, empty producer traces, artifact
absence, exact PID-path non-acquisition and final absence, concurrent
isolation, and cleanup for every selected row. Unaffected controls retain
diagnostic and public or semantic artifact-byte parity.
- **behavior derived from the pinned implementation** — this narrow
file-kind slice does not implement the complete suffix-first run front.
Regular or missing `_test.ww`, missing or logical `.ww`, multiple named
sources, finite FIFOs, and hidden regular sources retain their prior routes
and remain separately open where different. Recursive requests, ordinary
directory requests, and generalized imports are not changed.
The focused WW-native observer covers direct, symlinked, hidden, ordinary, and
`_test.ww` directory spellings; malformed-package and missing-import
precedence; exact requested diagnostics; empty tool/runtime traces; exact
PID-path non-acquisition and final absence; concurrency and cleanup;
trailing-separator,
non-`.ww`, regular-source, and dotted logical run controls; and unchanged
same-spelling build and raw/compile-only/assembly-only test boundaries. No
serialized representation changes: build workdir format remains `18`, test
workdir format remains `19`, semantic storage format remains `3`, and no cache
or result record is added.
## 12. Candidate architectures and hard-gate decision
Five candidates were developed as coherent systems, not as feature bins.

View File

@@ -370,10 +370,31 @@ ImportPath = ident { "." ident } .
no new package, dotted-import, graph, action, symbol, artifact, `.wwi`,
publication, or persistence identity. Raw `ww test`, `ww test -c`, and
`ww test -S` already use the same directory classification and are unchanged.
`ww run` retains its separate named-operand front door. Multiple operands,
recursive and logical requests, regular and non-regular source targets, and
dangling symlinks are not changed. Build workdir format remains 18, test
workdir format remains 19, and semantic storage format remains 3.
`ww run` retains its separate named-operand front door, with its
`.ww`-spelled directory rule specified next. Multiple operands, recursive
and logical requests, regular and non-regular source targets, and dangling
symlinks are not changed. Build workdir format remains 18, test workdir
format remains 19, and semantic storage format remains 3.
- For `ww run`, an existing selected target whose exact requested spelling
ends `.ww` is a named-source request when symlink-following `stat` reports a
directory. The command rejects it before shared resolution, directory
enumeration, source/import loading, graph/action construction, private run
scratch, producers, or runtime. A requested suffix `_test.ww` has the earlier
exact diagnostic
`ww: cannot run *_test.ww files (OPERAND)\n`; every other such directory has
exact diagnostic `OPERAND is a directory, should be a WW file\n`. Both forms
return status 1 with empty stdout and reproduce the requested operand bytes
unchanged. The rule follows a terminal symlink, includes `.hidden.ww` and
`_hidden.ww` directory spellings, and precedes any malformed package or
missing import inside the directory. A trailing separator does not end
`.ww`; ordinary non-`.ww` directories, dotted logical requests, regular and
missing operands, multiple named operands, and non-directory non-regular
targets retain their established routes. The rejected spelling and followed
target are diagnostic metadata only and create no package/import identity,
graph/action, symbol, artifact, `.wwi`, publication, transaction,
persistence, process, or filesystem owner. Build and all test forms retain
their distinct stat-first directory behavior. Build workdir format remains
18, test workdir format remains 19, and semantic storage format remains 3.
- `import acme.codec;` loads the canonical package `acme.codec`. If that
package declares `package wire;`, the importing file sees its exported names
as `wire.Name`; `codec.Name` is not an additional binding. An explicit alias

View File

@@ -278,12 +278,29 @@ parity, direct and symlinked `.ww` directories, a dotted dependency, output
modes, cold/warm transaction behavior, compiler and signaled-linker failure
preservation, selected-route concurrency, cleanup, and the exact test-command
behavior. Direct driver interruption remains owned by the unchanged directory
machinery and is not claimed fixed here. The shared resolver and `ww run` are
deliberately unchanged—and the observer
retains their pre-existing stage difference—because pinned Go's run command
has a distinct named-file front door.
No test product, result, package/import identity, or serialized format changes;
build remains 18, test remains 19, and semantic storage remains 3.
machinery and is not claimed fixed here.
Pinned Go's run command has a distinct suffix-first named-file front door.
Accordingly, an existing `ww run` target whose exact requested spelling ends
`.ww` and whose symlink-following `stat` result is a directory is rejected in
the twin run fronts before the shared resolver and private run scratch. An
`_test.ww` spelling emits exactly
`ww: cannot run *_test.ww files (OPERAND)\n`; every other selected `.ww`
directory emits exactly `OPERAND is a directory, should be a WW file\n`.
Both stages return status 1 with empty stdout, open no directory member, scan
no import, construct no package/graph/action, invoke no producer or runtime,
and create no run scratch or artifact. This includes direct and symlinked
directories and hidden directory spellings; directory contents cannot displace
the classifier diagnostic. A trailing separator and non-`.ww` or dotted
package requests retain the directory package route. The same-spelling build,
raw test, `test -c`, and directory `test -S` routes remain stat-first and keep
their existing diagnostics and artifact bytes. Thus this run change creates no
test product, result, package/import identity, test-process/filter change, or
serialized-format change; build remains 18, test remains 19, and semantic
storage remains 3. Regular or missing `_test.ww`, missing/logical `.ww`,
multiple named sources, finite FIFOs, and hidden regular sources are not
claimed by this existing-directory slice. The general direct-driver `.new`
interruption residue also remains open.
List mode uses that same product process and initialization boundary but starts
no per-test child. The shared language harness emits only selected qualified