docs(ORCH-078): ORCH-52e — стандарт трассировки ORCH-NNN + правило чтения ADR

Слой 4 (трассировка) эпика ORCH-52, замыкающий цепочку 52b/52c/52d.
Docs + prompts-only: src/**, STAGE_TRANSITIONS, QG_CHECKS, src/frontmatter.py,
схема БД — не тронуты; новый QG не вводится; ретро-фит 51 маркера вне объёма.

- Новый нормативный стандарт docs/_standards/TRACEABILITY.md: формат маркера,
  правило размещения, чтение истории с реальным проверяемым примером
  (src/serial_gate.py → ORCH-088 → ADR-001-serial-gate.md), fallback-доступ
  (git show origin/main:...), анти-археология (3+ → сводный сквозной ADR),
  каноничный текст правила чтения (единый источник).
- Точечные аддитивные врезки в промпты (52d-канон не переписан): developer.md
  (правило чтения чужого маркера + fallback, « X →  Y»), architect.md
  (правило чтения + анти-археология), reviewer.md (усиление оси «Соответствие
  ADR» под-пунктом: слом маркированного инварианта → finding ≥P1). Все три
  ссылаются на единый текст в TRACEABILITY.md, не копируют (анти-дубль BR-6).
- Сопутствующе: CLAUDE.md, docs/architecture/README.md (слой 4 эпика 52),
  CHANGELOG.md.
- Анти-регресс: расширен tests/test_agent_prompts_canon.py (9 новых проверок);
  проверки 52d и test_agent_frontmatter_no_model.py зелёные;
  полный pytest tests/ -q зелёный (1253 passed), src/ не изменён.

Refs: ORCH-078

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-09 15:38:24 +03:00
committed by orchestrator-deployer
parent 14f037a8a9
commit 572b3172cd
8 changed files with 292 additions and 4 deletions

View File

@@ -17,10 +17,11 @@ import pytest
_AGENTS = ("analyst", "architect", "developer", "reviewer", "tester", "deployer")
# tests/ is one level under the repo root; .openclaw/agents lives at the root.
_AGENTS_DIR = os.path.join(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
".openclaw", "agents",
)
_REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
_AGENTS_DIR = os.path.join(_REPO_ROOT, ".openclaw", "agents")
# ORCH-078 (ORCH-52e): the traceability-marker standard (layer 4 of epic ORCH-52).
_TRACEABILITY = os.path.join(_REPO_ROOT, "docs", "_standards", "TRACEABILITY.md")
# The 5 mandatory XML sections, in normative order (D1 / AC-1).
_REQUIRED_SECTIONS = ("context", "task", "deliverables", "constraints", "output_format")
@@ -94,6 +95,11 @@ def _read(agent: str) -> str:
return f.read()
def _read_repo(*parts: str) -> str:
with open(os.path.join(_REPO_ROOT, *parts), encoding="utf-8") as f:
return f.read()
@pytest.mark.parametrize("agent", _AGENTS)
def test_five_xml_sections_present(agent):
"""TC-01: each prompt carries all 5 XML sections (open + close tag)."""
@@ -163,3 +169,92 @@ def test_role_anti_regress_markers(agent):
text = _read(agent)
for marker in _ANTI_REGRESS[agent]:
assert marker in text, f"{agent}.md lost anti-regress marker {marker!r}"
# --------------------------------------------------------------------------- #
# ORCH-078 (ORCH-52e): traceability-marker standard + reading-rule anti-regress
# (TRZ §FR-1..FR-8; AC-1..AC-5, AC-8). Pure-text checks, NO `src/` import.
# --------------------------------------------------------------------------- #
def test_traceability_standard_exists_and_nonempty():
"""TC-01 (AC-1): docs/_standards/TRACEABILITY.md exists and is non-empty."""
assert os.path.isfile(_TRACEABILITY), "docs/_standards/TRACEABILITY.md is missing"
assert _read_repo("docs", "_standards", "TRACEABILITY.md").strip(), (
"TRACEABILITY.md is empty"
)
def test_traceability_describes_marker_format_and_placement():
"""TC-02 (AC-1): standard describes the ORCH-NNN marker and where it is placed."""
text = _read_repo("docs", "_standards", "TRACEABILITY.md")
assert "ORCH-NNN" in text, "TRACEABILITY.md does not describe the ORCH-NNN marker"
# placement rule: next to a non-trivial invariant (not on trivial code).
assert "инвариант" in text, "TRACEABILITY.md does not state the placement rule"
def test_traceability_has_real_verifiable_example():
"""TC-03 (AC-1): the worked example points at files that really exist in main.
A traceability standard whose example references a missing file/ADR would
refute itself, so the example must be checkable against the repo tree.
"""
text = _read_repo("docs", "_standards", "TRACEABILITY.md")
assert "src/serial_gate.py" in text and "ORCH-088" in text, (
"TRACEABILITY.md lacks the serial_gate/ORCH-088 worked example"
)
assert os.path.isfile(os.path.join(_REPO_ROOT, "src", "serial_gate.py")), (
"example references src/serial_gate.py which does not exist"
)
assert os.path.isfile(os.path.join(
_REPO_ROOT, "docs", "work-items", "ORCH-088", "06-adr",
"ADR-001-serial-gate.md",
)), "example references an ORCH-088 ADR that does not exist"
def test_traceability_documents_fallback_access():
"""TC-04 (AC-4): standard documents the git show origin/main fallback."""
text = _read_repo("docs", "_standards", "TRACEABILITY.md")
assert "git show origin/main:docs/work-items/" in text, (
"TRACEABILITY.md does not document the cross-branch ADR fallback"
)
def test_traceability_documents_anti_archeology():
"""TC-05 (AC-5): standard documents the 3+ markers -> cross-cutting ADR rule."""
text = _read_repo("docs", "_standards", "TRACEABILITY.md")
assert "docs/architecture/adr/" in text, (
"TRACEABILITY.md anti-archeology rule does not point at the cross-cutting ADR dir"
)
assert "3+" in text, "TRACEABILITY.md does not state the 3+ markers threshold"
def test_developer_carries_reading_rule_and_fallback():
"""TC-06 (AC-2, AC-4): developer.md carries the reading rule + standard + fallback."""
text = _read("developer")
assert "TRACEABILITY.md" in text, "developer.md does not reference TRACEABILITY.md"
assert "git show origin/main:docs/work-items/" in text, (
"developer.md does not carry the cross-branch ADR fallback"
)
def test_architect_carries_reading_rule_and_anti_archeology():
"""TC-07 (AC-2, AC-5): architect.md carries reading rule + anti-archeology."""
text = _read("architect")
assert "TRACEABILITY.md" in text, "architect.md does not reference TRACEABILITY.md"
assert "3+" in text, "architect.md does not carry the 3+ markers anti-archeology rule"
def test_reviewer_carries_traceability_control_axis():
"""TC-08 (AC-3): reviewer.md carries the traceability-compliance control axis."""
text = _read("reviewer")
assert "TRACEABILITY.md" in text, "reviewer.md does not reference TRACEABILITY.md"
def test_claude_md_and_readme_reference_traceability_standard():
"""TC-12 (AC-8): CLAUDE.md and architecture README reference the standard."""
assert "TRACEABILITY.md" in _read_repo("CLAUDE.md"), (
"CLAUDE.md does not reference docs/_standards/TRACEABILITY.md"
)
assert "TRACEABILITY.md" in _read_repo("docs", "architecture", "README.md"), (
"architecture README does not reference docs/_standards/TRACEABILITY.md"
)