net-kingdom published the first source-owned declaration (116643f). It passes emission-review. Record it as feedback, and file its session-scoped-silence incompatibility as demand/EmissionActivityScope.md. T02 is done, and T04 is in progress until activity-core answers. The adoption brief sent owners the 0.1.0 draft digest, because the candidate promotion changed the standard's text after the digest was taken. The export manifest also hard-coded status "draft". The manifest now derives status and version from the standard, a test pins that, and the brief names the candidate digest b08b4d95fc4b0bd3. The wire schema is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 121421@bnt-lap001 Assistant-Session: 36f8657c-ebfa-4a2e-9ba0-bff06738f233
267 lines
11 KiB
Python
267 lines
11 KiB
Python
from copy import deepcopy
|
|
import hashlib
|
|
import json
|
|
from pathlib import Path
|
|
import shutil
|
|
import tarfile
|
|
import tempfile
|
|
|
|
import pytest
|
|
import yaml
|
|
|
|
from info_tech_canon.cli import main
|
|
from info_tech_canon.generation import concept_ownership
|
|
from info_tech_canon.maintenance import (
|
|
check_generated,
|
|
concept_candidates,
|
|
export_emission_bundle,
|
|
source_evidence,
|
|
)
|
|
from info_tech_canon.contracts import coverage
|
|
from info_tech_canon.federation import (
|
|
import_manifest_review,
|
|
registered_drift,
|
|
registered_manifests,
|
|
)
|
|
from info_tech_canon.service import (
|
|
DEFAULT_INFOSPACE_ROOT,
|
|
concept_declaration_checks,
|
|
load_context,
|
|
validate_canon,
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def corpus(tmp_path):
|
|
root = tmp_path / "infospace"
|
|
shutil.copytree(DEFAULT_INFOSPACE_ROOT, root)
|
|
return root
|
|
|
|
|
|
def test_emission_cli_checks_versions_duplicates_and_bad_types(tmp_path, capsys):
|
|
source = DEFAULT_INFOSPACE_ROOT / "standards/emission-cadence/examples/qonto-assistant.yaml"
|
|
valid = yaml.safe_load(source.read_text())
|
|
path = tmp_path / "declaration.yaml"
|
|
path.write_text(yaml.safe_dump(valid))
|
|
assert main(["emission-review", str(path)]) == 0
|
|
assert json.loads(capsys.readouterr().out)["operational_truth_assessed"] is False
|
|
for change in ("version", "duplicate", "bad_type"):
|
|
data = deepcopy(valid)
|
|
if change == "version":
|
|
data["schema_version"] = "99.0"
|
|
elif change == "duplicate":
|
|
data["sources"].append(deepcopy(data["sources"][0]))
|
|
else:
|
|
data["sources"][0]["source_id"] = ["unhashable"]
|
|
path.write_text(yaml.safe_dump(data))
|
|
assert main(["emission-review", str(path)]) == 1
|
|
payload = json.loads(capsys.readouterr().out)
|
|
assert payload["errors"]
|
|
if change == "duplicate":
|
|
assert payload["errors"][0]["code"] == "duplicate_emission_cadence_source_id"
|
|
|
|
|
|
def test_freshness_detects_missing_and_stale_without_repair(corpus):
|
|
from info_tech_canon import generation
|
|
context = load_context(corpus)
|
|
for render in (generation.generate_indexes, generation.generate_tree, generation.generate_agent_briefs):
|
|
render(context)
|
|
assert check_generated(context)["ok"]
|
|
stale = corpus / "views/by-concept.md"
|
|
stale.write_text("stale\n")
|
|
missing = corpus / "agent/retrieval-index.json"
|
|
missing.unlink()
|
|
result = check_generated(context)
|
|
assert not result["ok"]
|
|
assert "views/by-concept.md" in result["stale"]
|
|
assert "agent/retrieval-index.json" in result["stale"]
|
|
assert stale.read_text() == "stale\n"
|
|
assert not missing.exists()
|
|
|
|
|
|
def test_bundle_is_reproducible_and_refuses_corruption(tmp_path):
|
|
first = export_emission_bundle(DEFAULT_INFOSPACE_ROOT, tmp_path)
|
|
second = export_emission_bundle(DEFAULT_INFOSPACE_ROOT, tmp_path)
|
|
assert first == second
|
|
path = Path(first["path"])
|
|
assert hashlib.sha256(path.read_bytes()).hexdigest() == first["sha256"]
|
|
with tarfile.open(path) as archive:
|
|
for name, digest in first["manifest"]["files"].items():
|
|
assert hashlib.sha256(archive.extractfile(name).read()).hexdigest() == digest
|
|
path.write_bytes(b"corrupted")
|
|
with pytest.raises(ValueError, match="Refusing"):
|
|
export_emission_bundle(DEFAULT_INFOSPACE_ROOT, tmp_path)
|
|
|
|
|
|
def test_bundle_manifest_reports_the_standards_own_status():
|
|
standard = (DEFAULT_INFOSPACE_ROOT / "standards/emission-cadence/"
|
|
"InfoTechCanonEmissionCadenceStandard.md").read_text()
|
|
manifest = export_emission_bundle(DEFAULT_INFOSPACE_ROOT, Path(tempfile.mkdtemp()))["manifest"]
|
|
assert f"status: {manifest['status']}\n" in standard
|
|
assert f"version: {manifest['document_version']}\n" in standard
|
|
assert "observer" in manifest["adoption_evidence"]
|
|
|
|
|
|
def test_mapping_schema_and_explicit_ownership_are_enforced(corpus):
|
|
from info_tech_canon.contracts import bound_artifact_errors
|
|
mapping = corpus / "mappings/capability-anchors.yaml"
|
|
data = yaml.safe_load(mapping.read_text())
|
|
del data["target"]
|
|
mapping.write_text(yaml.safe_dump(data))
|
|
assert bound_artifact_errors(load_context(corpus))[0]["code"] == "schema_violation"
|
|
pattern = corpus / "patterns/AgenticDrivesFunctional.md"
|
|
text = pattern.read_text()
|
|
# Reuse another artifact's title as an owned concept to create a real conflict.
|
|
owner = next(a.title for a in load_context(corpus).infospace.artifacts if a.kind == "kernel")
|
|
text = text.replace("owned_concepts:", f"owned_concepts:\n - {owner}")
|
|
pattern.write_text(text)
|
|
assert any(e["code"] == "concept_ownership_conflict" for e in validate_canon(corpus)["errors"])
|
|
|
|
|
|
def test_evidence_digest_tracks_content_but_excludes_reports(corpus):
|
|
before = source_evidence(corpus)
|
|
(corpus / "validation/latest.json").write_text("{}")
|
|
assert source_evidence(corpus)["corpus_sha256"] == before["corpus_sha256"]
|
|
(corpus / "mappings/README.md").write_text("changed")
|
|
assert source_evidence(corpus)["corpus_sha256"] != before["corpus_sha256"]
|
|
assert before["generated_at"]
|
|
|
|
|
|
def test_explicit_root_controls_capability_catalog(corpus, tmp_path):
|
|
from info_tech_canon.service import review_capability_record, CanonServiceError
|
|
(corpus / "models/capability/capabilities.yaml").unlink()
|
|
record = tmp_path / "record.json"
|
|
record.write_text('{"record_id":"example", "requires":[], "provisions":[]}')
|
|
with pytest.raises(CanonServiceError, match="catalog"):
|
|
review_capability_record(record, corpus)
|
|
|
|
|
|
def test_missing_mapping_schema_is_a_validation_finding(corpus):
|
|
(corpus / "schemas/mapping.schema.yaml").unlink()
|
|
payload = validate_canon(corpus)
|
|
assert not payload["ok"]
|
|
assert any(e["code"] == "mapping_schema_unreadable" for e in payload["errors"])
|
|
|
|
|
|
def test_authority_is_declared_where_the_kernel_map_assigns_it():
|
|
"""The gap that let itc-org:Authority pass the SecurityCanon conflict check."""
|
|
ownership = concept_ownership(load_context())
|
|
owners = {item["concept"]: item["owner"] for item in ownership["concepts"]}
|
|
|
|
assert owners["Authority"] == "model/organization"
|
|
assert owners["Actor"] == "model/organization"
|
|
assert not ownership["ownership_conflicts"]
|
|
|
|
|
|
def test_only_the_kernel_map_declares_no_concepts():
|
|
"""It assigns concepts to owners rather than defining them (T02)."""
|
|
report = concept_candidates(load_context())
|
|
|
|
assert report["silent_artifacts"] == ["kernel/itc-kernel-map"]
|
|
assert report["undeclared_total"] < report["candidate_total"] / 2
|
|
|
|
|
|
def test_concept_candidates_ignore_preserved_source():
|
|
report = concept_candidates(load_context())
|
|
paths = [item["path"] for item in report["artifacts"]]
|
|
assert paths
|
|
assert not [path for path in paths if path.startswith(("assimilation/", "seeds/"))]
|
|
|
|
|
|
def test_concept_coverage_cli_reports_one_artifact(capsys):
|
|
assert main(["concept-coverage", "--artifact", "model/identity"]) == 0
|
|
payload = json.loads(capsys.readouterr().out)
|
|
assert payload["ok"] is True
|
|
assert [item["artifact"] for item in payload["artifacts"]] == ["model/identity"]
|
|
|
|
|
|
def test_every_defined_concept_has_an_owner():
|
|
context = load_context()
|
|
result = concept_declaration_checks(context, concept_ownership(context))
|
|
|
|
assert not result["errors"]
|
|
assert not result["warnings"]
|
|
|
|
|
|
def test_declaration_warning_fires_for_a_concept_nobody_owns(corpus):
|
|
target = corpus / "standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md"
|
|
text = target.read_text(encoding="utf-8")
|
|
target.write_text(text.replace(" - Effective Access\n", "", 1), encoding="utf-8")
|
|
|
|
context = load_context(corpus)
|
|
result = concept_declaration_checks(context, concept_ownership(context))
|
|
|
|
warned = {item["artifact_id"]: item for item in result["warnings"]}
|
|
assert "standard/caring" in warned
|
|
assert "Effective Access" in warned["standard/caring"]["concepts"]
|
|
assert warned["standard/caring"]["code"] == "concept_defined_without_owner"
|
|
|
|
|
|
def test_declaration_error_fires_when_an_artifact_declares_nothing(corpus):
|
|
target = corpus / "models/security/InfoTechCanonSecurityModel.md"
|
|
text = target.read_text(encoding="utf-8")
|
|
target.write_text(text.split("---\n", 2)[2], encoding="utf-8")
|
|
|
|
context = load_context(corpus)
|
|
result = concept_declaration_checks(context, concept_ownership(context))
|
|
|
|
assert [item["artifact_id"] for item in result["errors"]] == ["model/security"]
|
|
|
|
|
|
def test_validation_coverage_reports_the_declaration_ratio():
|
|
report = coverage(load_context())["concept_declaration"]
|
|
|
|
assert report["silent_artifacts"] == ["kernel/itc-kernel-map"]
|
|
assert report["undeclared"] < report["declared"]
|
|
assert report["limit"]
|
|
|
|
|
|
def test_import_review_resolves_a_partner_manifest(tmp_path):
|
|
manifest = DEFAULT_INFOSPACE_ROOT / "interfaces/manifests/security-canon.json"
|
|
review = import_manifest_review(load_context(), manifest)
|
|
|
|
assert review["ok"] is True
|
|
assert review["resolved"] == review["declared"]
|
|
assert {entry["hash"] for entry in review["entries"]} == {"match"}
|
|
|
|
|
|
def test_import_review_reports_a_name_its_artifact_does_not_define(tmp_path):
|
|
source = json.loads(
|
|
(DEFAULT_INFOSPACE_ROOT / "interfaces/manifests/security-canon.json").read_text())
|
|
source["imports"][0]["concepts"] = ["Artifact"]
|
|
manifest = tmp_path / "imports.json"
|
|
manifest.write_text(json.dumps(source))
|
|
|
|
review = import_manifest_review(load_context(), manifest)
|
|
|
|
assert review["ok"] is False
|
|
finding = review["findings"][0]
|
|
assert finding["concept"] == "Artifact"
|
|
assert finding["code"] in {"import_wrong_artifact", "import_unowned"}
|
|
|
|
|
|
def test_registered_drift_names_the_partner_not_the_canon():
|
|
warnings = registered_drift(load_context())
|
|
|
|
assert all(item["code"] == "federation_import_drift" for item in warnings)
|
|
assert {item["partner"] for item in warnings} <= {"interface-canon", "security-canon"}
|
|
|
|
|
|
def test_import_review_cli_exits_non_zero_on_a_finding(tmp_path, capsys):
|
|
"""Built from a broken copy: a partner fixing its pins must not break this."""
|
|
source = json.loads(
|
|
(DEFAULT_INFOSPACE_ROOT / "interfaces/manifests/interface-canon.json").read_text())
|
|
source["imports"][0]["concepts"] = ["Interface"]
|
|
manifest = tmp_path / "imports.json"
|
|
manifest.write_text(json.dumps(source))
|
|
|
|
assert main(["import-review", str(manifest)]) == 1
|
|
payload = json.loads(capsys.readouterr().out)
|
|
assert [item["concept"] for item in payload["findings"]] == ["Interface"]
|
|
|
|
|
|
def test_registered_manifests_resolve_completely():
|
|
for item in registered_manifests(load_context()):
|
|
review = import_manifest_review(
|
|
load_context(), DEFAULT_INFOSPACE_ROOT / "interfaces/manifests" / item["file"])
|
|
assert review["ok"], (item["partner"], review["findings"])
|