Fleet changelogs · dev.ecs0.net
rdmsm4x-changelog-20260901-1831-project-state-v1.3-gate-scope-and-resume-dispatcher

rdmsm4x — project-state hook v1.3 (dirty-tree gate scope) + resume re-pin

The hook's own Stop reminder fired on a clean project; the gate behind it was counting the whole repository instead of the project, and has been scoped and redeployed to all six hosts.

Window: 2026-09-01 18:27 – 18:35 EDT · Host: rdmsm4x · Author: claude@rdmsm4x

1. What changed

scope file from → to
all six hosts ~/dev/fleet/ops/project-state/project_state_hook.py v1.2 00c0ca0031bd → v1.3 1163565b2e99
rdmsm4x ~/dev/fleet/ops/resume/PINNED-SESSION-fleetcc re-pinned, stale first-action removed
rdmsm4x ops/project-state/{SESSION-STATE.md,README.md} v1.3 sections added

Commits in ~/dev/fleet: 85493fc (re-pin), 1282dff (v1.3).

2. The defect

tree_changed() gates the Stop reminder so it only fires when the project actually changed. It ran:

git -C <proj> status --porcelain

git status reports the whole repository. -C sets the working directory; it does not scope the report. Every project nested inside ~/dev/fleet — a repo six agents write concurrently — therefore read as "changed" permanently.

Measured: ~/dev/fleet 292 dirty entries, ~/dev/fleet/ops/project-state 0. The gate said 292 and nagged about a clean project.

Fix: pass the project as a pathspec — git -C <proj> status --porcelain -- <proj>.

3. Verification

Both directions, because a gate whose failure mode is silence needs the negative case proven:

project dirty lines fires? expected
portfolio-consolidation (untouched) 0 no no
ops/project-state (hook edited this turn) 1 yes yes
ops/resume (another agent in flight) 15 yes yes

Before the fix all three returned 292. Deployment verified by sha on each host, not by exit code: all six report 1163565b2e99.

4. The pattern this is the third instance of

claimed to measure actually measured
wedged syspolicyd (2026-08-31) daemon health CPU% — 0.0%, healthy-looking because wedged
hook v1.1 (2026-08-31) project containing the marker marker's grandparent, truncated to depth 2
hook v1.2 (2026-09-01) this project's dirty files the entire repository's dirty files

All three returned a plausible value. All three were caught by the thing they were breaking, not by a test. A boolean cannot detect this class — record counts.

5. Resume path (informational, changed by a peer)

com.eastcoastscience.claude-resume-fleetcc was retired today under ISSUE-20260831-21 and moved to ops/resume/archive/launchagents-retired-20260901/ — nothing deleted. One agent, com.eastcoastscience.resume-dispatcher, now reads pins.d/30-fleetcc.pin, which points at PINNED-SESSION-fleetcc. Verified independently before relying on it: plist archived, dispatcher loaded, pin resolves, dispatcher.log shows five correct skips of this session by id.

The pin's own text was stale — it still named a checklist that ran this morning as FIRST ACTION ON RESUME. Rewritten. --status --dry-run after the edit still parses it.

Peer stated this session is "third of three under the cap", implying it is marginal. From the 18:19 run (dispatched=3 capped=2 live=11), the cap counts actual dispatches, not enumerated pins — eleven live sessions skipped without consuming a slot. At a cold boot priority 30 is inside the cap. Correction sent back.

6. How to undo

cd ~/dev/fleet && git revert 1282dff 85493fc

then redeploy the reverted project_state_hook.py to the five spokes the same way (base64 over ssh, verify sha per host). v1.2 backup for this host is in the session scratchpad only — the git history is the durable copy.

7. Outstanding, unchanged, none blocking

OPEN-4 (rdmsm4x LAN path; mitigated by a REMOVE-ME .local→Tailscale block in ~/.ssh/config), OPEN-2 for the four unrebooted spokes, OPEN-3, ISSUE-20260831-19 (why syspolicyd wedged — if it recurs, capture spindump <pid> BEFORE restarting the daemon). All are Rich's calls.