- capability_fit.py: open-world CapabilityRequirement; deterministic candidate discovery over Spine/Scaffold stores (kind + providing- relationship eligible; environment-contradiction excluded); fit levels EXACT/PARTIAL/INCOMPATIBLE/UNKNOWN from contracts+health, never names; resolution surface SATISFIED/REUSE/CONFIGURE/COMPOSE/ADAPT_EXISTING/ ACQUIRE_EXTERNAL/BUILD_NEW/INSUFFICIENT_EVIDENCE — BUILD_NEW never silent (insufficient evidence blocks it), brittle-coupling check (load-bearing missing contracts) forces BUILD_NEW or ACQUIRE with recorded rationale; composition covers via contract union, flagged temporary (permanence user-controlled); LLM semantic-fit seam records provider/model/reason/evidence/confidence — prose never authority - toolchain.py: EXISTING PROJECT TOOLCHAIN WINS; constraint keys fixed and language-free, values open-world; language change = CHANGE_MAJOR requiring user approval, never silent; unknown constraints -> INSUFFICIENT_EVIDENCE (no invented certainty); Python only selected because the project uses it — fixtures prove rust/ts/zig resolve - layout_contract.py: open-world regions (web/tui/qt coexist); stable ui:<component> identity surviving implementation changes; LOCKED requires user provenance (mechanically enforced); locked amendment requires authorized_by=user (enforced, reason required); deterministic adapter-observation gate PASS/FAIL/UNKNOWN — UNKNOWN never PASS; USER-LOCKED drift preserves the contract (deliberate exception to reality-wins), marks DRIFTING, creates maintenance item; flexible violation fails gate until repaired - REAL TUI PROOF: Rune's actual version display (issue #105, plan plans/2026-09-03-tui-footer.md) observed from source via deterministic adapter — footer-bar first child; gate cycle PASS -> controlled violation FAIL -> restore PASS; binding encoded scaffold-provenance (durable records establish placement; USER LOCK upgrade NEEDS CONFIRMATION — not fabricated) - capability/layout integration proven: version-display requirement discovers the existing capability + layout binding (REUSE), never builds another widget - 3 modules registered in Spine authority + canonical build + manifest regenerated (Tranche 2 lesson applied: no hand-edited structural facts) Tests: 53 new (fit 24 + toolchain 9 + layout 16 + real proof 4); suite 1439 green; henxels rc=0; pyright 0 errors on new modules.
118 lines
4.1 KiB
Python
118 lines
4.1 KiB
Python
"""test_toolchain.py — SCAFFOLD-TRANCHE-003 §28 test plan (A-G)."""
|
|
|
|
import os
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
|
|
|
|
from rune.toolchain import (
|
|
CONSTRAINT_KEYS,
|
|
DecisionRecord, # noqa: E402
|
|
ToolchainConstraints,
|
|
resolve_toolchain,
|
|
)
|
|
|
|
|
|
# A. existing project language strongly preferred
|
|
def test_existing_toolchain_wins():
|
|
d = resolve_toolchain(ToolchainConstraints(existing_language="python", target_platform="linux"))
|
|
assert d.resolution == "KEEP_EXISTING"
|
|
assert d.selected_language == "python"
|
|
assert d.user_approval_required is False
|
|
|
|
|
|
# B. Python selected when it's actually the project constraint (not by default)
|
|
def test_python_only_because_project_uses_it():
|
|
d = resolve_toolchain(ToolchainConstraints(existing_language="python", performance_sensitive=False))
|
|
assert d.selected_language == "python"
|
|
# and Python is never picked without the project constraint or a request
|
|
d2 = resolve_toolchain(ToolchainConstraints(target_platform="linux", deployment="server"))
|
|
assert d2.resolution == "INSUFFICIENT_EVIDENCE"
|
|
assert d2.selected_language == ""
|
|
|
|
|
|
# C. non-Python selected when the project clearly favors it
|
|
def test_rust_project_gets_rust():
|
|
d = resolve_toolchain(
|
|
ToolchainConstraints(existing_language="rust", existing_runtime="tokio", performance_sensitive=True)
|
|
)
|
|
assert d.selected_language == "rust"
|
|
assert d.resolution == "KEEP_EXISTING"
|
|
|
|
|
|
def test_typescript_project_gets_typescript():
|
|
d = resolve_toolchain(
|
|
ToolchainConstraints(existing_language="typescript", existing_framework="svelte", target_platform="web")
|
|
)
|
|
assert d.selected_language == "typescript"
|
|
|
|
|
|
# D. language change requires user approval — never silent
|
|
def test_requested_change_requires_approval():
|
|
d = resolve_toolchain(ToolchainConstraints(existing_language="python"), requested_language="rust")
|
|
assert d.resolution == "CHANGE_MAJOR"
|
|
assert d.user_approval_required is True
|
|
assert d.selected_language == "rust"
|
|
|
|
|
|
def test_change_with_performance_evidence_still_requires_approval():
|
|
d = resolve_toolchain(
|
|
ToolchainConstraints(existing_language="python", performance_sensitive=True),
|
|
requested_language="rust",
|
|
performance_evidence={"significant_benefit": True, "basis": "measured 10x on streaming parse"},
|
|
)
|
|
assert d.user_approval_required is True
|
|
|
|
|
|
def test_same_language_request_is_not_major():
|
|
d = resolve_toolchain(ToolchainConstraints(existing_language="python"), requested_language="python")
|
|
assert d.resolution == "KEEP_EXISTING"
|
|
assert d.user_approval_required is False
|
|
|
|
|
|
# E. rationale + full record persisted
|
|
def test_decision_record_is_complete_and_serializable():
|
|
d = resolve_toolchain(
|
|
ToolchainConstraints(existing_language="rust", existing_runtime="tokio", performance_sensitive=True),
|
|
evidence_refs=["bench-2026-09-13"],
|
|
)
|
|
r = d.to_dict()
|
|
for k in (
|
|
"selected_language",
|
|
"runtime",
|
|
"rationale",
|
|
"decisive_constraints",
|
|
"evidence_refs",
|
|
"confidence",
|
|
"user_approval_required",
|
|
"resolution",
|
|
):
|
|
assert k in r
|
|
assert "bench-2026-09-13" in r["evidence_refs"]
|
|
assert "existing project toolchain wins" in r["rationale"]
|
|
|
|
|
|
# F. unknown constraints → INSUFFICIENT_EVIDENCE, not invented certainty
|
|
def test_unknown_constraints_insufficient():
|
|
d = resolve_toolchain(ToolchainConstraints(target_platform="linux"))
|
|
assert d.resolution == "INSUFFICIENT_EVIDENCE"
|
|
assert d.selected_language == ""
|
|
assert d.confidence == 0.0
|
|
|
|
|
|
# G. languages/runtimes/frameworks stay open-world data
|
|
def test_open_world_values_roundtrip():
|
|
c = ToolchainConstraints(
|
|
existing_language="zig", existing_runtime="custom-rt", wibble="future-unknown-thing"
|
|
) # unknown key
|
|
assert c.unknown["wibble"] == "future-unknown-thing"
|
|
d = resolve_toolchain(c)
|
|
assert d.selected_language == "zig"
|
|
|
|
|
|
def test_constraint_keys_never_name_a_language():
|
|
langs = {"python", "rust", "typescript", "go", "c++", "zig", "java"}
|
|
assert not (CONSTRAINT_KEYS & langs)
|