Skip to content

pkg/fsroot uses three words for one concept, none of them the ruled vocabulary #685

Open

Description

@David-Noble-at-work

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:

  1. OpenSandboxed / OpenScratch — minimal, preserves the existing asymmetry
  2. OpenExisting / 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

  1. Rule the constructor pair — option 1 or 2 above
  2. fsroot.go: package doc, Dir doc, unexported types, per-method prose — one file, one pass
  3. The exported constructor and its 47 call sites
  4. The // Confinement: convention across 9 files
  5. Test-case labels
  6. Rename docs/plans/os-root-scoping.md's vocabulary to match (the plan title says "Scoping")
  7. make check green on Darwin and GOOS=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 — OpenConfined call sites and a // Confinement: comment
  • pkg/op/provider/plan/provider.go, pkg/op/provider/function/synthesize.go,
    pkg/op/provider/git/provider.go, pkg/op/provider/git/helpers.go — // Confinement: comments
  • pkg/op/triad_test.go — test-case labels
  • numerous OpenConfined call sites under pkg/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) in cmd/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:21 and :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:

  • Mode values ModeConfined, ModeUnconfined, ModeWritableUnconfined
  • Open(dir string, mode Mode) (Root, error) dispatching to OpenConfined / 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

  1. Rule the constructor pair — done: OpenExisting / OpenScratch
  2. Apply the constructor rename — done: 24 files, godoc links included
  3. Finish the rename residue: 18 Go string literals, 7 markdown mentions
  4. fsroot.go: package doc, Dir doc, unexported types (confinedDir, confinedScratchDir), per-method prose
  5. The // Confinement: convention across 9 files
  6. 4.5-fsroot-variants.md and its status companion — including the document title
  7. Mark env-minted-root.md superseded by 4.5
  8. Rename os-root-scoping.md's vocabulary to match
  9. make check green on Darwin and GOOS=linux

Metadata

Metadata

Labels

Area:CodeQualityCode quality and lintingEpic:QualityCoverageCode quality, coverage, and the lint gatesPriority:P3Someday, or on next contactSeverity:LowCosmetic, or a defect nobody is hittingchoreMaintenance work on the repo: build, CI, tooling, process

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions