-
Notifications
You must be signed in to change notification settings - Fork 182
Expand file tree
/
Copy pathrefresh-data.sh
More file actions
executable file
ยท350 lines (321 loc) ยท 18.8 KB
/
Copy pathrefresh-data.sh
File metadata and controls
executable file
ยท350 lines (321 loc) ยท 18.8 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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
#!/usr/bin/env bash
# refresh-data.sh โ ๅฟ่ทณ็จ็ๅฎไธ่ณๆๅทๆฐๅ
ฅๅฃ
#
# 14 ๅๆญฅ้ฉ๏ผv2026-05-28 ๅ Step 6 generate-dashboard-immune.py๏ผper dashboard-immune-wiring-2026-05-28๏ผ
# ไฟฎ่ฃ 5/17 โ 5/28 11 ๅคฉ silent stale๏ผ๏ผ
# 1. Git sync (auto-stash + pull, hard abort on failure)
# 2. fetch-sense-data.sh (CF + GA4 + SC + dashboard-analytics merge)
# + monitor-404.py (Step 2.5) (ๅ
จๆต้ 404 ๅธธ้ง็ฃๆธฌ โ resolution-based ๅ้ก๏ผ
# 2026-07-17 ๅ ๏ผper 14.99% hreflang ๆญป้ฃ็ตๆ นๅ ่ฟฝๆฅ)
# 3. sync-translations-json.py (sync _translations.json from frontmatter SSOT)
# 4. generate-spore-records.py (spores.json ๅฎๆด่จ้ๅฑค โ 2026-06-10 ่งฃ่ฆ)
# + generate-dashboard-spores.py (spore dashboard from SPORE-HARVESTS body โ Phase 6 primary)
# 5. i18n-coverage-audit.sh (UI string coverage dashboard)
# 6. generate-dashboard-immune.py (ๅ
็ซ็ณป็ตฑ 6-dim v2 score โ wire ไฟฎ่ฃ 5/17 silent stale)
# 7. npm run prebuild (dashboard-vitals/organism/articles/translations)
# 8. refresh-llms-txt.py (sync llms.txt content stats)
# 9. update-stats.sh (README + stats.json)
# 10. extract-build-perf.mjs (build perf trend dashboard)
# 11. verify dashboard freshness (mtime gate, REFLEXES #43)
# 12. validate-spore-data.py (SSOT consistency check)
# 13. sync-spore-links.py (regen knowledge/*.md sporeLinks identity pointer;
# v2 2026-06-10 โ metrics ๅทฒ็งปๅฑ
spores.json๏ผ
# ๆ็ซ ๅชๅจๆฐๅญขๅญ็ผๅธๆๆๆ diff)
# 14. generate-reports-index.py (regen reports/INDEX.md; per audit Layer 3)
#
# Removed in Phase 6 (2026-05-08):
# - extract-spore-metrics.py โ workaround for narrativeโstruct gap, no longer needed
# (SPORE-LOG ๆๆ่ฟฝ่นค deprecated; SPORE-HARVESTS body is canonical)
#
# ๅคฑๆ็ญ็ฅ๏ผ
# - cwd ไธๅจ git toplevel โ auto cd
# - working tree dirty โ auto stash + pop๏ผไธๅ skip pull๏ผ
# - git pull ็ๅคฑๆ โ hard abort๏ผ้ไบบ้กไปๅ
ฅ๏ผ
# - ไปปไฝ่ณๆๆบๅคฑๆ โ soft skip๏ผๅฟ่ทณ็นผ็บ็จๆจๅคฉ็ cache
#
# ๅผๅซ่
๏ผ
# - HEARTBEAT.md Beat 1๏ผใๅท่ก ่ณๆๆดๆฐ pipelineใ๏ผ
# - ~/.claude/scheduled-tasks/semiont-heartbeat/SKILL.md๏ผๆฏๆฅ 09:37๏ผ
# - .claude/skills/heartbeat/SKILL.md๏ผ/heartbeat ๅฝไปค๏ผ
# - .claude/skills/twmd-refresh/SKILL.md๏ผ/twmd-refresh ๅฝไปค๏ผ
#
# ่ฉณ่ฆ๏ผdocs/pipelines/DATA-REFRESH-PIPELINE.md
# 2026-04-11 session ฮต ๅปบ้
# 2026-05-02 ฮณ-late: ๅ i18n-coverage + verify freshness (REFLEXES #43)
# 2026-05-08 laughing-goldstine: Phase 0 SSOT cleanup
# - cwd assertion๏ผ้ฒ main repo ่ท worktree ่ทๆททๆท๏ผ
# - git-dirty ๆน auto-stash๏ผไธๅ silent skip pull๏ผ
# - ๆญฅ้ฉ็ทจ่ 1-12 ๆดๆธๅ๏ผ็งป้ค 2.5/2.7/2.8/2.9/3.5/4.5/5.5 decimals๏ผ
set -o pipefail
# โโโโโโโโโโโโโโโโโโ cwd assertion (Phase 0) โโโโโโโโโโโโโโโโโโ
# ้ๅป bug: ๅพ main repo ่ทฏๅพ่ท pipeline ๆ worktree ่ฝๅพ N ๅ commit
# โ ๅฏซ stale dashboard JSON โ ๅ ฑ้ฏ OVERDUE ๆธๅญ
TOPLEVEL="$(git rev-parse --show-toplevel 2>/dev/null)"
if [ -z "$TOPLEVEL" ]; then
echo "โ Not in a git repo โ refresh-data.sh requires git toplevel" >&2
exit 2
fi
if [ "$(pwd)" != "$TOPLEVEL" ]; then
cd "$TOPLEVEL"
echo "โน๏ธ cd โ $TOPLEVEL"
fi
GRN='\033[0;32m'
YEL='\033[0;33m'
RED='\033[0;31m'
DIM='\033[0;90m'
RST='\033[0m'
echo -e "${DIM}โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ${RST}"
echo -e "${GRN}๐งฌ ่ณๆๆดๆฐ Pipeline${RST}"
echo -e "${DIM} $(git rev-parse --abbrev-ref HEAD) @ $(git rev-parse --short HEAD)${RST}"
echo -e "${DIM}โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ${RST}"
echo ""
# โโโโโโโโโโโโโโโโโโ Step 1 โ Git sync โโโโโโโโโโโโโโโโโโ
# Phase 0 ้ๅฏซ: ไธๅ silent skip pull on dirty
# - working tree dirty โ auto-stash + pop
# - git pull ็ๅคฑๆ โ hard abort
echo -e "${GRN}[1/14]${RST} Git sync..."
DIRTY=0
if [ -n "$(git status --porcelain)" ]; then
DIRTY=1
STASH_LABEL="refresh-data-auto-$(date +%s)"
if git stash push -m "$STASH_LABEL" --include-untracked >/dev/null 2>&1; then
echo -e "${DIM} stashed local changes ($STASH_LABEL)${RST}"
else
echo -e "${RED}โ stash failed โ aborting pipeline${RST}"
exit 2
fi
fi
PULL_OK=1
if ! git pull --rebase origin main 2>&1 | tail -5; then
PULL_OK=0
fi
if [ "$DIRTY" = "1" ]; then
if git stash pop >/dev/null 2>&1; then
echo -e "${DIM} restored stashed changes${RST}"
else
echo -e "${YEL}โ ๏ธ stash pop conflict โ local changes still in 'git stash list' (label: $STASH_LABEL)${RST}"
echo -e "${YEL} manual fix: git stash pop / git stash drop${RST}"
fi
fi
if [ "$PULL_OK" = "0" ]; then
echo -e "${RED}โ git pull failed โ aborting pipeline${RST}"
echo -e "${YEL} ไบบ้กไปๅ
ฅ๏ผๆชขๆฅ merge conflict / detached HEAD / network${RST}"
exit 2
fi
echo -e "${DIM} โ HEAD now $(git rev-parse --short HEAD)${RST}"
echo ""
# โโโโโโโโโโโโโโโโโโ Step 2 โ three-source sense fetch โโโโโโโโโโโโโโโโโโ
# Soft fail: ไปปไฝ source ๅคฑๆ็จๆจๅคฉ cache
echo -e "${GRN}[2/14]${RST} ไธๆบๆ็ฅๆๅ..."
if bash scripts/tools/fetch-sense-data.sh 2>&1 | grep -E '^\[|^ [โ
โ ๏ธโ]|^๐|^[โ
โ ๏ธโ]' | tail -20; then
true
else
echo -e "${YEL}โ ๏ธ fetch-sense-data ้จๅๅคฑๆ โ ๅฟ่ทณ็นผ็บ${RST}"
fi
echo ""
# โโโโโโโโโโโโโโโโโโ Step 2.5 โ ๅ
จๆต้ 404 ๅธธ้ง็ฃๆธฌ โโโโโโโโโโโโโโโโโโ
# ็บไป้บผ: 2026-07-17 ๆฅๆ 14.99% CF 404 ็ๆ นๅ ๆฏ็ซ้ซ่ชๅทฑๅ็ 13,014 ๆข hreflang
# ๆญป้ฃ็ต๏ผๅทฒไฟฎ๏ผcommit f369f3c8e๏ผใๆขๆ analyze-crawler-404.py ๅช็ 10 ๅ
# crawler UA allowlist๏ผไบบ้ก 404 ็ตๆงๆง็ไธ่ฆใmonitor-404.py ็ๅ
จ้จๆต้๏ผ
# resolution-based ๅ้ก๏ผไธๆฏ็ regex๏ผ๏ผ่ผธๅบ reports/404-monitor/latest.json
# ็ตฆ Step 7 ไนๅพ็ generate-dashboard-alerts.mjs ่ฎ alertsใๅฎๆญฅๅคฑๆไธๆ pipelineใ
echo -e "${GRN}[2.5/14]${RST} ๅ
จๆต้ 404 ๅธธ้ง็ฃๆธฌ (monitor-404.py)..."
if python3 scripts/tools/monitor-404.py --days 1 2>&1 | tail -20; then
echo -e "${DIM} โ reports/404-monitor/{state,latest}.json ๅทฒๆดๆฐ${RST}"
else
echo -e "${YEL}โ ๏ธ monitor-404 ้จๅๅคฑๆ โ ๅฟ่ทณ็นผ็บ${RST}"
fi
echo ""
# โโโโโโโโโโโโโโโโโโ Step 3 โ sync _translations.json from translatedFrom frontmatter โโโโโโโโโโโโโโโโโโ
# ็บไป้บผ: file-level translatedFrom ๆฏ SSOT๏ผ_translations.json ๆฏ derived cache
echo -e "${GRN}[3/14]${RST} sync _translations.json from frontmatter..."
if python3 scripts/tools/sync-translations-json.py 2>&1 | tail -3; then
echo -e "${DIM} โ _translations.json synced${RST}"
fi
echo ""
# โโโโโโโโโโโโโโโโโโ Step 4 โ generate spore records + dashboard-spores.json โโโโโโโโโโโโโโโโโโ
# ็บไป้บผ: ็นๆฎๅจๅฎ็ data-driven ๆ็ฅ๏ผDashboard ๅญขๅญ้ขๆฟ่ณๆๆบ
# Phase 6: SPORE-HARVESTS body table ็บ primary (SPORE-LOG ๆๆ่ฟฝ่นค deprecated)
# 2026-06-10 ่งฃ่ฆ: spores.json = ๅญขๅญๅฎๆด่จ้ๅฑค๏ผmetrics + history๏ผ๏ผๆ็ซ frontmatter
# ๅชๅฉ identity pointer โ harvest ๅๅกซๅพๆญคๅชๅ spores.json๏ผไธๅ็ขฐ knowledge/*.md
# (reports/spore-data-architecture-2026-06-10.md / REFLEXES #43 ๆฐ JSON ้ฒ refresh)
echo -e "${GRN}[4/14]${RST} generate spore records + dashboard-spores.json..."
if python3 scripts/tools/generate-spore-records.py 2>&1 | tail -2; then
echo -e "${DIM} โ spores.json records generated${RST}"
else
echo -e "${YEL}โ ๏ธ generate-spore-records ้จๅๅคฑๆ โ ๅฟ่ทณ็นผ็บ${RST}"
fi
if python3 scripts/tools/generate-dashboard-spores.py 2>&1 | tail -3; then
echo -e "${DIM} โ dashboard-spores.json generated${RST}"
else
echo -e "${YEL}โ ๏ธ generate-dashboard-spores ้จๅๅคฑๆ โ ๅฟ่ทณ็นผ็บ${RST}"
fi
echo ""
# โโโโโโโโโโโโโโโโโโ Step 5 โ generate dashboard-i18n.json โโโโโโโโโโโโโโโโโโ
# ็บไป้บผ: UI ๅญไธฒ่ฆ่็ dashboard ไนๅ 12 ๅฐๆ stale๏ผๅๅ ๆฏ้ๅ็ๆๆญฅ้ฉๆฒ้ฒ refresh pipeline
echo -e "${GRN}[5/14]${RST} generate dashboard-i18n.json (UI string coverage)..."
if bash scripts/tools/i18n-coverage-audit.sh --json-out public/api/dashboard-i18n.json 2>&1 | tail -3; then
echo -e "${DIM} โ dashboard-i18n.json generated${RST}"
else
echo -e "${YEL}โ ๏ธ i18n-coverage-audit ้จๅๅคฑๆ โ ๅฟ่ทณ็นผ็บ${RST}"
fi
echo ""
# โโโโโโโโโโโโโโโโโโ Step 6 โ generate dashboard-immune.json โโโโโโโโโโโโโโโโโโ
# ็บไป้บผ: ๅ
็ซ็ณป็ตฑ 6-dim v2 score generator existed since 2026-05-17 but never wired into refresh pipeline.
# Step 11 freshness gate caught 5/17 โ 5/28 (11 days) silent stale across 22+ consecutive cycles.
# Wire here between i18n + prebuild so npm prebuild can consume IMMUNE_V2 flag downstream.
echo -e "${GRN}[6/14]${RST} generate dashboard-immune.json (6-dim immune score v2)..."
if python3 scripts/core/generate-dashboard-immune.py 2>&1 | tail -5; then
echo -e "${DIM} โ dashboard-immune.json generated${RST}"
else
echo -e "${YEL}โ ๏ธ generate-dashboard-immune ้จๅๅคฑๆ โ ๅฟ่ทณ็นผ็บ${RST}"
fi
echo ""
# โโโโโโโโโโโโโโโโโโ Step 6.5 โ fork-census radar (็นๆฎๆ็ฅๅฑค) โโโโโโโโโโโโโโโโโโ
# ็บไป้บผ: GA ๆผๆฐด้ท้ๅตๆธฌ้ๅคๆดป่็ fork โ registry.json๏ผ้จๅพ Step 7 prebuild ็
# generate-dashboard-forks.py ๆๅฝฑๆๅ
ฌ้ dashboard-forks.jsonใriding data-refresh
# flywheel ไธๅฆ้ cron (per FORK-CENSUS-PIPELINE.md)ใๆฐๅญไปฃๅฐ ๐ โ escalate OBSERVER-QUEUEใ
echo -e "${GRN}[6.5/14]${RST} fork-census radar (ๅญไปฃๆฎๆฅ)..."
if python3 scripts/tools/fork-census.py 2>&1 | tail -4; then
echo -e "${DIM} โ registry.json ๆดๆฐ๏ผ๐ NEW sightings = ๆฐๅญไปฃ โ OBSERVER-QUEUE๏ผ${RST}"
else
echo -e "${YEL}โ ๏ธ fork-census ๅคฑๆ๏ผGA ๆ?๏ผโ ๅฟ่ทณ็นผ็บ๏ผregistry ็่ๅผ${RST}"
fi
echo ""
# โโโโโโโโโโโโโโโโโโ Step 6.6 โ dashboard-status.json (๐ฉบ ็้็ๆ
board) โโโโโโโโโโโโโโโโโโ
# ็บไป้บผ: /dashboard ๆฐ sectionใ๐ฉบ ็้็ๆ
ใ่ฎ routine-live-state.json ร
# docs/semiont/memory/ fire ็่ทก + babel progress jsonl + alerts + gh run list๏ผ
# ๆๅฝฑๆ status.claude.com ๅผ็ๆ
ๆฟใ่ท Step 6 immune ๅๆฌพ๏ผๅ
ๅจ้่ฃก่ทไธๆฌก่ฎ
# ่ณๆๅจ Step 7 ไนๅๅฐฑๆฐ้ฎฎ๏ผไนๅทฒๆ้ฒ prebuild:dashboard chain๏ผStep 7 ๆๅ่ทไธๆฌก๏ผ
# ๅช็ญ็กๅฎณ๏ผใper reports/design-dashboard-status-section-2026-07-24.md ยงๅ
ญใ
echo -e "${GRN}[6.6/14]${RST} generate dashboard-status.json (routine + babel ็้็ๆ
)..."
if node scripts/core/generate-dashboard-status.mjs 2>&1 | tail -5; then
echo -e "${DIM} โ dashboard-status.json generated${RST}"
else
echo -e "${YEL}โ ๏ธ generate-dashboard-status ้จๅๅคฑๆ โ ๅฟ่ทณ็นผ็บ${RST}"
fi
echo ""
# โโโโโโโโโโโโโโโโโโ Step 7 โ prebuild dashboard data โโโโโโโโโโโโโโโโโโ
echo -e "${GRN}[7/14]${RST} npm run prebuild..."
if npm run prebuild > /tmp/prebuild.log 2>&1; then
tail -6 /tmp/prebuild.log
echo -e "${DIM} โ dashboard JSON ๅทฒ้็${RST}"
else
echo -e "${YEL}โ ๏ธ prebuild ๅคฑๆ โ Beat 1 ๆๆจ่จ build-broken (P0)${RST}"
tail -15 /tmp/prebuild.log
fi
rm -f /tmp/prebuild.log
echo ""
# โโโโโโโโโโโโโโโโโโ Step 8 โ refresh public/llms.txt content stats โโโโโโโโโโโโโโโโโโ
# ็บไป้บผ: llms.txt ๆฏ LLM training pipeline ็ robots.txt-equivalent๏ผๅฟ
้ ่ท dashboard-vitals ๅๆญฅ
echo -e "${GRN}[8/14]${RST} refresh public/llms.txt content stats..."
if python3 scripts/tools/refresh-llms-txt.py 2>&1 | tail -3; then
echo -e "${DIM} โ llms.txt ๅทฒๅๆญฅ dashboard-vitals${RST}"
else
echo -e "${YEL}โ ๏ธ refresh-llms-txt ้จๅๅคฑๆ โ ๅฟ่ทณ็นผ็บ${RST}"
fi
echo ""
# โโโโโโโโโโโโโโโโโโ Step 9 โ GitHub stats โโโโโโโโโโโโโโโโโโ
echo -e "${GRN}[9/14]${RST} GitHub stats..."
if bash scripts/tools/update-stats.sh > /tmp/stats.log 2>&1; then
tail -5 /tmp/stats.log
echo -e "${DIM} โ README/stats ๅทฒๅทๆฐ${RST}"
else
echo -e "${YEL}โ ๏ธ update-stats ๅคฑๆ โ ่ทณ้๏ผstats ไฟๆๆจๅคฉ${RST}"
tail -5 /tmp/stats.log
fi
rm -f /tmp/stats.log
echo ""
# โโโโโโโโโโโโโโโโโโ Step 10 โ extract build perf trend โโโโโโโโโโโโโโโโโโ
# ็บไป้บผ: 12 ๅคฉๅ
ง per-page render time ๆผฒ 70%๏ผ98ms โ 167ms๏ผๆฒไบบ็ผ็พ๏ผๅ ็บ build ๆ่ฝไธๅจ dashboard freshness check ็ฏๅ
echo -e "${GRN}[10/14]${RST} extract build perf trend..."
if node scripts/core/extract-build-perf.mjs --runs 30 2>&1 | tail -5; then
echo -e "${DIM} โ dashboard-build-perf.json updated${RST}"
else
echo -e "${YEL}โ ๏ธ extract-build-perf ้จๅๅคฑๆ โ ๅฟ่ทณ็นผ็บ${RST}"
fi
echo ""
# โโโโโโโโโโโโโโโโโโ Step 10b โ newsroom ็ทจ่ผฏๅฐ็ๆฟ โโโโโโโโโโโโโโโโโโ
# ็บไป้บผ: /semiont/newsroom ๅ
ฌ้็ทจ่ผฏๅฐ๏ผ2026-07-16 ่ช็๏ผๅพ้ๆฎต็ข็ฉ derive per-article ้ฒๅบฆ๏ผ
# ๆผ่ท = ็ๆฟๅ็ตๅจ่็พๆณ๏ผStep 11 freshness gate ๆๆ๏ผ
echo -e "${GRN}[10b/14]${RST} generate newsroom board..."
if python3 scripts/core/generate-newsroom-data.py --quiet 2>&1 | tail -2; then
echo -e "${DIM} โ dashboard-newsroom.json updated${RST}"
else
echo -e "${YEL}โ ๏ธ generate-newsroom-data ๅคฑๆ โ ๅฟ่ทณ็นผ็บ${RST}"
fi
echo ""
# โโโโโโโโโโโโโโโโโโ Step 11 โ verify dashboard freshness โโโโโโโโโโโโโโโโโโ
# REFLEXES #43: ๆฏๅ public/api/dashboard-*.json ้ฝๅฟ
้ ๆไปๅคฉ็ mtime๏ผๅฆๅ generator ๆผ่ทไบใ
# dashboard-analytics ๅฆ้ฉ lastUpdated๏ผmtime ๅช่ฝ่ญๆๆชๆก่ขซ็ขฐ้๏ผไธ่ฝ่ญๆ fresh
# sense cache ๆ็ต็ๅจๆชๅ
งใ่ฅ prebuild / parallel actor ๆๅ
งๅฎน่ฆๅ่ๅฟซ็
ง๏ผ็ถๅ ด้็ใ
echo -e "${GRN}[11/14]${RST} verify dashboard freshness..."
TODAY=$(date +%Y-%m-%d)
STALE_COUNT=0
STALE_LIST=""
ANALYTICS_FILE="public/api/dashboard-analytics.json"
ANALYTICS_DATE=$(python3 -c 'import json,sys; print((json.load(open(sys.argv[1])).get("lastUpdated") or "")[:10])' "$ANALYTICS_FILE" 2>/dev/null || true)
if [ "$ANALYTICS_DATE" != "$TODAY" ]; then
echo -e "${YEL}โ ๏ธ dashboard-analytics content stale ($ANALYTICS_DATE) โ rerun sense-cache merge${RST}"
python3 scripts/tools/generate-dashboard-analytics.py >/tmp/dashboard-analytics-step11.log 2>&1 || true
ANALYTICS_DATE=$(python3 -c 'import json,sys; print((json.load(open(sys.argv[1])).get("lastUpdated") or "")[:10])' "$ANALYTICS_FILE" 2>/dev/null || true)
if [ "$ANALYTICS_DATE" != "$TODAY" ]; then
STALE_COUNT=$((STALE_COUNT + 1))
STALE_LIST="$STALE_LIST โ dashboard-analytics.json โ lastUpdated ${ANALYTICS_DATE:-missing}\n"
else
echo -e "${DIM} โ dashboard-analytics ๅทฒๅพ fresh sense cache ้็${RST}"
fi
rm -f /tmp/dashboard-analytics-step11.log
fi
for f in public/api/dashboard-*.json; do
[ -f "$f" ] || continue
MTIME_DATE=$(stat -f "%Sm" -t "%Y-%m-%d" "$f" 2>/dev/null || stat -c "%y" "$f" 2>/dev/null | cut -d' ' -f1)
if [ "$MTIME_DATE" != "$TODAY" ]; then
STALE_COUNT=$((STALE_COUNT + 1))
STALE_LIST="$STALE_LIST โ $(basename $f) โ mtime $MTIME_DATE\n"
fi
done
if [ "$STALE_COUNT" -eq 0 ]; then
echo -e "${DIM} โ ๅ
จ้จ $(ls public/api/dashboard-*.json | wc -l | tr -d ' ') ๅ dashboard JSON ้ฝๆฏไปๅคฉ mtime๏ผanalytics content=$ANALYTICS_DATE${RST}"
else
echo -e "${RED}โ $STALE_COUNT ๅ dashboard ไธๆฏไปๅคฉ mtime๏ผgenerator ๆผ่ทไบ๏ผ๏ผ${RST}"
echo -e "$STALE_LIST"
echo -e "${YEL} ไฟฎๅพฉ: ๆๅฐๆ็ generator ๅ ้ฒ refresh-data.sh${RST}"
fi
echo ""
# โโโโโโโโโโโโโโโโโโ Step 12 โ spore data SSOT validation โโโโโโโโโโโโโโโโโโ
# ็บไป้บผ: dashboard freshness ๅช็ mtime๏ผไธๆชขๆฅ spore ่งฃๆๆญฃ็ขบๆง
# ้ๅป generator parser bug (K suffix) silent fail โ views_latest=null but mtime fresh
echo -e "${GRN}[12/14]${RST} spore data SSOT validation..."
if python3 scripts/tools/validate-spore-data.py 2>&1 | tail -4 | head -3; then
echo -e "${DIM} โ spore data validation passed${RST}"
else
echo -e "${RED}โ ๏ธ spore data validation reported issues โ see above${RST}"
fi
echo ""
# โโโโโโโโโโโโโโโโโโ Step 13 โ sync sporeLinks (v2 identity-only) โโโโโโโโโโโโโโโโโโ
# ็บไป้บผ: knowledge/*.md sporeLinks ้ๅปไบบ้กๆๅฏซ๏ผdrift from SPORE-LOG (identity SSOT)ใ
# Phase 3 ไนๅพๆฏ derived view๏ผv2 (2026-06-10) ไนๅพๅชๅฉ identity pointer๏ผid/platform/
# date/url๏ผ๏ผmetrics ไฝ spores.json โ ๆฌๆญฅ้ฉๅนณๆฅๆ็บ no-op๏ผๅชๅจๆฐๅญขๅญ็ผๅธๆฅๆ diffใ
echo -e "${GRN}[13/14]${RST} sync sporeLinks identity pointers (regen from spore-log.json)..."
if python3 scripts/tools/sync-spore-links.py --apply 2>&1 | tail -3; then
echo -e "${DIM} โ sporeLinks synced${RST}"
else
echo -e "${YEL}โ ๏ธ sync-spore-links ้จๅๅคฑๆ โ ๅฟ่ทณ็นผ็บ${RST}"
fi
echo ""
# โโโโโโโโโโโโโโโโโโ Step 13 โ regen reports/INDEX.md โโโโโโโโโโโโโโโโโโ
# ็บไป้บผ: reports/ ้ ๅฑค *.md ๆฃ่ฝ 113+ files / ๆฒๅ้กๆฒ็ดขๅผ๏ผper audit Layer 3 ้ซ leverage
# ่งฃ grep noise 90%๏ผใๆฏๆฅ regen ่ฎ INDEX ๅง็ตๆฐ้ฎฎ๏ผไธๆฌๅฎถไธ็ ดๅฃ 239 ๆขๆ referenceใ
# Script ็บ idempotent โ ๆฒๆน่ฎๅ INDEX content ไธๆจฃใ
echo -e "${GRN}[14/14]${RST} regen reports/INDEX.md..."
if python3 scripts/tools/generate-reports-index.py 2>&1 | tail -2; then
echo -e "${DIM} โ reports/INDEX.md ๆดๆฐ๏ผper audit Layer 3๏ผ${RST}"
else
echo -e "${YEL}โ ๏ธ reports/INDEX.md regen ๅคฑๆ โ ๅฟ่ทณ็นผ็บ${RST}"
fi
echo ""
echo -e "${DIM}โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ${RST}"
echo -e "${GRN}๐งฌ ่ณๆๆดๆฐ pipeline ๅฎๆ${RST}"
echo -e "${DIM}ไธไธๆญฅ๏ผHEARTBEAT.md Beat 1 ่จบๆท${RST}"
echo -e "${DIM}โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ${RST}"