Repository navigation
pkg/fsroot uses three words for one concept, none of them the ruled vocabulary #685
Description
Epic: #530
Follows: #677 — the claim vocabulary ruling of 2026-08-25
pkg/fsroot is inconsistent with itself and with the ruled vocabulary.
Inconsistent with itself, today
| Location | Word |
|---|---|
pkg/fsroot/fsroot.go:4 |
"Package fsroot provides confined filesystem roots" |
pkg/fsroot/fsroot.go:70 |
"Dir provides scoped filesystem operations" |
docs/plans/os-root-scoping.md |
titled "os.Root Scoping for Provider I/O" |
pkg/fsroot/fsroot.go:79 |
the // Confinement: comment convention |
Three words for one concept, in one package plus its plan.
Inconsistent with the ruling
#677 settled the vocabulary as Bazel's, which keeps the two halves distinct: sandboxing is the mechanism
(what an action can reach is restricted) and hermeticity is the outcome (same inputs, same outputs). The
claims are deterministic, idempotent, sandboxed.
sandboxed is the claim a method makes about routing its I/O through this package. The package should use the
same word.
Rejected en route, and recorded so it is not relitigated: root-based names carry three meanings here — /, a
designated subtree treated as a root, and the superuser. Neither Go nor the kernel names this property at all:
os.Root names a type, RESOLVE_BENEATH / RESOLVE_IN_ROOT name resolution flags, and os/root.go leaves the
property in prose ("beneath a root directory", "within a single directory tree", "outside the root").
Measured blast radius, 2026-08-25
| Surface | Count | Notes |
|---|---|---|
fsroot.go prose and unexported types (confinedDir, confinedScratchDir) |
~90 | package-local, safe |
OpenConfined — exported |
47 call sites | 20+ files across pkg/, cmd/ |
// Confinement: convention |
11 in 9 files | signing, runtime_environment, plan, function, git (×2), fsroot, selfinstall, man |
| Test-case labels naming the type | ~10 | pkg/op/triad_test.go, fsroot_test.go |
~150 edits across ~30 files.
A naming defect worth fixing while in here
OpenConfined and OpenScratch are an asymmetric pair: one names the property, the other names the
lifetime — but the package doc says plainly that both are confined, "one behavior, two lifetimes"
(fsroot.go:7). The current name therefore suggests a distinction that does not exist.
Two candidates:
OpenSandboxed/OpenScratch— minimal, preserves the existing asymmetryOpenExisting/OpenScratch— names both by lifetime, since both are sandboxed, and resolves the asymmetry
Sequencing
Do this on its own branch, after the tree is green. As of 2026-08-25 the working tree carries the access-
directive elimination with 34 packages failing; a 150-edit rename in the core I/O package interleaved with that
gives one tree two unrelated changes and no clean way to attribute a break.
Steps
- Rule the constructor pair — option 1 or 2 above
fsroot.go: package doc,Dirdoc, unexported types, per-method prose — one file, one pass- The exported constructor and its 47 call sites
- The
// Confinement:convention across 9 files - Test-case labels
- Rename
docs/plans/os-root-scoping.md's vocabulary to match (the plan title says "Scoping") make checkgreen on Darwin andGOOS=linux
Ruled 2026-08-25 — the constructor pair
OpenExisting / OpenScratch. Both constructors are sandboxed; the pair names the two lifetimes, which
is the only axis on which they actually differ. fsroot.go:7 already says so — "one behavior, two lifetimes" —
and OpenConfined contradicted it by naming the property, implying a distinction that does not exist.
This supersedes option 1 (OpenSandboxed / OpenScratch) recorded above. Step 1 is closed.
Sequencing constraint — #451 owns a serial window
#451 (rename op to workflow) states: "This owns a
serial window. Any in-flight branch under pkg/op/ conflicts irreparably while it runs."
This issue is exactly such a branch. Of its ~150 edits, the pkg/op/ share is substantial:
pkg/op/runtime_environment.go—OpenConfinedcall sites and a// Confinement:commentpkg/op/provider/plan/provider.go,pkg/op/provider/function/synthesize.go,
pkg/op/provider/git/provider.go,pkg/op/provider/git/helpers.go—// Confinement:commentspkg/op/triad_test.go— test-case labels- numerous
OpenConfinedcall sites underpkg/op/provider/
Therefore: this lands before #451's window opens, or after it closes. Never during. It is small and
mechanical, so before is strictly better — every reference it touches is one #451 would otherwise rewrite twice.
Ordering against the other gate is independent: the working tree must be green first (see Sequencing above).
Progress 2026-08-25 — the constructor rename is live
OpenConfined → OpenExisting was applied via GoLand's rename refactoring. 24 Go files carry OpenExisting.
GoLand correctly updated the godoc [OpenConfined] bracket links, which had been flagged as the likely silent
gap; it did not.
Residue — 18 Go occurrences, all string literals
Symbol references are complete. What remains compiles fine but names a function that no longer exists:
- 16 test failure messages —
t.Fatalf("fsroot.OpenConfined: %v", err)incmd/writ/writ/migrate/receipt_integration_test.go,pkg/document/document_test.go,pkg/fsroot/applymode_windows_test.go,pkg/fsroot/fsroot_test.go(5),pkg/op/provider/file/planspace_test.go,pkg/op/provider/plan/git_resume_test.go,pkg/op/provider/plan/lifecycle_api_test.go(4),pkg/op/provider/plan/lifecycle_e2e_test.go - 1 test name —
TestOpenConfined_CloseReleasesTheHandle(pkg/fsroot/fsroot_test.go:538) - 2 doc-comment examples —
pkg/assert/assert.go:21and:284, which use"fsroot.OpenConfined"to illustrate short-form function naming
Residue — 7 markdown mentions in 5 files
docs/architecture/3.5.1-archive-provider.md (1), docs/architecture/4.5-fsroot-variants.md (2),
docs/plans/env-minted-root.md (3), docs/plans/extract-starlark-from-op/phase-8/root-extraction.md (1).
Two documents found while verifying, both in scope
1. docs/architecture/4.5-fsroot-variants.md is the design doc of record — and its title carries the retired word
Titled "fsroot — One Confinement, Two Types", status "design draft (2026-08-18), rewritten 2026-08-19. No
implementation." Its §1 table is exactly what this issue changes:
| Opener | Type | Lifetime |
|---|---|---|
OpenConfined(dir) |
confinedDir |
the caller's |
OpenScratch(pattern) |
confinedScratchDir |
removes its tree on Close |
The title itself must change, not just the table — and its status companion carries the same wording. This
document was not known when the issue was filed; it is now the primary target.
2. docs/plans/env-minted-root.md is marked complete and describes an API that does not exist
Frontmatter: status: complete, issue #393, dated 2026-08-13. It specifies a Mode type and a dispatching
constructor:
ModevaluesModeConfined,ModeUnconfined,ModeWritableUnconfinedOpen(dir string, mode Mode) (Root, error)dispatching toOpenConfined/OpenUnconfined/
OpenWritableUnconfined
Measured 2026-08-25: ModeConfined, OpenUnconfined, and OpenWritableUnconfined appear in zero Go files.
4.5's status explains why: "The first draft specified three confinement variants from stated requirements;
tracing their consumers found the middle one unimplemented and the outer one justified by bootstrapping rather
than access, so the design collapses to a single confinement behaviour and two types."
So the three-variant design was superseded on 2026-08-19 and the plan was never marked so. A plan reading
complete while describing a rejected API is the same defect class this campaign is cataloguing. It needs a
supersession note pointing at 4.5.
Revised step list
Rule the constructor pair— done:OpenExisting/OpenScratchApply the constructor rename— done: 24 files, godoc links included- Finish the rename residue: 18 Go string literals, 7 markdown mentions
fsroot.go: package doc,Dirdoc, unexported types (confinedDir,confinedScratchDir), per-method prose- The
// Confinement:convention across 9 files 4.5-fsroot-variants.mdand its status companion — including the document title- Mark
env-minted-root.mdsuperseded by4.5 - Rename
os-root-scoping.md's vocabulary to match make checkgreen on Darwin andGOOS=linux
Activity
chore: sandbox vocabulary, lint-gate parity, and the access-directive…
Providers claim what they guarantee, and a type-checked pass holds th…