Skip to content
Merged
3 changes: 3 additions & 0 deletions .agents/skills/operational-home-layout/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ config/herdr-lifecycle-spawn-guard optional presence flag opting this home into
config/fleet-ledger optional presence flag opting this home in to the default-off fleet activity ledger state/fleet-ledger.jsonl that outside tools can follow; LOCAL, gitignored, and not inherited; see docs/fleet-ledger.md
config/firstmate-role optional LOCAL, gitignored firstmate-repository publication role; see docs/configuration.md "Firstmate role" for operator opt-in and secondmate inheritance
config/wait-no-turns optional presence flag opting this home into default-off waiting-worker behavior (brief waiting section, foreground pipeline drive, pending-reply hold, one fire-and-forget retry ring); LOCAL, gitignored, and not inherited; see docs/configuration.md "Waiting worker spends no turns"
config/pr-health-monitor optional presence flag opting this home into the default-off monitor of its owned PRs, which wakes once per condition per latest commit on a definite merge conflict or a failing required check and never changes a PR; LOCAL, gitignored, and not inherited; see docs/configuration.md "PR health monitor"
config/pipeline-spend optional presence flag opting this home in to default-off per-task no-mistakes spend recording in data/pipeline-spend.jsonl; LOCAL, gitignored, and not inherited; see docs/configuration.md "No-mistakes pipeline spend"
config/nm-home-resolver optional one-line absolute path of a site-provided executable that maps a task copy to its no-mistakes home for host-side reads when NM_HOME is unset; LOCAL, gitignored, and not inherited; see docs/configuration.md "No-mistakes home resolver"
config/ready-after-green optional presence flag opting this home into default-off withholding of a secondmate's PR-ready parent line until the child reports checks green; LOCAL, gitignored, and not inherited; see docs/configuration.md "PR-ready line after green"
Expand Down Expand Up @@ -106,6 +107,8 @@ state/ runtime records and signals; gitignored
mail.check.sh generated received-mail poll shim and its .check-trust binding; present only after bin/fm-mail-check.sh arm; report record .mail-check (mail schema: docs/configuration.md "Mail plane")
.mail-seen .mail-woken .mail-retry .mail-retry-pos .mail-turn .mail-seen.lock mail-plane poll cursor, emission journal, transient-fetch retry set, retry-scan position, contended-slot turn flag, and overlapping-poll lock; written only by bin/fm-mail.sh (mail schema: docs/configuration.md "Mail plane")
startup-growth.check.sh generated daily startup-growth poll shim and its .check-trust binding; present only after bin/fm-startup-growth-check.sh arm; its record .startup-growth-check holds the daily gate, the per-file growth baselines, and the last reported finding set, so removing it re-baselines growth silently and repeats a standing finding such as a budget overrun once (docs/configuration.md "Daily startup growth check")
pr-health.check.sh generated owned-PR health poll shim and its .check-trust binding; present only after bin/fm-pr-health.sh arm, which config/pr-health-monitor gates (docs/configuration.md "PR health monitor")
pr-health.json the health monitor's fm-pr-health.v1 record: per-PR fingerprints of the conditions already reported and the task branch-to-PR lookup cache, replaced by rename under .pr-health.lock; bin/fm-pr-health.sh owns the format
pending-replies/ parent-owned secondmate pending-reply records (correlation id, delivery vs reply, recovery, escalation); fm-pending-reply-lib.sh
procevent/ registered process-to-event sources, one private record per canonical source id; written only by bin/fm-procevent.sh, and their presence alone keeps supervision required (`process-event-sources` skill)
procevent-inbox/ private captured results and their durable handled-acknowledgement markers; source output lives here and never in an event line
Expand Down
5 changes: 5 additions & 0 deletions bin/fm-bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1664,6 +1664,11 @@ if [ "${FM_BOOTSTRAP_DETECT_ONLY:-0}" != 1 ]; then
"$SCRIPT_DIR/fm-contributions.sh" arm --if-owned >/dev/null \
|| echo "MISSING: contribution observation could not be armed; coverage is unconfirmed"
fi
if local_phase && [ -e "$CONFIG/pr-health-monitor" ] && command -v jq >/dev/null 2>&1 \
&& [ -d "$DATA" ] && [ -x "$SCRIPT_DIR/fm-pr-health.sh" ]; then
"$SCRIPT_DIR/fm-pr-health.sh" arm >/dev/null \
|| echo "MISSING: the PR health monitor could not be armed; owned PRs are not watched"
fi
if [ -n "$fleet_sync_pid" ]; then
wait "$fleet_sync_pid" || true
cat "$fleet_sync_out"
Expand Down
37 changes: 35 additions & 2 deletions bin/fm-contributions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,22 @@
# fm-contributions.sh ack <task> <url> <event-token>
# fm-contributions.sh retire <task> <url> captain <reason>
# fm-contributions.sh arm [--if-owned]
# fm-contributions.sh owned
# fm-contributions.sh enroll <task> <pr-url>
#
# snapshot is read-only and never contacts a forge. Its input is the canonical
# fleet snapshot's backlog/tasks pair; --all adds rows for supervisor inspection.
# URLs accepted by canonical_url in fm-contributions.jq and explicitly linked
# by a structured backlog row or a task's pr= are owned.
# Previously observed URLs remain in data/<task>/contributions.json after
# endpoint teardown. Repository-wide PR discovery never establishes ownership.
# Previously observed or enrolled URLs remain in data/<task>/contributions.json
# after endpoint teardown. Repository-wide PR discovery never establishes ownership.
# enroll records one task's supported PR URL as an unobserved record, so a PR
# the task opened is owned before any pr= exists; it changes nothing when the
# task already has a record for that URL and fails when that record is
# retired, so a retirement is never undone by rediscovery.
# owned prints the supported PR URLs this home owns as a JSON array of
# {url,tasks,final}, where final means a saved observation is merged or closed.
# It is read-only and never contacts a forge.
# Only canonical PR and issue URLs on the exact github.com host are supported;
# other accepted URLs remain visibly unmeasured.
# poll skips unsupported URLs without forge calls, unavailable output, wakes or
Expand Down Expand Up @@ -675,6 +684,30 @@ case "${1:-}" in
;;
poll) poll ;;
arm) arm "${2:-}" ;;
owned)
get_input; read_saved
[ "$ERRORS" -eq 0 ] || fail "$ERRORS unreadable contribution record(s); ownership is unverified"
jq_lib -n --slurpfile input "$TMP/input.json" --slurpfile saved "$TMP/saved.json" '
[$saved[0][] | .records[] | select(.error == null and (.observation.state | IN("merged","closed"))) | .url] as $final
| known($input[0];$saved[0]) | map(select((.url | supported_url) and (.url | contains("/pull/"))))
| group_by(.url) | map({url:.[0].url,tasks:(map(.task) | unique),final:(.[0].url | IN($final[]))})'
;;
enroll)
[ "$#" -eq 3 ] || fail 'enroll needs a task and a PR URL'
task=$2; url=$3
fm_pr_task_id_valid "$task" || fail 'invalid contribution task'
jq_lib -ne --arg url "$url" '$url | supported_url and contains("/pull/")' >/dev/null \
|| fail 'enroll needs a canonical github.com PR URL'
acquire; read_saved
[ "$ERRORS" -eq 0 ] || fail "$ERRORS unreadable contribution record(s); enrollment is unverified"
if jq -e --arg task "$task" --arg url "$url" 'any(.[] | select(.task == $task) | .records[]; .url == $url and .retired != null)' "$TMP/saved.json" >/dev/null; then
fail 'contribution is retired for this task; enrollment refused'
fi
if ! jq -e --arg task "$task" --arg url "$url" 'any(.[] | select(.task == $task) | .records[]; .url == $url)' "$TMP/saved.json" >/dev/null; then
jq -n --arg url "$url" '{url:$url,kind:"pr",checked_at:null,error:null,observation:null,verdict:null,seen:[],pending:[],notified:[]}' > "$TMP/row.json"
write_record "$task" "$TMP/row.json"
fi
;;
pending)
read_saved
[ "$ERRORS" -eq 0 ] || fail "$ERRORS unreadable contribution record(s); pending signals are unverified"
Expand Down
Loading
Loading