diff --git a/extensions/catalog.community.json b/extensions/catalog.community.json index f3cb0aea5c..c9013312cf 100644 --- a/extensions/catalog.community.json +++ b/extensions/catalog.community.json @@ -2890,10 +2890,10 @@ "repository-governance": { "name": "Repository Governance", "id": "repository-governance", - "description": "Generate or update the active Repository Governance Framework file with vertical SSOT routing and evidence.", + "description": "Generate project-governance projections from Spec Kit metadata", "author": "bigben", - "version": "2.0.6", - "download_url": "https://github.com/bigsmartben/spec-kit-agent-governance/archive/refs/tags/v2.0.6.zip", + "version": "3.0.2", + "download_url": "https://github.com/bigsmartben/spec-kit-agent-governance/archive/refs/tags/v3.0.2.zip", "repository": "https://github.com/bigsmartben/spec-kit-agent-governance", "homepage": "https://github.com/bigsmartben/spec-kit-agent-governance", "documentation": "https://github.com/bigsmartben/spec-kit-agent-governance/blob/main/README.md", @@ -2923,7 +2923,7 @@ "downloads": 0, "stars": 0, "created_at": "2026-05-14T00:00:00Z", - "updated_at": "2026-06-24T00:00:00Z" + "updated_at": "2026-07-03T00:00:00Z" }, "reqnroll-bdd": { "name": "Reqnroll BDD", diff --git a/extensions/repository-governance/CHANGELOG.md b/extensions/repository-governance/CHANGELOG.md index 2e043e8a05..f085dd9146 100644 --- a/extensions/repository-governance/CHANGELOG.md +++ b/extensions/repository-governance/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## Unreleased + +### Changed + +- Replace abstract vertical SSOT domains with fixed directory-tree SSOT entries: `agent-runtime/`, `engineering-runtime/`, `poc/`, `source-code/`, `test-code/`, and `other-tools/`. +- Treat matched directories and fixed directory-tree files as SSOT index source refs, including agent runtime paths, CI/CD and Docker/runtime files, source paths, test paths, and auxiliary tool configs. +- Rename the generated fallback and agent harness wording to Directory Tree and `agent-runtime/` wording. +- Add `poc/` as the pre-iteration exploration SSOT for technical spikes, architecture drafts, UC designs, prototypes, research notes, validation reports, and validation conclusions. +- Require POC promotion to cite a formal design or task before `source-code/` edits, and require validation record source refs or `NEEDS_CLARIFICATION:poc-validation-record`. + ## [3.0.2] - 2026-07-03 ### Changed diff --git a/extensions/repository-governance/README.md b/extensions/repository-governance/README.md index 210b9ef339..b2cc9a5c47 100644 --- a/extensions/repository-governance/README.md +++ b/extensions/repository-governance/README.md @@ -14,18 +14,18 @@ Generate project-governance projections for the active Spec Kit agent platform t - Update existing active target project-governance projections. - Scan repository areas as bounded evidence for missing-SSOT fallback. - Capture repository facts as bounded evidence for gap handling and CLI reporting. -- Structure generated instructions as repository-wide, path-scope, and agent-harness guidance. +- Structure generated instructions as repository-wide, directory-tree scope, and `agent-runtime/` guidance. - Project agent platform adapter rules from Spec Kit integration metadata. -- Index only explicit SSOT content entrypoints in the generated SSOT index. -- Report repository-local skills and MCP config files as evidence candidates only unless an explicit Agent Harness SSOT source names them. +- Index explicit fixed directory-tree SSOT entrypoints in the generated SSOT index. +- Report repository-local skills and MCP config files as evidence candidates only unless an explicit `agent-runtime/` SSOT source names them. - Analyze repository areas to depth 2 only for evidence and CLI summaries. -- Use Directory Structure fallback only when the Directory Structure SSOT is missing and task scope is explicit. +- Use Directory Tree fallback only when no fixed directory-tree SSOT matches, or the matched tree has no source_refs and task scope is explicit. - Overwrite the active agent platform target on generation. - Do not generate Copilot `.github/instructions/*.instructions.md` companion files. - Generate repository evidence from the current repository state on every run. - Review only the active agent platform target. - Remove legacy managed sections only from non-active context files enumerated by `CONTEXT_FILES`. -- Missing vertical SSOT is reported as a clarification need for governed changes; generated output must not invent repository policy from descriptive repository evidence. +- Missing fixed directory-tree SSOT is reported as a clarification need for governed changes; generated output must not invent repository policy from descriptive repository evidence. - Do not project full repository fact inventories, repository area lists, skill capability lists, or development command lists into the active target. ## Install @@ -67,28 +67,35 @@ uv run python tools/build_repository_governance_zip.py ## SSOT Index -- Architecture SSOT index: status, source_refs, and gap code. -- Engineering SSOT index: status, source_refs, and gap code. -- Code Style SSOT index: status, source_refs, and gap code. -- Directory Structure SSOT index: status, source_refs, and gap code. -- Agent Harness SSOT index: status, source_refs, and gap code. -- Repository-level and nested project evidence is scanned through explicit path families with bounded parent depth, but only explicit SSOT content entrypoints become SSOT index source_refs. -- `extension.yml` and `.extensionignore` are Engineering SSOT refs only in this extension source repository; other projects report them as evidence. +- `agent-runtime/` SSOT index: status, source_refs, and gap code. +- `engineering-runtime/` SSOT index: status, source_refs, and gap code. +- `poc/` SSOT index: status, source_refs, and gap code. +- `source-code/` SSOT index: status, source_refs, and gap code. +- `test-code/` SSOT index: status, source_refs, and gap code. +- `other-tools/` SSOT index: status, source_refs, and gap code. +- Repository-level and nested project evidence is scanned through fixed directory trees with bounded parent depth, and matched tree entrypoints become SSOT index source_refs. +- `agent-runtime/` examples include `.codex/`, `.claude/`, `AGENTS.md`, `CLAUDE.md`, and other agent rule files. +- `engineering-runtime/` examples include `.github/workflows/`, environment files, DevOps, CI/CD, Docker, manifests, lockfiles, permissions, password, key, and secrets surfaces. +- `poc/` examples include technical spikes, architecture drafts, UC designs, prototypes, research notes, validation reports, and validation conclusions before formal iteration. +- `source-code/` examples include client, server, API, route, library, script, command, and template code. +- `test-code/` examples include test code, fixtures, prepared data, resources, reports, and test conclusions. +- `other-tools/` examples include `.codegraph/`, editor tooling, MCP configs, and `tools/`. ## Instruction Layers - Repository-wide instructions summarize authority, active-target scope, write boundaries, validation commands, and handoff expectations. -- SSOT index maps Architecture, Engineering, Code Style, Directory Structure, and Agent Harness categories to source_refs and gap codes. -- SSOT routing maps task types and path families to Architecture, Engineering, Code Style, Directory Structure, and Agent Harness SSOT entries. +- SSOT index maps `agent-runtime/`, `engineering-runtime/`, `poc/`, `source-code/`, `test-code/`, and `other-tools/` to source_refs and gap codes. +- SSOT routing maps task types and repository paths to fixed directory-tree SSOT entries. - Path and task scope rules keep generated guidance deterministic without expanding the write surface. -- Agent harness instructions cover adapter behavior, repository-local skills, MCP discovery, external tools, permissions, and failure handling. +- `poc/` routing keeps exploration out of formal implementation: before editing `source-code/` from POC work, create or cite a formal design or task; POC conclusions need validation record source_refs under `poc/validation-reports/` or `NEEDS_CLARIFICATION:poc-validation-record`. +- Agent runtime instructions cover adapter behavior, repository-local skills, MCP discovery, external tools, permissions, and failure handling. - The extension emits one active target file and does not generate platform companion instruction files. ## Evidence Discovery - Repository facts are scanned from README files, project docs, repository policy files, feature specs, source/test paths, nested manifests, and runtime/build configuration. - Development command sources are scanned from package scripts or Python/uv test conventions. -- Scanned facts feed missing-SSOT handling and CLI evidence summaries; they are not projected as SSOT source_refs or full content lists into the active target unless they are explicit SSOT content entrypoints. +- Scanned facts feed missing-SSOT handling and CLI evidence summaries; only matched fixed directory-tree entrypoints are projected as SSOT source_refs. ## Agent Adapter @@ -96,7 +103,7 @@ uv run python tools/build_repository_governance_zip.py - Agent adapter layer: use explicit integration support when available; otherwise use generic fallback rules. - Platform projection layer: apply only rules supported by the active target file. -Repository-local `SKILL.md` files are reported as evidence and read when they match the task; they are not Agent Harness SSOT source_refs unless an explicit Agent Harness SSOT source names them. MCP config files are reported as candidates and evidence only; they are not SSOT source_refs, and active servers, resources, and tools must be enumerated from the agent platform runtime before use. +Repository-local `SKILL.md` files are reported as evidence and read when they match the task; they are not `agent-runtime/` SSOT source_refs unless an explicit `agent-runtime/` SSOT source names them. MCP config files are reported as candidates and evidence only; active servers, resources, and tools must be enumerated from the agent platform runtime before use. ## Verify diff --git a/extensions/repository-governance/commands/speckit.repository-governance.generate.md b/extensions/repository-governance/commands/speckit.repository-governance.generate.md index 2711146462..9d473daf14 100644 --- a/extensions/repository-governance/commands/speckit.repository-governance.generate.md +++ b/extensions/repository-governance/commands/speckit.repository-governance.generate.md @@ -30,6 +30,6 @@ $ARGUMENTS - active agent platform target - generated or updated - review target -- SSOT content index summary +- fixed directory-tree SSOT index summary - descriptive evidence scan summary - unresolved risks or clarification needs diff --git a/extensions/repository-governance/scripts/generate_repository_governance.py b/extensions/repository-governance/scripts/generate_repository_governance.py index 5d2b421ab5..f14abcb3ca 100755 --- a/extensions/repository-governance/scripts/generate_repository_governance.py +++ b/extensions/repository-governance/scripts/generate_repository_governance.py @@ -204,78 +204,64 @@ SPEC_KIT_METADATA = [".specify/integration.json", ".specify/init-options.json", ".specify/extensions.yml"] EVIDENCE_SCAN_MAX_PARENT_DEPTH = 3 SUPPORTED_ADAPTERS = {"codex", "zed"} -ARCHITECTURE_SSOT_FILES = ["ARCHITECTURE.md", "architecture.md"] -ARCHITECTURE_SSOT_GLOBS = [ - "docs/architecture*.md", - "docs/**/architecture*.md", - "adr/*.md", - "adr/**/*.md", - "adrs/*.md", - "adrs/**/*.md", +AGENT_RUNTIME_DIRS = [ + ".codex", + ".claude", + ".cursor", + ".augment", + ".junie", + ".kilocode", + ".lingma", + ".roo", + ".trae", + ".windsurf", ] -ENGINEERING_SSOT_FILES = [ - "CONTRIBUTING.md", - "contributing.md", - "DEVELOPMENT.md", - "development.md", - "RELEASE.md", - "release.md", - "VERSION", - "docs/engineering.md", - "docs/development.md", - "docs/release.md", - "docs/releases.md", - "docs/ci.md", - "docs/tooling.md", - "docs/commands.md", +ENGINEERING_RUNTIME_FILES = [ + ".editorconfig", + ".extensionignore", + ".gitignore", + "Dockerfile", + "compose.yml", + "compose.yaml", + "docker-compose.yml", + "docker-compose.yaml", + "extension.yml", + *PACKAGE_MANIFESTS, + *LOCKFILES, + *TASK_RUNNERS, + *BUILD_CONFIG_FILES, + *CODE_STYLE_FILES, + *RUNTIME_CONFIG_FILES, *EXTENSION_CONTRACT_FILES, ] -EXTENSION_ENGINEERING_SSOT_FILES = ["extension.yml", ".extensionignore"] -DIRECTORY_STRUCTURE_SSOT_FILES = [ - "STRUCTURE.md", - "structure.md", - "LAYOUT.md", - "layout.md", - "docs/structure.md", - "docs/directory-structure.md", - "docs/repository-structure.md", - "docs/layout.md", +ENGINEERING_RUNTIME_DIRS = [ + ".devcontainer", + ".github/workflows", + "ci", + "devops", + "deploy", + "deployment", + "docker", + "env", + "environments", + "helm", + "infra", + "k8s", + "terraform", ] -DIRECTORY_STRUCTURE_SSOT_GLOBS = [ - "docs/*structure*.md", - "docs/**/structure*.md", - "docs/**/directory-structure*.md", - "docs/**/repository-structure*.md", -] -AGENT_HARNESS_SSOT_FILES = [ - "AGENT_HARNESS.md", - "agent-harness.md", - "AGENT_GOVERNANCE.md", - "agent-governance.md", - "docs/agent-harness.md", - "docs/agent-governance.md", - "docs/agents.md", -] -AGENT_HARNESS_SSOT_GLOBS = [ - "docs/*agent*harness*.md", - "docs/**/*agent*harness*.md", - "docs/*agent*governance*.md", - "docs/**/*agent*governance*.md", -] -CODE_STYLE_SSOT_FILES = [ - ".editorconfig", - "STYLE.md", - "style.md", - "CODE_STYLE.md", - "code-style.md", - "docs/style.md", - "docs/code-style.md", - "docs/coding-style.md", -] -CODE_STYLE_SSOT_GLOBS = [ - "docs/*style*.md", - "docs/**/*style*.md", +POC_DIRS = [ + "poc", + "poc/technical-spikes", + "poc/architecture-drafts", + "poc/uc-designs", + "poc/prototypes", + "poc/research-notes", + "poc/validation-reports", ] +SOURCE_CODE_DIRS = ["src", "app", "client", "clients", "frontend", "web", "server", "backend", "api", "lib", "services", "packages", "apps", "cmd", "internal", "scripts", "commands", "templates"] +TEST_CODE_DIRS = ["test", "tests", "spec", "specs", "e2e", "fixtures", "testdata", "test-results", "coverage"] +TOOLING_DIRS = ["tools", ".codegraph", ".vscode", ".idea"] +TOOLING_FILES = ["codegraph.json", "codegraph.yml", ".codegraph.json", ".codegraph.yml", *MCP_CONFIG_NAMES] def main() -> int: @@ -344,46 +330,58 @@ def repository_evidence_lines(root: Path, state: dict[str, Any], init_options: d return lines -def architecture_ssot_refs(root: Path) -> list[str]: +def agent_runtime_ssot_refs(root: Path, init_options: dict[str, Any], state: dict[str, Any]) -> list[str]: + return unique_ordered( + [ + *existing_context_files(root, init_options, state), + *existing_dirs(root, AGENT_RUNTIME_DIRS), + ] + ) + + +def engineering_runtime_ssot_refs(root: Path) -> list[str]: return unique_ordered( [ - *existing_paths(root, ARCHITECTURE_SSOT_FILES), - *bounded_glob_files(root, ARCHITECTURE_SSOT_GLOBS), + *existing_paths(root, ENGINEERING_RUNTIME_FILES), + *existing_dirs(root, ENGINEERING_RUNTIME_DIRS), + *directory_files(root, ".github/workflows"), ] ) -def engineering_ssot_refs(root: Path) -> list[str]: - refs = existing_paths(root, ENGINEERING_SSOT_FILES) - if is_repository_governance_extension_source(root): - refs.extend(existing_paths(root, EXTENSION_ENGINEERING_SSOT_FILES)) - return unique_ordered(refs) +def source_code_ssot_refs(root: Path) -> list[str]: + return unique_ordered( + [ + *existing_dirs(root, SOURCE_CODE_DIRS), + *api_contract_paths(root), + *route_files(root), + ] + ) -def code_style_ssot_refs(root: Path) -> list[str]: +def poc_ssot_refs(root: Path) -> list[str]: return unique_ordered( [ - *existing_paths(root, CODE_STYLE_SSOT_FILES), - *bounded_glob_files(root, CODE_STYLE_SSOT_GLOBS), + *existing_dirs(root, POC_DIRS), + *directory_files(root, "poc/validation-reports"), ] ) -def directory_structure_ssot_refs(root: Path) -> list[str]: +def test_code_ssot_refs(root: Path) -> list[str]: return unique_ordered( [ - *existing_paths(root, DIRECTORY_STRUCTURE_SSOT_FILES), - *bounded_glob_files(root, DIRECTORY_STRUCTURE_SSOT_GLOBS), + *existing_dirs(root, TEST_CODE_DIRS), + *existing_paths(root, ["pytest.ini", "tox.ini", "vitest.config.js", "vitest.config.ts", "jest.config.js", "playwright.config.ts"]), ] ) -def agent_harness_ssot_refs(root: Path, init_options: dict[str, Any], state: dict[str, Any]) -> list[str]: +def tooling_ssot_refs(root: Path) -> list[str]: return unique_ordered( [ - *existing_context_files(root, init_options, state), - *existing_paths(root, AGENT_HARNESS_SSOT_FILES), - *bounded_glob_files(root, AGENT_HARNESS_SSOT_GLOBS), + *existing_dirs(root, TOOLING_DIRS), + *existing_paths(root, TOOLING_FILES), ] ) @@ -428,6 +426,8 @@ def bounded_named_files(root: Path, names: list[str], max_parent_depth: int = EV for path in files: relative = path.relative_to(root) path_text = relative.as_posix() + if name.startswith(".") and "/" not in name and path_text != name: + continue if (path_text == name or path.name == name) and len(relative.parts) - 1 <= max_parent_depth: matches.append(rel(root, path)) return unique_ordered(matches) @@ -438,9 +438,10 @@ def bounded_named_dirs(root: Path, names: list[str], max_parent_depth: int = EVI dirs = project_dirs(root) for name in names: for path in dirs: - if path.name != name: - continue relative = path.relative_to(root) + path_text = relative.as_posix() + if path_text != name and path.name != name: + continue if len(relative.parts) - 1 <= max_parent_depth: matches.append(f"{rel(root, path)}/") return unique_ordered(matches) @@ -792,9 +793,9 @@ def render_projection(root: Path, target: Path, state: dict[str, Any], init_opti "## Repository-Wide Instructions", f"- {style_lead(style)}", "- Treat this file as the active project-governance entrypoint for coding-agent work in this repository.", - "- Keep task reasoning grounded in source-backed repository facts, matched SSOT routes, and explicit user instructions.", - "- Keep edits scoped to the active task and matched path family.", - "- architecture methodology: owned by Architecture SSOT.", + "- Keep task reasoning grounded in source-backed repository facts, matched directory-tree routes, and explicit user instructions.", + "- Keep edits scoped to the active task and matched fixed directory tree.", + "- Fixed directory-tree SSOT: when a path matches `agent-runtime/`, `engineering-runtime/`, `poc/`, `source-code/`, `test-code/`, or `other-tools/`, route it to that SSOT.", "", "### Context", f"- Installed integrations: {', '.join(installed) if installed else 'none'}", @@ -806,20 +807,20 @@ def render_projection(root: Path, target: Path, state: dict[str, Any], init_opti *authority_default(), "", "## SSOT Index", - *vertical_ssot_registry_default(), + *directory_tree_ssot_registry_default(), "", *ssot_index_lines(root, state, init_options), "", "### Missing SSOT Handling", *missing_ssot_handling_default(), "", - "## Path And Task Scope Rules", + "## Directory Tree And Task Scope Rules", *task_scope_rules_default(), "", - "### Directory Structure Fallback", - *directory_structure_fallback_default(), + "### Directory Tree Fallback", + *directory_tree_fallback_default(), "", - "## Agent Harness", + "## agent-runtime", *agent_adapter_lines(root, target, default_key), "", *mcp_default(style), @@ -873,23 +874,28 @@ def remove_section(path: Path) -> None: path.write_text(updated, encoding="utf-8") -def directory_structure_fallback_default() -> list[str]: +def directory_tree_fallback_default() -> list[str]: return [ - "- Use only when Directory Structure SSOT is missing and the task scope is explicit.", - "- Treat scanned repository areas as descriptive context, not as approved directory policy.", + "- Use only when no fixed directory-tree SSOT matches, or the matched tree has no source_refs and the task scope is explicit.", + "- Treat scanned repository areas as descriptive context, not as approved path policy.", "- Keep new or moved files aligned with existing nearby conventions unless the user supplies a different target.", - "- Record `NEEDS_CLARIFICATION:DIRECTORY_STRUCTURE` in handoff when placement is ambiguous.", + "- Record the matched `NEEDS_CLARIFICATION:` gap in handoff when placement is ambiguous.", ] def task_scope_rules_default() -> list[str]: return [ - "- Source, API, route, runtime, infra, or dependency-boundary changes: read Architecture SSOT before planning edits.", - "- Build, release, CI, manifest, lockfile, command, template, or runtime configuration changes: read Engineering SSOT before edits.", - "- Formatting, linting, typing, testing, logging, comments, naming, or error-handling changes: read Code Style SSOT before edits.", - "- New files, moved files, generated assets, or directory responsibility changes: read Directory Structure SSOT before edits.", - "- Agent instructions, permissions, MCP, external tools, skills, validation, or failure-handling changes: read Agent Harness SSOT before edits.", - "- If multiple rules match, read every matched SSOT and apply the highest authority non-conflicting rule.", + "- Routing rule: seeing a file in one fixed directory tree classifies it as that SSOT; no match falls through to Directory Tree Fallback.", + "- `agent-runtime/`: `.codex/`, `.claude/`, `AGENTS.md`, `CLAUDE.md`, and other agent rule files; read `agent-runtime/` SSOT before edits.", + "- `engineering-runtime/`: `.github/workflows/`, Docker files, environment files, manifests, lockfiles, DevOps, infra, secrets, key, password, and permission surfaces; read `engineering-runtime/` SSOT before edits.", + "- `poc/`: `technical-spikes/`, `architecture-drafts/`, `uc-designs/`, `prototypes/`, `research-notes/`, and `validation-reports/`; read `poc/` SSOT before edits.", + "- `poc/` content is not formal implementation.", + "- Before editing `source-code/` from POC work, create or cite a formal design or task; implement from that artifact, not by copying experimental code directly.", + "- POC conclusions must include validation record source_refs under `poc/validation-reports/`; otherwise record `NEEDS_CLARIFICATION:poc-validation-record` in handoff.", + "- `source-code/`: `src/`, `app/`, `client/`, `server/`, `api/`, `lib/`, `services/`, `scripts/`, `commands/`, and `templates/`; read `source-code/` SSOT before edits.", + "- `test-code/`: `tests/`, `test/`, `e2e/`, `fixtures/`, `testdata/`, `test-results/`, and `coverage/`; read `test-code/` SSOT before edits.", + "- `other-tools/`: `tools/`, `.codegraph/`, MCP config files, `.vscode/`, and `.idea/`; read `other-tools/` SSOT before edits.", + "- If multiple trees match, read every matched SSOT and apply the highest authority non-conflicting rule.", ] @@ -897,13 +903,14 @@ def development_commands_default() -> list[str]: return ["- none recorded"] -def vertical_ssot_registry_default() -> list[str]: +def directory_tree_ssot_registry_default() -> list[str]: return [ - "- Architecture SSOT: owns architecture boundaries, interfaces, dependencies, runtime constraints, deployment assumptions, and scenario-level architecture decisions.", - "- Engineering SSOT: owns branch, version, release, CI/CD, collaboration process, standard tools, command entrypoints, configuration templates, and execution constraints.", - "- Code Style SSOT: owns naming, formatting, comments, error handling, logging, tests, and quality standards.", - "- Directory Structure SSOT: owns directory layout, file placement, module organization, and configuration locations.", - "- Agent Harness SSOT: owns agent task boundaries, tool usage, permissions, audit, validation, and failure handling.", + "- `agent-runtime/`: `.codex/`, `.claude/`, `AGENTS.md`, `CLAUDE.md`, and other agent rule files.", + "- `engineering-runtime/`: `.github/workflows/`, Docker files, environment files, manifests, lockfiles, DevOps, infra, and secrets/key/password configuration surfaces.", + "- `poc/`: pre-iteration exploration for technical spikes, architecture drafts, UC designs, prototypes, research notes, validation reports, and validation conclusions.", + "- `source-code/`: client, server, API, route, library, service, script, command, and template code.", + "- `test-code/`: test code, fixtures, prepared data, test resources, reports, and test conclusions.", + "- `other-tools/`: `tools/`, `.codegraph/`, MCP config files, `.vscode/`, `.idea/`, and auxiliary tool settings.", ] @@ -916,11 +923,12 @@ def ssot_index_lines(root: Path, state: dict[str, Any], init_options: dict[str, def ssot_index_data(root: Path, state: dict[str, Any], init_options: dict[str, Any]) -> list[tuple[str, list[str]]]: return [ - ("Architecture", architecture_ssot_refs(root)), - ("Engineering", engineering_ssot_refs(root)), - ("Code Style", code_style_ssot_refs(root)), - ("Directory Structure", directory_structure_ssot_refs(root)), - ("Agent Harness", agent_harness_ssot_refs(root, init_options, state)), + ("agent-runtime", agent_runtime_ssot_refs(root, init_options, state)), + ("engineering-runtime", engineering_runtime_ssot_refs(root)), + ("poc", poc_ssot_refs(root)), + ("source-code", source_code_ssot_refs(root)), + ("test-code", test_code_ssot_refs(root)), + ("other-tools", tooling_ssot_refs(root)), ] @@ -928,7 +936,7 @@ def ssot_index_entry(name: str, refs: list[str]) -> list[str]: status = "indexed" if refs else "missing" gap = "none" if refs else ssot_gap_code(name) return [ - f"- {name} SSOT index:", + f"- `{name}/` SSOT index:", f" - status: {status}", f" - source_refs: {format_index_refs(refs)}", f" - gap: {gap}", @@ -936,12 +944,12 @@ def ssot_index_entry(name: str, refs: list[str]) -> list[str]: def ssot_gap_code(name: str) -> str: - return f"NEEDS_CLARIFICATION:{name.replace(' ', '_').upper()}" + return f"NEEDS_CLARIFICATION:{name}" def missing_ssot_handling_default() -> list[str]: return [ - "- If a vertical SSOT is missing or incomplete, treat repository evidence as descriptive context only.", + "- If a fixed directory-tree SSOT is missing or incomplete, treat repository evidence as descriptive context only.", "- Before changing a surface governed by missing SSOT, ask for clarification or record `NEEDS_CLARIFICATION:` in handoff.", "- Use existing code and config facts for narrow edits only when task scope and validation are explicit.", "- Do not invent repository policy from descriptive repository evidence.", @@ -952,22 +960,22 @@ def authority_default() -> list[str]: return [ "1. Current user instruction", "2. Safety and permission constraints", - "3. Vertical SSOT documents", + "3. Fixed directory-tree SSOT documents", "4. Current repository code and configuration facts", "5. Active `PROJECT GOVERNANCE` projection", "6. Tests and CI results", "7. Historical documents", "8. Explicit assumptions for reversible local edits", - "- Active projection is generated routing guidance and is subordinate to explicit vertical SSOT documents or source-backed repository facts on substantive conflicts.", + "- Active projection is generated routing guidance and is subordinate to explicit fixed directory-tree SSOT documents or source-backed repository facts on substantive conflicts.", ] def repository_workflow_default() -> list[str]: return [ - "- Classify task type and path family before changing files.", - "- Read every SSOT route matched by Path And Task Scope Rules.", + "- Classify task type and fixed directory tree before changing files.", + "- Read every SSOT route matched by Directory Tree And Task Scope Rules.", "- Use SSOT Index source_refs as entrypoints, not as replacement content for the referenced sources.", - "- Run validation commands from explicit Engineering SSOT instructions or user direction when they match the changed surface.", + "- Run validation commands from explicit `engineering-runtime/` SSOT instructions or user direction when they match the changed surface.", "- Scope: active task only.", "- Preserve: user-authored edits.", "- Protected files: implementation paths, CI configuration, MCP configuration, secrets, permissions, tool settings, and arbitrary repository paths outside the resolved write surface.", @@ -1036,7 +1044,7 @@ def mcp_default(style: str) -> list[str]: def skill_default(style: str) -> list[str]: return [ - "- Repository-local skills are evidence only unless an explicit Agent Harness SSOT source names them.", + "- Repository-local skills are evidence only unless an explicit `agent-runtime/` SSOT source names them.", "- Read matching repository-local `SKILL.md` before planning or editing.", "- Treat skill scope declarations as task-local constraints.", "- If a matching skill lacks scope or validation guidance, ask for clarification before expanding writes.", diff --git a/extensions/repository-governance/templates/repository-governance-template.md b/extensions/repository-governance/templates/repository-governance-template.md index 780ab29726..d22d812656 100644 --- a/extensions/repository-governance/templates/repository-governance-template.md +++ b/extensions/repository-governance/templates/repository-governance-template.md @@ -13,80 +13,90 @@ Sync Impact Report - Framework: Project Governance Projection Framework. - Treat this file as the active project-governance entrypoint for coding-agent work in this repository. -- Keep task reasoning grounded in source-backed repository facts, matched SSOT routes, and explicit user instructions. -- Keep edits scoped to the active task and matched path family. -- architecture methodology: owned by Architecture SSOT. +- Keep task reasoning grounded in source-backed repository facts, matched directory-tree routes, and explicit user instructions. +- Keep edits scoped to the active task and matched fixed directory tree. +- Fixed directory-tree SSOT: when a path matches `agent-runtime/`, `engineering-runtime/`, `poc/`, `source-code/`, `test-code/`, or `other-tools/`, route it to that SSOT. ### Authority 1. Current user instruction 2. Safety and permission constraints -3. Vertical SSOT documents +3. Fixed directory-tree SSOT documents 4. Current repository code and configuration facts 5. Active `PROJECT GOVERNANCE` projection 6. Tests and CI results 7. Historical documents 8. Explicit assumptions for reversible local edits -- Active projection is generated routing guidance and is subordinate to explicit vertical SSOT documents or source-backed repository facts on substantive conflicts. +- Active projection is generated routing guidance and is subordinate to explicit fixed directory-tree SSOT documents or source-backed repository facts on substantive conflicts. ## SSOT Index -- Architecture SSOT: owns architecture boundaries, interfaces, dependencies, runtime constraints, deployment assumptions, and scenario-level architecture decisions. -- Engineering SSOT: owns branch, version, release, CI/CD, collaboration process, standard tools, command entrypoints, configuration templates, and execution constraints. -- Code Style SSOT: owns naming, formatting, comments, error handling, logging, tests, and quality standards. -- Directory Structure SSOT: owns directory layout, file placement, module organization, and configuration locations. -- Agent Harness SSOT: owns agent task boundaries, tool usage, permissions, audit, validation, and failure handling. -- Architecture SSOT index: +- `agent-runtime/`: `.codex/`, `.claude/`, `AGENTS.md`, `CLAUDE.md`, and other agent rule files. +- `engineering-runtime/`: `.github/workflows/`, Docker files, environment files, manifests, lockfiles, DevOps, infra, and secrets/key/password configuration surfaces. +- `poc/`: pre-iteration exploration for technical spikes, architecture drafts, UC designs, prototypes, research notes, validation reports, and validation conclusions. +- `source-code/`: client, server, API, route, library, service, script, command, and template code. +- `test-code/`: test code, fixtures, prepared data, test resources, reports, and test conclusions. +- `other-tools/`: `tools/`, `.codegraph/`, MCP config files, `.vscode/`, `.idea/`, and auxiliary tool settings. +- `agent-runtime/` SSOT index: - status: missing - source_refs: none detected - - gap: NEEDS_CLARIFICATION:ARCHITECTURE -- Engineering SSOT index: + - gap: NEEDS_CLARIFICATION:agent-runtime +- `engineering-runtime/` SSOT index: - status: missing - source_refs: none detected - - gap: NEEDS_CLARIFICATION:ENGINEERING -- Code Style SSOT index: + - gap: NEEDS_CLARIFICATION:engineering-runtime +- `poc/` SSOT index: - status: missing - source_refs: none detected - - gap: NEEDS_CLARIFICATION:CODE_STYLE -- Directory Structure SSOT index: + - gap: NEEDS_CLARIFICATION:poc +- `source-code/` SSOT index: - status: missing - source_refs: none detected - - gap: NEEDS_CLARIFICATION:DIRECTORY_STRUCTURE -- Agent Harness SSOT index: + - gap: NEEDS_CLARIFICATION:source-code +- `test-code/` SSOT index: - status: missing - source_refs: none detected - - gap: NEEDS_CLARIFICATION:AGENT_HARNESS + - gap: NEEDS_CLARIFICATION:test-code +- `other-tools/` SSOT index: + - status: missing + - source_refs: none detected + - gap: NEEDS_CLARIFICATION:other-tools ### Missing SSOT Handling -- If a vertical SSOT is missing or incomplete, treat repository evidence as descriptive context only. +- If a fixed directory-tree SSOT is missing or incomplete, treat repository evidence as descriptive context only. - Before changing a surface governed by missing SSOT, ask for clarification or record `NEEDS_CLARIFICATION:` in handoff. - Use existing code and config facts for narrow edits only when task scope and validation are explicit. - Do not invent repository policy from descriptive repository evidence. -## Path And Task Scope Rules +## Directory Tree And Task Scope Rules -- Source, API, route, runtime, infra, or dependency-boundary changes: read Architecture SSOT before planning edits. -- Build, release, CI, manifest, lockfile, command, template, or runtime configuration changes: read Engineering SSOT before edits. -- Formatting, linting, typing, testing, logging, comments, naming, or error-handling changes: read Code Style SSOT before edits. -- New files, moved files, generated assets, or directory responsibility changes: read Directory Structure SSOT before edits. -- Agent instructions, permissions, MCP, external tools, skills, validation, or failure-handling changes: read Agent Harness SSOT before edits. -- If multiple rules match, read every matched SSOT and apply the highest authority non-conflicting rule. +- Routing rule: seeing a file in one fixed directory tree classifies it as that SSOT; no match falls through to Directory Tree Fallback. +- `agent-runtime/`: `.codex/`, `.claude/`, `AGENTS.md`, `CLAUDE.md`, and other agent rule files; read `agent-runtime/` SSOT before edits. +- `engineering-runtime/`: `.github/workflows/`, Docker files, environment files, manifests, lockfiles, DevOps, infra, secrets, key, password, and permission surfaces; read `engineering-runtime/` SSOT before edits. +- `poc/`: `technical-spikes/`, `architecture-drafts/`, `uc-designs/`, `prototypes/`, `research-notes/`, and `validation-reports/`; read `poc/` SSOT before edits. +- `poc/` content is not formal implementation. +- Before editing `source-code/` from POC work, create or cite a formal design or task; implement from that artifact, not by copying experimental code directly. +- POC conclusions must include validation record source_refs under `poc/validation-reports/`; otherwise record `NEEDS_CLARIFICATION:poc-validation-record` in handoff. +- `source-code/`: `src/`, `app/`, `client/`, `server/`, `api/`, `lib/`, `services/`, `scripts/`, `commands/`, and `templates/`; read `source-code/` SSOT before edits. +- `test-code/`: `tests/`, `test/`, `e2e/`, `fixtures/`, `testdata/`, `test-results/`, and `coverage/`; read `test-code/` SSOT before edits. +- `other-tools/`: `tools/`, `.codegraph/`, MCP config files, `.vscode/`, and `.idea/`; read `other-tools/` SSOT before edits. +- If multiple trees match, read every matched SSOT and apply the highest authority non-conflicting rule. -### Directory Structure Fallback +### Directory Tree Fallback -- Use only when Directory Structure SSOT is missing and the task scope is explicit. -- Treat scanned repository areas as descriptive context, not as approved directory policy. +- Use only when no fixed directory-tree SSOT matches, or the matched tree has no source_refs and the task scope is explicit. +- Treat scanned repository areas as descriptive context, not as approved path policy. - Keep new or moved files aligned with existing nearby conventions unless the user supplies a different target. -- Record `NEEDS_CLARIFICATION:DIRECTORY_STRUCTURE` in handoff when placement is ambiguous. +- Record the matched `NEEDS_CLARIFICATION:` gap in handoff when placement is ambiguous. -## Agent Harness +## agent-runtime - Repository capability layer: source-backed repository-local skills and MCP candidates only. - Agent adapter layer: use explicit integration support when available; otherwise use generic fallback rules. - Platform projection layer: apply only rules supported by the active target file. -- Repository-local skills: evidence only unless an explicit Agent Harness SSOT source names them; read matching `SKILL.md` before planning or editing. +- Repository-local skills: evidence only unless an explicit `agent-runtime/` SSOT source names them; read matching `SKILL.md` before planning or editing. - MCP-backed external tools: indexed as MCP config candidates only; enumerate runtime tools before use. - Repository config candidates are evidence only unless the active adapter supports them. - If a matching skill lacks scope or validation guidance, ask for clarification before expanding writes. diff --git a/tests/integrations/test_integration_subcommand.py b/tests/integrations/test_integration_subcommand.py index e140ee0c8a..76b1943616 100644 --- a/tests/integrations/test_integration_subcommand.py +++ b/tests/integrations/test_integration_subcommand.py @@ -1265,9 +1265,6 @@ def test_install_defers_extension_commands_until_use(self, tmp_path): """ project = _init_project(tmp_path, "claude") - result = _run_in_project(project, ["extension", "add", "git"]) - assert result.exit_code == 0, f"extension add failed: {result.output}" - registry_path = project / ".specify" / "extensions" / ".registry" registered = json.loads(registry_path.read_text(encoding="utf-8"))[ "extensions" @@ -1307,8 +1304,6 @@ def test_install_does_not_register_disabled_extensions(self, tmp_path): """A disabled extension must not be registered for a newly installed agent.""" project = _init_project(tmp_path, "claude") - result = _run_in_project(project, ["extension", "add", "git"]) - assert result.exit_code == 0, f"extension add failed: {result.output}" result = _run_in_project(project, ["extension", "disable", "git"]) assert result.exit_code == 0, result.output @@ -1337,9 +1332,6 @@ def test_install_skills_mode_secondary_agent_defers_extension_artifacts(self, tm """ project = _init_project(tmp_path, "claude") - result = _run_in_project(project, ["extension", "add", "git"]) - assert result.exit_code == 0, f"extension add failed: {result.output}" - # Copilot is not multi_install_safe, so --force is required to add it # alongside the existing default integration. result = _run_in_project(project, [ @@ -1822,10 +1814,6 @@ def test_switch_migrates_extension_commands(self, tmp_path): """Switching should migrate extension commands to the new agent directory.""" project = _init_project(tmp_path, "kimi") - # Install the bundled git extension - result = _run_in_project(project, ["extension", "add", "git"]) - assert result.exit_code == 0, f"extension add failed: {result.output}" - # Verify git extension skills exist for kimi kimi_git_feature = project / ".kimi-code" / "skills" / "speckit-git-feature" / "SKILL.md" assert kimi_git_feature.exists(), "Git extension skill should exist for kimi" @@ -1877,9 +1865,6 @@ def test_switch_installed_target_backfills_extension_commands(self, tmp_path): """Switching to an already-installed agent should register extensions.""" project = _init_project(tmp_path, "claude") - result = _run_in_project(project, ["extension", "add", "git"]) - assert result.exit_code == 0, f"extension add failed: {result.output}" - registry_path = project / ".specify" / "extensions" / ".registry" registered = json.loads(registry_path.read_text(encoding="utf-8"))[ "extensions" @@ -1911,9 +1896,6 @@ def test_switch_migrates_copilot_skills_extension_commands(self, tmp_path): """Copilot --skills should receive extension skills, not .agent.md files.""" project = _init_project(tmp_path, "opencode") - result = _run_in_project(project, ["extension", "add", "git"]) - assert result.exit_code == 0, f"extension add failed: {result.output}" - result = _run_in_project(project, [ "integration", "switch", "copilot", "--script", "sh", @@ -1961,8 +1943,6 @@ def test_switch_does_not_register_disabled_extensions(self, tmp_path): """Disabled extensions should stay disabled and should not migrate commands.""" project = _init_project(tmp_path, "opencode") - result = _run_in_project(project, ["extension", "add", "git"]) - assert result.exit_code == 0, f"extension add failed: {result.output}" result = _run_in_project(project, ["extension", "disable", "git"]) assert result.exit_code == 0, result.output @@ -2529,9 +2509,6 @@ def test_upgrade_backfills_extension_commands_for_agent(self, tmp_path): """ project = _init_project(tmp_path, "claude") - result = _run_in_project(project, ["extension", "add", "git"]) - assert result.exit_code == 0, f"extension add failed: {result.output}" - result = _run_in_project(project, [ "integration", "install", "codex", "--script", "sh", @@ -2580,8 +2557,6 @@ def test_upgrade_non_active_agent_preserves_active_agent_skills(self, tmp_path): """ # Active agent: copilot in skills mode → git extension renders as skills. project = _init_project(tmp_path, "copilot", integration_options="--skills") - result = _run_in_project(project, ["extension", "add", "git"]) - assert result.exit_code == 0, f"extension add failed: {result.output}" skill = project / ".github" / "skills" / "speckit-git-feature" / "SKILL.md" assert skill.exists(), "precondition: active copilot has the git extension skill" diff --git a/tests/test_extensions.py b/tests/test_extensions.py index 98ae25d525..153f97259c 100644 --- a/tests/test_extensions.py +++ b/tests/test_extensions.py @@ -229,7 +229,7 @@ def test_core_command_names_match_bundled_templates(self): assert CORE_COMMAND_NAMES == expected - @pytest.mark.parametrize("extension_id", ("arch", "preview")) + @pytest.mark.parametrize("extension_id", ("arch", "preview", "repository-governance")) def test_bundled_default_catalogs_match_manifest(self, extension_id): """Bundled default extension packages, catalogs, and command lists stay aligned.""" from tests.integrations.community_defaults import DEFAULT_EXTENSION_COMMANDS