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
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# Changelog

## 0.25.0 — 2026-06-05

### feat: doctor advisory + repair backfill for the Development Philosophy section (BRO-1409)

Follow-up to 0.24.0 (BRO-1406). The scaffold's idempotent-never-overwrite policy means newly-templated *content* never reaches existing workspaces — so the Development Philosophy section shipped only to new installs. This closes that gap for the section: `bstack doctor` surfaces it and `bstack repair` backfills it.

### Changed

- **`scripts/doctor.sh`** — new §4b advisory: if `AGENTS.md` lacks `## Development Philosophy`, print an `[info]` nudge to run `bstack repair`. Informational only — a pre-0.24.0 workspace legitimately lacks it; it is **not** a GAP and does **not** fail `--strict` (mirrors the §12 Pillars / §13 dogfood convention).
- **`scripts/repair.sh`** — new `backfill_philosophy_section()`: extracts the section verbatim from the template (heading → `## Bstack Core Automation Primitives` anchor, exclusive) via files only (no shell interpolation of content), and inserts it before the target's own anchor line in both `AGENTS.md` and `CLAUDE.md`. Runs before the "fully bstack-compliant" early-exit (same pattern as the hook merge), since the advisory is not a GAP. Idempotent (skips if present) and non-destructive (insert-only; skips with a warning if the anchor is absent). Honors `--dry-run` / `--apply-all`.
- **`tests/philosophy-backfill.test.sh`** — new: backfill + position + content-integrity + idempotency + `--dry-run` + missing-anchor + doctor-advisory (13 assertions).
- **`references/new-workspace-flow.md`** — documents §4b + the repair backfill.

### Notes

- Primitive count unchanged (**20**). Governance-substrate tooling, not a P-row.
- Backfill targets *content* gaps the never-overwrite scaffold skips — a general pattern (the hook merge does the same for `.claude/settings.json`).
- `VERSION` 0.24.0 → 0.25.0.

## 0.24.0 — 2026-06-05

### feat: scaffold a Development Philosophy section into AGENTS.md/CLAUDE.md on install (BRO-1406)
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.24.0
0.25.0
4 changes: 3 additions & 1 deletion references/new-workspace-flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Both paths wire the RCS control loop. `bootstrap.sh` scaffolds governance files

## What `bstack doctor` reports

§1–§13 v0.13.0 substrate checks · §14 RCS λ compute + drift · §15 G0/G1/G2 wiring · §16 L0 tool-call audit summary · §17 L1 reflex compliance · §18 L2 promotion throttle · §19 multi-layer composite health (`L0=stable L1=stable L2=stable L3=stable` form) · §20 federation registry · §21 closure-contract arcs · §22 composite-ω drift trend · **§23 control-loop closure verdict** — the single "is the loop wired + connected + running?" answer (substrate-absent / wired-but-idle / wired+running+closing). New workspaces show §16–§18 + §23 as informational ("no audit log yet" / "wired but idle") until first events fire; For CI lanes that must fail on an idle loop, run `BSTACK_LOOP_STRICT=1 doctor.sh --strict` — `BSTACK_LOOP_STRICT=1` records the gap but only `--strict` changes the exit code, so **both** are required.
§1–§13 v0.13.0 substrate checks · **§4b Development Philosophy advisory** (informational since 0.25.0 — flags an AGENTS.md that predates the 0.24.0 templated section; backfill with `bstack repair`; never a GAP, never fails `--strict`) · §14 RCS λ compute + drift · §15 G0/G1/G2 wiring · §16 L0 tool-call audit summary · §17 L1 reflex compliance · §18 L2 promotion throttle · §19 multi-layer composite health (`L0=stable L1=stable L2=stable L3=stable` form) · §20 federation registry · §21 closure-contract arcs · §22 composite-ω drift trend · **§23 control-loop closure verdict** — the single "is the loop wired + connected + running?" answer (substrate-absent / wired-but-idle / wired+running+closing). New workspaces show §16–§18 + §23 as informational ("no audit log yet" / "wired but idle") until first events fire; For CI lanes that must fail on an idle loop, run `BSTACK_LOOP_STRICT=1 doctor.sh --strict` — `BSTACK_LOOP_STRICT=1` records the gap but only `--strict` changes the exit code, so **both** are required.

## Common gotchas

Expand All @@ -50,6 +50,8 @@ Both paths wire the RCS control loop. `bootstrap.sh` scaffolds governance files

`bstack onboard --force` redoes the wizard. `bstack repair` detects missing pieces (G0/G1/G2 hooks, audit dir, parameters.toml) and re-runs the relevant installer. Both are idempotent — existing files are preserved unless `--force` is passed; settings.json merges are structurally idempotent via `_bstack_primitive` markers.

`bstack repair` also **backfills newly-templated *content*** into existing governance files where the scaffold's never-overwrite policy would otherwise skip it. Since 0.25.0 it inserts the `## Development Philosophy` section (templated in 0.24.0) into a pre-existing `AGENTS.md`/`CLAUDE.md` — runs before the "fully bstack-compliant" early-exit (like the hook merge), is insert-only + idempotent, and skips with a warning if the `## Bstack Core Automation Primitives` anchor is absent (never guesses a location).

## See also

- `references/primitives.md` §P11 — Empirical Feedback Loop discipline
Expand Down
16 changes: 16 additions & 0 deletions scripts/doctor.sh
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,22 @@ if [ -f "$AGENTS" ]; then
done
fi

# ── 4b. AGENTS.md Development Philosophy section (advisory, backfillable) ────
# Templated since bstack 0.24.0. A workspace bootstrapped before then
# legitimately lacks it — this is NOT a contract violation (the P1-P20 contract
# is unchanged), so it is reported as an informational advisory only: never a
# GAP, never fails --strict (mirrors §12 Pillars / §13 dogfood convention).
# `bstack repair` backfills it from the template.
section "4b. AGENTS.md Development Philosophy (advisory)"
if [ -f "$AGENTS" ]; then
if grep -qE "^## Development Philosophy" "$AGENTS"; then
ok "AGENTS.md has Development Philosophy section"
else
echo " [info] AGENTS.md has no Development Philosophy section (templated since 0.24.0)"
echo " → backfill: bstack repair (informational; not a gap, does not fail --strict)"
fi
fi

# ── 5. policy.yaml required blocks ──────────────────────────────────────────
section "5. .control/policy.yaml blocks"
POL="$WORKSPACE/.control/policy.yaml"
Expand Down
106 changes: 106 additions & 0 deletions scripts/repair.sh
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,105 @@ PYEOF
fi
}

