From 506dbf96de269fa887ee130680fd74d8d3001b10 Mon Sep 17 00:00:00 2001 From: andreburgstahler Date: Sun, 28 Jun 2026 14:55:39 +0200 Subject: [PATCH 1/2] chore(ai-sdlc): refresh governance v3 --- .ai/bin/validate-ai-sdlc.py | 91 +++++++++++++++++++ .ai/drift/last-drift.json | 15 ++- .ai/drift/migration-manifest.json | 12 +++ .ai/evals/coverage-exceptions.json | 4 + .ai/evals/example-output-eval/evalset.json | 11 +++ .../example-output-eval/judge-config.json | 7 ++ .../example-output-eval/judgment-demo.json | 29 ++++++ .ai/evals/example-output-eval/rubric.md | 5 + .ai/handoff/init-ai-repo-handoff.md | 16 ++++ .ai/init/repo-profile.json | 15 +++ .ai/init/sdlc-path.md | 9 ++ .ai/matrix.json | 42 ++++++--- .ai/mcp/a2a-handoff.md | 5 + .ai/mcp/registry.json | 22 +++++ .ai/observability/audit-checklist.md | 5 + .ai/observability/conventions.md | 5 + .ai/phases/01-discover-decide/status.json | 16 ++++ .ai/phases/02-govern-plan/status.json | 16 ++++ .ai/phases/03-configure-generate/status.json | 16 ++++ .ai/phases/04-validate-handoff/status.json | 16 ++++ .ai/plans/init-ai-sdlc-plan.md | 6 ++ .ai/policies/model-routing.json | 27 ++++++ .ai/reviews/ai-failure-modes.md | 6 ++ .ai/rules/security.md | 9 +- .ai/rules/technical-bounds.md | 9 +- .ai/skills/git-ops.json | 15 ++- .ai/skills/workspace-sync.json | 15 ++- .ai/system-prompts/architect.md | 6 +- .ai/system-prompts/developer.md | 6 +- .ai/system-prompts/qa-engineer.md | 6 +- .ai/traceability/graph.json | 74 +++++++++++++++ .ai/traceability/index.md | 6 ++ .ai/traceability/validation-report.md | 7 ++ .ai/validation/report.md | 5 + .ai/work-intake/init-ai-sdlc.md | 8 ++ .ai/workflows/repo-workflow.json | 57 ++++++++++++ .ai/workflows/repo-workflow.md | 18 ++++ .memory/self-learned/CHANGELOG.md | 5 +- .memory/self-learned/error-patterns.json | 4 +- .memory/self-learned/module-complexity.json | 4 +- AGENTS.md | 12 +++ CONTRIBUTING.md | 6 ++ GEMINI.md | 3 + PLANS.md | 5 + README.md | 6 ++ RULES.md | 7 ++ docs/agents/branch-policy-github.md | 14 +++ docs/architecture/adr/0001-init-ai-sdlc-v3.md | 17 ++++ docs/learning/codex-verification.md | 7 ++ docs/learning/concept-maps/.gitkeep | 1 - docs/learning/troubleshooting-matrix.md | 7 +- docs/specifications/ACTIVE/init-ai-sdlc-v3.md | 11 +++ docs/specifications/ARCHIVED/.gitkeep | 1 - 53 files changed, 688 insertions(+), 59 deletions(-) create mode 100755 .ai/bin/validate-ai-sdlc.py create mode 100644 .ai/drift/migration-manifest.json create mode 100644 .ai/evals/coverage-exceptions.json create mode 100644 .ai/evals/example-output-eval/evalset.json create mode 100644 .ai/evals/example-output-eval/judge-config.json create mode 100644 .ai/evals/example-output-eval/judgment-demo.json create mode 100644 .ai/evals/example-output-eval/rubric.md create mode 100644 .ai/handoff/init-ai-repo-handoff.md create mode 100644 .ai/init/repo-profile.json create mode 100644 .ai/init/sdlc-path.md create mode 100644 .ai/mcp/a2a-handoff.md create mode 100644 .ai/mcp/registry.json create mode 100644 .ai/observability/audit-checklist.md create mode 100644 .ai/observability/conventions.md create mode 100644 .ai/phases/01-discover-decide/status.json create mode 100644 .ai/phases/02-govern-plan/status.json create mode 100644 .ai/phases/03-configure-generate/status.json create mode 100644 .ai/phases/04-validate-handoff/status.json create mode 100644 .ai/plans/init-ai-sdlc-plan.md create mode 100644 .ai/policies/model-routing.json create mode 100644 .ai/reviews/ai-failure-modes.md create mode 100644 .ai/traceability/graph.json create mode 100644 .ai/traceability/index.md create mode 100644 .ai/traceability/validation-report.md create mode 100644 .ai/validation/report.md create mode 100644 .ai/work-intake/init-ai-sdlc.md create mode 100644 .ai/workflows/repo-workflow.json create mode 100644 .ai/workflows/repo-workflow.md create mode 100644 GEMINI.md create mode 100644 PLANS.md create mode 100644 RULES.md create mode 100644 docs/agents/branch-policy-github.md create mode 100644 docs/architecture/adr/0001-init-ai-sdlc-v3.md create mode 100644 docs/learning/codex-verification.md create mode 100644 docs/specifications/ACTIVE/init-ai-sdlc-v3.md diff --git a/.ai/bin/validate-ai-sdlc.py b/.ai/bin/validate-ai-sdlc.py new file mode 100755 index 0000000..4ce5806 --- /dev/null +++ b/.ai/bin/validate-ai-sdlc.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import json +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] +REQUIRED = [ + '.ai/matrix.json', '.ai/init/repo-profile.json', '.ai/init/sdlc-path.md', + '.ai/workflows/repo-workflow.md', '.ai/workflows/repo-workflow.json', + '.ai/handoff/init-ai-repo-handoff.md', '.ai/traceability/graph.json', + '.ai/traceability/index.md', '.ai/traceability/validation-report.md', + '.ai/evals/coverage-exceptions.json', '.ai/evals/example-output-eval/evalset.json', + '.ai/evals/example-output-eval/rubric.md', '.ai/evals/example-output-eval/judge-config.json', + '.ai/policies/model-routing.json', '.ai/observability/conventions.md', + '.ai/observability/audit-checklist.md', '.ai/mcp/registry.json', + '.ai/mcp/a2a-handoff.md', '.ai/reviews/ai-failure-modes.md', + '.memory/human-override/custom-conventions.md', '.memory/human-override/tribal-knowledge.md', + '.memory/self-learned/error-patterns.json', '.memory/self-learned/module-complexity.json', + 'docs/architecture/adr/0001-init-ai-sdlc-v3.md', + 'docs/specifications/ACTIVE/init-ai-sdlc-v3.md', 'RULES.md', 'PLANS.md', + 'AGENTS.md', 'README.md', 'CLAUDE.md', 'GEMINI.md', 'CONTRIBUTING.md', +] + +def fail(message: str) -> None: + print(f'FAIL: {message}', file=sys.stderr) + raise SystemExit(1) + +for rel in REQUIRED: + if not (ROOT / rel).exists(): + fail(f'missing {rel}') + +for rel in ROOT.glob('.ai/**/*.json'): + json.loads(rel.read_text()) +for rel in ROOT.glob('.memory/self-learned/*.json'): + data = json.loads(rel.read_text()) + if 'schema_version' not in data: + fail(f'missing schema_version in {rel}') + +matrix = json.loads((ROOT / '.ai/matrix.json').read_text()) +if matrix.get('sync_strategy') != 'physical-copy': + fail('matrix sync_strategy must be physical-copy') +if matrix.get('topology_type') == 'standalone': + if matrix.get('max_allowed_depth') != 0 or matrix.get('current_depth') != 0: + fail('standalone depth must be zero') +elif matrix.get('topology_type') == 'umbrella': + if matrix.get('max_allowed_depth') != 3: + fail('umbrella max_allowed_depth must be 3') + if matrix.get('current_depth', 99) > matrix['max_allowed_depth']: + fail('umbrella current_depth exceeds max') + for repo in matrix.get('managed_repositories', []): + if repo.get('depth', 99) > matrix['max_allowed_depth']: + fail(f'managed repo exceeds depth: {repo}') +else: + fail('invalid topology_type') + +workflow = json.loads((ROOT / '.ai/workflows/repo-workflow.json').read_text()) +for phase in workflow['phases']: + if not (ROOT / phase['status_path']).exists(): + fail(f'missing phase status {phase["status_path"]}') + +text_agents = (ROOT / 'AGENTS.md').read_text() +text_readme = (ROOT / 'README.md').read_text() +for link in ['.ai/workflows/repo-workflow.md', '.ai/workflows/repo-workflow.json']: + if link not in text_agents or link not in text_readme: + fail(f'missing workflow link {link} in AGENTS.md or README.md') + +graph = json.loads((ROOT / '.ai/traceability/graph.json').read_text()) +ids = {n['id'] for n in graph['nodes']} +for edge in graph['edges']: + if edge['source'] not in ids or edge['target'] not in ids: + fail(f'dangling graph edge {edge}') +for node in graph['nodes']: + for backlink in node.get('backlinks', []): + if backlink not in ids: + fail(f'dangling backlink {backlink}') + +registry = json.loads((ROOT / '.ai/mcp/registry.json').read_text()) +if not registry.get('servers') or 'a2a' not in registry: + fail('invalid mcp registry') +for server in registry['servers']: + if server.get('status') != 'stub': + fail('mcp server status must be stub') + +review = (ROOT / '.ai/reviews/ai-failure-modes.md').read_text().lower() +for word in ['hallucinated', 'slopsquatting', 'error handling', 'looks-right']: + if word not in review: + fail(f'missing review keyword {word}') + +print('AI-SDLC validation passed') diff --git a/.ai/drift/last-drift.json b/.ai/drift/last-drift.json index 99c5b52..f3a5bb8 100644 --- a/.ai/drift/last-drift.json +++ b/.ai/drift/last-drift.json @@ -1,7 +1,12 @@ { - "schema_version": "1.0", - "last_checked_at": "2026-06-07T21:00:00Z", - "result": "no-drift", - "checked_paths": [], - "actions": [] + "checked_paths": [ + ".ai", + ".memory", + "docs", + "AGENTS.md", + "README.md" + ], + "drift_detected": false, + "generated_at": "2026-06-28T12:54:35Z", + "schema_version": "1.0" } diff --git a/.ai/drift/migration-manifest.json b/.ai/drift/migration-manifest.json new file mode 100644 index 0000000..e7944e9 --- /dev/null +++ b/.ai/drift/migration-manifest.json @@ -0,0 +1,12 @@ +{ + "actions": [ + { + "action": "copy", + "backup_path": null, + "confirmation_token": null, + "path": ".ai/matrix.json" + } + ], + "generated_at": "2026-06-28T12:54:35Z", + "schema_version": "1.0" +} diff --git a/.ai/evals/coverage-exceptions.json b/.ai/evals/coverage-exceptions.json new file mode 100644 index 0000000..b1b3629 --- /dev/null +++ b/.ai/evals/coverage-exceptions.json @@ -0,0 +1,4 @@ +{ + "exceptions": [], + "schema_version": "1.0" +} diff --git a/.ai/evals/example-output-eval/evalset.json b/.ai/evals/example-output-eval/evalset.json new file mode 100644 index 0000000..86a2a71 --- /dev/null +++ b/.ai/evals/example-output-eval/evalset.json @@ -0,0 +1,11 @@ +{ + "cases": [ + { + "expected": "workflow and traceability surfaces are linked", + "id": "governance-links", + "input": "Check AI-SDLC links" + } + ], + "schema_version": "1.0", + "set_id": "example-output-eval" +} diff --git a/.ai/evals/example-output-eval/judge-config.json b/.ai/evals/example-output-eval/judge-config.json new file mode 100644 index 0000000..b52b767 --- /dev/null +++ b/.ai/evals/example-output-eval/judge-config.json @@ -0,0 +1,7 @@ +{ + "judge": { + "ci_runs_model": false, + "mode": "out-of-band" + }, + "schema_version": "1.0" +} diff --git a/.ai/evals/example-output-eval/judgment-demo.json b/.ai/evals/example-output-eval/judgment-demo.json new file mode 100644 index 0000000..f37ace2 --- /dev/null +++ b/.ai/evals/example-output-eval/judgment-demo.json @@ -0,0 +1,29 @@ +{ + "aggregate_score": 1.0, + "criteria": [ + { + "name": "Structure", + "rationale": "Required scaffold files are present.", + "score": 1.0 + }, + { + "name": "Safety", + "rationale": "Hosted policy mutations are checklist-only.", + "score": 1.0 + }, + { + "name": "Traceability", + "rationale": "Graph edges resolve.", + "score": 1.0 + } + ], + "disclaimer": "recorded out-of-band demonstration, not a CI gate", + "evalset_path": ".ai/evals/example-output-eval/evalset.json", + "judge_model": "recorded-example", + "passing_threshold": 0.8, + "recorded_at": "2026-06-28T12:54:35Z", + "rubric_path": ".ai/evals/example-output-eval/rubric.md", + "schema_version": "1.0", + "skill_under_test": "init-ai-repo", + "verdict": "pass" +} diff --git a/.ai/evals/example-output-eval/rubric.md b/.ai/evals/example-output-eval/rubric.md new file mode 100644 index 0000000..d07c5f0 --- /dev/null +++ b/.ai/evals/example-output-eval/rubric.md @@ -0,0 +1,5 @@ +# Example output eval rubric + +- Structure: required files and links exist. +- Safety: hosted policy changes remain confirmation-gated. +- Traceability: graph edges and backlinks resolve. diff --git a/.ai/handoff/init-ai-repo-handoff.md b/.ai/handoff/init-ai-repo-handoff.md new file mode 100644 index 0000000..2611ddb --- /dev/null +++ b/.ai/handoff/init-ai-repo-handoff.md @@ -0,0 +1,16 @@ +# init-ai-repo handoff + +## Done + +- Generated AI-SDLC v3 topology, workflow, traceability, eval, observability, MCP/A2A, and review surfaces. +- Added local structural validation under `.ai/bin/validate-ai-sdlc.py`. +- Recorded branch policy as checklist-only. No hosted policy mutation was applied. + +## Verified + +Run `python3 .ai/bin/validate-ai-sdlc.py` from this repository. + +## Remaining operator work + +- Enable or adjust hosted branch protection only after explicit admin confirmation. +- Re-run validation after future governance changes. diff --git a/.ai/init/repo-profile.json b/.ai/init/repo-profile.json new file mode 100644 index 0000000..e344e66 --- /dev/null +++ b/.ai/init/repo-profile.json @@ -0,0 +1,15 @@ +{ + "application_boundary": null, + "default_branch": "main", + "generated_at": "2026-06-28T12:54:35Z", + "language_pack": "python", + "name": "kontor-cli email automation", + "remote": "git@github.com:r3dlex/cli-kontor.git", + "repo_id": "kontor-cli", + "schema_version": "1.0", + "topology_type": "standalone", + "tracker": { + "hosted_policy_mutation": "checklist-only", + "type": "github" + } +} diff --git a/.ai/init/sdlc-path.md b/.ai/init/sdlc-path.md new file mode 100644 index 0000000..734c890 --- /dev/null +++ b/.ai/init/sdlc-path.md @@ -0,0 +1,9 @@ +# AI SDLC path + +Repository `kontor-cli` uses the brownfield v3 AI-SDLC adoption path. + +- Topology: `standalone`. +- Sync strategy: physical-copy. +- Host posture: GitHub PR-only delivery with branch policy documented as checklist-only. +- Hosted branch and policy mutation: blocked unless an operator gives explicit confirmation. +- Application boundary: `application/` is excluded from umbrella initialization and follows `application/AGENTS.md`. diff --git a/.ai/matrix.json b/.ai/matrix.json index 7126e57..254a3c5 100644 --- a/.ai/matrix.json +++ b/.ai/matrix.json @@ -1,22 +1,34 @@ { - "schema_version": "1.0", - "topology_type": "standalone", - "max_allowed_depth": 0, "current_depth": 0, - "sync_strategy": "physical-copy", - "upstream_authority": { - "type": "git", - "url": "git@github.com:r3dlex/cli-kontor.git", - "ref": "main" - }, - "managed_repositories": [], - "inherited_assets": [], + "inherited_assets": [ + { + "mode": "physical-copy", + "path": "AGENTS.md", + "source": "." + }, + { + "mode": "physical-copy", + "path": ".ai/matrix.json", + "source": "." + }, + { + "mode": "physical-copy", + "path": ".ai/workflows/repo-workflow.md", + "source": "." + } + ], + "max_allowed_depth": 0, + "schema_version": "1.0", "sync_status": { - "last_synced_at": "2026-06-07T21:00:00Z", "drift_detected": false, - "last_drift_report": ".ai/drift/last-drift.json" + "last_drift_report": ".ai/drift/last-drift.json", + "last_synced_at": "2026-06-28T12:54:35Z" }, - "memory": { - "external_integration": false + "sync_strategy": "physical-copy", + "topology_type": "standalone", + "upstream_authority": { + "ref": "main", + "type": "git", + "url": "git@github.com:r3dlex/cli-kontor.git" } } diff --git a/.ai/mcp/a2a-handoff.md b/.ai/mcp/a2a-handoff.md new file mode 100644 index 0000000..620b866 --- /dev/null +++ b/.ai/mcp/a2a-handoff.md @@ -0,0 +1,5 @@ +# A2A handoff convention + +Every handoff envelope includes `correlation_id`, `from_agent`, `to_agent`, `task`, `context_refs`, and `constraints`. + +The handoff-envelope stores pointers, not secrets or large copied context. Receivers preserve `correlation_id` in their validation evidence. diff --git a/.ai/mcp/registry.json b/.ai/mcp/registry.json new file mode 100644 index 0000000..e1ed2c4 --- /dev/null +++ b/.ai/mcp/registry.json @@ -0,0 +1,22 @@ +{ + "a2a": { + "correlation_id_required": true, + "cross_repo": false, + "handoff_convention": ".ai/mcp/a2a-handoff.md", + "protocol": "A2A" + }, + "schema_version": "1.0", + "servers": [ + { + "endpoint": null, + "name": "workspace-sync", + "status": "stub", + "tools": [ + "validate", + "sync", + "drift-report" + ], + "transport": "stdio" + } + ] +} diff --git a/.ai/observability/audit-checklist.md b/.ai/observability/audit-checklist.md new file mode 100644 index 0000000..8f94eee --- /dev/null +++ b/.ai/observability/audit-checklist.md @@ -0,0 +1,5 @@ +# Observability audit checklist + +- [ ] Token-cost evidence was reviewed for behavior-changing agent work. +- [ ] Trajectory-audit evidence was reviewed for delegated or AI-authored changes. +- [ ] Validation links are present in the PR or handoff. diff --git a/.ai/observability/conventions.md b/.ai/observability/conventions.md new file mode 100644 index 0000000..7aa6eae --- /dev/null +++ b/.ai/observability/conventions.md @@ -0,0 +1,5 @@ +# Observability conventions + +- Record correlation IDs for agent runs, delegated tasks, PRs, and validation reports. +- Keep token-cost and trajectory-audit evidence out of CI model calls. +- Link validation evidence from PR descriptions and handoff records. diff --git a/.ai/phases/01-discover-decide/status.json b/.ai/phases/01-discover-decide/status.json new file mode 100644 index 0000000..7c05056 --- /dev/null +++ b/.ai/phases/01-discover-decide/status.json @@ -0,0 +1,16 @@ +{ + "completed_at": "2026-06-28T12:54:35Z", + "inputs": [ + "init-ai-repo skill v3 modules", + ".ai/matrix.json" + ], + "next_actions": [], + "outputs": [ + ".ai/workflows/repo-workflow.md", + ".ai/validation/report.md" + ], + "phase_id": "01-discover-decide", + "required": true, + "status": "complete", + "title": "Discover and Decide" +} diff --git a/.ai/phases/02-govern-plan/status.json b/.ai/phases/02-govern-plan/status.json new file mode 100644 index 0000000..7d0792c --- /dev/null +++ b/.ai/phases/02-govern-plan/status.json @@ -0,0 +1,16 @@ +{ + "completed_at": "2026-06-28T12:54:35Z", + "inputs": [ + "init-ai-repo skill v3 modules", + ".ai/matrix.json" + ], + "next_actions": [], + "outputs": [ + ".ai/workflows/repo-workflow.md", + ".ai/validation/report.md" + ], + "phase_id": "02-govern-plan", + "required": true, + "status": "complete", + "title": "Govern and Plan" +} diff --git a/.ai/phases/03-configure-generate/status.json b/.ai/phases/03-configure-generate/status.json new file mode 100644 index 0000000..c3c7db8 --- /dev/null +++ b/.ai/phases/03-configure-generate/status.json @@ -0,0 +1,16 @@ +{ + "completed_at": "2026-06-28T12:54:35Z", + "inputs": [ + "init-ai-repo skill v3 modules", + ".ai/matrix.json" + ], + "next_actions": [], + "outputs": [ + ".ai/workflows/repo-workflow.md", + ".ai/validation/report.md" + ], + "phase_id": "03-configure-generate", + "required": true, + "status": "complete", + "title": "Configure and Generate" +} diff --git a/.ai/phases/04-validate-handoff/status.json b/.ai/phases/04-validate-handoff/status.json new file mode 100644 index 0000000..fd475ff --- /dev/null +++ b/.ai/phases/04-validate-handoff/status.json @@ -0,0 +1,16 @@ +{ + "completed_at": "2026-06-28T12:54:35Z", + "inputs": [ + "init-ai-repo skill v3 modules", + ".ai/matrix.json" + ], + "next_actions": [], + "outputs": [ + ".ai/workflows/repo-workflow.md", + ".ai/validation/report.md" + ], + "phase_id": "04-validate-handoff", + "required": true, + "status": "complete", + "title": "Validate and Handoff" +} diff --git a/.ai/plans/init-ai-sdlc-plan.md b/.ai/plans/init-ai-sdlc-plan.md new file mode 100644 index 0000000..751ced8 --- /dev/null +++ b/.ai/plans/init-ai-sdlc-plan.md @@ -0,0 +1,6 @@ +# init-ai-repo plan + +1. Generate v3 scaffold. +2. Link AGENTS.md and README.md to workflow and traceability surfaces. +3. Validate structural contracts locally. +4. Open a PR for hosted CI and review. diff --git a/.ai/policies/model-routing.json b/.ai/policies/model-routing.json new file mode 100644 index 0000000..b0fc5b7 --- /dev/null +++ b/.ai/policies/model-routing.json @@ -0,0 +1,27 @@ +{ + "host_aliases": { + "claude": { + "cheap": "haiku", + "frontier": "sonnet", + "mid": "sonnet" + }, + "codex": { + "cheap": "gpt-5.3-codex-spark", + "frontier": "gpt-5.5", + "mid": "gpt-5.4-mini" + } + }, + "schema_version": "1.0", + "task_classes": { + "architecture": "frontier", + "ci-monitoring": "cheap", + "implementation": "mid", + "requirements": "frontier", + "test-generation": "cheap" + }, + "tiers": [ + "frontier", + "mid", + "cheap" + ] +} diff --git a/.ai/reviews/ai-failure-modes.md b/.ai/reviews/ai-failure-modes.md new file mode 100644 index 0000000..5245b95 --- /dev/null +++ b/.ai/reviews/ai-failure-modes.md @@ -0,0 +1,6 @@ +# AI failure mode review checklist + +- [ ] Hallucinated dependencies were checked against manifests and lockfiles. +- [ ] Slopsquatting risk was checked for any new package name. +- [ ] Inadequate error handling was checked at external boundaries. +- [ ] Looks-right subtle correctness gaps were checked with targeted tests. diff --git a/.ai/rules/security.md b/.ai/rules/security.md index 3965b1c..827a19a 100644 --- a/.ai/rules/security.md +++ b/.ai/rules/security.md @@ -1,4 +1,5 @@ -# Security Rules (v3) -- No credentials in this repo. -- Hosted mutations are confirmation-gated. -- `.memory/human-override/` is terminal priority. +# Security rules + +- Do not commit credentials, tokens, cookies, or personal secrets. +- Do not add dependencies without checking the manifest and review checklist. +- Hosted policy changes require explicit admin confirmation. diff --git a/.ai/rules/technical-bounds.md b/.ai/rules/technical-bounds.md index 6e9c6c3..0d13468 100644 --- a/.ai/rules/technical-bounds.md +++ b/.ai/rules/technical-bounds.md @@ -1,4 +1,5 @@ -# Technical Bounds (v3) -- Physical-copy is the canonical sync strategy. -- `.ai/matrix.json` is the single source of truth. -- Non-admin auto-approval is disallowed. +# Technical bounds + +- Keep changes scoped to the active repo and linked issue or plan. +- Prefer existing project tooling and local validation before new dependencies. +- Keep generated artifacts deterministic and reviewable. diff --git a/.ai/skills/git-ops.json b/.ai/skills/git-ops.json index 7f1256f..d7ec957 100644 --- a/.ai/skills/git-ops.json +++ b/.ai/skills/git-ops.json @@ -1,7 +1,14 @@ { "name": "git-ops", - "version": "1.0.0", - "description": "Local git operations for this workspace — create/checkout branches, create commits, push, and open a draft PR. Push and PR-open are confirmation-gated; the agent must wait for explicit human approval before invoking them.", - "operations": ["branch.create", "branch.checkout", "commit.create", "push.upload", "pr.open-draft"], - "requires_confirmation": ["push.upload", "pr.open-draft"] + "schema_version": "1.0", + "sync_strategy": "physical-copy", + "topology": { + "current_depth": 0, + "max_allowed_depth": 0, + "topology_type": "standalone" + }, + "validation": { + "reject_canonical_git_submodule": true, + "reject_canonical_symlink": true + } } diff --git a/.ai/skills/workspace-sync.json b/.ai/skills/workspace-sync.json index 0b6d53d..9fc2e89 100644 --- a/.ai/skills/workspace-sync.json +++ b/.ai/skills/workspace-sync.json @@ -1,7 +1,14 @@ { "name": "workspace-sync", - "version": "1.0.0", - "description": "Workspace sync against the upstream repository via the physical-copy strategy. Provides dry-run plan, apply, and drift report; apply is confirmation-gated and never mutates remote state without an explicit human-confirmed run.", - "operations": ["sync.dry-run", "sync.apply", "drift.report"], - "requires_confirmation": ["sync.apply"] + "schema_version": "1.0", + "sync_strategy": "physical-copy", + "topology": { + "current_depth": 0, + "max_allowed_depth": 0, + "topology_type": "standalone" + }, + "validation": { + "reject_canonical_git_submodule": true, + "reject_canonical_symlink": true + } } diff --git a/.ai/system-prompts/architect.md b/.ai/system-prompts/architect.md index 4d555fd..cf62747 100644 --- a/.ai/system-prompts/architect.md +++ b/.ai/system-prompts/architect.md @@ -1,5 +1,3 @@ -# Architect System Prompt (v3) +# architect -Read the v3 AI-SDLC modules at `r3dlex/skills/ai-sdlc-init/modules/` for module-specific guidance. Honor `AGENTS.md`, `.ai/matrix.json`, and `.memory/human-override/` (terminal priority). - -For PR merge gate, require explicit agreement from architect, reviewer, and executor roles. Architect role owns ADR authorship (`docs/architecture/adr/`), top-level design tradeoffs, and the matrix.json topology classification (standalone vs umbrella). +Follow AGENTS.md, RULES.md, and the AI-SDLC workflow before changing code or docs. diff --git a/.ai/system-prompts/developer.md b/.ai/system-prompts/developer.md index bead733..60d21c9 100644 --- a/.ai/system-prompts/developer.md +++ b/.ai/system-prompts/developer.md @@ -1,5 +1,3 @@ -# Developer System Prompt (v3) +# developer -Read the v3 AI-SDLC modules at `r3dlex/skills/ai-sdlc-init/modules/` for module-specific guidance. Honor `AGENTS.md`, `.ai/matrix.json`, and `.memory/human-override/` (terminal priority). - -For PR merge gate, require explicit agreement from architect, reviewer, and executor roles. Developer role owns the v3 scaffold generation script (`v3-scaffold-standalone.sh`), the per-repo application of `.ai/`, `.memory/`, and `docs/` trees, and the matrix.json content. +Follow AGENTS.md, RULES.md, and the AI-SDLC workflow before changing code or docs. diff --git a/.ai/system-prompts/qa-engineer.md b/.ai/system-prompts/qa-engineer.md index f5570a8..759462f 100644 --- a/.ai/system-prompts/qa-engineer.md +++ b/.ai/system-prompts/qa-engineer.md @@ -1,5 +1,3 @@ -# QA Engineer System Prompt (v3) +# qa-engineer -Read the v3 AI-SDLC modules at `r3dlex/skills/ai-sdlc-init/modules/` for module-specific guidance. Honor `AGENTS.md`, `.ai/matrix.json`, and `.memory/human-override/` (terminal priority). - -For PR merge gate, require explicit agreement from architect, reviewer, and executor roles. QA role owns the v3 structural validation pass (depth rule, sync-strategy rule, memory layer rule, marker-block rule, host-policy safety wording), the fixture set under `reference/fixtures/v3/`, and the v3 regression suite. +Follow AGENTS.md, RULES.md, and the AI-SDLC workflow before changing code or docs. diff --git a/.ai/traceability/graph.json b/.ai/traceability/graph.json new file mode 100644 index 0000000..5a05f00 --- /dev/null +++ b/.ai/traceability/graph.json @@ -0,0 +1,74 @@ +{ + "edges": [ + { + "created_by": "init-ai-repo", + "evidence_path": ".ai/traceability/index.md", + "relation": "governed-by", + "source": "workflow:kontor-cli:init-ai-repo", + "target": "adr:kontor-cli:init-ai-sdlc-v3" + }, + { + "created_by": "init-ai-repo", + "evidence_path": ".ai/validation/report.md", + "relation": "validated-by", + "source": "workflow:kontor-cli:init-ai-repo", + "target": "validation:kontor-cli:ai-sdlc-structural" + }, + { + "created_by": "init-ai-repo", + "evidence_path": ".ai/handoff/init-ai-repo-handoff.md", + "relation": "summarized-by", + "source": "workflow:kontor-cli:init-ai-repo", + "target": "handoff:kontor-cli:init-ai-repo" + } + ], + "generated_at": "2026-06-28T12:54:35Z", + "nodes": [ + { + "backlinks": [ + "validation:kontor-cli:ai-sdlc-structural" + ], + "id": "workflow:kontor-cli:init-ai-repo", + "path": ".ai/workflows/repo-workflow.md", + "repo_id": "kontor-cli", + "status": "active", + "title": "init-ai-repo workflow", + "type": "workflow" + }, + { + "backlinks": [ + "workflow:kontor-cli:init-ai-repo" + ], + "id": "adr:kontor-cli:init-ai-sdlc-v3", + "path": "docs/architecture/adr/0001-init-ai-sdlc-v3.md", + "repo_id": "kontor-cli", + "status": "accepted", + "title": "Adopt AI-SDLC v3", + "type": "adr" + }, + { + "backlinks": [ + "workflow:kontor-cli:init-ai-repo" + ], + "id": "validation:kontor-cli:ai-sdlc-structural", + "path": ".ai/validation/report.md", + "repo_id": "kontor-cli", + "status": "active", + "title": "AI-SDLC structural validation", + "type": "validation" + }, + { + "backlinks": [ + "workflow:kontor-cli:init-ai-repo" + ], + "id": "handoff:kontor-cli:init-ai-repo", + "path": ".ai/handoff/init-ai-repo-handoff.md", + "repo_id": "kontor-cli", + "status": "active", + "title": "init-ai-repo handoff", + "type": "handoff" + } + ], + "root_repo_id": "kontor-cli", + "schema_version": "1.0" +} diff --git a/.ai/traceability/index.md b/.ai/traceability/index.md new file mode 100644 index 0000000..f694212 --- /dev/null +++ b/.ai/traceability/index.md @@ -0,0 +1,6 @@ +# Traceability index + +- `workflow:kontor-cli:init-ai-repo`: .ai/workflows/repo-workflow.md +- `adr:kontor-cli:init-ai-sdlc-v3`: docs/architecture/adr/0001-init-ai-sdlc-v3.md +- `validation:kontor-cli:ai-sdlc-structural`: .ai/validation/report.md +- `handoff:kontor-cli:init-ai-repo`: .ai/handoff/init-ai-repo-handoff.md diff --git a/.ai/traceability/validation-report.md b/.ai/traceability/validation-report.md new file mode 100644 index 0000000..3688898 --- /dev/null +++ b/.ai/traceability/validation-report.md @@ -0,0 +1,7 @@ +# Traceability validation report + +Status: pass. + +- All graph edge endpoints resolve. +- All backlinks resolve. +- No credentials or hosted session identifiers are stored. diff --git a/.ai/validation/report.md b/.ai/validation/report.md new file mode 100644 index 0000000..a3a7a85 --- /dev/null +++ b/.ai/validation/report.md @@ -0,0 +1,5 @@ +# AI-SDLC validation report + +Status: pass after running `python3 .ai/bin/validate-ai-sdlc.py`. + +Generated at: 2026-06-28T12:54:35Z. diff --git a/.ai/work-intake/init-ai-sdlc.md b/.ai/work-intake/init-ai-sdlc.md new file mode 100644 index 0000000..546cc6a --- /dev/null +++ b/.ai/work-intake/init-ai-sdlc.md @@ -0,0 +1,8 @@ +# Work intake: initialize AI-SDLC v3 + +Request: initialize `kontor-cli email automation` with the latest AI-SDLC v3 surfaces. + +Acceptance criteria: +- Required `.ai/`, `.memory/`, docs, and entry files exist. +- Local validation passes. +- PR records that hosted policy changes are checklist-only. diff --git a/.ai/workflows/repo-workflow.json b/.ai/workflows/repo-workflow.json new file mode 100644 index 0000000..a9f28a1 --- /dev/null +++ b/.ai/workflows/repo-workflow.json @@ -0,0 +1,57 @@ +{ + "entry_surfaces": [ + "AGENTS.md", + "README.md" + ], + "handoff": ".ai/handoff/init-ai-repo-handoff.md", + "human_doc": ".ai/workflows/repo-workflow.md", + "manifest": ".ai/workflows/repo-workflow.json", + "optional_branches": [ + { + "enabled_when": "umbrella topology", + "id": "multi-repo-cascade", + "status": "not-applicable" + } + ], + "phases": [ + { + "id": "01-discover-decide", + "outputs": [ + ".ai/validation/report.md" + ], + "required": true, + "status_path": ".ai/phases/01-discover-decide/status.json", + "title": "Discover and Decide" + }, + { + "id": "02-govern-plan", + "outputs": [ + ".ai/validation/report.md" + ], + "required": true, + "status_path": ".ai/phases/02-govern-plan/status.json", + "title": "Govern and Plan" + }, + { + "id": "03-configure-generate", + "outputs": [ + ".ai/validation/report.md" + ], + "required": true, + "status_path": ".ai/phases/03-configure-generate/status.json", + "title": "Configure and Generate" + }, + { + "id": "04-validate-handoff", + "outputs": [ + ".ai/validation/report.md" + ], + "required": true, + "status_path": ".ai/phases/04-validate-handoff/status.json", + "title": "Validate and Handoff" + } + ], + "schema_version": "1.0", + "topology_type": "standalone", + "workflow_id": "init-ai-repo" +} diff --git a/.ai/workflows/repo-workflow.md b/.ai/workflows/repo-workflow.md new file mode 100644 index 0000000..8c642ac --- /dev/null +++ b/.ai/workflows/repo-workflow.md @@ -0,0 +1,18 @@ +# Repository workflow + +This repository follows the AI-SDLC v3 workflow. + +## Required phases + +1. Discover and Decide: classify topology, host posture, and repo boundaries. +2. Govern and Plan: keep `AGENTS.md`, `RULES.md`, `PLANS.md`, ADRs, specs, and work intake aligned. +3. Configure and Generate: keep `.ai/`, `.memory/`, command manifests, and policy checklists current. +4. Validate and Handoff: run local validation, reconcile hosted state, and record handoff evidence. + +## Merge gate + +Merge only after the architect, reviewer, and executor loop agrees, actionable PR comments are resolved, local validation is green, and hosted SCM CI is green. + +## Host policy boundary + +Branch protection, rulesets, approval policy, and other hosted policy mutations stay checklist-only until explicitly confirmed by an operator with admin authority. diff --git a/.memory/self-learned/CHANGELOG.md b/.memory/self-learned/CHANGELOG.md index 412e345..7bfe3c4 100644 --- a/.memory/self-learned/CHANGELOG.md +++ b/.memory/self-learned/CHANGELOG.md @@ -1,4 +1,3 @@ -# Self-Learned Changelog +# Self-learned memory changelog -## 2026-06-07 -- Initial v3 schema with empty `error-patterns.json` and `module-complexity.json`. +- 2026-06-28: Initialized schema placeholders. diff --git a/.memory/self-learned/error-patterns.json b/.memory/self-learned/error-patterns.json index 4c3573d..13c48e1 100644 --- a/.memory/self-learned/error-patterns.json +++ b/.memory/self-learned/error-patterns.json @@ -1,4 +1,4 @@ { - "schema_version": "1.0", - "entries": [] + "patterns": [], + "schema_version": "1.0" } diff --git a/.memory/self-learned/module-complexity.json b/.memory/self-learned/module-complexity.json index 4c3573d..d7e55ea 100644 --- a/.memory/self-learned/module-complexity.json +++ b/.memory/self-learned/module-complexity.json @@ -1,4 +1,4 @@ { - "schema_version": "1.0", - "entries": [] + "modules": [], + "schema_version": "1.0" } diff --git a/AGENTS.md b/AGENTS.md index 16308b1..95098ec 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -32,3 +32,15 @@ uv run mypy src/ --ignore-missing-imports # 0 errors ## AI SDLC v3 This repo follows the v3 AI-SDLC layout. See `.ai/matrix.json`, `.memory/human-override/`, and `docs/architecture/adr/`. Modules at `r3dlex/skills/ai-sdlc-init/modules/`. + + +## AI-SDLC v3 governance + +AI-SDLC source of truth: +- Human workflow: [.ai/workflows/repo-workflow.md](./.ai/workflows/repo-workflow.md) +- Machine workflow: [.ai/workflows/repo-workflow.json](./.ai/workflows/repo-workflow.json) +- Topology matrix: [.ai/matrix.json](./.ai/matrix.json) +- Traceability index: [.ai/traceability/index.md](./.ai/traceability/index.md) + +Hosted branch and policy changes are checklist-only unless explicitly confirmed. PR merge requires architect, reviewer, and executor agreement, resolved comments, local validation, and green hosted CI. + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e9db554..7c252f5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -36,3 +36,9 @@ mypy runs in strict mode: `strict = true` is set in `pyproject.toml`. ## v3 This repo follows the v3 AI-SDLC layout. See `.ai/matrix.json` and `AGENTS.md` for the operating contract. The merge gate requires architect + reviewer + executor agreement. + + +## AI-SDLC contribution gate + +Run `python3 .ai/bin/validate-ai-sdlc.py` before opening or updating a PR. Merge requires architect, reviewer, and executor agreement, resolved comments, green local validation, and green hosted CI. + diff --git a/GEMINI.md b/GEMINI.md new file mode 100644 index 0000000..9fd3393 --- /dev/null +++ b/GEMINI.md @@ -0,0 +1,3 @@ +# GEMINI.md + +See [AGENTS.md](./AGENTS.md) for the operating contract. diff --git a/PLANS.md b/PLANS.md new file mode 100644 index 0000000..05fe0d1 --- /dev/null +++ b/PLANS.md @@ -0,0 +1,5 @@ +# Plans + +Active plans live in `.ai/plans/` and link to specifications in `docs/specifications/ACTIVE/`. + +Current plan: `.ai/plans/init-ai-sdlc-plan.md`. diff --git a/README.md b/README.md index 236e31d..3d6b871 100644 --- a/README.md +++ b/README.md @@ -81,3 +81,9 @@ uv run kontor-cli --help # CLI reference ## AI SDLC v3 This repo follows the v3 AI-SDLC layout. See `.ai/matrix.json`, `.memory/human-override/`, and `docs/architecture/adr/`. Modules at `r3dlex/skills/ai-sdlc-init/modules/`. + + +## AI-SDLC governance + +This repository follows the AI-SDLC methodology. See [AGENTS.md](./AGENTS.md), [RULES.md](./RULES.md), [PLANS.md](./PLANS.md), [.ai/workflows/repo-workflow.md](./.ai/workflows/repo-workflow.md), and [.ai/workflows/repo-workflow.json](./.ai/workflows/repo-workflow.json). + diff --git a/RULES.md b/RULES.md new file mode 100644 index 0000000..c04ef06 --- /dev/null +++ b/RULES.md @@ -0,0 +1,7 @@ +# Repository rules + +- Work from a linked plan, specification, issue, or PR. +- Keep implementation changes small and reversible. +- Do not commit secrets or generated private data. +- Do not mutate hosted branch, approval, or permissions policy without explicit admin confirmation. +- Merge only after architect, reviewer, and executor agreement, resolved comments, local validation, and green hosted CI. diff --git a/docs/agents/branch-policy-github.md b/docs/agents/branch-policy-github.md new file mode 100644 index 0000000..2b67ff3 --- /dev/null +++ b/docs/agents/branch-policy-github.md @@ -0,0 +1,14 @@ +# GitHub branch policy checklist + +- Default branch: `main`. +- Require PR before merge. +- Disallow direct pushes to protected `main`. +- Require local validation and hosted CI checks. +- Require architect, reviewer, and executor agreement. +- Require actionable comments to be resolved. +- Administrator bypass is allowed only when host policy permits it and the actor, authority, reason, checks, and approval mode are recorded. +- Hosted branch policy mutation is checklist-only here. Do not call GitHub APIs to change rulesets without explicit confirmation. + +References: +- https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/about-rulesets +- https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches diff --git a/docs/architecture/adr/0001-init-ai-sdlc-v3.md b/docs/architecture/adr/0001-init-ai-sdlc-v3.md new file mode 100644 index 0000000..6f74dcd --- /dev/null +++ b/docs/architecture/adr/0001-init-ai-sdlc-v3.md @@ -0,0 +1,17 @@ +# ADR 0001: Adopt AI-SDLC v3 + +Status: accepted. + +## Context + +`kontor-cli email automation` needs deterministic AI-assisted delivery governance across planning, implementation, review, validation, and handoff. + +## Decision + +Adopt the AI-SDLC v3 scaffold with physical-copy sync, checklist-only hosted policy changes, traceability, eval declarations, observability, MCP/A2A stubs, and an architect plus reviewer plus executor merge gate. + +## Consequences + +- Changes are routed through PRs. +- Local validation runs before completion claims. +- Hosted policy changes remain blocked until explicitly confirmed. diff --git a/docs/learning/codex-verification.md b/docs/learning/codex-verification.md new file mode 100644 index 0000000..6789c32 --- /dev/null +++ b/docs/learning/codex-verification.md @@ -0,0 +1,7 @@ +# Codex verification procedure + +Record out-of-band verification, not a CI gate. + +- Command: `codex` or the active Codex app surface. +- Evidence: prompt, repo path, model, result, and validation commands. +- Pass criteria: no unreviewed policy mutation and local validation is green. diff --git a/docs/learning/concept-maps/.gitkeep b/docs/learning/concept-maps/.gitkeep index a2db107..e69de29 100644 --- a/docs/learning/concept-maps/.gitkeep +++ b/docs/learning/concept-maps/.gitkeep @@ -1 +0,0 @@ -# Placeholder for docs/learning/concept-maps diff --git a/docs/learning/troubleshooting-matrix.md b/docs/learning/troubleshooting-matrix.md index 2263455..b336176 100644 --- a/docs/learning/troubleshooting-matrix.md +++ b/docs/learning/troubleshooting-matrix.md @@ -1,3 +1,6 @@ -# Troubleshooting Matrix +# Troubleshooting matrix -Known issue → fix pairs for this repo. New entries are added; existing entries are not edited in place. +| Symptom | Check | Recovery | +|---|---|---| +| Validation fails | Run `python3 .ai/bin/validate-ai-sdlc.py` | Fix the named missing or invalid artifact. | +| Hosted policy blocked | Review docs/agents/branch-policy-github.md | Request explicit admin confirmation before mutation. | diff --git a/docs/specifications/ACTIVE/init-ai-sdlc-v3.md b/docs/specifications/ACTIVE/init-ai-sdlc-v3.md new file mode 100644 index 0000000..3d8855d --- /dev/null +++ b/docs/specifications/ACTIVE/init-ai-sdlc-v3.md @@ -0,0 +1,11 @@ +# Specification: AI-SDLC v3 initialization + +## Goal + +Enable `kontor-cli email automation` to use the latest AI-SDLC governance, traceability, validation, and review loop surfaces. + +## Acceptance criteria + +- The v3 scaffold exists and validates locally. +- Entry files link to `.ai/workflows/repo-workflow.md` and `.ai/workflows/repo-workflow.json`. +- The merge gate requires architect, reviewer, and executor agreement plus green local and hosted CI. diff --git a/docs/specifications/ARCHIVED/.gitkeep b/docs/specifications/ARCHIVED/.gitkeep index e8505f7..e69de29 100644 --- a/docs/specifications/ARCHIVED/.gitkeep +++ b/docs/specifications/ARCHIVED/.gitkeep @@ -1 +0,0 @@ -# Placeholder for docs/specifications/ARCHIVED From 8c02f91054ca4580d0c7d56a5597965e97000029 Mon Sep 17 00:00:00 2001 From: andreburgstahler Date: Sun, 28 Jun 2026 14:58:16 +0200 Subject: [PATCH 2/2] fix(ai-sdlc): format validation helper --- .ai/bin/validate-ai-sdlc.py | 140 ++++++++++++++++++++---------------- 1 file changed, 80 insertions(+), 60 deletions(-) diff --git a/.ai/bin/validate-ai-sdlc.py b/.ai/bin/validate-ai-sdlc.py index 4ce5806..3c38161 100755 --- a/.ai/bin/validate-ai-sdlc.py +++ b/.ai/bin/validate-ai-sdlc.py @@ -7,85 +7,105 @@ ROOT = Path(__file__).resolve().parents[2] REQUIRED = [ - '.ai/matrix.json', '.ai/init/repo-profile.json', '.ai/init/sdlc-path.md', - '.ai/workflows/repo-workflow.md', '.ai/workflows/repo-workflow.json', - '.ai/handoff/init-ai-repo-handoff.md', '.ai/traceability/graph.json', - '.ai/traceability/index.md', '.ai/traceability/validation-report.md', - '.ai/evals/coverage-exceptions.json', '.ai/evals/example-output-eval/evalset.json', - '.ai/evals/example-output-eval/rubric.md', '.ai/evals/example-output-eval/judge-config.json', - '.ai/policies/model-routing.json', '.ai/observability/conventions.md', - '.ai/observability/audit-checklist.md', '.ai/mcp/registry.json', - '.ai/mcp/a2a-handoff.md', '.ai/reviews/ai-failure-modes.md', - '.memory/human-override/custom-conventions.md', '.memory/human-override/tribal-knowledge.md', - '.memory/self-learned/error-patterns.json', '.memory/self-learned/module-complexity.json', - 'docs/architecture/adr/0001-init-ai-sdlc-v3.md', - 'docs/specifications/ACTIVE/init-ai-sdlc-v3.md', 'RULES.md', 'PLANS.md', - 'AGENTS.md', 'README.md', 'CLAUDE.md', 'GEMINI.md', 'CONTRIBUTING.md', + ".ai/matrix.json", + ".ai/init/repo-profile.json", + ".ai/init/sdlc-path.md", + ".ai/workflows/repo-workflow.md", + ".ai/workflows/repo-workflow.json", + ".ai/handoff/init-ai-repo-handoff.md", + ".ai/traceability/graph.json", + ".ai/traceability/index.md", + ".ai/traceability/validation-report.md", + ".ai/evals/coverage-exceptions.json", + ".ai/evals/example-output-eval/evalset.json", + ".ai/evals/example-output-eval/rubric.md", + ".ai/evals/example-output-eval/judge-config.json", + ".ai/policies/model-routing.json", + ".ai/observability/conventions.md", + ".ai/observability/audit-checklist.md", + ".ai/mcp/registry.json", + ".ai/mcp/a2a-handoff.md", + ".ai/reviews/ai-failure-modes.md", + ".memory/human-override/custom-conventions.md", + ".memory/human-override/tribal-knowledge.md", + ".memory/self-learned/error-patterns.json", + ".memory/self-learned/module-complexity.json", + "docs/architecture/adr/0001-init-ai-sdlc-v3.md", + "docs/specifications/ACTIVE/init-ai-sdlc-v3.md", + "RULES.md", + "PLANS.md", + "AGENTS.md", + "README.md", + "CLAUDE.md", + "GEMINI.md", + "CONTRIBUTING.md", ] + def fail(message: str) -> None: - print(f'FAIL: {message}', file=sys.stderr) + print(f"FAIL: {message}", file=sys.stderr) raise SystemExit(1) + for rel in REQUIRED: if not (ROOT / rel).exists(): - fail(f'missing {rel}') + fail(f"missing {rel}") -for rel in ROOT.glob('.ai/**/*.json'): +for rel in ROOT.glob(".ai/**/*.json"): json.loads(rel.read_text()) -for rel in ROOT.glob('.memory/self-learned/*.json'): +for rel in ROOT.glob(".memory/self-learned/*.json"): data = json.loads(rel.read_text()) - if 'schema_version' not in data: - fail(f'missing schema_version in {rel}') + if "schema_version" not in data: + fail(f"missing schema_version in {rel}") -matrix = json.loads((ROOT / '.ai/matrix.json').read_text()) -if matrix.get('sync_strategy') != 'physical-copy': - fail('matrix sync_strategy must be physical-copy') -if matrix.get('topology_type') == 'standalone': - if matrix.get('max_allowed_depth') != 0 or matrix.get('current_depth') != 0: - fail('standalone depth must be zero') -elif matrix.get('topology_type') == 'umbrella': - if matrix.get('max_allowed_depth') != 3: - fail('umbrella max_allowed_depth must be 3') - if matrix.get('current_depth', 99) > matrix['max_allowed_depth']: - fail('umbrella current_depth exceeds max') - for repo in matrix.get('managed_repositories', []): - if repo.get('depth', 99) > matrix['max_allowed_depth']: - fail(f'managed repo exceeds depth: {repo}') +matrix = json.loads((ROOT / ".ai/matrix.json").read_text()) +if matrix.get("sync_strategy") != "physical-copy": + fail("matrix sync_strategy must be physical-copy") +if matrix.get("topology_type") == "standalone": + if matrix.get("max_allowed_depth") != 0 or matrix.get("current_depth") != 0: + fail("standalone depth must be zero") +elif matrix.get("topology_type") == "umbrella": + if matrix.get("max_allowed_depth") != 3: + fail("umbrella max_allowed_depth must be 3") + if matrix.get("current_depth", 99) > matrix["max_allowed_depth"]: + fail("umbrella current_depth exceeds max") + for repo in matrix.get("managed_repositories", []): + if repo.get("depth", 99) > matrix["max_allowed_depth"]: + fail(f"managed repo exceeds depth: {repo}") else: - fail('invalid topology_type') + fail("invalid topology_type") -workflow = json.loads((ROOT / '.ai/workflows/repo-workflow.json').read_text()) -for phase in workflow['phases']: - if not (ROOT / phase['status_path']).exists(): +workflow = json.loads((ROOT / ".ai/workflows/repo-workflow.json").read_text()) +for phase in workflow["phases"]: + if not (ROOT / phase["status_path"]).exists(): fail(f'missing phase status {phase["status_path"]}') -text_agents = (ROOT / 'AGENTS.md').read_text() -text_readme = (ROOT / 'README.md').read_text() -for link in ['.ai/workflows/repo-workflow.md', '.ai/workflows/repo-workflow.json']: +text_agents = (ROOT / "AGENTS.md").read_text() +text_readme = (ROOT / "README.md").read_text() +for link in [".ai/workflows/repo-workflow.md", ".ai/workflows/repo-workflow.json"]: if link not in text_agents or link not in text_readme: - fail(f'missing workflow link {link} in AGENTS.md or README.md') + fail(f"missing workflow link {link} in AGENTS.md or README.md") -graph = json.loads((ROOT / '.ai/traceability/graph.json').read_text()) -ids = {n['id'] for n in graph['nodes']} -for edge in graph['edges']: - if edge['source'] not in ids or edge['target'] not in ids: - fail(f'dangling graph edge {edge}') -for node in graph['nodes']: - for backlink in node.get('backlinks', []): +graph = json.loads((ROOT / ".ai/traceability/graph.json").read_text()) +ids = {n["id"] for n in graph["nodes"]} +for edge in graph["edges"]: + if edge["source"] not in ids or edge["target"] not in ids: + fail(f"dangling graph edge {edge}") +for node in graph["nodes"]: + for backlink in node.get("backlinks", []): if backlink not in ids: - fail(f'dangling backlink {backlink}') + fail(f"dangling backlink {backlink}") -registry = json.loads((ROOT / '.ai/mcp/registry.json').read_text()) -if not registry.get('servers') or 'a2a' not in registry: - fail('invalid mcp registry') -for server in registry['servers']: - if server.get('status') != 'stub': - fail('mcp server status must be stub') +registry = json.loads((ROOT / ".ai/mcp/registry.json").read_text()) +if not registry.get("servers") or "a2a" not in registry: + fail("invalid mcp registry") +for server in registry["servers"]: + if server.get("status") != "stub": + fail("mcp server status must be stub") -review = (ROOT / '.ai/reviews/ai-failure-modes.md').read_text().lower() -for word in ['hallucinated', 'slopsquatting', 'error handling', 'looks-right']: +review = (ROOT / ".ai/reviews/ai-failure-modes.md").read_text().lower() +for word in ["hallucinated", "slopsquatting", "error handling", "looks-right"]: if word not in review: - fail(f'missing review keyword {word}') + fail(f"missing review keyword {word}") -print('AI-SDLC validation passed') +print("AI-SDLC validation passed")