Skip to content

os.Hostname.Set onto the CLI-invocation substrate: model the invocation, derive the argv (#8467 grain) - #10211

Merged
gunbai-bot[bot] merged 2 commits into
mainfrom
session/clever-boar-81
Sep 3, 2026
Merged

gunbai-bot[bot] merged 2 commits into
mainfrom
session/clever-boar-81

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Subject

os.Hostname.Set's realization was a hand-authored argv row — transport shell { argv: ["hostnamectl", "set-hostname", "{desired}"] } — the exact defect the CLI-invocation lane exists to remove: the subcommand and operand were opaque literals in a transport DSL, so the op's own flags were hand-typed rather than derived from cited rows. This is the #8467 grain of the shell→dag census §5.A hostname row (the §5.B "call a typed op" grain landed at #7194; this cut replaces the op's realization).

The shape mirrors the jq vertical: model the invocation, derive the argv, execute through a process handler whose only literal is the executable.

Change

  • extdeps.tools.hostname: hostnamectl_set_hostname_verb is ONE cited row (freedesktop hostnamectl(1)); HostnameSetInvocation { desired: DnsLabel } is what a caller describes; the lowering emits a two-argument surface [set-hostname, desired] (subcommand = FixedToken with lex-rule spelling, operand = BoundToken); hostname_set_invocation_process_plan seals into a sole_constructor plan; hostname_set_execute_plan runs it through the new hostnamectl.Process.Run handler; hostname_set_classify_observation owns the exit contract (0 = applied, nonzero = failed with stderr). os.Hostname.Set is deleted with its transport row (the jq precedent: the semantic op with hardwired argv is removed, the invocation layer answers its question).
  • gunbc.hostname_set: the local leg builds the invocation and executes the sealed plan; the SSH legs' privileged argv (sudo -n <path> set-hostname <desired>) reads the same cited verb, so local and remote legs cannot drift. The full-argv projection hostname_set_argv is derived (executable + rendered surface), not a second authority. The now-tautological hostname_set_operation_argv/hostname_set_operation_argv_matches_authority scaffolding is deleted.
  • Witnesses: new hermetic lowering witness (hostname_set_invocation_lowering_witness_test.dag) asserting the exact surface, the full-argv projection, the bound-operand perturbation, and the exit contract; the census and host-identity witnesses repointed onto the invocation path.
  • The v1 false-refusal rosters (five remain) and the census §5.A ledger note the deletion.

Verification

  • Build lane clean: regen first_generation_equal=true (153/153), generated-artifact 36/36 match, failed=0.
  • Witnesses lane clean: FloorClean, 3515 executed, failed=0; the new and updated witness modules are in the admitted set.
  • infer_semantics_witness bin runs clean with the updated roster.
  • Pre-commit / pre-push cargo fmt --all --check: clean.

Brian Searls added 2 commits September 3, 2026 09:52
…on, derive the argv (#8467 grain)

The hostnamectl set-hostname vertical's realization was a hand-authored argv row —
`transport shell { argv: ["hostnamectl", "set-hostname", "{desired}"] }` — the exact
defect the CLI-invocation lane exists to remove: the subcommand and the operand were
opaque literals in a transport DSL, so the operation's own flags were hand-typed rather
than derived from cited rows. This is the #8467 grain of the shell->dag census's §5.A
hostname row: the §5.B grain (call a typed op) landed at #7194; the op's *realization*
is what this cut replaces.

The shape mirrors the jq vertical exactly:
- `hostnamectl_set_hostname_verb` is ONE cited row (freedesktop hostnamectl(1)); every
  argv derivation reads it, so a differently-spelled subcommand cannot reach argv.
- `HostnameSetInvocation { desired }` is what a caller describes — no flag, no argv
  position. A DnsLabel keeps the operand inside the hostnamectl-safe grammar.
- The lowering emits a two-argument surface [set-hostname, desired]: the subcommand as a
  FixedToken (spelling owned by the lex table), the operand as a BoundToken (spelling
  carried by the invocation). The executable is the handler's fixed tool name, exactly
  as jq.Process's transport row spells "jq".
- `hostname_set_invocation_process_plan` seals the surface into a sole_constructor plan;
  `hostname_set_execute_plan` runs it through the new `hostnamectl.Process.Run` handler;
  `hostname_set_classify_observation` owns the exit contract (0 = applied, nonzero =
  failed with stderr), so no domain code reads a raw exit code.

os.Hostname.Set is deleted with its transport row (the jq precedent: the semantic op
with hardwired argv is removed, the invocation layer answers its question). The local
leg (`hostname_set_local`) now builds the invocation and executes the sealed plan; the
SSH legs' privileged argv (`sudo -n <path> set-hostname <desired>`) reads the same
cited verb, so the local and remote legs cannot drift. The full-argv projection
`hostname_set_argv` is derived (executable + rendered surface) rather than a second
authority.

Witnesses: a new hermetic lowering witness (hostname_set_invocation_lowering_witness)
asserts the exact surface, the full-argv projection, the bound-operand perturbation,
and the exit contract; the census and host-identity witnesses are repointed onto the
invocation path. The v1 false-refusal rosters and the census ledger note the deletion.

Verified locally: build lane clean (regen first_generation_equal=true,
generated-artifact 36/36 match), witnesses lane clean (FloorClean, 3515 executed,
0 failed), infer_semantics_witness bin runs clean.
…ening a lowering refusal to Empty

Review advisory (PR #10211): the full-argv projection's `Rejected => Empty` arm was a
silent widen — a lowering refusal would surface as an empty list a caller could mistake
for a real projection, against DESIGN section 5's "a failure arm must refuse, never
widen". It was loud-in-practice (the witnesses' `""` join mismatch) but dishonest as a
production-module projection.

`hostname_set_argv` now returns Outcome<List<String>>: a lowering refusal is carried as
Rejected, and the three witness consumers match the Outcome instead of reading a bare
list that has already swallowed the refusal. The jq vertical's own lowering witnesses
do the same (their `argv_of` renders Rejected to false), but there the widen lives in
the test file; here it was in the production module.
@gunbai-bot

gunbai-bot Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the review advisory: hostname_set_argv now returns Outcome<List> — a lowering refusal is carried as Rejected rather than widened to an empty list (DESIGN §5). The three witness consumers match the Outcome. Verified locally: parse clean, namespace admitted, my witnesses pass (failed=0); the only floor refusals were unrelated v2-emit/execution witnesses hitting the 500ms CPU deadline under shared-host load.

— sent from clever-boar-81

@gunbai-bot
gunbai-bot Bot merged commit 739f1a5 into main Sep 3, 2026
12 of 14 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/clever-boar-81 branch September 3, 2026 14:22
@briansrls
briansrls restored the session/clever-boar-81 branch September 3, 2026 14:23
gunbai-bot Bot pushed a commit that referenced this pull request Sep 3, 2026
…ero-consumer ruling request

The census's §5.A table still read `extdeps.os.id` as a NEW op at
`dag/extdeps/os/id.dag` -- the stale row a survey read as "still pending". The
op landed on #7194 at its post-#7231 home `dag/extdeps/tools/id.dag` (module
`extdeps.tools.id`, service `os.Id`, ops `Uid`/`Gid`/`Lookup`), hermetic witness
`test.claim.shell_dag_census_5a_typed_ops_witness` (`witness_os_id_uid_realizes_hermetically`,
`witness_os_id_gid_realizes_hermetically`, `witness_os_id_lookup_realizes_hermetically`).
The row now says so, cited by module and symbol rather than position, and the
consumer column states the true status: `host_effect_realize`'s ssh probes
already consume the typed argv rows `id_uid_argv`/`id_gid_argv` (absolute-path
variants), and `fleet_posix_accounts` `probe_command` is NOT-a-shell-site
(census §4 row) -- authored provenance, live proof `deploy_access_check_observed`.

The same PR files a ruling request, not a deletion: `id_lookup_argv` (the
`id <user>` verb) has zero production references -- measured denominator, grep
of `dag/` + `src/v2/test/` at `739f1a548f` (post-#10211): the definition, the
hermetic-witness call, and service-name rows in the effect-plan tests, nothing
more. Zero references is not deadness in this repo (env-gated and emitted-path
consumers exist that grep does not see), and the row's named consumers are
reclassified (`fleet_posix_accounts` -- NOT-a-shell-site) or deferred
(`spark/managed_access_apply` create-script bodies -- dissolve-on marker, no
operator verdict). Retain-as-reserved or retire is the operator's call; the row
records the measured denominator and asks for it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants