Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
48457ba
feat(bin): record durable task usage so cleanup cannot erase attribution
GodKimba Sep 1, 2026
2cb4d82
docs(ledger): state the ledger contract once and cross-reference it e…
GodKimba Sep 1, 2026
0ffd6b3
no-mistakes(review): fix ledger status class, identity collision, and…
GodKimba Sep 1, 2026
8758d84
no-mistakes(review): harden ledger identity validation, status-class …
GodKimba Sep 1, 2026
cf07ff5
no-mistakes(review): size PR URL bound to the forge validator; split …
GodKimba Sep 1, 2026
aebb66a
no-mistakes(review): read status vocabulary from its owner; stop stat…
GodKimba Sep 1, 2026
7b4f6bc
no-mistakes(review): capture status class before home removal; widen …
GodKimba Sep 1, 2026
5e4233a
no-mistakes(review): record a remote endpoint's own backend, never th…
GodKimba Sep 1, 2026
3f7fd46
no-mistakes(document): correct stale ledger backend contract in archi…
GodKimba Sep 1, 2026
6b526f1
no-mistakes(ci): give the gotmp teardown fixture its ledger siblings
GodKimba Sep 1, 2026
7f0cea3
no-mistakes(ci): capture a retired mate's axes before its home is rem…
GodKimba Sep 1, 2026
3ca73fa
no-mistakes(ci): name a project the task record carries, never call i…
GodKimba Sep 1, 2026
ce010b9
no-mistakes(review): record unpinned remote axes; bound the ledger st…
GodKimba Sep 2, 2026
c357fed
no-mistakes(review): record a remote secondmate's own incarnation token
GodKimba Sep 2, 2026
9056a93
no-mistakes(review): mint an incarnation for Orca recovery records; c…
GodKimba Sep 2, 2026
8933cde
no-mistakes(test): qualify ledger seq guarantee with clock-regression…
GodKimba Sep 2, 2026
72d7760
no-mistakes(document): correct ledger call-site count in architecture…
GodKimba Sep 2, 2026
1a29c71
no-mistakes(ci): measure the ledger suite's serial shard weight
GodKimba Sep 2, 2026
99972b7
no-mistakes(document): order the task-usage ledger entry in AGENTS.md…
GodKimba Sep 2, 2026
669f994
no-mistakes(ci): rewrap the reconcile identity comment this branch le…
GodKimba Sep 2, 2026
bad0900
no-mistakes(ci): re-measure the ledger shard hint from green runs only
GodKimba Sep 2, 2026
1d95e9f
no-mistakes(ci): name the attestation-rebind remedy the gate check po…
GodKimba Sep 2, 2026
dc1bd19
no-mistakes(review): record the spawn usage row before the deferred-s…
GodKimba Sep 2, 2026
592aac6
no-mistakes(review): record the remote secondmate usage row before ar…
GodKimba Sep 2, 2026
f823bba
no-mistakes(review): pair every launch commit with its usage row
GodKimba Sep 2, 2026
d7baac9
no-mistakes(document): sync ledger call-site prose and serial shard t…
GodKimba Sep 2, 2026
9ddd2ac
no-mistakes(lint): quote two literal test ids to clear SC2100
GodKimba Sep 2, 2026
ac1c0ae
no-mistakes(ci): point the ledger header's lifecycle reference at its…
GodKimba Sep 2, 2026
d7efb48
no-mistakes(ci): state the shard headroom for the partition this doc …
GodKimba Sep 2, 2026
1941ebb
fix(bin): record every task a forced retirement discards
GodKimba Sep 2, 2026
ba227d4
no-mistakes(review): qualify ledger sweep survival claim for remote r…
GodKimba Sep 2, 2026
4eeedc2
no-mistakes(document): correct remote-leg ledger survival wording in …
GodKimba Sep 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ data/ personal fleet records; LOCAL, gitignored as a whole
learnings.md fleet-local operational facts and gotchas; LOCAL, gitignored; dated, evidence-backed, curated, and updated with inspect-then-update - rewrite and prune rather than append forever, the same contract as captain.md; created lazily, absent until this home has a learning to store
projects.md thin fleet navigation registry recording each project's standing delivery posture; firstmate-private, parsed for mechanical sync and seeding by fm-project-mode.sh (section 6)
secondmates.md local and remote secondmate routing table; firstmate-private, maintained by the secondmate seed helpers (section 6)
task-usage.jsonl durable append-only record of the harness, model, and workflow behind each task outcome; firstmate-private, never read by supervision, and owned end to end by bin/fm-usage-ledger.sh
<id>/brief.md per-task crewmate brief, or per-secondmate charter brief when kind=secondmate
<id>/report.md scout task deliverable, written by the crewmate; survives teardown
projects/ cloned repos; gitignored; read-only except under hard rule 1's concrete captain-approved project operation exception
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Pushing through it runs an AI-driven review/test/lint pipeline in an isolated wo

A GitHub Actions check (`Require no-mistakes`) runs on PRs targeting `main` and requires both the deterministic signature and a parseable structured attestation from no-mistakes v1.46.0 or newer.
The attestation must bind to the current PR head commit and report the review, test, and document steps as completed, so a stale attestation, a missing `head_sha`, or a skipped required step fails.
Because that binding is to one commit, any later commit leaves the check red - including a fix the pipeline itself commits after writing the attestation - so re-push with `git push no-mistakes` to bind a fresh attestation to the new head instead of editing the PR body by hand.
It evaluates every PR opening and body edit independently, reruns after head synchronization or reopening, and prevents a later edit from replacing an earlier pending compliance check.
GitHub Actions and Dependabot are exempt so their automation keeps working, but other contributor PRs that do not satisfy the attestation contract will not be reviewed or merged.

Expand Down
9 changes: 9 additions & 0 deletions bin/fm-merge-local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,19 @@
# auto-approves), and only as a clean fast-forward - it refuses a diverged branch
# and tells you to have the crewmate rebase. See AGENTS.md prime directives,
# project management, and task lifecycle.
# A confirmed landing also appends the landed commit to this home's durable
# task-usage ledger, so a local-only outcome is joinable to the harness and
# model that produced it; bin/fm-usage-ledger.sh owns that schema.
# Usage: fm-merge-local.sh <task-id>
set -eu

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
FM_ROOT="${FM_ROOT_OVERRIDE:-$(cd "$SCRIPT_DIR/.." && pwd)}"
FM_HOME="${FM_HOME:-${FM_ROOT_OVERRIDE:-$FM_ROOT}}"
STATE="${FM_STATE_OVERRIDE:-$FM_HOME/state}"
DATA="${FM_DATA_OVERRIDE:-$FM_HOME/data}"
# shellcheck source=bin/fm-usage-ledger-lib.sh
. "$SCRIPT_DIR/fm-usage-ledger-lib.sh"
"$FM_ROOT/bin/fm-guard.sh" || true
# Role partition: landing local-only work is MAIN-owned; the Pi supervision
# branch reports readiness and never lands (contract: bin/fm-lease-lib.sh;
Expand Down Expand Up @@ -71,4 +77,7 @@ fi
before=$(git -C "$PROJ" rev-parse --short "$DEFAULT")
git -C "$PROJ" merge --ff-only "$BRANCH" >/dev/null
after=$(git -C "$PROJ" rev-parse --short "$DEFAULT")
LANDED=$(git -C "$PROJ" rev-parse "$DEFAULT")
fm_usage_ledger_record "$FM_HOME" "$STATE" "$DATA" merge "$ID" \
--meta "$META" --landing "$LANDED" --outcome merged
echo "merged $BRANCH into local $DEFAULT ($before -> $after) in $PROJ"
12 changes: 12 additions & 0 deletions bin/fm-merge-outcome-lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
# is committed, so a failed commit stays eligible for at-least-once retry and
# may rarely duplicate rather than leave a merge silent.
#
# A confirmed merge is also appended to this home's durable task-usage ledger
# before the marker is committed, so an ordinary teardown cannot later erase the
# only link between the landed PR and the harness and model that produced it.
# bin/fm-usage-ledger.sh owns that schema and bin/fm-usage-ledger-lib.sh owns the
# rule that a failed ledger write never turns a landed merge into a failure.
#
# Sourced by bin/fm-pr-merge.sh, bin/fm-watch.sh, and tests. No side effects on
# source beyond its sourced libraries.

