Skip to content

Migrate host-hygiene reaper and liveness onto typed observation; delete host_hygiene_*_script - #8583

Merged
briansrls merged 1 commit into
mainfrom
session/zesty-wren-670
Aug 19, 2026
Merged

briansrls merged 1 commit into
mainfrom
session/zesty-wren-670

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Summary

host_hygiene_reaper_script.dag and host_hygiene_liveness_script.dag held hand-concatenated bash text bodies — a scaffold whose dissolution trigger (typed-argv host-effect routing, #5828-era) has landed. This migrates both verticals onto typed observation/remediation and deletes both script modules in the same cut (DESIGN §3 replacement migration — no dual-authority interim).

  • gunbc.host_hygiene_reaper_observe (OBSERVE): per-slot cgroup/system.control observation via the existing systemctl_show_read seam (extended with SystemdUnitProperty::ActiveState) and direct filesystem_read/shell.Test.IsDirectory. Reuses the existing single authority gunbc.host_converge.gunbc_runner_all_slots_unit_glob rather than re-declaring the runner-slot glob.
  • gunbc.host_hygiene_reaper_remediate (MUTATE): the bound is structural, not a literal check embedded in a script — every ResidualReapEffect variant carries a unit derived from a vetted observation, and the module recomputes residual_reap_action internally rather than accepting a caller-supplied action, so the decision core's permanent RED-control residual_reap_action_absorbing_fallback_widen_sketch fixture is unreachable from any effect path.
  • gunbc.host_hygiene_liveness_observe (OBSERVE): journal-line parsing (last matching "Listening for Jobs" line, epoch extraction, freshness age) as pure .dag folds over one typed extdeps.systemd.Journalctl.UnitLog read, replacing the deleted script's hand-written journalctl | grep | tail pipeline.
  • New extdeps: extdeps.posix.signal (kill -TERM) and extdeps.systemd.journalctl (journalctl -u ... -o short-unix), both anchored to their upstream authorities and carrying mock_response for hermetic replay.
  • Decision cores (gunbc.host_hygiene_reaper / _liveness) are unchanged except their placeholder ReadAbsent reason strings, which now name the real live-evidence entrypoint. No import was added back from the decision core to the observe modules — avoids a cycle.
  • Replaced the four script-coupled tests (which called into the deleted shell-text bodies) with witnesses against the new typed functions.

Confirmed via corpus-wide grep that the reaper script's dead systemd-unit-install machinery had zero consumers anywhere (matching live_deploy/spec.dag's own note that it "is installed by NOBODY"), so deleting the whole file was safe as one cut.

CI reality: CI's floor is hermetic-only (eval_mock_response replays declared results; argv is never constructed/executed). The live shell/systemctl/journalctl/kill-issuing functions (observe_residual_slot, apply_residual_reap_effect, host_hygiene_observe_slot_listening's transport leg) are reachable only from the wet path, never from a test fn, and are marked UNEXECUTED-IN-CI with a stated promotion trigger (a wet/live CI lane, which does not exist today). The new tests exercise the pure decision/parsing functions directly (green-by-execution), plus one hermetic end-to-end read of host_hygiene_observe_slot_listening against Journalctl.UnitLog's declared mock_response.

Test plan

  • CTRL_BUILD_MODE=local cargo build --release --bin gunbc --bin claim_batch --bin claim_executor — builds clean
  • claim_batch --source-root dag --source-root src/v2 --entry dag/test/claim/host_hygiene_reaper_test.dag --functions <all 16> --hermetic — 16/16 PASS
  • claim_batch --source-root dag --source-root src/v2 --entry dag/test/claim/host_hygiene_liveness_test.dag --functions <all 12> --hermetic — 12/12 PASS
  • Corpus-wide grep confirms no remaining consumer of the deleted script modules or their functions outside historical prose (own migration-narrative comments + a pre-existing, deliberately out-of-scope mention in live_deploy/spec.dag)

🤖 Generated with Claude Code

…te host_hygiene_*_script

host_hygiene_reaper_script.dag and host_hygiene_liveness_script.dag held
hand-concatenated bash text bodies whose dissolution trigger (typed-argv
host-effect routing) has landed. Both verticals are now split into
observe/mutate sub-modules built on typed reads:

- gunbc.host_hygiene_reaper_observe: per-slot cgroup/system.control
  observation via the existing systemctl_show_read seam (extended with
  SystemdUnitProperty::ActiveState) and direct filesystem_read/shell.Test.
- gunbc.host_hygiene_reaper_remediate: the reaper's MUTATE half. The
  bound is structural, not a literal check in a script: every effect
  variant carries a unit derived from a vetted observation, and the
  module recomputes residual_reap_action internally rather than
  accepting a caller-supplied action, so the decision core's permanent
  RED-control widen-sketch fixture is unreachable from any effect path.
- gunbc.host_hygiene_liveness_observe: journal-line parsing (last
  matching "Listening for Jobs" line, epoch extraction, freshness age)
  as pure .dag folds over one typed extdeps.systemd.Journalctl.UnitLog
  read, replacing the deleted script's hand-written pipeline.

New extdeps: extdeps.posix.signal (kill -TERM) and
extdeps.systemd.journalctl (journalctl -u ... -o short-unix), both
anchored to their upstream authorities and carrying mock_response for
hermetic replay. extdeps.systemd's SystemdUnitProperty gained
ActiveState rather than minting a second read op. Both new observe
modules reuse the existing gunbc.host_converge.gunbc_runner_all_slots_unit_glob
authority instead of re-declaring the runner-slot glob literal.

The decision cores (gunbc.host_hygiene_reaper / _liveness) are
unchanged except for their placeholder ReadAbsent reason strings, which
now name the real live-evidence entrypoint; no import was added back
from the decision core to the observe modules, avoiding a cycle.

Replaced the four script-coupled tests (which called into the deleted
shell-text bodies) with witnesses against the new typed functions:
pure ResidualReapEffect derivation for the reaper (build-cache refusal,
active-unit refusal, override-only vs kill-and-remove, no-action), and
both pure journal-line parsing and a mocked-transport end-to-end read
for liveness. All are green-by-execution under claim_batch --hermetic.

Confirmed via corpus-wide grep that the reaper script's dead
systemd-unit-install machinery had zero consumers anywhere (matching
live_deploy/spec.dag's own note that it "is installed by NOBODY"), so
deleting the whole file was safe as one replacement-migration cut.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@briansrls
briansrls merged commit ffa16a5 into main Aug 19, 2026
1 check passed
@briansrls
briansrls deleted the session/zesty-wren-670 branch August 19, 2026 23:45
briansrls pushed a commit that referenced this pull request Sep 5, 2026
…e denominator to its head

The banner asserted that absence of a name is not discharge because a rename
looks identical. It now demonstrates it, with six names that already have
verdicts on main and do not all point the same way:

  srv3_chown_directory_to_current_user  discharged        61bf47b (#8590)
  host_build_cache_provision_script     discharged        40f2fb6 (#8825)
  four host_hygiene_reap_*_body         files deleted     ffa16a5 (#8583)
  git_fetch_script                      RENAME, not gone  (unadjudicated)

Three causes, one grep signature. The host_hygiene row is the sharpest: the
commit that discharges those four names does not mention them, so the evidence
is not reachable from the symbol at all -- which is precisely why the per-row
lane cannot be done by symbol search. All four commits are ancestors of main, so
the table is head-safe independent of the SS1.C corrections landing separately in
 #10529.

The denominator now says it was measured at 70925ee and is valid only there:
any later edit that strikes a row through changes what the closed-marker grep
counts, so the 180/41/~139 split moves and must be re-derived rather than quoted.
The demonstration table sits inside the blockquote, so it does not itself perturb
the row count -- re-derived at 180 after the edit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GCBVTWARwTLkAfVWaGfKA
briansrls pushed a commit that referenced this pull request Sep 5, 2026
… flag the census's dead-ci.yml population (#10537)

* Correct the stale ci_floor_peak rows and flag the census's dead-ci.yml population

gunbc.plans.shell_emission_model's Phase 1 PARTIAL row still said While emit's
one production consumer, ci_floor_peak_emit, has cond and body "still raw shell
strings". That was true when written and is stale: ecbd086 (#7978, shell ->
dag Phase 1 cgroup vertical, 2026-08-08, ancestor of origin/main) replaced both
leaves, and the membership assign with them, with derived text from a typed
NearestAncestorContaining (std.path_intent) plus extdeps.linux.proc_self_cgroup
membership, lowered through bash_orch_if / bash_proc_self_cgroup, refusing with
a located marker rather than widening. git log -S on both
bash_nearest_ancestor_locate_cond_command and ci_floor_peak_nearest_ancestor_spec,
scoped to that file, returns exactly that commit as first introduction.

The correction carries the residue forward rather than reading as completion:
the peak calibration leaves on the same pipeline and the runtime-scan transport
in bash_membership_assign_from_source are still raw String Run.command values,
declared Phase 2 typed filesystem observation by the module itself.

Three census rows in docs/plans/shell-to-dag-residual-census-and-arc-completion.md
carried the same stale claim -- the SS1.A "concat-built floor-peak/cgroup runners"
row, the SS4.E already-on-emit row, and the SS4.J Phase-1 dispatch row that still
listed the two leaves as unassigned open work. That last one is what dispatched a
lane onto discharged work.

Sweeping the class turned up a larger root cause, filed as a banner rather than
silently truncated: .github/workflows/ci.yml was deleted by 611fd02 (#8283,
FLOOR-Y cutover), CI is now the witnesses.yml emission from
gunbc.witness_floor_workflow, and this census mentions none of that while still
naming ci.yml drift+parse as its byte-oracle in four places. A symbol-existence
check over the SS4.J dispatch roster found ~20 named production symbols with no
declaration anywhere in the .dag corpus. The banner states the denominator (180
data rows, 41 already closed, ~139 asserting live state) and states explicitly
what it does NOT establish: absence of a name is not discharge, since a rename
looks identical -- git_fetch_script is gone while git_fetch_no_tags_shell and
git_fetch_prune_shell exist. Per-row adjudication needs its own lane.

Model-side prose only; no seed growth, no .rs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GCBVTWARwTLkAfVWaGfKA

* Name the instrument behind the banner's counts, so the banner is not the next stale row

The staleness banner cited bare counts (180 data rows / 41 closed / ~139 live)
and a ~20-name absent-symbol list. Transcribed numbers under a dated claim are
exactly the defect the banner is about, one layer up: nothing re-derives them,
so they rot without anyone touching either end.

The banner now carries the two checks that produce them, verified to reproduce
their stated output as printed at 70925ee, and says to run them rather than
read them. It also states the second check's raw output honestly -- 50
candidates, of which the ~20 production symbols are what survives discarding
module names, the commit-sha and fn-fragment spellings the banner itself
introduced, and already-struck rows -- so the gap between "50 out" and "20
listed" cannot be mistaken for a miscount. The ci.yml deletion is the one claim
that is not count-shaped and its own one-line derivation is given.

The dispatch prohibition is unchanged and deliberate: a banner that describes
staleness while still permitting dispatch off the rows is a documented hazard
with no refusal.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GCBVTWARwTLkAfVWaGfKA

* Turn the banner's absent-symbol list into a demonstration, and pin the denominator to its head

The banner asserted that absence of a name is not discharge because a rename
looks identical. It now demonstrates it, with six names that already have
verdicts on main and do not all point the same way:

  srv3_chown_directory_to_current_user  discharged        61bf47b (#8590)
  host_build_cache_provision_script     discharged        40f2fb6 (#8825)
  four host_hygiene_reap_*_body         files deleted     ffa16a5 (#8583)
  git_fetch_script                      RENAME, not gone  (unadjudicated)

Three causes, one grep signature. The host_hygiene row is the sharpest: the
commit that discharges those four names does not mention them, so the evidence
is not reachable from the symbol at all -- which is precisely why the per-row
lane cannot be done by symbol search. All four commits are ancestors of main, so
the table is head-safe independent of the SS1.C corrections landing separately in
 #10529.

The denominator now says it was measured at 70925ee and is valid only there:
any later edit that strikes a row through changes what the closed-marker grep
counts, so the 180/41/~139 split moves and must be re-derived rather than quoted.
The demonstration table sits inside the blockquote, so it does not itself perturb
the row count -- re-derived at 180 after the edit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GCBVTWARwTLkAfVWaGfKA

* Re-derive on the merged tree: correct a worked example reading found, repin the denominator

Reading every row either PR touched on the merged tree -- rather than trusting
the clean auto-merge -- turned up an error in my own worked-examples table.

 #10529's srv3 row names a live successor, srv3_ensure_directory_owned_by_current_user
(gunbc.host_effect_realize), so srv3_chown_directory_to_current_user was not
plain "discharged" as my table said: it was RENAMED AND CLIMBED at once. That is
a fourth cause a two-way discharge/rename split cannot express, and calling it
discharged loses the successor a reader needs to find. The table now carries all
four causes: dissolution, file deletion upstream of the name, bare rename, and
rename-plus-climb.

The denominator moved exactly as predicted. Re-derived on the merged tree it is
180 rows / 43 closed / ~137 live, against 41/~139 one merge earlier; #10529
striking two more SS1.C rows through is the whole difference. The banner now says
so, because a split that moves within one merge of being written is the argument
for naming the recipe rather than a bookkeeping detail. Measurement is pinned to
the merge of 70925ee with origin/main 16a702e.

Controls re-run on the merged tree, not carried forward: the four
bash_nearest_ancestor_locate_* call sites still stand and #7978 is an ancestor of
the merged HEAD; ci.yml is still absent with witnesses.yml present and #8283 an
ancestor; git_fetch_script is still absent while git_fetch_no_tags_shell and
git_fetch_prune_shell exist, so the rename example still discriminates. Diff is
still model-side prose only -- no .rs, no seed growth.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GCBVTWARwTLkAfVWaGfKA

---------

Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 5, 2026
§4.I — ci_native_cache_root_toolchain_segment_command
  DELETED #7436 (003d960). CASE 1 dissolution — toolchain segment
  computation reordered after setup-rust-toolchain; fallback table entry
  struck through as RESOLVED.

§4.J.A — ci_floor_stamp_merge_admission_script
  All three raw leaves (ci_floor_stamp_ambient_exit_command,
  ci_floor_stamp_root_command, merge_admission_stamp_command) DELETED
  #7522 (87a4af3). CASE 1 dissolution. 'PARTIAL #7293' status stale.

§4.J.B — ci_floor_materialization_receipt_gate_script,
  ci_floor_resolve_receipt_gate_script
  DELETED #7470 (b01cdf4). CASE 1 dissolution — WalkPlan success
  stages finalization dissolved both receipt gates.

§4.J.C (ci_spec.dag table):
  - gunbc_ci_floor_only_script DELETED #9252 — CASE 1
  - ci_regen_floor_skip_shortcut_script DELETED #8406 — CASE 1
  - gunbc_ci_regen_floor_only_script DELETED #8406 — CASE 1
  - scheduler_invoke/scheduler_invoke_with DELETED #9252 — CASE 1
  - git_fetch_script RENAMED #6833 — CASE 3 (successor:
    git_fetch_no_tags_shell / git_fetch_prune_shell)

§4.J.D (ownership table):
  - Merge-admission row: all three raw leaves struck #7522 (CLOSED)
  - CI materialization row: both receipt gates struck #7470 (CLOSED)
  - CI-spec row: stale symbols struck through individually
  - Already-routed row: ci_selection_control_script #8283,
    gunbc_ci_run_script #9252, ci_regen_ensure_rustfmt_path_script
    #8406 (and 11 rustfmt raw leaves) struck through
  - Runtime terminal row: host_effect_plan_placeholder_effect
    DELETED #10509
  - Deferred srv3 row: srv3_chown_directory_to_current_user struck
    #8796 (ref §4.D), all 4 host_hygiene_reap_*_body + liveness body
    struck #8583 (ref §4.A)

All deletion commits verified as ancestors of origin/main ✅.

Part of #10537's per-row adjudication program.
briansrls added a commit that referenced this pull request Sep 5, 2026
….E, §4.I, §4.J (#10576)

* Correct §4.A hygiene-reaper row: CASE 2 — four host_hygiene_reap_*_body symbols deleted by #8583

The §4.A row at L379 described host_hygiene_reaper_script.dag's 4
body symbols as A5-deferred. The file was deleted by ffa16a5
(#8583, Migrate host-hygiene reaper and liveness onto typed observation)
and the construction was migrated to typed host_hygiene_reaper_observe.dag
/ host_hygiene_reaper_remediate.dag / host_hygiene_liveness_observe.dag.
No direct successor body names exist — CASE 2 (file deletion upstream)
with hybrid CASE 1 (body names dissolved).

Verification:
- ffa16a5 is ancestor of origin/main ✅
- host_hygiene_reaper_script.dag: D in #8583's diff
- zero files define host_hygiene_reap_install_units_body et al.
- observe/remediate files present at dag/gunbc/host/

Part of #10537's per-row adjudication program.

* Correct §4.D srv3_chown_directory_to_current_user: CASE 4 — renamed AND climbed

The row at §4.D L436 listed srv3_chown_directory_to_current_user
as A5-deferred (srv3). It was actually renamed AND climbed by
20ad5b3 (#8796): successor is
gunbc.host_effect_realize.srv3_ensure_directory_owned_by_current_user.
New name has a stronger guarantee (readback-based, not chown exit-status
based).

This is CASE 4 (rename plus climb) — distinct from CASE 1 (dissolution)
because the construction did not disappear; it acquired a better name
and a stronger guarantee.

Verification:
- 20ad5b3 is ancestor of origin/main ✅
- srv3_chown_directory_to_current_user: 0 declaration files
- srv3_ensure_directory_owned_by_current_user: 2 declaration files

Part of #10537's per-row adjudication program.

* Correct §4.E: 4 stale foreign-executor rows

Four symbols claimed as 'already on emit' are no longer present in the
corpus. Each is struck through with its deletion commit:

1. ci_selection_control_script — DELETED by 611fd02 (#8283, CI floor cut).
   CASE 1/2: the ci.yml file was deleted and its selection-control script
   dissolved with it. Successor workflow is witnesses.yml via
   gunbc.witness_floor_workflow.

2. gunbc_ci_run_script — DELETED by 489346f (#9252, plan/walk CLI delete).
   CASE 1: the gunbc ci verb was deleted, taking its run script.

3. ci_regen_ensure_rustfmt_path_script — DELETED by 3b431f3 (#8406,
   REGEN ROOT CUT). CASE 1: regen_stage0 root deleted; rustfmt path
   script was zero-consumer machinery.

4. expected_live_deploy_retract_script — DELETED by d409b75 (#7909,
   Phase A release identity refactor). CASE 1: recategorized to
   runtime-present, then dissolved.

All four deletion commits are ancestors of origin/main ✅.

Part of #10537's per-row adjudication program.

* Correct §4.I, §4.J, §4.D ownership table: 18+ stale symbols

§4.I — ci_native_cache_root_toolchain_segment_command
  DELETED #7436 (003d960). CASE 1 dissolution — toolchain segment
  computation reordered after setup-rust-toolchain; fallback table entry
  struck through as RESOLVED.

§4.J.A — ci_floor_stamp_merge_admission_script
  All three raw leaves (ci_floor_stamp_ambient_exit_command,
  ci_floor_stamp_root_command, merge_admission_stamp_command) DELETED
  #7522 (87a4af3). CASE 1 dissolution. 'PARTIAL #7293' status stale.

§4.J.B — ci_floor_materialization_receipt_gate_script,
  ci_floor_resolve_receipt_gate_script
  DELETED #7470 (b01cdf4). CASE 1 dissolution — WalkPlan success
  stages finalization dissolved both receipt gates.

§4.J.C (ci_spec.dag table):
  - gunbc_ci_floor_only_script DELETED #9252 — CASE 1
  - ci_regen_floor_skip_shortcut_script DELETED #8406 — CASE 1
  - gunbc_ci_regen_floor_only_script DELETED #8406 — CASE 1
  - scheduler_invoke/scheduler_invoke_with DELETED #9252 — CASE 1
  - git_fetch_script RENAMED #6833 — CASE 3 (successor:
    git_fetch_no_tags_shell / git_fetch_prune_shell)

§4.J.D (ownership table):
  - Merge-admission row: all three raw leaves struck #7522 (CLOSED)
  - CI materialization row: both receipt gates struck #7470 (CLOSED)
  - CI-spec row: stale symbols struck through individually
  - Already-routed row: ci_selection_control_script #8283,
    gunbc_ci_run_script #9252, ci_regen_ensure_rustfmt_path_script
    #8406 (and 11 rustfmt raw leaves) struck through
  - Runtime terminal row: host_effect_plan_placeholder_effect
    DELETED #10509
  - Deferred srv3 row: srv3_chown_directory_to_current_user struck
    #8796 (ref §4.D), all 4 host_hygiene_reap_*_body + liveness body
    struck #8583 (ref §4.A)

All deletion commits verified as ancestors of origin/main ✅.

Part of #10537's per-row adjudication program.

---------

Co-authored-by: Brian Searls <briansearls1@gmail.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.

1 participant