CI Pipeline / best-practices (push) Successful in 9s
CI Pipeline / documentation (push) Successful in 5s
CI Pipeline / canary (push) Successful in 31s
CI Pipeline / lint (push) Successful in 38s
Auto-version and Release / release (push) Successful in 42s
CI Pipeline / type-check (push) Successful in 31s
CI Pipeline / gitea-offline (push) Successful in 18s
CI Pipeline / unit-tests (push) Successful in 1m3s
CI Pipeline / required-checks (push) Successful in 1s
deploy / deploy (push) Successful in 3m29s
- construction_decision.py: the adoption layer — Need intake (references Task/Intent by pointer, never duplicates), requirement normalization (gaps recorded, never invented), deterministic discovery+fit+resolution across authorities with merge precedence (BUILD_NEW never a fallback across merges; normalization gaps block it), toolchain decision (existing toolchain wins), USER-LOCKED layout obligation inheritance, approval gate (material changes require user; approved-bounded work never re-asks), durable model-independent decision trace, contract generation populated from the trace. Research routing is an HONEST SEAM: recorded route, not executed ADAPT call (§6). - scaffold.py contract-quality repair (Tranche 3 defects): closure now distinguishes predicted_existing_affected / expected_new / correctly_predicted / predicted_but_unaffected / expected_new_observed / expected_new_missing / genuinely_unexpected_new; prediction cannot self-certify observation; legacy keys (missed/needless/observed) preserved — old contracts readable without migration - layout obligations: affected UI component/region/implementation pulls its Layout Contract into generated obligations; USER-LOCKED obligations state that changes require explicit user authorization; unrelated backend changes inherit none - REAL LIVE PROOF (§24): the contract-quality Need ran through the new path — discovered module:scaffold (PARTIAL fit on closure-quality contract), ADAPT_EXISTING verdict, python KEEP_EXISTING, approval covered by SCAFFOLD-TRANCHE-004, generated LIVE-CONTRACT-QUALITY-001, implemented, verified (10 contract-quality tests), closed with repaired semantics — which correctly flagged parent-tranche surfaces as outside this bounded contract's scope (RED honored, attribution recorded) - baseline correction recorded: Tranche 3 pre-build = 1386 tests (report wording corrected in contract-quality notes, provenance kept) - version-display lock status: still scaffold-provenance, USER-LOCKED upgrade PENDING USER CONFIRMATION (not fabricated) Tests: 37 new (decision path 15, contract quality 10, layout obligations 10, plus repaired-closure compat); suite 1476 green; henxels rc=0; pyright 0 errors on new/changed modules.
157 lines
5.6 KiB
Python
157 lines
5.6 KiB
Python
"""test_layout_obligations.py — SCAFFOLD-TRANCHE-004 §31 test plan (A-H)."""
|
|
|
|
import os
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
|
|
|
|
from rune import construction_decision as cd # noqa: E402
|
|
from rune import layout_contract as lc # noqa: E402
|
|
from rune import scaffold as sc # noqa: E402
|
|
from rune import structural_store as ss # noqa: E402
|
|
from rune import toolchain as tc # noqa: E402
|
|
|
|
|
|
def _doc_with_layouts():
|
|
doc = ss.new_doc()
|
|
lc.define_region(doc, "footer-bar", provenance="scaffold", evidence_refs=["issue-105"])
|
|
lc.define_region(doc, "header", provenance="user")
|
|
# version display: scaffold-provenance (NOT user-locked — §21 status)
|
|
lc.bind_component(
|
|
doc,
|
|
"version_display",
|
|
"footer-bar",
|
|
provenance="scaffold",
|
|
order=0,
|
|
evidence_ref="issue-105",
|
|
implementation="src/rune/rune_tui.py:VersionLabel",
|
|
)
|
|
# a user-locked element for authority tests
|
|
lc.bind_component(doc, "status_bar", "footer-bar", lock=True, provenance="user", order=1, evidence_ref="user-2026")
|
|
return doc
|
|
|
|
|
|
def _need(**kw):
|
|
d = dict(
|
|
need_id="n",
|
|
objective="tweak footer",
|
|
origin="builder",
|
|
constraints={},
|
|
evidence_refs=["x"],
|
|
approval_context="covered by contract",
|
|
)
|
|
d.update(kw)
|
|
return cd.Need(**d)
|
|
|
|
|
|
# A. affected UI component pulls its Layout Contract into obligations
|
|
def test_a_ui_component_inherits_layout_obligation():
|
|
doc = _doc_with_layouts()
|
|
obs = cd.layout_obligations_for(doc, ["ui:version_display"])
|
|
assert len(obs) == 1
|
|
o = obs[0]
|
|
assert o["component"] == "ui:version_display"
|
|
assert o["region"] == "footer-bar"
|
|
assert o["lock"] is False
|
|
assert "layout_contract_check must PASS" in o["verification"]
|
|
|
|
|
|
# B. unrelated backend change inherits NO layout obligations
|
|
def test_b_backend_change_no_layout_obligations():
|
|
doc = _doc_with_layouts()
|
|
assert cd.layout_obligations_for(doc, ["module:memory_store"]) == []
|
|
assert cd.layout_obligations_for(doc, ["capability:exporter"]) == []
|
|
|
|
|
|
def test_b2_implementation_path_match_pulls_contract():
|
|
doc = _doc_with_layouts()
|
|
obs = cd.layout_obligations_for(doc, ["src/rune/rune_tui.py"])
|
|
assert any(o["component"] == "ui:version_display" for o in obs)
|
|
|
|
|
|
# C. FLEXIBLE layout obligation carried correctly
|
|
def test_c_flexible_obligation():
|
|
doc = _doc_with_layouts()
|
|
s = sc.Scaffold("/tmp/never-required", "x")
|
|
o = s.layout_obligations(doc, ["ui:version_display"])[0]
|
|
assert o["lock"] is False
|
|
assert "movable only via authorized layout amendment" in o["obligation"]
|
|
assert o["verification"] == "layout_contract_check must PASS"
|
|
|
|
|
|
# D. USER-LOCKED layout obligation blocks unauthorized change
|
|
def test_d_user_locked_obligation_blocks():
|
|
doc = _doc_with_layouts()
|
|
s = sc.Scaffold("/tmp/never-required", "x")
|
|
obs = s.layout_obligations(doc, ["ui:status_bar"])
|
|
assert len(obs) == 1
|
|
o = obs[0]
|
|
assert o["lock"] is True
|
|
assert "USER-LOCKED" in o["obligation"]
|
|
assert "explicit user authorization" in o["obligation"]
|
|
assert "USER-LOCKED placement unchanged" in o["verification"]
|
|
# and the live-path approval gate fires for locked surfaces
|
|
gate = cd.needs_user_approval(
|
|
"ADAPT_EXISTING",
|
|
tc.resolve_toolchain(tc.ToolchainConstraints(existing_language="python")),
|
|
obs,
|
|
_need(approval_context=""),
|
|
)
|
|
assert gate["required"] is True
|
|
assert "USER-LOCKED" in gate["reasons"][0]
|
|
|
|
|
|
# E. user-authorized layout amendment passes
|
|
def test_e_user_authorized_amendment_passes():
|
|
doc = _doc_with_layouts()
|
|
lc.amend_layout_contract(
|
|
doc,
|
|
"status_bar",
|
|
new_region="header",
|
|
authorized_by="user",
|
|
reason="user reposition",
|
|
evidence_ref="user-2026-09-13",
|
|
)
|
|
# contract follows the user's explicit change
|
|
e = ss.entity(doc, "layout:ui:status_bar")
|
|
assert e["identities"]["region"] == "header"
|
|
# obligation now reflects the amended placement
|
|
s = sc.Scaffold("/tmp/never-required", "x")
|
|
obs = s.layout_obligations(doc, ["ui:status_bar"])
|
|
assert obs[0]["region"] == "header"
|
|
|
|
|
|
# F. unavailable layout adapter remains UNKNOWN — never PASS
|
|
def test_f_unknown_never_pass():
|
|
doc = _doc_with_layouts()
|
|
result = lc.check_layout(doc, {}) # no adapter observations
|
|
assert result["verdict"] == "UNKNOWN"
|
|
assert all(c["verdict"] == "UNKNOWN" for c in result["checks"])
|
|
|
|
|
|
# G. drift does NOT rewrite USER-LOCKED intent
|
|
def test_g_drift_preserves_user_locked():
|
|
doc = _doc_with_layouts()
|
|
violating = {"ui:status_bar": {"region": "header", "order": 0}}
|
|
out = lc.layout_drift(doc, violating)
|
|
assert out["gate"] == "FAIL"
|
|
e = ss.entity(doc, "layout:ui:status_bar")
|
|
assert e["identities"]["region"] == "footer-bar" # user intent preserved
|
|
assert e["status"] == "DRIFTING"
|
|
assert e["identities"]["lock"] is True
|
|
# maintenance item records the violation for user review
|
|
assert ss.entity(doc, "maintenance:layout-drift-ui:status_bar") is not None
|
|
|
|
|
|
# H. version-display stays scaffold-provenance until explicit confirmation
|
|
def test_h_version_display_not_user_locked():
|
|
doc = _doc_with_layouts()
|
|
e = ss.entity(doc, "layout:ui:version_display")
|
|
assert e["identities"]["provenance"] == "scaffold"
|
|
assert e["identities"]["lock"] is False # pending user confirmation (§21)
|
|
# any attempt to lock it without user provenance is refused
|
|
with pytest.raises(ValueError, match="user provenance"):
|
|
lc.bind_component(doc, "version_display", "footer-bar", lock=True, provenance="builder")
|