Expand All @@ -31,6 +37,8 @@ _FM_MERGE_OUTCOME_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
. "$_FM_MERGE_OUTCOME_LIB_DIR/fm-pr-lib.sh"
# shellcheck source=bin/fm-secondmate-parent-lib.sh
. "$_FM_MERGE_OUTCOME_LIB_DIR/fm-secondmate-parent-lib.sh"
# shellcheck source=bin/fm-usage-ledger-lib.sh
. "$_FM_MERGE_OUTCOME_LIB_DIR/fm-usage-ledger-lib.sh"

# The secondmate identity of the home reporting, or non-zero when this home is
# a main home (1) or carries an unusable identity marker (2). Mirrors
Expand Down Expand Up @@ -130,6 +138,10 @@ fm_merge_outcome_report() { # <home> <state> <task-id> <pr-url> <origin>
"check: merge landed: $id $FM_PR_URL" || status=1
fi
if [ "$status" -eq 0 ]; then
# Both origins land here, so a merge this home performed and a merge its
# poll detected leave the same durable usage record.
fm_usage_ledger_record "$home" "$state" "${FM_DATA_OVERRIDE:-$home/data}" \
merge "$id" --meta "$state/$id.meta" --pr "$FM_PR_URL" --outcome merged
fm_pr_poll_merge_mark_notified "$state" "$id" \
"$provider" "$host" "$path" "$number" || status=1
fi
Expand Down
12 changes: 12 additions & 0 deletions bin/fm-pr-check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,24 @@
# live only in a private sidecar and are never interpolated into shell source.
# A GitHub pull request URL and a GitLab merge request URL are both accepted,
# including a merge request on a self-hosted GitLab instance.
# After the poll is published, the PR's identity is also appended to this home's
# durable task-usage ledger, so the outcome can later be joined to the harness
# and model that produced it; bin/fm-usage-ledger.sh owns that schema.
# Usage: fm-pr-check.sh <task-id> <pr-url>
set -eu

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
FM_ROOT="${FM_ROOT_OVERRIDE:-$(cd "$SCRIPT_DIR/.." && pwd)}"
FM_HOME="${FM_HOME:-${FM_ROOT_OVERRIDE:-$FM_ROOT}}"
STATE="${FM_STATE_OVERRIDE:-$FM_HOME/state}"
DATA="${FM_DATA_OVERRIDE:-$FM_HOME/data}"

# shellcheck source=bin/fm-pr-lib.sh
. "$SCRIPT_DIR/fm-pr-lib.sh"
# shellcheck source=bin/fm-wake-lib.sh
. "$SCRIPT_DIR/fm-wake-lib.sh"
# shellcheck source=bin/fm-usage-ledger-lib.sh
. "$SCRIPT_DIR/fm-usage-ledger-lib.sh"

if [ "$#" -ne 2 ]; then
echo "error: invalid PR check request" >&2
Expand Down Expand Up @@ -132,4 +138,10 @@ fm_pr_poll_publish_prepared || {
echo "error: could not publish PR poll" >&2
exit 1
}
# The meta now carries the canonical pr= (and pr_head= when the forge supplied
# one), so the ledger reads this task's axes and PR identity from one source.
PR_HEAD_ARGS=()
[ -z "$PR_HEAD" ] || PR_HEAD_ARGS=(--pr-head "$PR_HEAD")
fm_usage_ledger_record "$FM_HOME" "$STATE" "$DATA" pr "$ID" \
--meta "$META" --pr "$URL" "${PR_HEAD_ARGS[@]+"${PR_HEAD_ARGS[@]}"}"
printf 'armed: state/%s.check.sh\n' "$ID"
27 changes: 14 additions & 13 deletions bin/fm-secondmate-reconcile.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@
# fm-send under its final route lock, and before the cooldown commit so a retired
# endpoint is never nudged or allowed to silence its replacement.
#
# A persistent REMOTE secondmate's parent-side metadata intentionally has no
# spawn_gen (docs/remote-secondmates.md). Such a row is legitimate and markerless
# by construction, not corrupt, so it uses its sampled remote_host as the separate
# identity guard. The current metadata must still have no spawn_gen and must still
# name that host. A row with neither identity fails loudly.
# A persistent REMOTE secondmate route seeded before its parent-side metadata
# carried a spawn_gen has none (docs/remote-secondmates.md). Such a row is
# legitimate and markerless, not corrupt, so it uses its sampled remote_host as
# the separate identity guard. The current metadata must still have no spawn_gen
# and must still name that host. A row with neither identity fails loudly.
#
# Notify exits 0 when no delivery or cooldown-recording failure is known,
# including when a home was skipped for lock contention or a stale endpoint;
Expand Down Expand Up @@ -164,9 +164,10 @@ meta_remote_host() {
# Confirms the row's sampled identity still matches the mate's current
# metadata. When a spawn generation was sampled, that generation alone is the
# identity, exactly as before. When none was sampled - the only legitimate
# case is a persistent remote secondmate, whose parent metadata never carries
# one - the sampled host substitutes, and the metadata must still carry no
# spawn_gen of its own or the row's assumed identity model no longer holds.
# case is a persistent remote secondmate route seeded before its parent
# metadata carried one - the sampled host substitutes, and the metadata must
# still carry no spawn_gen of its own or the row's assumed identity model no
# longer holds.
# Sets REVALIDATE_REASON to "no-identity" (nothing here can be safely
# identified; report failed) or "stale" (identified, but changed; report
# stale) on any non-zero return.
Expand Down Expand Up @@ -430,11 +431,11 @@ cmd_notify() {

# Only a real inventory mismatch is a books problem the mate can fix; every
# other invalidity is either unreadable state or nothing to reconcile.
# spawn_gen is empty only for a persistent remote secondmate, whose parent
# metadata never carries one (bin/fm-spawn.sh's spawn_remote_secondmate());
# host is its substitute identity there and is otherwise unused. Both are
# still character-restricted so a malformed sample cannot masquerade as
# either a live incarnation token or a live host.
# spawn_gen is empty only for a persistent remote secondmate route seeded
# before its parent metadata carried one; host is its substitute identity
# there and is otherwise unused. Both are still character-restricted so a
# malformed sample cannot masquerade as either a live incarnation token or
# a live host.
#
# Rows join on ASCII unit separator (0x1F), not @tsv: bash's IFS-whitespace
# `read` collapses consecutive tabs, which would silently drop a
Expand Down
74 changes: 69 additions & 5 deletions bin/fm-spawn.sh
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,12 @@
# success line and state/<id>.meta omit them.
# Every fresh spawn or relaunch records a new spawn_gen= incarnation token so durable
# consumers can distinguish a replacement worker that reuses the same task id.
# A launch appends this incarnation's durable usage record
# (bin/fm-usage-ledger.sh; call policy in bin/fm-usage-ledger-lib.sh) as soon as
# its task record is committed beyond rollback, so a launch that afterwards
# fails or is interrupted while leaving that record and its worker in place is
# recorded exactly like an uninterrupted one; a dispatch whose record was rolled
# back appends nothing.
# When the home session's frozen trace-context decision is enabled (see
# docs/configuration.md and bin/fm-trace-context-lib.sh), the meta also records
# one W3C traceparent= carrier, the same value injected into the pane as
Expand Down Expand Up @@ -303,6 +309,8 @@ fm_backlog_directory_present "$STATE" "state directory" || {
. "$SCRIPT_DIR/fm-trace-context-lib.sh"
# shellcheck source=bin/fm-remote-readiness-lib.sh
. "$SCRIPT_DIR/fm-remote-readiness-lib.sh"
# shellcheck source=bin/fm-usage-ledger-lib.sh
. "$SCRIPT_DIR/fm-usage-ledger-lib.sh"
# Fail closed before any fleet mutation: a no-mistakes gate agent must never spawn
# a direct report (see bin/fm-gate-refuse-lib.sh).
fm_refuse_if_gate_agent
Expand Down Expand Up @@ -442,7 +450,7 @@ fi
spawn_remote_secondmate() {
local id=$1 remote host root home harness positional model effort backend out rc meta tmp
local remote_backend remote_target remote_harness remote_herdr_session registry_lock remote_lock remote_generation
local remote_traceparent remote_recorded_traceparent
local remote_traceparent remote_recorded_traceparent recorded_model recorded_effort
local -a launch_args
id=${POS[0]:-}
fm_task_id_creation_valid "$id" || { echo "error: invalid task id" >&2; return 2; }
Expand Down Expand Up @@ -649,6 +657,11 @@ spawn_remote_secondmate() {
# reports it here so the parent does not deny the agent's actual identity.
remote_recorded_traceparent=$(printf '%s\n' "$out" | sed -n 's/^traceparent=//p' | tail -1)
fm_trace_context_valid "$remote_recorded_traceparent" || remote_recorded_traceparent=
# "-" is the launch wire protocol's unpinned sentinel; the task record states
# an unpinned axis as "default", the same value fm-spawn's local task-record
# writer records for it.
recorded_model=${model#-}
recorded_effort=${effort#-}
tmp="$meta.tmp.$$"
{
echo "window=remote:$id"
Expand All @@ -660,8 +673,9 @@ spawn_remote_secondmate() {
echo "mode=secondmate"
echo "yolo=off"
echo "tasktmp="
echo "model=${model#-}"
echo "effort=${effort#-}"
echo "model=${recorded_model:-default}"
echo "effort=${recorded_effort:-default}"
echo "spawn_gen=$remote_generation"
echo "home=$home"
echo "projects=$(secondmate_registry_field "$DATA/secondmates.md" "$id" projects)"
echo "remote_host=$host"
Expand Down Expand Up @@ -689,6 +703,13 @@ spawn_remote_secondmate() {
fm_lock_release "$remote_lock" || true
fm_lock_release "$registry_lock" || true
fm_lock_release "$SPAWN_TASK_LOCK" || true
# A remote secondmate's task record is owned by this home, so its usage row
# belongs in this home's ledger too. It is written here, past the publication
# that committed that record and before every step below that can still fail
# while leaving the launched agent and its record in place, so an agent this
# home preserves is never invisible. Its incarnation is the inheritance
# generation this launch minted, so relaunching the same id is its own row.
fm_usage_ledger_record "$FM_HOME" "$STATE" "$DATA" spawn "$id" --meta "$meta"
"$SCRIPT_DIR/fm-home-summary-refresh.sh" --best-effort || true
if ! "$SCRIPT_DIR/fm-procevent-remote-reply.sh" arm "$id" >/dev/null; then
echo "error: remote secondmate $id launched, but its reply source could not be armed; endpoint metadata is preserved" >&2
Expand All @@ -699,6 +720,10 @@ spawn_remote_secondmate() {
}

BACKEND=
# This process's incarnation token, minted once so every task record it
# publishes - the ordinary launch and the Orca cleanup-recovery record written
# from the abort path below - names the same incarnation.
SPAWN_GEN="s$(date +%s).${BASHPID:-$$}.$RANDOM"
ORCA_ABORT_CLEANUP=0
ORCA_WORKTREE_ID=
ORCA_TERMINAL=
Expand All @@ -718,6 +743,7 @@ SPAWN_META_LOCK=
SPAWN_META_LOCK_HELD=0
SPAWN_META_PUBLISH_STARTED=0
SPAWN_FRESH_COMMIT_PENDING=0
SPAWN_USAGE_ROW_RECORDED=0
SPAWN_TASK_SET_LOCK=
SPAWN_TASK_SET_LOCK_HELD=0
RELAUNCH_REPLACEMENT_PENDING=0
Expand Down Expand Up @@ -814,6 +840,10 @@ spawn_abort_cleanup() {
fi
mkdir -p "$STATE" 2>/dev/null || true
if [ -d "$STATE" ]; then
# This record exists BECAUSE the launch was abandoned and its Orca
# worktree survived, so it deliberately gets no spawn usage row: a row
# here would assert a worker that never ran. The ledger's spawn rows
# are written only past a commit point that a real launch reached.
SPAWN_META_TMP="$STATE/.$ID.meta.orca-recovery.${BASHPID:-$$}"
{
echo "window=$W"
Expand All @@ -828,6 +858,7 @@ spawn_abort_cleanup() {
echo "tasktmp=${TASK_TMP:-}"
echo "model=${MODEL:-default}"
echo "effort=${EFFORT:-default}"
echo "spawn_gen=$SPAWN_GEN"
echo "backend=orca"
echo "orca_worktree_id=$ORCA_WORKTREE_ID"
[ -z "${ORCA_TERMINAL:-}" ] || echo "terminal=$ORCA_TERMINAL"
Expand Down Expand Up @@ -2829,7 +2860,6 @@ fi

META_WINDOW=$T
[ "$BACKEND" = orca ] && META_WINDOW=$W
SPAWN_GEN="s$(date +%s).${BASHPID:-$$}.$RANDOM"
SPAWN_META_PATH="$STATE/$ID.meta"
if [ "$SPAWN_META_LOCK_HELD" != 1 ]; then
SPAWN_META_LOCK=$(fm_meta_lock_path "$STATE/$ID.meta") || exit 1
Expand Down Expand Up @@ -2922,6 +2952,24 @@ spawn_commit_backlog_transition() {
fm_backlog_atomic_transition dispatch "$STATE/$ID.meta" "$DATA" "$ID" "$STATE"
}

# The single owner of this incarnation's durable usage row, called as the
# statement immediately after each point that leaves a launch's task record
# committed beyond rollback, so no code can sit between a commit and its row for
# a later early return, signal exit, or error path to slip into. Recording twice
# is a no-op, so the two local commit points - a relaunch's replacement
# publication and a fresh spawn's fused In-flight transition - yield exactly one
# row per incarnation, and a relaunch mints a new spawn_gen so its replacement
# worker is its own row. It reaches every harness and every spawn-capable
# backend because the single-task path is the one place all of them converge,
# and a batch re-execs that path once per pair. Never gates the lifecycle: the
# call policy in bin/fm-usage-ledger-lib.sh warns and returns 0.
spawn_record_usage_row() {
[ "$SPAWN_USAGE_ROW_RECORDED" = 0 ] || return 0
SPAWN_USAGE_ROW_RECORDED=1
fm_usage_ledger_record "$FM_HOME" "$STATE" "$DATA" spawn "$ID" \
--meta "$STATE/$ID.meta"
}

if [ "$RELAUNCH" -eq 1 ]; then
SPAWN_META_PUBLISH_STARTED=1
if ! fm_backlog_atomic_transition publish "$SPAWN_META_TMP" "$STATE/$ID.meta" "task record" "$STATE"; then
Expand All @@ -2931,6 +2979,10 @@ if [ "$RELAUNCH" -eq 1 ]; then
RELAUNCH_REPLACEMENT_PENDING=0
SPAWN_META_PUBLISH_STARTED=0
SPAWN_META_TMP=
# Nothing rolls a replacement record or its busy generation back from here, so
# this is where the relaunch's record becomes permanent and every later exit
# leaves a live replacement worker behind.
spawn_record_usage_row
fi
# A dispatch or relaunch keeps the per-task meta lock through launch delivery.
# The backlog mutation is deliberately the final fallible commit below, so
Expand Down Expand Up @@ -3018,6 +3070,10 @@ spawn_record_traceparent() {
SPAWN_META_LOCK_HELD=1
acquired=1
fi
# This publication updates a record that already exists rather than creating
# an incarnation, so it deliberately gets no usage row of its own: the launch
# it belongs to records once at its own commit point, and a second row here
# would double-count one incarnation.
SPAWN_META_TMP="$STATE/.$ID.meta.trace.${BASHPID:-$$}"
if [ ! -f "$meta" ] || [ ! -w "$meta" ] \
|| ! awk -F= '$1 != "traceparent"' "$meta" > "$SPAWN_META_TMP" \
Expand Down Expand Up @@ -3136,8 +3192,16 @@ trap - HUP INT TERM
if [ "$SPAWN_BACKLOG_COMMIT_STATUS" -ne 0 ]; then
exit "$SPAWN_BACKLOG_COMMIT_STATUS"
fi
fm_lock_release "$SPAWN_META_LOCK"
fm_lock_release "$SPAWN_META_LOCK" || true
SPAWN_META_LOCK_HELD=0
# A fresh spawn's record becomes permanent here and not at its publication: a
# failed or rolled-back dispatch has already exited above, and every earlier
# launch-delivery failure unwound the provisional record, so this is the first
# point at which a fresh launch is committed. The release above is deliberately
# non-fatal so nothing can exit between that commit and the row, and the row
# stays outside the meta lock so a slow ledger cannot hold a lifecycle lock.
spawn_record_usage_row

if [ -n "$SPAWN_DEFERRED_SIGNAL" ]; then
case "$SPAWN_DEFERRED_SIGNAL" in
HUP) SPAWN_DEFERRED_SIGNAL_STATUS=129 ;;
Expand Down
Loading
Loading