Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -410,8 +410,8 @@ jobs:
bearings_output=$(/bin/bash tests/fm-bearings-snapshot.test.sh)
printf '%s\n' "$bearings_output"
bearings_count=$(printf '%s\n' "$bearings_output" | grep -c '^ok - ')
[ "$bearings_count" -eq 42 ] || {
echo "::error::expected 42 Bearings tests, got $bearings_count"
[ "$bearings_count" -eq 45 ] || {
echo "::error::expected 45 Bearings tests, got $bearings_count"
exit 1
}

Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ __pycache__/
# Captain-private local operating choices; never published. Anchored to the
# repo root so a config-named directory elsewhere in the tree stays visible.
/config/
# Phone-bridge passcode hash, sessions, and logs. Mode 0700 at runtime; never publish.
/bridge/
# Generated per-task hook artifacts (also written into each task worktree's
# .git/info/exclude by fm-spawn). Tracked here so a primary checkout cannot
# accidentally stage them into a PR.
Expand Down
30 changes: 26 additions & 4 deletions bin/fm-bearings-snapshot.sh
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,15 @@
# --all-recorded-prs include every locally recorded PR
# --all-unhealthy include every unhealthy endpoint
# --all-pr-repos query every discovered repository under --include-prs
# --passive-view named read-only observation for the phone bridge page;
# skips the away-mode return guard so a refresh still works
# while the captain is away. Ordinary Bearings chat still
# calls the guard. Refuses --include-prs (local-only).
# -h,--help usage
#
# Output contract: `fm-bearings.v1`. Read-only; no locks, no mutation, no reports.
# in_flight rows include a captain-facing `title` (backlog title, else a
# non-id fallback). `doing` remains the internal current-state detail.
set -u

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
Expand Down Expand Up @@ -103,7 +109,8 @@ validate_bound FM_BEARINGS_PR_LIMIT "$FM_BEARINGS_PR_LIMIT"

usage() {
cat <<'EOF'
usage: fm-bearings-snapshot.sh [--json] [--include-prs] [--fields <list>]
usage: fm-bearings-snapshot.sh [--json] [--include-prs] [--passive-view]
[--fields <list>]
[--all-in-flight] [--all-decisions]
[--all-secondmates] [--all-landed]
[--all-reports] [--all-queued]
Expand All @@ -112,8 +119,10 @@ usage: fm-bearings-snapshot.sh [--json] [--include-prs] [--fields <list>]

Compact bearings projection over fm-fleet-snapshot.sh. TOON by default.
Default is LOCAL-ONLY (no network); --include-prs is the only path that fetches.
--passive-view is the named away-mode exception for the phone bridge page;
ordinary invocations still refuse while away mode is on.

Default fields: schema, home, generated, prs, in_flight{id,kind,state,doing},
Default fields: schema, home, generated, prs, in_flight{id,kind,state,title,doing},
secondmates{id,state,doing,provenance,freshness,age_seconds,contradiction,reason},
decisions_open{id,key,verb,summary,owner}, landed{id,what,artifact,owner},
gates{id,title,blocked_by,reason,owner}, reports{id,path}, recorded_prs{id,url},
Expand Down Expand Up @@ -147,11 +156,13 @@ ALL_LANDED=0
ALL_RECORDED_PRS=0
ALL_UNHEALTHY=0
ALL_PR_REPOS=0
PASSIVE_VIEW=0
FIELDS=""
while [ $# -gt 0 ]; do
case "$1" in
--json) FORMAT=json ;;
--include-prs) INCLUDE_PRS=1 ;;
--passive-view) PASSIVE_VIEW=1 ;;
--all-reports) ALL_REPORTS=1 ;;
--all-queued) ALL_QUEUED=1 ;;
--all-in-flight) ALL_IN_FLIGHT=1 ;;
Expand All @@ -171,10 +182,19 @@ done

command -v jq >/dev/null 2>&1 || { echo "fm-bearings-snapshot: jq not found" >&2; exit 1; }

if [ "$PASSIVE_VIEW" = 1 ] && [ "$INCLUDE_PRS" = 1 ]; then
echo "fm-bearings-snapshot: --passive-view is local-only and refuses --include-prs" >&2
exit 2
fi

# The deterministic return-catch-up owner must clear before this or any other
# ordinary captain request proceeds. Bearings does not reproduce that policy;
# it only consults the shared read-only gate.
"$SCRIPT_DIR/fm-afk-return.sh" guard || exit $?
# it only consults the shared read-only gate. --passive-view is the named
# exception for the phone bridge observation: that page is most useful while
# the captain is away, and it must not copy or skip the guard in bridge code.
if [ "$PASSIVE_VIEW" != 1 ]; then
"$SCRIPT_DIR/fm-afk-return.sh" guard || exit $?
fi

NOW=${FM_BEARINGS_NOW:-$(date -u +%Y-%m-%dT%H:%M:%SZ)}
if [ "$ALL_LANDED" = 1 ] || [ "$ALL_SECONDMATES" = 1 ]; then
Expand Down Expand Up @@ -397,12 +417,14 @@ MODEL=$(printf '%s' "$SNAP" | jq \
| select(.backlog.current_role != "held" or .current_state.state == "working")
| {id, kind,
state: .current_state.state,
title: ((.backlog.title // "Untitled work") | trunc(90)),
doing: ((.current_state.detail // "") as $d
| (if $d != "" then $d else (.hints.last_event_text // "") end) | trunc(90))
} ]
+ [ $secondmate_views[]
| select(.bearings_state == "active_child_work")
| {id,kind:"secondmate",state:.bearings_state,
title:"Second-mate work",
doing:([.active_children[] | .id + ": " + (.doing // .state)] | join("; ") | trunc(90))} ]) as $in_flight_all
| ([ .backlog.records[]
| select(.structured and .captain_actionable == true)
Expand Down
Loading
Loading