Skip to content

writ reads neither writ.segments nor writ.scopes, so both extensible sets are unreachable #765

Open

Description

@David-Noble-at-work

Feature: #762 — The writ lifecycle surface: reconcile, scopes, and the vocabulary settlement

writ cannot resolve a segment or a scope from configuration, so both extensible sets are unreachable and
every operation runs against the builtins alone.

Blocked on this

--scope (#762) has nothing to select until scopes
can be introduced. Custom segments have been documented since the schema was written and have never worked
(#746).

The shape, settled 2026-08-31

One key per concept, holding both the names and their values. A key introduces the name; its value sets it.

writ:
  segments:
    ROLE: desktop            # introduced and set
    SITE:                    # introduced; set by WRIT_SEGMENT_SITE or --segment
  scopes:
    Staging: ~/staging/root  # a custom scope
    Home: ~/staging/home     # a BUILTIN's root, overridden
  vars:
    USER_NAME: "Your Name"   # what templates interpolate, and nothing else

Specified in docs/architecture/10-command-line-interface.md §11.

This changes writ.segments from an array to a map. Cheap now, because nothing reads it; expensive the
moment something does. Both keys' readers land in the same change that documents them, so scopes do not
repeat #746.

Work

  • writ.segments is read: names introduced, values taken, and a key with no value left unset for the
    environment or a flag to fill. DetectSegmentsWithNames exists for this and has no production caller.
  • writ.scopes is read the same way, with a builtin's key overriding its default root.
  • vars stops carrying segment values; it holds template variables alone.
  • Introducing a builtin scope's name is an error on a platform where it does not resolve, and permitted
    as an override where it does. Segment builtins resolve everywhere, so segments need no such rule.
  • An undeclared --segment or --scope errors, naming what is accepted. SetValues already does this
    for segments and has no production caller either.

Verification

  • writ.scopes: {Staging: ~/staging} plus --scope=Staging deploys beneath ~/staging.
  • writ.scopes: {Home: ~/staging/home} redirects the builtin.
  • writ.scopes: {ProgramFiles: /opt/pf} errors on Unix and is accepted on Windows.
  • writ.segments: {ROLE: desktop} selects <project>.desktop directories.
  • writ.segments: {ROLE:} leaves ROLE unset, so no .desktop directory matches until
    WRIT_SEGMENT_ROLE or --segment supplies one.
  • A vars entry no longer sets a segment.

Related

#746 (segments unwired — superseded in scope by this), #762 (the lifecycle and scope design), #763 (the
doubled environment prefix, which WRIT_SEGMENT_<NAME> sidesteps by reading os.Getenv directly).

Activity

  1. added
    bugSomething isn't working
    Area:CLICommand-line interface
    taskImplementation work item
    Epic:WritDeploymentwrit deployment: layers, adoption, and drift
    on Sep 1, 2026
  2. David-Noble-at-work commented on Sep 30, 2026

    @David-Noble-at-work
    ContributorAuthor

    #944's PR, #992, merged 2026-09-30 as e440151a and delivers this issue's segments half. The scopes half stays here. #970, the segments writ upgrade and writ reconcile didn't see, closed with it.

    The segments shape is not the one settled here on 2026-08-31. writ.segments is an ordered list, not a map, because a directory name carries the extra segments in the order they're declared (ruled 2026-09-30). Each entry is a name, the values it may take, and optionally this machine's value (cmd/internal/config/writ.go:11-29, schema/devlore-config.json:241). docs/architecture/10-command-line-interface.md §11 (:895-930) now shows the list for segments and keeps the map for scopes.

    At e440151a:

    • writ.segments is read by resolveSegments (cmd/writ/writ/config.go:284-306) for writ deploy, writ upgrade, writ reconcile and writ adopt (config.go:94, :144, :180, :246). All four take --segment (cmd/writ/writ/commands.go:58, :196, :261; cmd/writ/writ/adopt_cmd.go:83).
    • A value comes from --segment NAME=value, else WRIT_SEGMENT_<NAME>, else value in configuration (cmd/writ/writ/segment/detect.go:49-84). A segment with no value matches no directory name.
    • An undeclared name or value is refused, from the flag and from the environment alike (detect.go:100-115). OS, DISTRO and ARCH take either without a declaration.
    • A declaration is refused, with every problem listed, when it has any of these (pkg/selector/selector.go:253-295, ValidateSegments):
      • a segment with no name
      • a name that's built in: OS, DISTRO or ARCH
      • a name declared twice
      • an empty value
      • a value that's an OS or distribution word
      • a value that's an architecture word
      • a value declared twice, by one segment or by two
      • a value that isn't one of its segment's values
    • vars holds template variables alone (cmd/internal/config/writ.go:13, schema/devlore-config.json:302).
    • DetectSegmentsWithNames and SetValues, which the work list names, are deleted (the plan's Q14). segment.Resolve does their job.

    Still this issue's: nothing reads writ.scopes. WritConfig has no field for it (cmd/internal/config/writ.go:8-16). It exists only in schema/devlore-config.json:227-240 and, commented out, in schema/defaults/writ.yaml:29. --scope is not registered on deploy, upgrade, reconcile or decommission. The work list's scope items and the three scope checks under Verification are unchanged.

    #746, which this issue superseded, is still open, although its complaint that writ.segments has no reader no longer holds.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Area:CLICommand-line interfaceEpic:WritDeploymentwrit deployment: layers, adoption, and driftbugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions