Skip to content

Count finished groups from each host's database; keep hosts holding unconsolidated work (#347) - #352

Merged
NewGraphEnvironment merged 11 commits into
mainfrom
347-study-area-run-sh-counts-finished-groups
Oct 18, 2026
Merged

NewGraphEnvironment merged 11 commits into
mainfrom
347-study-area-run-sh-counts-finished-groups

Conversation

@NewGraphEnvironment

Copy link
Copy Markdown
Owner

Summary

  • Each host's finished groups now come from its database, not its log text. study_area_run.sh used to count [wsg_run_one] <WSG> done lines anchored at line start. In run 20261017_004619-3f4c713b an R warning flushed without a newline put the marker mid-line on 18 finished groups, so the driver left them out of consolidate and would have burned the only copy (study_area_run.sh counts finished groups from log text and burns hosts holding unconsolidated work #347).
    • Finished = <schema>.log rows for the run_uid with date_end set, read over the route schema_consolidate.R uses (ssh → docker exec -i fresh-db psql). Output is framed by sentinels: no sentinels means unknown, never "nothing", because ssh can exit 0 whatever the remote command did.
    • The log is still read, anywhere on a line, and only adds: consolidate takes database ∪ log done, because .lnk_log_run_finish() is a soft UPDATE after persist and a lost LNK_RUN_UID leaves run_uid NULL. SKIP comes from the log alone; it writes no row.
  • A cloud host that may hold unconsolidated work is never burned, on any exit path.
    • Each cypher is held from dispatch. It is released only when it is settled (its dispatch session ended 0, recorded only after wait returns, and consolidate is not running) and, after consolidate, its database holds no group this run finished. consolidate deletes what it copied from the source, so this measures what was not consolidated.
    • What is left on a kept host is split: finished (database row, log done, or streams_mapping_code rows, which within a run only the final persist writes), partial (a group that failed after the pre-persist: never consolidated, does not hold the host), and unknown (rows that were there before dispatch, per a pre-dispatch baseline, or mapping-code rows with no baseline: they hold the host and are never recovered). On an unsettled host nothing is called partial.
    • A host whose database did not answer is left out of consolidate (it would sink the others) and kept.
    • Kept hosts, and hosts whose burn did not complete, are listed in <TS>_kept_hosts.tsv: reason, run_uid, schema, the three group sets, whether they were measured, and the commands that print the address and burn the host. The banner prints from the EXIT trap and says whether the recompute ran, and the run exits non-zero. --keep-cyphers alone is not a failure; a host it keeps for cause still is.
    • Pre-flight fails on a cypher droplet already up in this run's workspaces, which is most likely a host an earlier run kept.
    • CYPHERS_UP is set before the spin, so a failed spin of one workspace no longer exits with the others' droplets unburned.
  • The incomplete final line warning is gone from every group's log: cabd_blkey_xref.csv ends with a newline in all four bundles. Each bundle's config_hash moves (provenance, by operator call).
  • RUNBOOK §8d "Which host may be burned" carries the rules, including how to recover a kept host; the CLAUDE.md status fact is updated.

Evidence

  • tests/testthat/test-study_area_hosts.R: 120 expectations, run in bash ≥ 4 with stubbed ssh / psql / tofu / doctl and a mock cypher_down.sh. They include:

    • a host log with every done marker mid-line reports complete;
    • a host with a finished group left after consolidate is not burned, and a failed group's partial rows neither hold it nor get recovered;
    • a driver killed while waiting on a host, or during consolidate, reports the host unsettled;
    • an abort before dispatch burns everything, as before.

    They skip when data-raw/ is absent (R CMD check), and fail rather than skip without bash ≥ 4.

  • 26 mutants of the lib, each caught. The issue's "restore the anchored match", read as counting from the log with main's sed, fails 9 tests, including the mid-line fixture.

  • Live, local fwapg:

    • the finished probe returns 241 for run 20261017_004619-3f4c713b;
    • the remote half of the route returns both sentinels and 241 rows;
    • the baseline and mapping-code probes answer, and a missing table reads as unknown;
    • a --preflight-only run sources the lib and passes the doctl and droplet legs.

    The ssh leg to a live cypher was not run (it needs a paid spin).

  • devtools::test(): 3058 pass, 5 fail, none from this branch. Three need the :63333 tunnel, which was down; two are the golden dams count, which fails the same on clean main.

  • Review: a plan review and five /code-check rounds, 13 findings fixed. Every round from 2 on found a defect inside the previous fix, all one mechanism: a label on observed rows needs provenance and settledness. The loop ended by enumerating both (the two writers to a cypher after dispatch, the two sources of its rows, every printed label), not on a quiet round. Records are in planning/archive/2026-10-issue-347-host-completeness-db/.

Fixes #347.

Relates to NewGraphEnvironment/sred#24

🤖 Generated with Claude Code

https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx

NewGraphEnvironment and others added 11 commits October 17, 2026 10:32
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx
…nsolidated work (#347)

New data-raw/study_area_hosts.sh: host_finished reads <schema>.log for the
run_uid (date_end set), framed by sentinels so an unreachable host is
unknown rather than empty; host_log_reported matches markers anywhere on a
line (diagnosis and SKIP only); burn_cyphers burns only hosts not held and
records every kept host in ${TS}_kept_hosts.tsv. Tests run the lib in bash
with stubbed ssh/psql/tofu/doctl and a mock cypher_down.sh; five mutants,
all caught.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx
Completeness reads each host's database; consolidate takes database plus
log-done groups and leaves out a host whose database did not answer. A
cypher is held from dispatch and released only when its session exited 0
and, after consolidate, no streams rows are left on it for any group it ran
or finished. Held and failed-burn hosts are listed in ${TS}_kept_hosts.tsv
and the run exits non-zero. CYPHERS_UP is set before the spin so a failed
spin cannot leak droplets, and pre-flight fails on a cypher already up in
this run's workspaces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx
Every group's log carried an 'incomplete final line' warning from this
file. config_hash moves for each bundle; it is provenance, not a gate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx
#347)

From /code-check round 1. The kept-hosts file listed groups consolidate had
already taken, and recovering them would have deleted the dispatcher's copy.
--keep-cyphers no longer hides a host held for cause.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx
From /code-check round 2. A group that failed after the pre-persist leaves
streams rows; it was listed for recovery, which would have replaced the
dispatcher's copy with a broken one, and it held the host forever. Finished
now means database, log done, or streams_mapping_code rows (final persist
only); partial groups neither hold the host nor appear in the recover list.
Recovery now ends with a recompute. The lib declares every map it uses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx
#347)

From /code-check round 3. A host whose session has not ended 0 is
unsettled: its unfinished groups may still be building, so they are never
called partial. The recovery text says whether the recompute ran. A
pre-dispatch baseline keeps an image's mapping-code rows from counting as
this run's; with no baseline they hold the host and are never recovered.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx
…'s signals (#347)

From /code-check round 4's enumeration. A driver killed while waiting on a
host saw it settled; a trap report before accounting had no finish
signals; the baseline missed an image's mapping-code rows. A group with
rows from before dispatch and no finish signal is now unknown, never
partial.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx
… cause (#347)

From /code-check round 5. A driver killed during consolidate recorded
groups that consolidate was about to remove from the host. The two writes
the driver makes to a cypher after dispatch (the dispatch session and
schema_consolidate) are now both covered by the settledness rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WJE2szSCkeV9R3qKhuSwyx
@NewGraphEnvironment
NewGraphEnvironment merged commit 95f6d24 into main Oct 18, 2026
1 check passed
@NewGraphEnvironment
NewGraphEnvironment deleted the 347-study-area-run-sh-counts-finished-groups branch October 18, 2026 02:02
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.

study_area_run.sh counts finished groups from log text and burns hosts holding unconsolidated work

1 participant