-
Notifications
You must be signed in to change notification settings - Fork 0
173 lines (169 loc) · 7.67 KB
/
Copy pathdashboard_refresh.yml
File metadata and controls
173 lines (169 loc) · 7.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
name: Dashboard Refresh
# Keeps the generated task page (`dashboard.md`, linked from the README) in
# step with the Mind it describes. The page is rendered by PyAutoBrain's intake
# conductor from `draft/`, `active/` and the registry files, so any push that
# files, issues, parks or ships a task makes it stale.
#
# It went stale before this workflow existed: between its first commit and
# 2026-08-11 the page was regenerated by hand 4 times while 33 commits touched
# `draft/`. A dashboard nobody trusts is worse than no dashboard, and a linked
# one is read by people who were not in the session that changed the backlog.
#
# Same shape as lifecycle_drift.yml (issue #116): on pull requests a stale page
# is an error the author fixes on the branch; on pushes to main it is SELF-
# HEALED with a bot commit, because Mind pushes land directly on main from many
# concurrent agent sessions and an alarm-only check would just email a human.
#
# The generation stamp is excluded from the drift comparison (`--check`), so a
# re-render on an unchanged Mind is not drift and this never commits daily.
#
# The nightly cron (human ask, 2026-08-21) is the routine rebuild: it catches
# what push triggers cannot — generator changes merged in PyAutoBrain (the
# renderer lives there, so no Mind path fires), epics.md edits, and any render
# that depends on the passage of time. A no-op night commits nothing.
on:
schedule:
- cron: "20 3 * * *"
push:
branches: [main]
paths:
- "draft/**"
- "active/**"
- "active.md"
- "parked.md"
- "planned.md"
- "condemned.md"
- "dashboard.md"
- "dashboard.html"
pull_request:
paths:
- "draft/**"
- "active/**"
- "active.md"
- "parked.md"
- "planned.md"
- "condemned.md"
- "dashboard.md"
- "dashboard.html"
workflow_dispatch:
# contents: write is needed by the self-heal push on main; PR runs never push.
# actions: write → re-dispatch pages_dashboard.yml after a heal: the heal
# commit is made with GITHUB_TOKEN, which never triggers other workflows, so
# without the explicit dispatch the Pages page stays stale while the repo
# copy is fresh (bitten 2026-08-21 — the epic-grouping render).
permissions:
contents: write
actions: write
jobs:
refresh:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
path: PyAutoMind
# The renderer lives with the intake conductor, not here — the Mind holds
# the state, the Brain reasons over it (ORGANISM.md).
- uses: actions/checkout@v4
with:
repository: PyAutoLabs/PyAutoBrain
path: PyAutoBrain
# The contents blocks in planned.md / parked.md / condemned.md are
# generated too (scripts/registry_toc.py) and take the same contract as
# the dashboard pages: PR runs fail on drift, pushes to main self-heal.
- name: registry contents blocks (self-healing on push to main)
working-directory: PyAutoMind
run: |
if python3 scripts/registry_toc.py --check; then
exit 0
fi
# Only PR runs error-without-healing; push, the nightly schedule and
# manual dispatch all self-heal main.
if [ "${GITHUB_EVENT_NAME}" = "pull_request" ]; then
echo "::error::registry contents blocks are stale — run 'python3 scripts/registry_toc.py --write' on this branch and commit the result"
exit 1
fi
echo "registry contents blocks are stale on main — self-healing"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
for attempt in 1 2 3; do
git fetch origin main
git reset --hard FETCH_HEAD
if python3 scripts/registry_toc.py --check; then
echo "tip of main is already fresh (healed by a concurrent push)"
exit 0
fi
python3 scripts/registry_toc.py --write
if ! python3 scripts/registry_toc.py --check; then
echo "::error::'registry_toc.py --write' did not converge — script bug, repair by hand"
exit 1
fi
git add planned.md parked.md condemned.md
git commit -m "mind: self-heal registry contents blocks"
if git push origin HEAD:main; then
echo "healed on attempt ${attempt}"
exit 0
fi
echo "push rejected (attempt ${attempt}) — retrying on the new tip of main"
done
echo "::error::could not push the healed contents blocks after 3 attempts"
exit 1
- name: dashboard freshness (self-healing on push to main)
working-directory: PyAutoMind
run: |
BRAIN=../PyAutoBrain/agents/conductors/intake/_intake.py
# Exit 1 is drift and nothing else. Any other non-zero code means the
# renderer itself could not run — a Brain/Mind version skew, say —
# and reporting that as "the page is stale" sends whoever reads the
# log to fix the wrong file. (This PR's own first run: PyAutoBrain
# main had no `--check` yet, argparse exited 2, and the step blamed
# dashboard.md.)
check() {
local rc=0
python3 "$BRAIN" --mind . dashboard --check || rc=$?
if [ "$rc" -gt 1 ]; then
echo "::error::the dashboard renderer exited ${rc} — that is not drift. Check that PyAutoBrain main still provides 'intake dashboard --check'."
exit 1
fi
return "$rc"
}
if check; then
exit 0
fi
# Only PR runs error-without-healing (see the registry step above).
if [ "${GITHUB_EVENT_NAME}" = "pull_request" ]; then
echo "::error::dashboard.md is stale — run 'pyauto-brain intake --apply dashboard' on this branch and commit the result"
exit 1
fi
echo "dashboard.md is stale on main — self-healing"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
# Each attempt rebuilds on the current tip of main, so a concurrent
# push (the usual cause of a rejected push) never needs a rebase.
# The heal push uses the default GITHUB_TOKEN, which does not trigger
# workflow runs, so it cannot loop.
for attempt in 1 2 3; do
git fetch origin main
git reset --hard FETCH_HEAD
if check; then
echo "tip of main is already fresh (healed by a concurrent push)"
exit 0
fi
python3 "$BRAIN" --mind . --apply dashboard
if ! check; then
echo "::error::'--apply dashboard' did not converge — renderer bug, repair by hand"
exit 1
fi
git add dashboard.md dashboard.html
git commit -m "mind: self-heal stale dashboard pages"
if git push origin HEAD:main; then
echo "healed on attempt ${attempt}"
# Token pushes never trigger pages_dashboard.yml — publish the
# healed page explicitly or the Pages site stays stale.
GH_TOKEN="${{ github.token }}" gh workflow run pages_dashboard.yml --ref main \
|| echo "::warning::could not dispatch pages_dashboard.yml — the Pages page will lag until its next trigger"
exit 0
fi
echo "push rejected (attempt ${attempt}) — retrying on the new tip of main"
done
echo "::error::could not push the healed dashboard after 3 attempts"
exit 1