Skip to content

ui takes the root namespace and replaces print and fail #698

Open

Description

@David-Noble-at-work

Epic: #445 — The Starlark authoring surface
Plan: docs/plans/ui-at-root.md

Problem

Starlark ships two output builtins — print and fail — and devlore owns neither.

A script's print resolves to starlark.Universe, is formatted by the interpreter, and is written straight
to stderr by starlark-go's default. It never reaches status.Narrator, so it is invisible to --quiet, to
any output shaping we choose, and to the diagnostics stream that #507 will introduce. fail is the same
story on the error path.

Meanwhile ui already has methods that mean exactly these things, and five more besides.

The shape of the fix

Marking the ui provider +devlore:root=true surfaces all six methods as top-level globals. Because
Starlark's resolver checks predeclared before universal (resolve.go:437 precedes :441), and
CamelToSnake maps Print→print and Fail→fail, the builtins are replaced — with no interception
code, no starlark.Universe mutation, and no Thread.Print hook.

receiver_type.go:66 already documents this case, using note() as its example. This would be the first
real use of the RoleModule|RoleRoot branch that runtime.go:125 calls reserved.

What it buys

Today After
print stderr, via starlark-go status.Narrator, like everything else
fail interpreter error text narrated, then raised
note warn error succeed ui.note(...) top-level, which is what an author reaching for print wanted
#507 diagnostics stream print bypasses it print rides it

Prerequisite

ui.Print(msg string) takes one string. The builtin is variadic with a sep keyword. Replacing the
builtin with a narrower signature would break every print(a, b) in the tree — so the variadic change
lands first (see the task below).

Ruling needed

Does error belong in the global namespace? note, warn, succeed, print, and fail are safe
words to claim. error is an ordinary word for a script to want as a variable, and a predeclared name
cannot be assigned over at module scope — error = compute() becomes a resolve error, not a shadow.
Options: accept it, give the global a different name while keeping ui.Error, or leave Error off root.

Out of scope, but noted

  • The other builtins — dir, getattr, hasattr, type, repr — stay the universe's. Three are
    reflection over the surface, which is a real question for a hermetic runtime, and a separate one.
  • Eight sites construct starlark.Thread independently and none sets Thread.Print. Irrelevant once
    print is predeclared (the builtin is never reached), but any policy needing the thread hook would
    have to set it eight times.

Activity

  1. David-Noble-at-work commented on Aug 26, 2026

    @David-Noble-at-work
    ContributorAuthor

    Tasks: #699 (variadic signatures), #700 (root placement + call-site sweep). Sequential — the replacement must accept what the builtin accepted before it can replace it.

  2. David-Noble-at-work commented on Aug 26, 2026

    @David-Noble-at-work
    ContributorAuthor

    Both rulings settled.

    1. No sep keyword — Print(args ...any) joined with " ". Zero sep= call sites in the tree. See ui.Provider methods take variadic arguments #699.
    2. error keeps the global name — script authors adopt err for the variable, as Go authors do. See Mark ui +devlore:root=true and sweep the ui.* call sites #700.

    Plan docs/plans/ui-at-root.md is updated and approved.

  3. David-Noble-at-work commented on Aug 26, 2026

    @David-Noble-at-work
    ContributorAuthor

    Scope narrowed: no signature changes. #699 is closed; #700 carries the whole job.

    The variadic prerequisite dissolved. Both ways of widening ui.Print to match the builtin fail:

    • Printf semantics re-scan a string Starlark's % operator already rendered — 50% off becomes 50%!o(MISSING)ff
    • Variadic space-join receives Go natives after toGoInto, so True/None/lists render as true/<nil>/[a b] instead of True/None/["a"]

    (msg string) is the correct signature: the script renders with Starlark's own str() and %, and hands over a finished string. Survey confirms the tree already works this way — 64 print and 65 fail sites, zero multi-argument, zero non-string.

    Remaining work is one directive, one defect fix, and a 231-site sweep. See #700 and docs/plans/ui-at-root.md.

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

Metadata

Metadata

Labels

Area:ArchitectureSystem architecture and designEpic:StarlarkSurfaceThe Starlark authoring surfacePriority:P2Scheduled, not urgentfeatureDeliverable unit within an epic

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions