diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c58758..577c459 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,28 @@ # Changelog +## 0.17.0 — 2026-05-22 + +### Crystallize `BROOMVA_ROOT` env-var convention (BRO-1223 follow-up) + +Adds `references/conventions.md` — a new home for cross-cutting workspace conventions (the things every script should follow but no single primitive owns). First entry: **C1 — `BROOMVA_ROOT` env-var as the workspace-root override**, with rule-of-three earned across 6 callsites in 3 repos (broomva/kg, broomva/bookkeeping, broomva/workspace). + +The convention prevents the failure mode surfaced by the haystack benchmark suite (BRO-1223): scripts that hardcode `~/broomva` silently overwrote the live workspace when invoked with non-standard layouts (e.g., isolated `/tmp/` fixtures). Documented patterns for Python + bash; documented `BROOMVA_WORKSPACE` (used by `bstack doctor`) as a historical synonym treated as semantically equivalent. + +- **NEW** `references/conventions.md` — first cross-cutting workspace convention reference. Includes a candidate ledger for 4 additional patterns observed once during this session (LLM-as-index architecture, auto-compact catalog, haystack benchmark pattern, defensive post-conversion bounds check) — all awaiting rule-of-three before promotion. +- **CHANGED** `VERSION` — `0.16.0` → `0.17.0`. Additive minor bump — no behavior change, new reference doc. + +### Why a new file (not extending an existing one) + +`references/primitives.md` defines primitive contracts; `dogfood-patterns.md` defines per-stack validation patterns; `stack-architecture.md` describes the architectural composition. None is the right home for cross-cutting workspace conventions that span all primitives. A dedicated file keeps each reference doc's scope clean. + +### Candidate ledger philosophy + +The ledger at the bottom of `references/conventions.md` mirrors the workspace-side `research/entities/pattern/bstack-engine.md` candidate ledger — but listed here for bstack agents who don't have the workspace substrate available. The 4 listed candidates (LLM-as-index, auto-compact, haystack pattern, defensive bounds check) all derive from BRO-1223 work but are single-instance today; promotion to a full convention entry awaits 2 more recurrences each. Per the P16 Crystallize discipline: ≥3 instances + concrete mechanism + stated invariant + stated failure mode. + +### Refs + +BRO-1223 follow-up. Linear MCP still down at session ship time — ticket creation deferred. + ## 0.16.0 — 2026-05-22 ### Multi-layer RCS closure — extending the control loop across L0/L1/L2 diff --git a/VERSION b/VERSION index 04a373e..c5523bd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.16.0 +0.17.0 diff --git a/references/conventions.md b/references/conventions.md new file mode 100644 index 0000000..0594ad4 --- /dev/null +++ b/references/conventions.md @@ -0,0 +1,109 @@ +# bstack workspace conventions + +Conventions that apply to **scripts and skills running inside a bstack workspace**. Distinct from `references/primitives.md` (which defines the primitive contract) and `references/dogfood-patterns.md` (which defines per-stack validation patterns). This file documents cross-cutting workspace conventions — the things every script should follow but no single primitive owns. + +Each convention crystallizes here only after **rule-of-three** (≥3 distinct callsites, concrete mechanism, stated invariant, stated failure mode) per the **Crystallize (P16)** discipline. Single-instance conventions live in the candidate ledger at the bottom of this file until they earn promotion. + +--- + +## C1 — `BROOMVA_ROOT` env var as the workspace-root override + +**Rule**: any script that needs to resolve "where is the workspace root?" MUST honor `BROOMVA_ROOT` env var with a fallback to `$HOME/broomva`. + +**Why**: enables (a) CI runners where the workspace isn't at `~/broomva`, (b) co-developers with different host layouts, (c) isolated benchmark/test fixtures under `/tmp/`, (d) parallel worktrees that need to point at a different root than the default. + +**Canonical patterns** + +Python (top of module, single source of truth — read once at import time): + +```python +import os +from pathlib import Path +BROOMVA_ROOT = Path(os.environ.get("BROOMVA_ROOT", Path.home() / "broomva")) +ENTITIES_DIR = BROOMVA_ROOT / "research" / "entities" +# … +``` + +Bash (top of script, with shell-default expansion): + +```bash +BROOMVA_ROOT="${BROOMVA_ROOT:-${HOME}/broomva}" +POLICY_FILE="${BROOMVA_ROOT}/.control/policy.yaml" +# … +``` + +**Invariant**: every workspace path is derived from `BROOMVA_ROOT`; no script hardcodes `Path.home() / "broomva"` or `~/broomva` directly past the env-var resolution. + +**Failure mode prevented**: scripts that hardcode `~/broomva` silently overwrite the live workspace when invoked with non-standard layouts. The benchmark suite (`scripts/bench-kg-haystack.py` in broomva/workspace) surfaced this concretely — `bookkeeping index` running with `BROOMVA_ROOT=/tmp/x` would silently write to `~/broomva/docs/knowledge-index.md` because it ignored the env var. Forbids that class of regression. + +**Known callsites** (BRO-1223 follow-up — these are why this convention earned rule-of-three): + +1. `~/.claude/skills/kg/scripts/kg.py` (and the published broomva/kg v0.2.x) +2. `~/broomva/skills/bookkeeping/scripts/bookkeeping.py` +3. `~/broomva/scripts/bench-kg.py` +4. `~/broomva/scripts/bench-kg-haystack.py` +5. `~/broomva/scripts/knowledge-catalog-refresh-hook.sh` +6. `~/broomva/skills/bookkeeping/tests/test_index.py` + +**Historical synonym**: `BROOMVA_WORKSPACE` was used by `bstack/scripts/doctor.sh` (and downstream `scripts/compute-lambda.sh` invocations) before this convention was crystallized. Treat `BROOMVA_WORKSPACE` as **semantically equivalent** to `BROOMVA_ROOT` for backward compatibility, but new scripts SHOULD use `BROOMVA_ROOT` going forward. A defensive read: + +```python +# accept either name, prefer BROOMVA_ROOT +BROOMVA_ROOT = Path( + os.environ.get("BROOMVA_ROOT") + or os.environ.get("BROOMVA_WORKSPACE") + or (Path.home() / "broomva") +) +``` + +**`bstack doctor` check** (future, optional): could audit that workspace scripts read the env var rather than hardcoding the path. Today this is honor-system — agents reading this file enforce it. + +--- + +## Candidate ledger — patterns observed once, awaiting rule-of-three + +Per `research/entities/pattern/bstack-engine.md` (the meta-primitive ledger in the workspace substrate), patterns observed only once stay in the ledger until ≥2 more instances accumulate. Listed here so future agents working on bstack don't re-derive them blind. + +### CL-1 — LLM-as-index architecture (substrate → catalog → loader) + +The composition shipped in BRO-1223 as the bstack knowledge graph: substrate stays canonical markdown, one projection (the dense catalog at `docs/knowledge-index.md`) routes the loading agent, agent reads bodies on demand, inferences fold back into the substrate as commits. + +**Status**: 1 substrate instance (the kg knowledge graph). Promotion requires 2 more substrate instances (e.g., a code-search index, a doc-search index) that follow the same shape. + +### CL-2 — Auto-compact catalog at high entity counts + +In `bookkeeping cmd_index` (now in broomva/bookkeeping main), per-entity caps automatically tighten (claim 220→100 chars, top-5→top-3 edges, top-4→top-2 tags) when entity count exceeds 5000 — keeps catalog tokens under the 1M context ceiling. Schema bumps `dense-catalog-v2-compact`; frontmatter carries `compact: true/false`. + +**Status**: 1 implementation. Promotion requires 2 more "growing-substrate, single-projection" composers that follow the same density-degrades-gracefully pattern. + +### CL-3 — Haystack benchmark pattern for retrieval skills + +Synthetic substrate generator (`gen-kg-fixture.py`) + multi-scale harness (`bench-kg-haystack.py`) with seeded needles split into Class-A (catalog-vocab) + Class-B (body-only-vocab) for ground-truth recall measurement. + +**Status**: 1 instance (KG). Promotion belongs in `references/dogfood-patterns.md` as Pattern G (or H) once 2 more retrieval skills adopt the same Class-A/B seeding methodology. + +### CL-4 — Defensive post-conversion bounds check + +The `STALE_WARN_SECONDS = int(value * 3600)` floor-to-zero edge case (P20 R5): `stale_warn_hours: 0.0001` survived the pre-multiplication `<= 0` guard but floored to 0 after `int()` truncation, re-triggering the failure the guard was meant to prevent. Fix: guard **both** before and after conversion. + +**Status**: 1 instance. Promotion belongs in a future `references/defensive-coding.md` (or similar) once 2 more bounds-check classes accumulate. + +--- + +## How to add a convention here + +1. **Observe** the pattern in ≥3 distinct callsites across the workspace, with a concrete mechanism + stated invariant + stated failure mode. +2. **Write the entry** following C1's shape: rule, why, canonical patterns (one per language), invariant, failure mode prevented, known callsites. +3. **Reference the BRO ticket** that produced the rule-of-three so future maintainers can audit. +4. **Move it out of the candidate ledger** if it was there. +5. **Bump bstack VERSION** + add CHANGELOG entry citing this file. + +Don't promote on single instances. Don't crystallize aesthetic preferences ("clean code", "elegant design"). The bar is: *recurring failure mode that a stated mechanism prevents, validated by ≥3 production callsites.* + +--- + +## See also + +- `references/primitives.md` — primitive contracts (P1–P20) +- `references/dogfood-patterns.md` — P11 per-stack validation patterns +- `research/entities/pattern/bstack-engine.md` (in workspace substrate) — full candidate ledger across all crystallization candidates