docs(#95): IMP-95 u11 status-board markers + idempotence/regex tests (docs+test only)
Some checks failed
Multi-MDX Regression (IMP-91) / multi-mdx-regression (push) Failing after 20s
Some checks failed
Multi-MDX Regression (IMP-91) / multi-mdx-regression (push) Failing after 20s
- Add section 9 to PHASE-Z-PIPELINE-STATUS-BOARD.md carving section 3 item (j)
into 8 IMP-95 sub-axes (j1-j8). j1-j5 = trace-only, j6-j8 = guarded.
- Marker grammar: <!-- IMP-95:<axis> -->VALUE<!-- /IMP-95 --> (distinct from
IMP-91 grammar so scripts/update_status_board.py MARKER_RE cannot rewrite
IMP-95 cells).
- Allowed value enum: {pending, trace-only, guarded, active}.
- tests/scripts/test_update_status_board.py: +1 import, +4 module-level
constants, +3 test functions verifying marker presence/count (8), value
domain enum, IMP-91 updater isolation against IMP-95 cells, and IMP-95
regex rewrite idempotence. IMP-91 tests untouched.
- No production-code touched. Default-OFF flag posture preserved; all cells
trace-only or guarded.
This commit is contained in:
@@ -6,6 +6,7 @@ into the GitHub Actions workflow; these tests guard the contract.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
@@ -14,6 +15,15 @@ sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
||||
|
||||
import update_status_board as usb # noqa: E402
|
||||
|
||||
IMP95_BOARD_PATH = (
|
||||
REPO_ROOT / "docs" / "architecture" / "PHASE-Z-PIPELINE-STATUS-BOARD.md"
|
||||
)
|
||||
IMP95_MARKER_RE = re.compile(
|
||||
r"(<!-- IMP-95:(j\d+) -->)(.*?)(<!-- /IMP-95 -->)", re.DOTALL
|
||||
)
|
||||
IMP95_EXPECTED_AXES = {"j1", "j2", "j3", "j4", "j5", "j6", "j7", "j8"}
|
||||
IMP95_ALLOWED_VALUES = {"pending", "trace-only", "guarded", "active"}
|
||||
|
||||
|
||||
SAMPLE_REPORT = {
|
||||
"tests": [
|
||||
@@ -60,3 +70,43 @@ def test_update_board_text_is_idempotent() -> None:
|
||||
once = usb.update_board_text(board, outcomes)
|
||||
twice = usb.update_board_text(once, outcomes)
|
||||
assert once == twice == "<!-- IMP-91:F2:05 -->PASS<!-- /IMP-91 -->"
|
||||
|
||||
|
||||
def test_imp95_markers_present_and_well_formed() -> None:
|
||||
"""IMP-95 sub-axis markers all present in section 9 with allowed values."""
|
||||
board = IMP95_BOARD_PATH.read_text(encoding="utf-8")
|
||||
matches = IMP95_MARKER_RE.findall(board)
|
||||
axes = {axis for _, axis, _, _ in matches}
|
||||
assert axes == IMP95_EXPECTED_AXES, (
|
||||
f"IMP-95 axes drift: expected {IMP95_EXPECTED_AXES}, got {axes}"
|
||||
)
|
||||
for _, axis, value, _ in matches:
|
||||
assert value in IMP95_ALLOWED_VALUES, (
|
||||
f"IMP-95 {axis} value {value!r} outside allowed set {IMP95_ALLOWED_VALUES}"
|
||||
)
|
||||
|
||||
|
||||
def test_imp95_markers_isolated_from_imp91_updater() -> None:
|
||||
"""`update_board_text` (IMP-91) MUST NOT rewrite IMP-95 markers — distinct closing tag."""
|
||||
sample = (
|
||||
"<!-- IMP-95:j1 -->trace-only<!-- /IMP-95 --> "
|
||||
"<!-- IMP-91:F0:01 -->?<!-- /IMP-91 -->"
|
||||
)
|
||||
outcomes = {("F0", "01"): "PASS"}
|
||||
rewritten = usb.update_board_text(sample, outcomes)
|
||||
assert "<!-- IMP-95:j1 -->trace-only<!-- /IMP-95 -->" in rewritten
|
||||
assert "<!-- IMP-91:F0:01 -->PASS<!-- /IMP-91 -->" in rewritten
|
||||
|
||||
|
||||
def test_imp95_marker_rewrite_is_idempotent() -> None:
|
||||
"""Regex-driven IMP-95 cell rewrite is byte-identical on second application."""
|
||||
board = "<!-- IMP-95:j1 -->pending<!-- /IMP-95 -->"
|
||||
|
||||
def rewrite(text: str, value: str) -> str:
|
||||
return IMP95_MARKER_RE.sub(
|
||||
lambda m: f"{m.group(1)}{value}{m.group(4)}", text
|
||||
)
|
||||
|
||||
once = rewrite(board, "trace-only")
|
||||
twice = rewrite(once, "trace-only")
|
||||
assert once == twice == "<!-- IMP-95:j1 -->trace-only<!-- /IMP-95 -->"
|
||||
|
||||
Reference in New Issue
Block a user