# ── Development Philosophy backfill (helper) ───────────────────────────────
# Inserts the `## Development Philosophy` section (templated since bstack 0.24.0)
# into an existing AGENTS.md / CLAUDE.md that predates it. The scaffold is
# idempotent-never-overwrite, so existing workspaces never receive newly-
# templated *content* — only freshly-created files. This closes that gap for
# this one section.
#
# Idempotent + non-destructive: skips if the section is already present; skips
# with a warning if the insertion anchor (`## Bstack Core Automation
# Primitives`) is absent (never guesses a location). Extracts the section
# verbatim from the template (heading → Primitives anchor, exclusive) via files
# only — no shell interpolation of the content — so backticks/quotes/pipes in
# the section survive intact.
backfill_philosophy_section() {
local target="$1" # AGENTS.md | CLAUDE.md
local template="$2" # AGENTS.md.template | CLAUDE.md.template
local tgt="$WORKSPACE_DIR/$target"
local tpl="$TEMPLATES_DIR/$template"
local anchor="## Bstack Core Automation Primitives"
# Anchor regex tolerant of trailing whitespace + CRLF (a realistic line-ending
# variant must NOT become a silent no-op). The CR is stripped before matching.
local anchor_re='^## Bstack Core Automation Primitives[[:space:]]*$'
[ -f "$tgt" ] || return # nothing to backfill into
[ -f "$tpl" ] || { echo " [skip] $target philosophy — template missing: $template"; return; }
grep -qE "^## Development Philosophy" "$tgt" && return # already present (idempotent)
# BOTH source and destination must carry the anchor: the template needs it to
# *bound* the extracted section (else awk runs heading→EOF and over-copies);
# the target needs it to *locate* the insertion point. grep the files directly
# — `[[:space:]]*$` absorbs trailing spaces AND a trailing CR, so this is
# CRLF-tolerant without a `tr | grep -q` pipe (which under `set -o pipefail`
# fails spuriously: grep -q closes the pipe early on a match → SIGPIPE on tr).
if ! grep -qE "$anchor_re" "$tpl"; then
echo " [skip] $target philosophy — template lacks anchor; cannot bound section"
return
fi
if ! grep -qE "$anchor_re" "$tgt"; then
echo " [skip] $target philosophy — anchor '$anchor' not found (insert manually)"
return
fi
if [ "$DRY_RUN" = "1" ]; then
echo " [dry-run] would backfill Development Philosophy into $target"
return
fi
if ! confirm "Backfill Development Philosophy section into $target?"; then
echo " [skip] $target philosophy (declined)"
return
fi
local secfile tmp
secfile="$(mktemp)" || { echo " [skip] $target philosophy — mktemp failed"; return; }
# Section block = template lines from the heading up to (excluding) the anchor.
# CR is stripped first so the awk delimiters match on a CRLF template too.
# The pipeline's exit status is checked (under `set -o pipefail` a tr/awk/write
# failure surfaces here); it is SIGPIPE-safe because awk drains all of tr's
# output (no early close). The content checks below catch a partial/empty write.
if ! tr -d '\r' < "$tpl" | awk '
/^## Development Philosophy$/ { f=1 }
/^## Bstack Core Automation Primitives[ \t]*$/ { f=0 }
f { print }
' > "$secfile"; then
echo " [skip] $target philosophy — extraction pipeline failed"
rm -f "$secfile"
return
fi
if [ ! -s "$secfile" ] || ! grep -qE "^## Development Philosophy" "$secfile"; then
echo " [skip] $target philosophy — could not extract section from $template"
rm -f "$secfile"
return
fi
tmp="$(mktemp)" || { echo " [skip] $target philosophy — mktemp failed"; rm -f "$secfile"; return; }
# Insert the section immediately before the first anchor line (CR/space-tolerant).
if ! awk -v secfile="$secfile" '
function isanchor(s) { sub(/\r$/, "", s); sub(/[ \t]+$/, "", s); return (s == "## Bstack Core Automation Primitives") }
isanchor($0) && !done {
while ((getline line < secfile) > 0) print line
close(secfile)
done = 1
}
{ print }
' "$tgt" > "$tmp"; then
echo " [skip] $target philosophy — insertion failed (awk)"
rm -f "$secfile" "$tmp"
return
fi
rm -f "$secfile"
# Verify the section actually landed BEFORE committing the write. Guards the
# probe-vs-inserter mismatch and any awk no-op — never report a false [fix].
if ! grep -qE "^## Development Philosophy" "$tmp"; then
echo " [skip] $target philosophy — anchor not matched during insert (no change)"
rm -f "$tmp"
return
fi
if ! mv "$tmp" "$tgt"; then
echo " [skip] $target philosophy — could not write $target"
rm -f "$tmp"
return
fi
echo " [fix] backfilled Development Philosophy into $target"
}

# ── Hook re-wire (helper) ──────────────────────────────────────────────────
# Idempotently merges every hook in assets/templates/settings.json.snippet
# into $WORKSPACE_DIR/.claude/settings.json. Existing entries are never
Expand Down Expand Up @@ -223,6 +322,13 @@ if [ "$DRY_RUN" = "1" ] || confirm "Merge missing hooks from settings.json.snipp
merge_hooks_into_settings
fi

# Backfill templated-since-0.24.0 governance content that even a *compliant*
# (pre-0.24.0) workspace can lack — run BEFORE the compliance early-exit, like
# the hook merge above, because the Development Philosophy advisory is not a
# GAP (so doctor still reports "fully bstack-compliant" without it).
backfill_philosophy_section "AGENTS.md" "AGENTS.md.template"
backfill_philosophy_section "CLAUDE.md" "CLAUDE.md.template"

if echo "$GAPS_OUTPUT" | grep -q "fully bstack-compliant"; then
echo " ✓ no other gaps — workspace already bstack-compliant"
exit 0
Expand Down
Loading
Loading