Implement canon conformance and maintenance optimizations
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a06e82-3e08-7042-a79d-438ac6eed8db
This commit is contained in:
parent
a2e7f22d8d
commit
b081d39da1
64 changed files with 4491 additions and 373 deletions
|
|
@ -9,9 +9,13 @@ from typing import Any
|
|||
|
||||
|
||||
BENCH_PACKAGE = "_info_tech_canon_infospace_bench"
|
||||
BENCH_SOURCE_ROOT = (
|
||||
Path(__file__).resolve().parents[3] / "infospace-bench" / "src" / "infospace_bench"
|
||||
)
|
||||
_spec = importlib.util.find_spec("infospace_bench")
|
||||
if _spec is None or not _spec.submodule_search_locations:
|
||||
raise RuntimeError("Install infospace-bench==0.1.0 before using the canon service")
|
||||
# The upstream __init__ imports optional database/engine integrations. Resolve
|
||||
# its installed location without executing that initializer; load only the
|
||||
# reference-data modules needed here. No sibling checkout is assumed.
|
||||
BENCH_SOURCE_ROOT = Path(next(iter(_spec.submodule_search_locations)))
|
||||
|
||||
|
||||
def _ensure_package() -> ModuleType:
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ from pathlib import Path
|
|||
from typing import Any
|
||||
|
||||
import yaml
|
||||
from .paths import infospace_root
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
CATALOG_PATH = REPO_ROOT / "infospace" / "models" / "capability" / "capabilities.yaml"
|
||||
|
|
@ -33,7 +34,7 @@ MATURITY_ORDER = tuple(f"D{i}" for i in range(8))
|
|||
|
||||
|
||||
def load_catalog(path: Path | None = None) -> dict[str, Any]:
|
||||
catalog_path = path or CATALOG_PATH
|
||||
catalog_path = path or infospace_root() / "models/capability/capabilities.yaml"
|
||||
if not catalog_path.is_file():
|
||||
raise CapabilityReviewError(
|
||||
"capability_catalog_missing",
|
||||
|
|
|
|||
|
|
@ -113,6 +113,21 @@ def build_parser() -> argparse.ArgumentParser:
|
|||
capability_review.add_argument("record")
|
||||
capability_review.set_defaults(handler=_capability_review)
|
||||
|
||||
emission = sub.add_parser("emission-review", help="Validate a source-owned YAML/JSON cadence declaration")
|
||||
emission.add_argument("record")
|
||||
emission.set_defaults(handler=_emission_review)
|
||||
coverage = sub.add_parser("validation-coverage", help="List implemented checks and explicit limits")
|
||||
coverage.set_defaults(handler=_coverage)
|
||||
freshness = sub.add_parser("check-generated", help="Check projections without changing source files")
|
||||
freshness.set_defaults(handler=_check_generated)
|
||||
inventory = sub.add_parser("scope-inventory", help="Derive scope counts from the artifact registry")
|
||||
inventory.set_defaults(handler=_scope_inventory)
|
||||
bundle = sub.add_parser("export-emission-contract", help="Export a content-addressed contract tar")
|
||||
bundle.add_argument("destination")
|
||||
bundle.set_defaults(handler=_export_emission)
|
||||
benchmark = sub.add_parser("benchmark-reads", help="Measure ten uncached inspect calls")
|
||||
benchmark.set_defaults(handler=_benchmark_reads)
|
||||
|
||||
api = sub.add_parser("api", help="Run the read-only local API")
|
||||
api.add_argument("--host", default="127.0.0.1")
|
||||
api.add_argument("--port", type=int, default=8765)
|
||||
|
|
@ -207,6 +222,41 @@ def _capability_review(args: argparse.Namespace) -> dict[str, Any]:
|
|||
return review_capability_record(args.record, _root(args))
|
||||
|
||||
|
||||
def _emission_review(args):
|
||||
from .contracts import review_emission
|
||||
return review_emission(args.record, _root(args))
|
||||
|
||||
|
||||
def _coverage(args):
|
||||
from .contracts import coverage
|
||||
from .service import load_context
|
||||
return coverage(load_context(_root(args)))
|
||||
|
||||
|
||||
def _check_generated(args):
|
||||
from .maintenance import check_generated
|
||||
from .service import load_context
|
||||
return check_generated(load_context(_root(args)))
|
||||
|
||||
|
||||
def _scope_inventory(args):
|
||||
from .maintenance import scope_inventory
|
||||
from .service import load_context
|
||||
return dict(scope_inventory(load_context(_root(args))), ok=True)
|
||||
|
||||
|
||||
def _export_emission(args):
|
||||
from .maintenance import export_emission_bundle
|
||||
from .paths import infospace_root
|
||||
return export_emission_bundle(infospace_root(_root(args)), Path(args.destination))
|
||||
|
||||
|
||||
def _benchmark_reads(args):
|
||||
from .maintenance import benchmark_reads
|
||||
from .paths import infospace_root
|
||||
return benchmark_reads(infospace_root(_root(args)))
|
||||
|
||||
|
||||
def _profile_inspect(args: argparse.Namespace) -> dict[str, Any]:
|
||||
return profile_inspect(args.profile, _root(args))
|
||||
|
||||
|
|
|
|||
82
src/info_tech_canon/contracts.py
Normal file
82
src/info_tech_canon/contracts.py
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
"""Reusable declaration checks. Shape validity never proves operational truth."""
|
||||
|
||||
from collections import Counter
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from jsonschema import Draft202012Validator
|
||||
from jsonschema.exceptions import SchemaError
|
||||
import yaml
|
||||
|
||||
from .paths import infospace_root
|
||||
|
||||
|
||||
def schema_errors(instance: Any, schema: dict) -> list[dict]:
|
||||
try:
|
||||
Draft202012Validator.check_schema(schema)
|
||||
except SchemaError as exc:
|
||||
return [{"code": "invalid_schema", "message": exc.message}]
|
||||
return [
|
||||
{"code": "schema_violation", "instance_path": "/".join(map(str, e.path)),
|
||||
"message": e.message}
|
||||
for e in sorted(Draft202012Validator(schema).iter_errors(instance),
|
||||
key=lambda e: tuple(map(str, e.path)))
|
||||
]
|
||||
|
||||
|
||||
def emission_errors(instance: Any, schema: dict) -> list[dict]:
|
||||
errors = schema_errors(instance, schema)
|
||||
if isinstance(instance, dict) and isinstance(instance.get("sources"), list):
|
||||
counts = Counter(entry.get("source_id") for entry in instance["sources"]
|
||||
if isinstance(entry, dict) and isinstance(entry.get("source_id"), str))
|
||||
duplicates = sorted(key for key, count in counts.items() if count > 1)
|
||||
if duplicates:
|
||||
errors.append({"code": "duplicate_emission_cadence_source_id",
|
||||
"source_ids": duplicates})
|
||||
return errors
|
||||
|
||||
|
||||
def review_emission(path: str | Path, root: Path | str | None = None) -> dict:
|
||||
from .service import CanonServiceError
|
||||
|
||||
try:
|
||||
schema = yaml.safe_load((infospace_root(root) / "schemas/emission-cadence.schema.yaml").read_text())
|
||||
instance = yaml.safe_load(Path(path).read_text())
|
||||
except (OSError, yaml.YAMLError) as exc:
|
||||
raise CanonServiceError("declaration_unreadable", str(exc)) from exc
|
||||
errors = emission_errors(instance, schema)
|
||||
return {"ok": not errors, "contract": "emission-cadence/0.1", "errors": errors,
|
||||
"operational_truth_assessed": False}
|
||||
|
||||
|
||||
def coverage(context: Any) -> dict:
|
||||
"""Report actual checks and their limits rather than claiming full conformance."""
|
||||
bindings = {"mapping": "mapping.schema.yaml"}
|
||||
rows = []
|
||||
for artifact in sorted(context.infospace.artifacts, key=lambda a: a.id):
|
||||
schema = bindings.get(artifact.kind)
|
||||
rows.append({"id": artifact.id, "kind": artifact.kind, "schema": schema,
|
||||
"checks": "schema-and-references" if schema else "structural-or-specialized"})
|
||||
return {"ok": True, "artifacts": rows,
|
||||
"specialized": ["capability catalog/record", "practice pattern",
|
||||
"emission cadence example", "consumer packs"],
|
||||
"not_proven": ["ownership of concepts only in prose", "all Markdown links",
|
||||
"consumer adoption", "cross-version interoperability",
|
||||
"CARING effective access", "mapping rationale completeness"]}
|
||||
|
||||
|
||||
def bound_artifact_errors(context: Any) -> list[dict]:
|
||||
errors = []
|
||||
try:
|
||||
schema = yaml.safe_load((context.infospace_root / "schemas/mapping.schema.yaml").read_text())
|
||||
except (OSError, yaml.YAMLError) as exc:
|
||||
return [{"code": "mapping_schema_unreadable", "message": str(exc)}]
|
||||
for artifact in context.infospace.artifacts:
|
||||
if artifact.kind != "mapping":
|
||||
continue
|
||||
try:
|
||||
data = yaml.safe_load((context.infospace_root / artifact.path).read_text())
|
||||
errors.extend(dict(error, artifact_id=artifact.id) for error in schema_errors(data, schema))
|
||||
except (OSError, yaml.YAMLError) as exc:
|
||||
errors.append({"code": "mapping_unreadable", "artifact_id": artifact.id, "message": str(exc)})
|
||||
return errors
|
||||
108
src/info_tech_canon/maintenance.py
Normal file
108
src/info_tech_canon/maintenance.py
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
"""Reproducible projections, portable contract exports, and read measurements."""
|
||||
|
||||
from collections import Counter
|
||||
from dataclasses import replace
|
||||
from datetime import datetime, timezone
|
||||
import hashlib
|
||||
import io
|
||||
import json
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import statistics
|
||||
import subprocess
|
||||
import tarfile
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
from . import generation
|
||||
|
||||
|
||||
def scope_inventory(context) -> dict:
|
||||
return {"artifact_count": len(context.infospace.artifacts),
|
||||
"kinds": dict(sorted(Counter(a.kind for a in context.infospace.artifacts).items())),
|
||||
"standards": sorted(a.id for a in context.infospace.artifacts if a.kind == "standard"),
|
||||
"models": sorted(a.id for a in context.infospace.artifacts if a.kind == "model")}
|
||||
|
||||
|
||||
def check_generated(context) -> dict:
|
||||
"""Render only into a disposable copy; never repair the source as a check."""
|
||||
with tempfile.TemporaryDirectory(prefix="canon-freshness-") as temporary:
|
||||
target = Path(temporary) / "infospace"
|
||||
shutil.copytree(context.infospace_root, target)
|
||||
copied = replace(context, infospace_root=target)
|
||||
files = {}
|
||||
for render in (generation.generate_indexes, generation.generate_tree,
|
||||
generation.generate_agent_briefs):
|
||||
for item in render(copied)["files"]:
|
||||
path = Path(item["path"])
|
||||
files[str(path.relative_to(target))] = path.read_bytes()
|
||||
stale = []
|
||||
for relative, expected in files.items():
|
||||
original = context.infospace_root / relative
|
||||
if not original.is_file() or original.read_bytes() != expected:
|
||||
stale.append(relative)
|
||||
return {"ok": not stale, "checked": len(files), "stale": sorted(stale)}
|
||||
|
||||
|
||||
def source_evidence(root: Path) -> dict:
|
||||
digest = hashlib.sha256()
|
||||
# Include source and generated corpus; exclude reports to avoid self-hashing.
|
||||
for path in sorted(root.rglob("*")):
|
||||
if path.is_file() and "validation" not in path.relative_to(root).parts:
|
||||
digest.update(str(path.relative_to(root)).encode() + b"\0" + path.read_bytes() + b"\0")
|
||||
def git(*args):
|
||||
try:
|
||||
result = subprocess.run(["git", "-C", str(root.parent), *args],
|
||||
capture_output=True, text=True, check=False)
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
return result.stdout.strip() if result.returncode == 0 else None
|
||||
status = git("status", "--porcelain")
|
||||
return {"generated_at": datetime.now(timezone.utc).isoformat(),
|
||||
"revision": git("rev-parse", "HEAD"),
|
||||
"dirty": bool(status) if status is not None else None,
|
||||
"corpus_sha256": digest.hexdigest(),
|
||||
"digest_scope": "all infospace files except validation reports"}
|
||||
|
||||
|
||||
def export_emission_bundle(root: Path, destination: Path) -> dict:
|
||||
"""Content-addressed deterministic tar; a changed contract gets a new name."""
|
||||
paths = ["schemas/emission-cadence.schema.yaml",
|
||||
"standards/emission-cadence/InfoTechCanonEmissionCadenceStandard.md",
|
||||
"standards/emission-cadence/examples/qonto-assistant.yaml"]
|
||||
files = {path: (root / path).read_bytes() for path in paths}
|
||||
manifest = {"contract": "emission-cadence/0.1", "status": "draft",
|
||||
"files": {name: hashlib.sha256(data).hexdigest() for name, data in files.items()},
|
||||
"semantic_checks": ["unique source_id in sources"],
|
||||
"adoption_evidence": "Two independent source-owned implementations required; example does not count."}
|
||||
files["manifest.json"] = (json.dumps(manifest, sort_keys=True, indent=2) + "\n").encode()
|
||||
output = io.BytesIO()
|
||||
with tarfile.open(fileobj=output, mode="w", format=tarfile.USTAR_FORMAT) as archive:
|
||||
for name, data in sorted(files.items()):
|
||||
info = tarfile.TarInfo(name)
|
||||
info.size = len(data)
|
||||
info.mode = 0o644
|
||||
archive.addfile(info, io.BytesIO(data))
|
||||
data = output.getvalue()
|
||||
digest = hashlib.sha256(data).hexdigest()
|
||||
destination.mkdir(parents=True, exist_ok=True)
|
||||
path = destination / f"emission-cadence-0.1-{digest}.tar"
|
||||
try:
|
||||
with path.open("xb") as stream:
|
||||
stream.write(data)
|
||||
except FileExistsError:
|
||||
if path.read_bytes() != data:
|
||||
raise ValueError(f"Refusing to overwrite different bundle contents: {path}")
|
||||
return {"ok": True, "path": str(path), "sha256": digest, "manifest": manifest}
|
||||
|
||||
|
||||
def benchmark_reads(root: Path, runs: int = 10) -> dict:
|
||||
from .service import inspect_canon
|
||||
samples = []
|
||||
for _ in range(runs):
|
||||
started = time.perf_counter()
|
||||
inspect_canon(root)
|
||||
samples.append((time.perf_counter() - started) * 1000)
|
||||
return {"ok": True, "operation": "inspect", "runs": runs,
|
||||
"median_ms": statistics.median(samples), "max_ms": max(samples),
|
||||
"cache": "none; benchmark does not establish a production latency requirement"}
|
||||
15
src/info_tech_canon/paths.py
Normal file
15
src/info_tech_canon/paths.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
"""Corpus location is independent of the installed Python package."""
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def infospace_root(root: Path | str | None = None) -> Path:
|
||||
if root:
|
||||
return Path(root).resolve()
|
||||
if os.environ.get("INFO_TECH_CANON_ROOT"):
|
||||
return Path(os.environ["INFO_TECH_CANON_ROOT"]).resolve()
|
||||
local = Path.cwd() / "infospace"
|
||||
if local.is_dir():
|
||||
return local.resolve()
|
||||
return Path(__file__).resolve().parents[2] / "infospace"
|
||||
|
|
@ -19,10 +19,11 @@ from .bench import (
|
|||
run_collection_checks,
|
||||
)
|
||||
from .validation import structural_checks
|
||||
from .paths import infospace_root
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
DEFAULT_INFOSPACE_ROOT = REPO_ROOT / "infospace"
|
||||
DEFAULT_INFOSPACE_ROOT = infospace_root()
|
||||
|
||||
REVIEW_KIT_COMPONENTS = {
|
||||
"manifest": "agent/review-kit/review-kit.yaml",
|
||||
|
|
@ -65,18 +66,18 @@ class CanonContext:
|
|||
|
||||
|
||||
def load_context(root: Path | str | None = None) -> CanonContext:
|
||||
infospace_root = Path(root) if root else DEFAULT_INFOSPACE_ROOT
|
||||
resolved_root = infospace_root(root)
|
||||
try:
|
||||
infospace = load_infospace(infospace_root)
|
||||
infospace = load_infospace(resolved_root)
|
||||
except Exception as exc:
|
||||
raise CanonServiceError(
|
||||
"infospace_load_failed",
|
||||
f"Unable to load infospace at {infospace_root}",
|
||||
{"root": str(infospace_root), "reason": str(exc)},
|
||||
f"Unable to load infospace at {resolved_root}",
|
||||
{"root": str(resolved_root), "reason": str(exc)},
|
||||
) from exc
|
||||
return CanonContext(
|
||||
repo_root=REPO_ROOT,
|
||||
infospace_root=infospace_root,
|
||||
repo_root=resolved_root.parent,
|
||||
infospace_root=resolved_root,
|
||||
infospace=infospace,
|
||||
)
|
||||
|
||||
|
|
@ -217,6 +218,11 @@ def validate_canon(root: Path | str | None = None) -> dict[str, Any]:
|
|||
structural = structural_checks(context)
|
||||
errors.extend(structural["errors"])
|
||||
warnings.extend(structural["warnings"])
|
||||
from .contracts import bound_artifact_errors, coverage
|
||||
errors.extend(bound_artifact_errors(context))
|
||||
ownership = generation.concept_ownership(context)
|
||||
errors.extend(dict(item, code="concept_ownership_conflict")
|
||||
for item in ownership["ownership_conflicts"])
|
||||
|
||||
return {
|
||||
"ok": not errors,
|
||||
|
|
@ -224,6 +230,7 @@ def validate_canon(root: Path | str | None = None) -> dict[str, Any]:
|
|||
"warnings": warnings,
|
||||
"metrics": checks.metrics,
|
||||
"details": checks.details,
|
||||
"coverage": coverage(context),
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -232,6 +239,8 @@ def write_validation_report(
|
|||
root: Path | str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
payload = validate_canon(root)
|
||||
from .maintenance import source_evidence
|
||||
payload["evidence"] = source_evidence(infospace_root(root))
|
||||
path = Path(destination)
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
||||
|
|
@ -335,7 +344,7 @@ def review_capability_record(
|
|||
from .capability import CapabilityReviewError, review_path
|
||||
|
||||
try:
|
||||
return review_path(path)
|
||||
return review_path(path, infospace_root(root) / "models/capability/capabilities.yaml")
|
||||
except CapabilityReviewError as exc:
|
||||
raise CanonServiceError(exc.code, exc.message) from exc
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ REQUIRED_SCHEMAS = (
|
|||
"capability-record.schema.yaml",
|
||||
"attribute-value-type.schema.yaml",
|
||||
"practice-pattern.schema.yaml",
|
||||
"emission-cadence.schema.yaml",
|
||||
)
|
||||
|
||||
RETRIEVAL_BRIEF_KINDS = {
|
||||
|
|
@ -397,7 +398,8 @@ def structural_checks(context: Any) -> dict[str, list[dict[str, Any]]]:
|
|||
_check_required_top_level_files(context.repo_root, errors)
|
||||
_check_required_infospace_dirs(context.infospace_root, errors)
|
||||
_check_required_schemas(context.infospace_root, errors)
|
||||
_check_capability_catalog(errors)
|
||||
_check_capability_catalog(context.infospace_root, errors)
|
||||
_check_emission_cadence_contract(context.infospace_root, errors)
|
||||
_check_canon_paths(context.repo_root, context.infospace_root, errors)
|
||||
_check_artifact_index(context.repo_root, context.infospace_root, errors)
|
||||
_check_practice_pattern_assets(
|
||||
|
|
@ -599,11 +601,11 @@ def _check_required_infospace_dirs(
|
|||
)
|
||||
|
||||
|
||||
def _check_capability_catalog(errors: list[dict[str, Any]]) -> None:
|
||||
from .capability import check_catalog_contract
|
||||
def _check_capability_catalog(infospace_root: Path, errors: list[dict[str, Any]]) -> None:
|
||||
from .capability import check_catalog_contract, load_catalog
|
||||
|
||||
try:
|
||||
errors.extend(check_catalog_contract())
|
||||
errors.extend(check_catalog_contract(load_catalog(infospace_root / "models/capability/capabilities.yaml")))
|
||||
except Exception as exc: # pragma: no cover - catalog missing is structural
|
||||
errors.append(
|
||||
{
|
||||
|
|
@ -613,6 +615,20 @@ def _check_capability_catalog(errors: list[dict[str, Any]]) -> None:
|
|||
)
|
||||
|
||||
|
||||
def _check_emission_cadence_contract(
|
||||
infospace_root: Path,
|
||||
errors: list[dict[str, Any]],
|
||||
) -> None:
|
||||
from .contracts import emission_errors
|
||||
|
||||
schema = _read_yaml(infospace_root / "schemas/emission-cadence.schema.yaml", errors)
|
||||
example_path = "standards/emission-cadence/examples/qonto-assistant.yaml"
|
||||
example = _read_yaml(infospace_root / example_path, errors)
|
||||
if isinstance(schema, dict):
|
||||
errors.extend(dict(error, path=example_path)
|
||||
for error in emission_errors(example, schema))
|
||||
|
||||
|
||||
def _check_required_schemas(
|
||||
infospace_root: Path,
|
||||
errors: list[dict[str, Any]],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue