diff --git a/Makefile b/Makefile index b7b874c..6071ca5 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: build test validate dist release-dry-run clean +.PHONY: build test validate validate-maturity dist release-dry-run clean BIN := holmes DIST_DIR := dist @@ -17,7 +17,10 @@ build: test: go test ./... -validate: build +validate-maturity: + python3 tools/validate_maturity.py + +validate: build validate-maturity python3 tools/validate_holmes.py bin/$(BIN) --version bin/$(BIN) doctor diff --git a/repo.maturity.yaml b/repo.maturity.yaml new file mode 100644 index 0000000..e31c8ca --- /dev/null +++ b/repo.maturity.yaml @@ -0,0 +1,62 @@ +schemaVersion: repo-maturity.v1 +repository: SocioProphet/holmes +plane: runtime +status: active +canonicality: canonical +owners: + - SocioProphet +maturity: + level: M2 + targetLevel: M3 + evidence: + - README.md defines Holmes purpose, product family, Slash Topics training role, proof-claim reasoning role, repo boundaries, and integration path. + - docs/ARCHITECTURE.md defines Holmes product components, service boundaries, TriTRPC method families, and promotion rules. + - docs/NLP_COMPONENT_ALIGNMENT.md defines governed NLP component coverage and Slash Topics topic-model training alignment. + - docs/PROOF_CLAIM_CONTRACT.md defines the Propose -> Explain -> Verify proof-claim contract and policy-admission boundary. + - examples/holmes-surface.json provides the machine-readable Holmes product surface fixture. + - examples/holmes-proof-claim-contract.json provides deterministic proof-claim reasoning fixture coverage. + - tools/validate_holmes.py validates Holmes surface and proof-claim contract fixtures. + - Makefile provides build, test, validate, dist, and release-dry-run targets. + - .github/workflows/validate.yml runs make validate and make release-dry-run on pull requests and main pushes. +validation: + commands: + - make validate + ciRequired: true + lastKnownStatus: pending +integrations: + - repository: SocioProphet/functional-model-surfaces + relationship: normative cross-surface standards and maturity model reference + required: true + - repository: SocioProphet/prophet-platform + relationship: runtime deployment and platform records after contracts stabilize + required: true + - repository: SocioProphet/sherlock-search + relationship: discovery, retrieval, evidence search, and investigation input surface + required: true + - repository: SocioProphet/slash-topics + relationship: governed topic-pack semantics and topic-model training consumer + required: true + - repository: SociOS-Linux/nlplab + relationship: Linux-native NLP lab execution and benchmark receipts + required: true + - repository: SourceOS-Linux/sourceos-model-carry + relationship: SourceOS client references and signed service carry refs + required: true + - repository: SocioProphet/ontogenesis + relationship: canonical semantic contracts for claims, traces, truth bounds, and contradiction artifacts + required: true + - repository: SocioProphet/policy-fabric + relationship: downstream policy admission for Holmes evidence and proof artifacts + required: true + - repository: SocioProphet/agentplane + relationship: governed execution after policy outcomes are decided + required: true + - repository: SocioProphet/sociosphere + relationship: workspace governance and maturity ingestion + required: false +nextActions: + - Add negative fixtures and a negative-fixture runner so Holmes can honestly claim M3. + - Replace deterministic not-yet-wired CLI stubs with service-backed Sherlock, graph, and governance adapters. + - Add schema files for Holmes surface, proof-claim contract, and Slash Topics training references. + - Add release notes, checksums, and provenance attestations for M4 readiness. + - Register Holmes in workspace-inventory or Sociosphere scorecard ingestion. diff --git a/tools/validate_maturity.py b/tools/validate_maturity.py new file mode 100644 index 0000000..13b4dfa --- /dev/null +++ b/tools/validate_maturity.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import re +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +MATURITY = ROOT / "repo.maturity.yaml" + +REQUIRED_HEADER_VALUES = { + "schemaVersion": "repo-maturity.v1", + "repository": "SocioProphet/holmes", + "plane": "runtime", + "status": "active", + "canonicality": "canonical", +} +REQUIRED_TEXT = [ + "owners:", + " - SocioProphet", + "maturity:", + " level: M2", + " targetLevel: M3", + "validation:", + " commands:", + " - make validate", + " ciRequired: true", + "integrations:", + "nextActions:", +] +REQUIRED_INTEGRATIONS = { + "SocioProphet/functional-model-surfaces", + "SocioProphet/prophet-platform", + "SocioProphet/sherlock-search", + "SocioProphet/slash-topics", + "SociOS-Linux/nlplab", + "SourceOS-Linux/sourceos-model-carry", + "SocioProphet/ontogenesis", + "SocioProphet/policy-fabric", + "SocioProphet/agentplane", + "SocioProphet/sociosphere", +} +ALLOWED_VALIDATION_STATUS = {"pending", "passing", "failing", "unknown"} + + +def fail(message: str) -> int: + print(f"ERROR: {message}", file=sys.stderr) + return 1 + + +def scalar(text: str, key: str) -> str | None: + match = re.search(rf"^{re.escape(key)}:\s*(.+?)\s*$", text, flags=re.MULTILINE) + if not match: + return None + return match.group(1).strip().strip('"') + + +def count_list_items_in_section(text: str, section: str) -> int: + match = re.search(rf"^{re.escape(section)}:\n(?P(?:\s+.*\n?)*)", text, flags=re.MULTILINE) + if not match: + return 0 + body = match.group("body") + return len(re.findall(r"^\s+-\s+", body, flags=re.MULTILINE)) + + +def main() -> int: + if not MATURITY.exists(): + return fail("missing repo.maturity.yaml") + text = MATURITY.read_text() + + for key, expected in REQUIRED_HEADER_VALUES.items(): + observed = scalar(text, key) + if observed != expected: + return fail(f"{key} must be {expected!r}; got {observed!r}") + + for required in REQUIRED_TEXT: + if required not in text: + return fail(f"missing required maturity text: {required}") + + status = scalar(text, "lastKnownStatus") + if status not in ALLOWED_VALIDATION_STATUS: + return fail(f"validation.lastKnownStatus must be one of {sorted(ALLOWED_VALIDATION_STATUS)}; got {status!r}") + + missing_integrations = sorted(repo for repo in REQUIRED_INTEGRATIONS if repo not in text) + if missing_integrations: + return fail(f"missing integrations: {missing_integrations}") + + evidence_count = count_list_items_in_section(text, " evidence") + if evidence_count < 6: + return fail(f"maturity.evidence should contain at least 6 concrete evidence items; got {evidence_count}") + + next_actions = count_list_items_in_section(text, "nextActions") + if next_actions < 3: + return fail(f"nextActions should contain at least 3 roadmap items; got {next_actions}") + + print("OK: Holmes maturity manifest validated") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())