Snapshot WIP: solver HP epic progress, BPHX/HX physics, BMAD skill refresh.
Some checks failed
CI / check (push) Has been cancelled

Capture uncommitted solver robustness work (regularization, domain errors, linear solver lifecycle, tube DP/MSH), web workbench updates, and synced BMAD skills across IDE agent folders before starting BPHX pressure-drop.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-19 16:35:31 +02:00
parent 88620790d6
commit 5bd180b5b8
1363 changed files with 101041 additions and 58547 deletions

View File

@@ -0,0 +1,257 @@
#!/usr/bin/env python3
# /// script
# requires-python = ">=3.10"
# ///
"""lint-spine — the mechanical half of spine decision-integrity, done deterministically.
LLMs miscount IDs and miss literal placeholders; a grep does not. This linter owns the
checks a script does better than a prompt, and leaves the semantic half (is each Rule
actually enforceable? does the boundary make sense?) to the rubric walker.
It reads ARCHITECTURE-SPINE.md from a workspace and reports, as compact JSON on stdout:
- placeholder literal TBD / TODO / "similar to AD-n" / unfilled {template-token}
- ad_id duplicate or non-monotonic AD-n identifiers
- ad_fields an AD-n block missing Binds / Prevents / Rule
- version_pin a ## Stack table row with no version
Fenced code blocks are blanked (replaced with equal-count blank lines) before scanning, so
mermaid and source trees don't trip false positives AND reported line numbers still line up
with the real file. Reported lines are absolute file lines (frontmatter offset added). Exit
code is always 0 — findings travel in the JSON; the caller (Reviewer Gate / rubric walker)
decides what to do with them.
"""
from __future__ import annotations
import argparse
import json
import re
import sys
from pathlib import Path
SPINE = "ARCHITECTURE-SPINE.md"
AD_HEADING = re.compile(r"^#{2,4}\s*AD-(\d+)\b(.*)$", re.MULTILINE)
HEADING = re.compile(r"^#{1,6}\s", re.MULTILINE)
FENCE = re.compile(r"```.*?```", re.DOTALL)
PLACEHOLDER_WORD = re.compile(r"\b(TBD|TODO|FIXME|XXX)\b")
SIMILAR_TO = re.compile(r"similar to AD-\d+", re.IGNORECASE)
TEMPLATE_TOKEN = re.compile(r"\{[a-z_][a-z0-9_ /.-]*\}")
def split_frontmatter(text: str) -> tuple[str, str, int]:
"""Return (frontmatter, body, body_line_offset).
Frontmatter is the content between the first two lines that are *exactly* `---`
(line-exact, like memlog.split — a `---` inside a value or a body thematic break never
truncates it). body_line_offset is the number of file lines before the body begins, so a
body-relative line number plus the offset gives the absolute file line. Absent frontmatter
→ ('', text, 0)."""
lines = text.split("\n")
if lines and lines[0] == "---":
for i in range(1, len(lines)):
if lines[i] == "---":
fm = "\n".join(lines[1:i])
body = "\n".join(lines[i + 1:])
return fm, body, i + 1
return "", text, 0
def blank_fences(text: str) -> str:
"""Replace each fenced block with the same number of newlines, so scanning skips fenced
content while every line number outside the fence stays put."""
return FENCE.sub(lambda m: "\n" * m.group(0).count("\n"), text)
def line_of(text: str, idx: int) -> int:
return text.count("\n", 0, idx) + 1
def find_placeholders(body: str, offset: int) -> list[dict]:
findings: list[dict] = []
scan = blank_fences(body)
# (regex, label, severity) — TBD/TODO and dangling cross-refs are unambiguous; a bare
# {template-token} can be legitimate brace prose, so it is flagged low ("possible") to keep
# the mechanical pass near-zero false-positive rather than train reviewers to ignore it.
for rx, label, severity in (
(PLACEHOLDER_WORD, "placeholder marker", "high"),
(SIMILAR_TO, "unresolved cross-reference", "high"),
(TEMPLATE_TOKEN, "possible unfilled template token (verify)", "low"),
):
for m in rx.finditer(scan):
findings.append({
"category": "placeholder",
"severity": severity,
"detail": f"{label}: {m.group(0)!r}",
"location": f"{SPINE} (line {offset + line_of(scan, m.start())})",
})
return findings
def find_frontmatter_placeholders(frontmatter: str) -> list[dict]:
"""Catch unfilled tokens left in frontmatter (e.g. paradigm/scope/date) — part of the
spine contract, but outside the body that find_placeholders scans."""
findings: list[dict] = []
for rx, label, severity in (
(PLACEHOLDER_WORD, "placeholder marker", "high"),
(TEMPLATE_TOKEN, "possible unfilled template token (verify)", "low"),
):
for m in rx.finditer(frontmatter):
findings.append({
"category": "placeholder",
"severity": severity,
"detail": f"frontmatter {label}: {m.group(0)!r}",
"location": f"{SPINE} frontmatter (line {1 + line_of(frontmatter, m.start())})",
})
return findings
def find_ad_issues(body: str, offset: int) -> list[dict]:
findings: list[dict] = []
scan = blank_fences(body) # AD headings shown inside a code fence are not live ADs
matches = list(AD_HEADING.finditer(scan))
seen: dict[int, int] = {}
prev: int | None = None
for m in matches:
num = int(m.group(1))
file_line = offset + line_of(scan, m.start())
loc = f"{SPINE} AD-{num} (line {file_line})"
if num in seen:
findings.append({
"category": "ad_id",
"severity": "high",
"detail": f"AD-{num} id reused (also at line {seen[num]})",
"location": loc,
})
else:
seen[num] = file_line
if prev is not None and num <= prev:
findings.append({
"category": "ad_id",
"severity": "high",
"detail": f"AD-{num} is non-monotonic (follows AD-{prev}); ids must ascend and never renumber",
"location": loc,
})
prev = num if prev is None else max(prev, num)
# block text = from this heading to the next heading of any level
start = m.end()
nxt = HEADING.search(scan, start)
block = scan[start:nxt.start()] if nxt else scan[start:]
low = block.lower()
missing = [f for f in ("binds", "prevents", "rule") if f not in low]
if missing:
findings.append({
"category": "ad_fields",
"severity": "high",
"detail": f"AD-{num} missing required field(s): {', '.join(missing)}",
"location": loc,
})
return findings
def find_unpinned_stack(body: str, offset: int) -> list[dict]:
"""Flag a `## Stack` table row that names something but leaves its version blank or a
placeholder. Pinning lives in the body table now, not frontmatter. A row whose name is
still a `{token}` skeleton is left to the placeholder pass, not double-reported here.
Fences are blanked first (like find_placeholders / find_ad_issues), so a pipe-row or
heading inside a code block is never read as live Stack content. The heading match is
`## Stack` with a word boundary, so a renamed heading (`## Stack & Versions`) still
counts. Name and Version columns are located from the header row, so a reordered table
pairs name to version correctly; both default to the canonical positions (0, 1)."""
findings: list[dict] = []
in_stack = False
header_seen = False
name_idx, ver_idx = 0, 1
scan = blank_fences(body)
for i, raw in enumerate(scan.splitlines()):
if HEADING.match(raw):
in_stack = re.match(r"^##\s+Stack\b", raw) is not None
header_seen = False
name_idx, ver_idx = 0, 1
continue
if not in_stack or not raw.lstrip().startswith("|"):
continue
if set(raw.strip()) <= set("|-: "):
continue # separator row
cells = _table_cells(raw)
if not header_seen:
header_seen = True
for j, c in enumerate(cells):
if c.lower() == "name":
name_idx = j
elif c.lower() == "version":
ver_idx = j
continue
name = cells[name_idx] if len(cells) > name_idx else ""
version = cells[ver_idx] if len(cells) > ver_idx else ""
if not name or TEMPLATE_TOKEN.search(name):
continue
if not version or TEMPLATE_TOKEN.search(version):
findings.append({
"category": "version_pin",
"severity": "medium",
"detail": f"Stack entry {name!r} has no version",
"location": f"{SPINE} (line {offset + i + 1})",
})
return findings
def _table_cells(row: str) -> list[str]:
"""Split a markdown table row into trimmed cells, dropping the leading/trailing pipe."""
s = row.strip()
if s.startswith("|"):
s = s[1:]
if s.endswith("|"):
s = s[:-1]
return [c.strip() for c in s.split("|")]
def lint(text: str) -> dict:
frontmatter, body, offset = split_frontmatter(text)
findings: list[dict] = []
findings += find_frontmatter_placeholders(frontmatter)
findings += find_placeholders(body, offset)
findings += find_ad_issues(body, offset)
findings += find_unpinned_stack(body, offset)
counts: dict[str, int] = {}
for f in findings:
counts[f["severity"]] = counts.get(f["severity"], 0) + 1
return {
"ok": len(findings) == 0,
"spine": SPINE,
"total_findings": len(findings),
"by_severity": counts,
"findings": findings,
}
def main(argv: list[str] | None = None) -> int:
ap = argparse.ArgumentParser(description="Lint an architecture spine for mechanical integrity.")
ap.add_argument("--workspace", required=True, help="run folder containing ARCHITECTURE-SPINE.md")
ap.add_argument("-o", "--output", help="write JSON here instead of stdout")
args = ap.parse_args(argv)
spine_path = Path(args.workspace) / SPINE
if not spine_path.exists():
result = {"ok": False, "error": f"{spine_path} not found", "findings": [], "total_findings": 0}
else:
try:
text = spine_path.read_text(encoding="utf-8")
except (OSError, UnicodeDecodeError) as e:
# honor the "exit code is always 0" contract: a read/decode failure travels in JSON
result = {"ok": False, "error": f"could not read {spine_path}: {e}", "findings": [], "total_findings": 0}
else:
result = lint(text)
out = json.dumps(result, indent=2)
if args.output:
Path(args.output).write_text(out + "\n", encoding="utf-8")
else:
print(out)
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -0,0 +1,270 @@
# /// script
# requires-python = ">=3.10"
# dependencies = ["pytest>=8.0"]
# ///
"""Tests for lint_spine.py. Run: uv run --with pytest pytest scripts/tests/test_lint_spine.py
The spine under test: a clean spine lints empty; the linter catches exactly the
mechanical defects a prompt is unreliable at — literal placeholders, AD-n id breakage,
AD-n blocks missing required fields, and unpinned Stack versions.
"""
import importlib.util
import json
import re
import sys
from pathlib import Path
import pytest
_SPEC = importlib.util.spec_from_file_location(
"lint_spine", Path(__file__).resolve().parent.parent / "lint_spine.py"
)
lint_spine = importlib.util.module_from_spec(_SPEC)
sys.modules["lint_spine"] = lint_spine
_SPEC.loader.exec_module(lint_spine)
CLEAN = """---
name: 'Demo'
---
## Invariants & Rules
### AD-1 — single write path
- **Binds:** all
- **Prevents:** divergent mutation
- **Rule:** state changes only through the command bus
### AD-2 — layered deps `[ADOPTED]`
- **Binds:** all
- **Prevents:** import cycles
- **Rule:** ui -> app -> domain, never backward
```mermaid
flowchart LR
A --> B{decision}
```
## Stack
| Name | Version |
| --- | --- |
| fastapi | 0.115 |
| pydantic | 2.9 |
"""
def cats(result):
return sorted(f["category"] for f in result["findings"])
def test_clean_spine_passes():
result = lint_spine.lint(CLEAN)
assert result["ok"] is True
assert result["total_findings"] == 0
def test_mermaid_braces_not_flagged():
# the {decision} node lives in a fenced block and must not read as a template token
result = lint_spine.lint(CLEAN)
assert "placeholder" not in cats(result)
def test_placeholder_markers_caught():
text = CLEAN.replace("the command bus", "TBD")
result = lint_spine.lint(text)
assert "placeholder" in cats(result)
def test_similar_to_caught():
text = CLEAN.replace("import cycles", "similar to AD-1")
result = lint_spine.lint(text)
assert any("cross-reference" in f["detail"] for f in result["findings"])
def test_unfilled_template_token_caught():
text = CLEAN.replace("single write path", "{decision}")
result = lint_spine.lint(text)
assert any(f["category"] == "placeholder" for f in result["findings"])
def test_duplicate_ad_id_caught():
text = CLEAN.replace("### AD-2 — layered deps `[ADOPTED]`", "### AD-1 — layered deps")
result = lint_spine.lint(text)
assert "ad_id" in cats(result)
def test_non_monotonic_ad_id_caught():
text = CLEAN.replace("### AD-2 — layered deps `[ADOPTED]`", "### AD-5 — layered deps").replace(
"### AD-1 — single write path", "### AD-9 — single write path"
)
result = lint_spine.lint(text)
assert any("non-monotonic" in f["detail"] for f in result["findings"])
def test_missing_field_caught():
text = CLEAN.replace("- **Rule:** state changes only through the command bus\n", "")
result = lint_spine.lint(text)
assert any(f["category"] == "ad_fields" and "rule" in f["detail"] for f in result["findings"])
def test_unpinned_dep_caught():
text = CLEAN.replace("| fastapi | 0.115 |", "| fastapi | |")
result = lint_spine.lint(text)
assert "version_pin" in cats(result)
def test_placeholder_version_caught():
text = CLEAN.replace("| fastapi | 0.115 |", "| fastapi | {pin} |")
result = lint_spine.lint(text)
assert any(f["category"] == "version_pin" and "fastapi" in f["detail"] for f in result["findings"])
def test_no_stack_section_ok():
text = CLEAN.split("## Stack")[0]
result = lint_spine.lint(text)
assert "version_pin" not in cats(result)
def test_stack_skeleton_row_not_version_pinned():
# a leftover {token} name is the placeholder pass's job, not a double-reported version_pin
text = CLEAN.replace("| fastapi | 0.115 |", "| {language / framework} | {pinned version} |")
result = lint_spine.lint(text)
assert "version_pin" not in cats(result)
def test_stack_html_comment_not_parsed_as_row():
text = CLEAN.replace("## Stack\n", "## Stack\n\n<!-- SEED — verified current 2026-06 -->\n")
result = lint_spine.lint(text)
assert "version_pin" not in cats(result)
def test_template_token_is_low_severity():
# a bare {token} can be legitimate brace prose; it is flagged, but low (not high) so the
# mechanical pass stays near-zero false-positive
text = CLEAN.replace("single write path", "{decision}")
result = lint_spine.lint(text)
toks = [f for f in result["findings"] if f["category"] == "placeholder" and "template token" in f["detail"]]
assert toks and all(f["severity"] == "low" for f in toks)
def test_no_frontmatter_body_still_scanned():
text = "## Invariants\n\n### AD-1 — x\n\n- **Binds:** all\n- **Prevents:** drift\n- **Rule:** TBD\n"
result = lint_spine.lint(text)
assert "placeholder" in cats(result) # TBD caught even with no frontmatter
def test_frontmatter_value_with_dashes_not_truncated():
# a value containing '---' must not be read as the closing fence (line-exact close)
text = ("---\nname: 'x'\nscope: 'phase 1 --- phase 2'\n---\n\n"
"## Stack\n\n| Name | Version |\n| --- | --- |\n| fastapi | |\n")
result = lint_spine.lint(text)
assert any(f["category"] == "version_pin" for f in result["findings"]) # read past the inline ---
def test_ad_heading_in_fence_not_counted():
text = (
"---\nname: 'x'\n---\n\n"
"### AD-1 — real\n\n- **Binds:** all\n- **Prevents:** drift\n- **Rule:** do x\n\n"
"## Docs\n\n```text\n### AD-2 — illustrative only, no fields\n```\n"
)
result = lint_spine.lint(text)
assert result["ok"] is True # the fenced AD-2 is not a live AD → no ad_fields/ad_id finding
def test_stack_table_flags_only_the_unpinned_row():
text = ("---\nname: 'x'\n---\n\n## Stack\n\n| Name | Version |\n| --- | --- |\n"
"| fastapi | 0.115 |\n| redis | |\n")
result = lint_spine.lint(text)
pins = [f for f in result["findings"] if f["category"] == "version_pin"]
assert len(pins) == 1 and "redis" in pins[0]["detail"]
def test_stack_table_all_pinned_ok():
text = ("---\nname: 'x'\n---\n\n## Stack\n\n| Name | Version |\n| --- | --- |\n"
"| fastapi | 0.115 |\n")
result = lint_spine.lint(text)
assert "version_pin" not in cats(result)
def test_fenced_stack_rows_not_parsed():
# an illustrative fenced table under ## Stack must not be read as live rows (fences are
# blanked first, like every other pass) — a blank-version row inside a fence is not a finding
text = ("---\nname: 'x'\n---\n\n## Stack\n\n| Name | Version |\n| --- | --- |\n"
"| fastapi | 0.115 |\n\n```text\n| example | |\n```\n")
result = lint_spine.lint(text)
assert "version_pin" not in cats(result)
def test_fenced_stack_heading_not_live():
# a `## Stack` heading shown inside a code fence is not the live Stack section
text = ("---\nname: 'x'\n---\n\n## Docs\n\n```md\n## Stack\n\n| foo | |\n```\n")
result = lint_spine.lint(text)
assert "version_pin" not in cats(result)
def test_renamed_stack_heading_still_scanned():
# the heading match is word-boundary, so a varied `## Stack` heading still counts
text = ("---\nname: 'x'\n---\n\n## Stack & Versions\n\n| Name | Version |\n| --- | --- |\n"
"| redis | |\n")
result = lint_spine.lint(text)
pins = [f for f in result["findings"] if f["category"] == "version_pin"]
assert len(pins) == 1 and "redis" in pins[0]["detail"]
def test_reordered_columns_pair_name_to_version():
# Version-then-Name header: the unpinned row must still be flagged by its real name
text = ("---\nname: 'x'\n---\n\n## Stack\n\n| Version | Name |\n| --- | --- |\n"
"| 0.115 | fastapi |\n| | redis |\n")
result = lint_spine.lint(text)
pins = [f for f in result["findings"] if f["category"] == "version_pin"]
assert len(pins) == 1 and "redis" in pins[0]["detail"]
def test_placeholder_line_number_is_absolute():
# a TBD after a multi-line fence reports its real file line (fence blanked, not collapsed)
text = (
"---\nname: 'x'\n---\n\n"
"## A\n\n"
"```text\nf1\nf2\nf3\n```\n\n"
"TBD here\n"
)
result = lint_spine.lint(text)
ph = next(f for f in result["findings"] if "TBD" in f["detail"])
n = int(re.search(r"line (\d+)", ph["location"]).group(1))
assert n == 13
def test_missing_spine_file_reports_error(tmp_path, capsys):
rc = lint_spine.main(["--workspace", str(tmp_path)])
out = json.loads(capsys.readouterr().out)
assert rc == 0 and out["ok"] is False and "not found" in out["error"]
def test_frontmatter_unfilled_token_caught():
# an unfilled {scope}/{paradigm}/{date} in frontmatter is part of the contract and must lint
text = "---\nname: 'x'\nscope: '{what this spine governs}'\n---\n\n## Invariants\n"
result = lint_spine.lint(text)
fm = [f for f in result["findings"] if f["category"] == "placeholder" and "frontmatter" in f["detail"]]
assert fm and any("template token" in f["detail"] for f in fm)
def test_frontmatter_tbd_caught():
text = "---\nname: 'x'\nstatus: TBD\n---\n\n## Invariants\n"
result = lint_spine.lint(text)
assert any(f["category"] == "placeholder" and "frontmatter" in f["detail"] and "TBD" in f["detail"]
for f in result["findings"])
def test_unreadable_spine_returns_error_not_crash(tmp_path, capsys):
# a spine that exists but can't be UTF-8 decoded must yield error JSON + exit 0, not a traceback
(tmp_path / lint_spine.SPINE).write_bytes(b"\xff\xfe bad bytes not utf-8")
rc = lint_spine.main(["--workspace", str(tmp_path)])
out = json.loads(capsys.readouterr().out)
assert rc == 0 and out["ok"] is False and "could not read" in out["error"]
if __name__ == "__main__":
sys.exit(pytest.main([__file__, "-q"]))