diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index accbe87..c876e07 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,9 +51,16 @@ jobs: with: node-version: '20' + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: '3.13' + - name: Install dependencies run: npm ci --no-audit --no-fund + - name: Install pinned official Agent Skills validator + run: python -m pip install -r requirements/skills-ref.txt + - name: Run release gate run: npm run release:check diff --git a/.github/workflows/publish-pack.yml b/.github/workflows/publish-pack.yml index 8321cad..ae07123 100644 --- a/.github/workflows/publish-pack.yml +++ b/.github/workflows/publish-pack.yml @@ -34,12 +34,22 @@ jobs: node-version: '20' registry-url: 'https://registry.npmjs.org' + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: '3.13' + - name: Install dependencies run: npm ci --no-audit --no-fund + - name: Install pinned official Agent Skills validator + run: python -m pip install -r requirements/skills-ref.txt + - name: Verify pack publishability run: npm run release:check + - name: Verify fresh pre-publication gate + run: npm run release:prepublication:check + - name: Publish pack working-directory: extensions/${{ inputs.pack }} env: diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 5275661..e3a9418 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -26,9 +26,16 @@ jobs: node-version: '20' registry-url: 'https://registry.npmjs.org' + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: '3.13' + - name: Install dependencies run: npm ci + - name: Install pinned official Agent Skills validator + run: python -m pip install -r requirements/skills-ref.txt + - name: Verify release identity shell: bash run: | @@ -49,6 +56,9 @@ jobs: - name: Release gate run: npm run release:check + - name: Verify fresh pre-publication gate + run: npm run release:prepublication:check + - name: Publish godpowers with provenance run: npm publish --provenance --access public env: diff --git a/.godpowers/PROGRESS.mdx b/.godpowers/PROGRESS.mdx index 69faaeb..3d7acea 100644 --- a/.godpowers/PROGRESS.mdx +++ b/.godpowers/PROGRESS.mdx @@ -40,7 +40,7 @@ - [DECISION] PRD and ROADMAP were reconstructed from the shipped v2.1.1 codebase with stable requirement ids, and the linkage map was populated via `scripts/reconstruct-self-ledger.js`. Deliverable status lives in `.godpowers/REQUIREMENTS.mdx`: 32 of 33 requirements done, 1 in progress (deliverable-progress, unreleased), 100% requirement-to-code coverage. - + # Godpowers Progress - [DECISION] This file is a generated human-readable view of `.godpowers/state.json`. @@ -66,13 +66,13 @@ | 9 | Planning | Design | not-required | - | 2026-07-13T05:12:51.236Z | | 10 | Planning | Product | not-required | - | 2026-07-13T05:12:51.236Z | | 11 | Planning | Architecture | done | arch/ARCH.mdx | 2026-07-13T05:45:00.000Z | -| 12 | Planning | Roadmap | done | roadmap/ROADMAP.mdx | 2026-07-13T08:08:49.000Z | +| 12 | Planning | Roadmap | done | roadmap/ROADMAP.mdx | 2026-07-13T15:56:11.591Z | | 13 | Planning | Stack | done | stack/DECISION.mdx | 2026-07-13T05:12:51.236Z | | 14 | Building | Repo | done | repo/AUDIT.mdx | 2026-07-13T05:57:20.000Z | -| 15 | Building | Build | done | build/STATE.mdx | 2026-07-13T07:59:42.000Z | +| 15 | Building | Build | done | build/STATE.mdx | 2026-07-13T15:59:58.000Z | | 16 | Shipping | Deploy | done | deploy/STATE.mdx | 2026-07-13T08:08:49.000Z | | 17 | Shipping | Observe | done | observe/STATE.mdx | 2026-07-13T07:59:42.000Z | -| 18 | Shipping | Harden | done | harden/FINDINGS.mdx | 2026-07-13T07:59:42.000Z | +| 18 | Shipping | Harden | done | harden/FINDINGS.mdx | 2026-07-13T15:59:58.000Z | | 19 | Shipping | Launch | done | launch/STATE.mdx | 2026-07-13T08:08:49.000Z | diff --git a/.godpowers/build/STATE.mdx b/.godpowers/build/STATE.mdx index 2dfca70..bdf79d1 100644 --- a/.godpowers/build/STATE.mdx +++ b/.godpowers/build/STATE.mdx @@ -1,5 +1,5 @@ - + # Godpowers Build State - [DECISION] This file is a generated human-readable view of `.godpowers/state.json` for `tier-2.build`. @@ -9,22 +9,22 @@ - [DECISION] Step: Building: Build. - [DECISION] Status: `done`. - [DECISION] Artifact: `.godpowers/build/STATE.mdx`. -- [DECISION] Updated: 2026-07-13T07:59:42.000Z. -- [DECISION] Notes: All implementation and behavioral tests pass.. +- [DECISION] Updated: 2026-07-13T15:59:58.000Z. +- [DECISION] Notes: All implementation, behavioral, standards, coverage, audit, and package checks pass for version 5.5.0.. ## Verification Commands | Command | Status | Exit code | Ran at | Duration ms | Diagnostics | |---|---|---|---|---|---| -| npm test | pass | 0 | 2026-07-13T07:59:42.000Z | 44100 | All test commands passed with 94.65% line, 79.28% branch, and 96.93% function coverage. | -| npm run pack:check | pass | 0 | 2026-07-13T07:59:42.000Z | 700 | Root npm package contents verified: 577 files. | -| npm run pack:mcp:check | pass | 0 | 2026-07-13T07:59:42.000Z | 400 | MCP package contents verified: 8 files. | -| npm run release:check | pass | 0 | 2026-07-13T07:59:42.000Z | 45000 | Aggregate coverage, per-file coverage across 96 expected runtime modules, dependency audit, 141 self-project truth checks, public surface, root package, and MCP package checks passed. | +| npm test | pass | 0 | 2026-07-13T15:59:58.000Z | 41300 | All test commands passed in 41.3 seconds. | +| npm run pack:check | pass | 0 | 2026-07-13T15:59:58.000Z | - | Root npm package contents verified: 582 files. | +| npm run pack:mcp:check | pass | 0 | 2026-07-13T15:59:58.000Z | - | MCP package contents verified: 8 files. | +| npm run release:check | pass | 0 | 2026-07-13T15:59:58.000Z | 46000 | Official skill validation, Pillars 1.1 conformance, 94.64 percent line coverage, 79.26 percent branch coverage, 96.77 percent function coverage, per-file coverage across 98 runtime modules, dependency audit, 141 self-project truth checks, public surface, root package, and MCP package checks passed. | ## Evidence Fields | Field | Value | |---|---| -| release-version | 5.4.0 | +| release-version | 5.5.0 | diff --git a/.godpowers/docs/REPO-DOC-SYNC.mdx b/.godpowers/docs/REPO-DOC-SYNC.mdx index e616d75..966145d 100644 --- a/.godpowers/docs/REPO-DOC-SYNC.mdx +++ b/.godpowers/docs/REPO-DOC-SYNC.mdx @@ -109,3 +109,14 @@ - [DECISION] Repo documentation sync status before apply was fresh. - [DECISION] Repo documentation sync status after apply is fresh. - [DECISION] No mechanical repo documentation files were changed. + +## 2026-07-13T15:52:41.841Z + +- [DECISION] Repo documentation sync status before apply was stale. +- [DECISION] Repo documentation sync status after apply is stale. +- [DECISION] Refreshed README.md for readme-version-badge. +- [DECISION] Refreshed USERS.md for users-version. +- [DECISION] Refreshed ARCHITECTURE.md for architecture-version. +- [DECISION] Refreshed docs/ROADMAP.md for roadmap-version. +- [DECISION] Refreshed docs/reference.md for reference-version. +- [HYPOTHESIS] god-docs-writer should review CHANGELOG.md, RELEASE.md, SECURITY.md. diff --git a/.godpowers/harden/FINDINGS.mdx b/.godpowers/harden/FINDINGS.mdx index dea1ef3..5f8aee3 100644 --- a/.godpowers/harden/FINDINGS.mdx +++ b/.godpowers/harden/FINDINGS.mdx @@ -2,7 +2,7 @@ - [DECISION] Date: 2026-07-13. - [DECISION] Reviewer: autonomous product trust hardening run. -- [DECISION] Scope: installer, host capability detection, Quick Proof, state reconciliation, release checks, package contents, and production dependencies. +- [DECISION] Scope: CLI and SDK routing, installer and release workflows, hash-bound public activation, package contents, and production dependencies. ## Summary @@ -15,20 +15,20 @@ - [DECISION] Launch gate: PASSED. -## OWASP Coverage - -| Category | Status | Evidence | -|---|---|---| -| A01 Broken Access Control | Reviewed | [DECISION] No application authorization surface exists in the package runtime. | -| A02 Cryptographic Failures | Reviewed | [DECISION] Event integrity uses SHA-256 and no product secrets are stored. | -| A03 Injection | Reviewed | [DECISION] Shell-sensitive helpers prefer argument-array process execution. | -| A04 Insecure Design | Reviewed | [DECISION] Level-4 release actions remain user-owned and guarded. | -| A05 Security Misconfiguration | Reviewed | [DECISION] Host guarantees fail closed without active-session evidence. | -| A06 Vulnerable Components | Reviewed | [DECISION] `npm audit --omit=dev` is a release check and the core has no production dependency. | -| A07 Authentication Failures | Reviewed | [DECISION] Authentication is delegated to host and release providers, with no local credential store. | -| A08 Data Integrity Failures | Reviewed | [DECISION] Checksummed state views, event hash chains, and self-truth checks protect release claims. | -| A09 Logging Failures | Reviewed | [DECISION] Events, checkpoints, gate results, and sync logs remain inspectable on disk. | -| A10 SSRF | Reviewed | [DECISION] Core runtime does not expose a server-side URL fetch endpoint. | +## OWASP Web Top 10:2025 Coverage + +| Category | Manual procedure | Result | Evidence or finding | +|---|---|---|---| +| A01:2025 Broken Access Control | Trace CLI project-root access and inspect the new routing and gate modules for user-controlled URL fetches or internal-resource access | Not Applicable, no network server or URL fetch boundary exists in the reviewed runtime | `scripts/test-product-routing.js`; `scripts/test-prepublication-gate.js`; source inspection of `lib/product-routing.js` and `lib/prepublication-gate.js` | +| A02:2025 Security Misconfiguration | Exercise missing, invalid, pending, and stale hardening state through the public activation gate | pass, invalid or incomplete authority fails closed | `scripts/test-prepublication-gate.js` missing, invalid, incomplete, and stale-state cases | +| A03:2025 Software Supply Chain Failures | Verify dependency audit, immutable workflow action identities, package allowlist contents, provenance workflow, and pre-publish gate ordering | pass | `npm audit --omit=dev`; `.github/workflows/publish.yml`; `.github/workflows/publish-pack.yml`; `scripts/check-package-contents.js` | +| A04:2025 Cryptographic Failures | Mutate reviewed hardening bytes and verify SHA-256 revision mismatch blocks publication | pass | `lib/prepublication-gate.js`; `scripts/test-prepublication-gate.js` hash-mutation case | +| A05:2025 Injection | Pass explicit and ambiguous product text plus project path arguments through parsing without shell interpolation | pass | `lib/product-routing.js`; `lib/prepublication-gate.js`; `scripts/test-product-routing.js`; `scripts/test-prepublication-gate.js` | +| A06:2025 Insecure Design | Exercise ambiguous form selection, accepted Critical status, stale timestamp, and missing gate abuse cases | pass, ambiguity remains open and every unsafe activation case blocks | `scripts/test-product-routing.js`; `scripts/test-prepublication-gate.js` | +| A07:2025 Authentication Failures | Inspect credential and session ownership across the local runtime and publication workflows | Not Applicable, authentication is delegated to the active AI host, GitHub, and npm with no local credential store | `.github/workflows/publish.yml`; `SECURITY.md`; source inspection | +| A08:2025 Software or Data Integrity Failures | Record the exact hardening revision, then alter findings bytes and authoritative hardening state independently | pass, either change invalidates the gate | `scripts/test-prepublication-gate.js` revision and authoritative-update cases | +| A09:2025 Security Logging and Alerting Failures | Trigger a blocked gate and verify a non-zero command result plus explicit blocking reasons for CI and operator action | pass | `lib/prepublication-gate.js`; `scripts/test-prepublication-gate.js`; publish workflow gate step | +| A10:2025 Mishandling of Exceptional Conditions | Inject malformed JSON, missing files, incomplete state, invalid timestamps, stale updates, and changed Critical counts | pass, all cases fail closed without public activation | `scripts/test-prepublication-gate.js` exceptional-condition cases | ## Findings @@ -38,5 +38,5 @@ ## Have-Nots Checklist - [x] [DECISION] Manual code and contract review supplemented automated dependency checks. -- [x] [DECISION] Every OWASP category has an explicit package-specific disposition. +- [x] [DECISION] Every OWASP Web Top 10:2025 category has an explicit package-specific procedure, result, and evidence reference. - [x] [DECISION] Critical findings count is zero. diff --git a/.godpowers/launch/PREPUBLICATION.mdx b/.godpowers/launch/PREPUBLICATION.mdx new file mode 100644 index 0000000..2248f31 --- /dev/null +++ b/.godpowers/launch/PREPUBLICATION.mdx @@ -0,0 +1,19 @@ +--- +schema-version: 1 +checked_at: "2026-07-13T16:01:05.617Z" +hardening_revision: "sha256:f7bcf07a292362d2f40dcf7f2a8f40c35facb70fd5621e2c569a20d2a2d1b337" +hardening_updated_at: "2026-07-13T15:59:58.000Z" +critical_total: 0 +critical_unresolved: 0 +critical_accepted: 0 +policy: "block-unresolved-critical" +verdict: "pass" +--- +# Pre-Publication Gate + +- [DECISION] Checked at: 2026-07-13T16:01:05.617Z. +- [DECISION] Hardening revision: sha256:f7bcf07a292362d2f40dcf7f2a8f40c35facb70fd5621e2c569a20d2a2d1b337. +- [DECISION] Hardening updated at: 2026-07-13T15:59:58.000Z. +- [DECISION] Critical findings: 0 total, 0 unresolved or accepted. +- [DECISION] Verdict: pass. +- [DECISION] Any later hardening revision or hardening state update invalidates this gate. diff --git a/.godpowers/roadmap/ROADMAP.mdx b/.godpowers/roadmap/ROADMAP.mdx index e10f54d..10b2191 100644 --- a/.godpowers/roadmap/ROADMAP.mdx +++ b/.godpowers/roadmap/ROADMAP.mdx @@ -1,14 +1,14 @@ # Roadmap -> Reconciled against the Godpowers 5.4.0 published release. Increments carry a +> Reconciled against the Godpowers 5.5.0 release candidate. Increments carry a > stable M-slug id, a Status, and the PRD requirement ids they deliver. Status is > derived from current artifacts, linkage, and executable evidence. ## Evidence Provenance -- [DECISION] Evidence generated at: `2026-07-13T08:08:49.000Z`. -- [DECISION] Source version: `5.4.0`. -- [DECISION] Source hash `package.json`: `sha256:b4408eb0bd0365433a55d2a29b23d45a52874117f7228caa7bbf487123dfa1f5`. +- [DECISION] Evidence generated at: `2026-07-13T15:55:18.000Z`. +- [DECISION] Source version: `5.5.0`. +- [DECISION] Source hash `package.json`: `sha256:3cdde60011cd4891c7c6109bec611176d56d6d6c1c92d3bcc28d5bba9e810f5b`. - [DECISION] Source hash `.godpowers/prd/PRD.mdx`: `sha256:239990ed2eb267c26d3de744bf318d6260bfd67463fec8e7ccccbc348fc1712c`. - [DECISION] Source hash `.godpowers/arch/ARCH.mdx`: `sha256:ec90f0ec06d07fbc67c3b5ac22f3ae882a10d714ef230316f75823709e44642b`. - [DECISION] Source hash `.godpowers/stack/DECISION.mdx`: `sha256:cc9e9227262d9d472fa7806fbafc9a83b8e621728c3652fae1a423a867989ce3`. diff --git a/.godpowers/runs/20260713-arc-pillars-1-1-hardening/ORCHESTRATOR-HANDOFF.mdx b/.godpowers/runs/20260713-arc-pillars-1-1-hardening/ORCHESTRATOR-HANDOFF.mdx new file mode 100644 index 0000000..f558940 --- /dev/null +++ b/.godpowers/runs/20260713-arc-pillars-1-1-hardening/ORCHESTRATOR-HANDOFF.mdx @@ -0,0 +1,22 @@ +# Arc-Ready And Pillars 1.1 Hardening Handoff + +- [DECISION] Project root: `/Users/hprincivil/Projects/godpowers`. +- [DECISION] This is a brownfield resume from authoritative `.godpowers/state.json` state. +- [DECISION] Invocation mode is autonomous implementation with release authority. +- [DECISION] The user authorized implementation, commits, pushes, merges, GitHub release creation, release asset publication, npm publication, and repository cleanup. +- [DECISION] The target is a release-quality Godpowers version that closes every evidenced gap against Arc-Ready 1.1.0 and Pillars 1.1.0. +- [DECISION] Read `.godpowers/state.json`, `.godpowers/CHECKPOINT.mdx`, `.godpowers/intent.yaml`, current tier artifacts, and this handoff before choosing work. +- [DECISION] Treat `.godpowers/PROGRESS.mdx` and tier state views as generated human views when state exists. +- [DECISION] Compute the Pillars load set before each major command while repairing the Pillars implementation itself from the authoritative Pillars 1.1.0 specification at `/Users/hprincivil/Projects/pillars/SPEC.md`. +- [DECISION] Read `/Users/hprincivil/Projects/arc-ready/SKILL.md`, its product-form router, domain registry, OWASP 2025 router, completion gates, and evaluation cases as upstream evidence. +- [DECISION] Implement Pillars 1.1 nested scopes, path-derived identities, portable token matching, offline absent catalogs, conditional soft references, context budgets, conformance fixtures, and the current catalog. +- [DECISION] Separate Godpowers specialist agent source contracts from the project Pillars namespace while preserving installed runtime agent paths and compatibility. +- [DECISION] Implement form-first routing, four-axis domain composition, form-specific completion evidence, OWASP 2025 coverage, and a hash-bound pre-publication gate that invalidates after hardening changes. +- [DECISION] Add Arc-Ready artifact import and managed sync-back without overwriting Arc-Ready-owned canonical files. +- [DECISION] Add pinned official Agent Skills validation, align root skill metadata, and add deterministic plus live-harness evaluation evidence. +- [DECISION] Update all affected docs, routes, workflows, schemas, templates, package allowlists, tests, generated state, release notes, and version references. +- [DECISION] Use the autonomous repair loop until focused tests, full tests, release checks, official validators, package checks, and isolated published-install checks pass. +- [DECISION] Do not bypass safe-sync, unresolved Critical findings, validation failures, package mismatches, or publication verification failures. +- [DECISION] Follow `references/orchestration/GOD-MODE-RUNBOOK.md` for the project-run contract. +- [DECISION] GitHub and npm identities are already authenticated and available for the authorized release actions. +- [OPEN QUESTION] None. The user explicitly authorized the full implementation and release path. Owner: user. Due: resolved in this invocation. diff --git a/.godpowers/state.json b/.godpowers/state.json index 65afeee..485df8b 100644 --- a/.godpowers/state.json +++ b/.godpowers/state.json @@ -102,9 +102,9 @@ "roadmap": { "status": "done", "artifact": "roadmap/ROADMAP.mdx", - "artifact-hash": "sha256:521fa57871ab83fb22167056f63916bdbc13db0739d22f2a39be4e77f69c1a27", - "updated": "2026-07-13T08:08:49.000Z", - "notes": "Roadmap provenance is pinned to current source hashes and version 5.4.0." + "artifact-hash": "sha256:1d0287c2779f1f83d5596a971f2b643f12b91799e2e9a4dcfca1b5fa3413b0b4", + "updated": "2026-07-13T15:56:11.591Z", + "notes": "Roadmap provenance is pinned to current source hashes and version 5.5.0." }, "stack": { "status": "done", @@ -126,45 +126,43 @@ "status": "done", "artifact": "build/STATE.mdx", "artifact-hash": null, - "updated": "2026-07-13T07:59:42.000Z", - "notes": "All implementation and behavioral tests pass.", + "updated": "2026-07-13T15:59:58.000Z", + "notes": "All implementation, behavioral, standards, coverage, audit, and package checks pass for version 5.5.0.", "verification": { "commands": [ { "command": "npm test", "status": "pass", "exitCode": 0, - "ranAt": "2026-07-13T07:59:42.000Z", - "durationMs": 44100, - "diagnostics": "All test commands passed with 94.65% line, 79.28% branch, and 96.93% function coverage." + "ranAt": "2026-07-13T15:59:58.000Z", + "durationMs": 41300, + "diagnostics": "All test commands passed in 41.3 seconds." }, { "command": "npm run pack:check", "status": "pass", "exitCode": 0, - "ranAt": "2026-07-13T07:59:42.000Z", - "durationMs": 700, - "diagnostics": "Root npm package contents verified: 577 files." + "ranAt": "2026-07-13T15:59:58.000Z", + "diagnostics": "Root npm package contents verified: 582 files." }, { "command": "npm run pack:mcp:check", "status": "pass", "exitCode": 0, - "ranAt": "2026-07-13T07:59:42.000Z", - "durationMs": 400, + "ranAt": "2026-07-13T15:59:58.000Z", "diagnostics": "MCP package contents verified: 8 files." }, { "command": "npm run release:check", "status": "pass", "exitCode": 0, - "ranAt": "2026-07-13T07:59:42.000Z", - "durationMs": 45000, - "diagnostics": "Aggregate coverage, per-file coverage across 96 expected runtime modules, dependency audit, 141 self-project truth checks, public surface, root package, and MCP package checks passed." + "ranAt": "2026-07-13T15:59:58.000Z", + "durationMs": 46000, + "diagnostics": "Official skill validation, Pillars 1.1 conformance, 94.64 percent line coverage, 79.26 percent branch coverage, 96.77 percent function coverage, per-file coverage across 98 runtime modules, dependency audit, 141 self-project truth checks, public surface, root package, and MCP package checks passed." } ] }, - "release-version": "5.4.0" + "release-version": "5.5.0" } }, "tier-3": { @@ -268,34 +266,33 @@ "harden": { "status": "done", "artifact": "harden/FINDINGS.mdx", - "artifact-hash": "sha256:892ad01284310eb806f541385db875490459ed9d54a20bbe2d51ad31fd0e54e2", - "updated": "2026-07-13T07:59:42.000Z", - "notes": "All recorded trust findings are remediated and no unresolved Critical finding remains.", + "artifact-hash": "sha256:f7bcf07a292362d2f40dcf7f2a8f40c35facb70fd5621e2c569a20d2a2d1b337", + "updated": "2026-07-13T15:59:58.000Z", + "notes": "OWASP Web Top 10:2025 review is complete, the release gate is passed for version 5.5.0, and no unresolved Critical finding remains.", "verification": { "commands": [ { "command": "npm test", "status": "pass", "exitCode": 0, - "ranAt": "2026-07-13T07:59:42.000Z", - "durationMs": 44100, - "diagnostics": "All test commands passed with 94.65% line, 79.28% branch, and 96.93% function coverage." + "ranAt": "2026-07-13T15:59:58.000Z", + "durationMs": 41300, + "diagnostics": "All test commands passed in 41.3 seconds." }, { "command": "npm audit --omit=dev", "status": "pass", "exitCode": 0, - "ranAt": "2026-07-13T07:59:42.000Z", - "durationMs": 800, + "ranAt": "2026-07-13T15:59:58.000Z", "diagnostics": "Found 0 vulnerabilities." }, { "command": "npm run release:check", "status": "pass", "exitCode": 0, - "ranAt": "2026-07-13T07:59:42.000Z", - "durationMs": 45000, - "diagnostics": "Aggregate coverage, per-file coverage across 96 expected runtime modules, dependency audit, 141 self-project truth checks, public surface, root package, and MCP package checks passed." + "ranAt": "2026-07-13T15:59:58.000Z", + "durationMs": 46000, + "diagnostics": "Official standards, complete tests, aggregate and per-file coverage, dependency audit, 141 self-project truth checks, package verification, installer isolation, full-arc integration, and dogfood checks passed." } ] }, diff --git a/AGENTS.md b/AGENTS.md index 7fff1e8..535a04c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,6 +15,8 @@ projects from raw idea to hardened production. - `SKILL.md` is the main entry point, loaded by AI coding tools - `skills/` contains individual command skills (one per file) +- `agents/` contains Pillars 1.1 project context only +- `specialists/` contains source contracts installed into each supported host agent registry - `routing/` contains command routing metadata and intent recipes - `workflows/` contains executable workflow YAML - `references/` contains per-tier reference material (antipatterns, examples) @@ -48,14 +50,16 @@ projects from raw idea to hardened production. This is a Godpowers project. Godpowers uses the Pillars standard as its native project context layer. Coding agents read project context from `./agents/*.md` before changing code, while `.godpowers/` remains the Godpowers workflow state and artifact layer. +This project follows Pillars 1.1.0. Coding agents read project pillar files before acting. + ## At the start of any task -1. Load every pillar whose frontmatter has `always_load: true`. -2. Scan remaining pillar frontmatter and select task-relevant primaries from `triggers` and `covers`. -3. Add each primary pillar direct `must_read_with` dependencies, depth 1 only. -4. Read every pillar body in the computed load set. -5. Read `see_also` pillars only when the task explicitly touches that area. -6. Follow Rules, apply Workflows, heed Watchouts, and ask before deciding open Gaps. +1. Resolve scopes from repository root to the task target. A scope contains both `AGENTS.md` and `agents/`. Apply outer scopes first and let the nearest scope win conflicts. +2. Inventory pillar frontmatter recursively, local exclusions, and optional `agents/catalog.yaml` absent concerns in each scope. +3. Load every pillar whose frontmatter has `always_load: true`. Match remaining `triggers` with the Pillars portable ASCII token matcher to select primaries and absent concerns. +4. Add each primary pillar direct `must_read_with` dependencies, depth 1 only. Path-qualified sub-pillars use identities such as `auth/agent-registration`. +5. Add a selected pillar `see_also` target only when the task matches the target identity, triggers, or covers. Do not follow soft references recursively. +6. Read every selected body. Follow Rules, apply Workflows, heed Watchouts, and ask before deciding open Gaps. ## Handling missing pillars @@ -63,10 +67,11 @@ Coding agents read project context from `./agents/*.md` before changing code, wh |---|---| | `status: present` | Load and comply. | | `status: stub` | Treat the concern as acknowledged but undecided. Ask before making domain decisions. | -| Name in `excluded:` | Treat as intentionally not applicable. | -| Relevant but absent | Infer from code, state the assumption, and recommend authoring the pillar. | +| Name in `excluded:` | Treat as intentionally not applicable in that scope. | +| Trigger matches local `agents/catalog.yaml` entry | Infer from code, state the assumption, and recommend authoring the pillar. | +| No local file, exclusion, or catalog entry | Make no Pillars-specific claim about that concern. | -If `context.md` or `repo.md` is missing, pause and create stubs before continuing. +If `context.md` or `repo.md` is missing and not explicitly excluded, pause and ask the human to create a stub or record an exclusion. ## Excluded pillars @@ -106,7 +111,7 @@ There is exactly one orchestrator: `god-orchestrator`. It owns writes to ### Active artifacts -- orchestration: `runs/20260713-product-trust-hardening/ORCHESTRATOR-HANDOFF.mdx` +- orchestration: `runs/20260713-arc-pillars-1-1-hardening/ORCHESTRATOR-HANDOFF.mdx` - preflight: `preflight/PREFLIGHT.mdx` - archaeology: `archaeology/REPORT.mdx` - tech-debt: `tech-debt/ASSESSMENT.mdx` diff --git a/ARCHITECTURE-MAP.md b/ARCHITECTURE-MAP.md index dae77f9..efb5e18 100644 --- a/ARCHITECTURE-MAP.md +++ b/ARCHITECTURE-MAP.md @@ -57,7 +57,7 @@ skills/*.md v routing/*.yaml | - +--> agents/god-*.md + +--> specialists/god-*.md | +--> built-in runtime helpers | @@ -640,7 +640,7 @@ godpowers/ ├── README.md, CHANGELOG.md, LICENSE, CONTRIBUTING.md, SECURITY.md, USERS.md ├── ARCHITECTURE.md <- Design doc ├── ARCHITECTURE-MAP.md <- This file -├── package.json (v5.4.0) +├── package.json (v5.5.0) ├── .github/workflows/ <- CI + npm publish workflows │ ├── bin/install.js <- CLI installer (15 runtimes) @@ -673,7 +673,7 @@ godpowers/ │ ├── events.v1.json │ └── workflow.v1.json │ -├── lib/ <- Real JS runtime (98 modules) +├── lib/ <- Real JS runtime (100 modules) │ ├── state.js <- state model + drift detection │ ├── events.js <- OTel-shape event log + hash chain │ ├── router.js <- command routing @@ -736,7 +736,7 @@ godpowers/ --- -## Numbers (as of v5.4.0) +## Numbers (as of v5.5.0) | Component | Count | |-----------|-------| @@ -751,7 +751,7 @@ godpowers/ | Templates | 14 | | Reference documents | 39 | | JSON Schemas | 7 | -| **JS runtime modules** | **98** | +| **JS runtime modules** | **100** | | **External integrations** | **5** (all detect-and-delegate; none vendored): Google Labs design.md, Impeccable, awesome-design-md, SkillUI, vercel-labs/agent-browser + Playwright | | Hooks | 2 | | Dogfood scenarios | 5 | diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 43bf565..c132b10 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,6 +1,6 @@ # Godpowers Architecture (v3 Design Target) -> Status: STABLE v5.4.0 published release (Godplans 1.1 two-artifact contracts, lifecycle-safe dispatch, complete GP and requirement traceability, and the existing production runtime surface) +> Status: STABLE v5.5.0 (Godplans 1.1 two-artifact contracts, lifecycle-safe dispatch, complete GP and requirement traceability, and the existing production runtime surface) > Authors: Godpowers Team > Last updated: 2026-07-13 @@ -79,6 +79,13 @@ Native Pillars context: | `agents/context.md` | **Identity**: domain language and product invariants | Pillars | | `agents/repo.md` | **Layout**: repository structure and naming | Pillars | | `agents/*.md` | **Routed context**: task-specific project truth | Pillars | +| `agents/catalog.yaml` | **Absent inventory**: known concerns not yet authored | Pillars 1.1 | + +Pillars 1.1 routing uses path-derived identities, portable ASCII token +matching, direct dependency depth, conditional soft references, scoped +exclusions, and root-to-target nested scope precedence. Specialist source +contracts are separate under `specialists/` and install into each host's +`agents/` registry. Godpowers workflow state: @@ -331,7 +338,7 @@ the AI coding tool. `skills/*.md` command files match 120 `routing/*.yaml` route files, including the `god` front door and every shipped `god-*` command. -[DECISION] The runtime surface also includes 40 `agents/god-*.md` specialist +[DECISION] The source surface also includes 40 `specialists/god-*.md` specialist agents, 13 workflow YAML files, and 44 intent recipes. [DECISION] The current route graph has 68 built-in or local-runtime command @@ -500,7 +507,7 @@ helper, recipe, or command flow that cannot be parsed, planned, packed, or traced back to a slash-command surface. [DECISION] The architecture audit graph is: -`skills/*.md` -> `routing/*.yaml` -> `agents/god-*.md` or built-in helper -> +`skills/*.md` -> `routing/*.yaml` -> `specialists/god-*.md` or built-in helper -> `workflows/*.yaml` -> `routing/recipes/*.yaml` -> `docs/command-flows.md` -> `package.json` and `scripts/check-package-contents.js`. diff --git a/CHANGELOG.md b/CHANGELOG.md index 161b096..83793da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,40 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [5.5.0] - 2026-07-13 + +Arc-Ready and Pillars conformance release. This release makes product shape, +domain composition, public activation, and project context mechanically +testable across the full Godpowers lifecycle. + +### Added + +- Product-form routing for web applications, APIs and services, CLIs and SDKs, + mobile and desktop products, data and ML systems, and infrastructure or IaC. +- Four-axis domain composition across product form, archetype, industry, and + regulatory overlays, with form-specific vertical slices and completion + evidence. +- A hash-bound pre-publication gate that re-reads hardening evidence, records + Critical counts and timestamps, and invalidates after any authoritative + hardening change. +- Arc-Ready 1.1 artifact detection, read-only import, and managed sync-back + through `.arc-ready/GODPOWERS-SYNC.md`. +- Pillars 1.1 catalog, path identity, portable matcher, nested scope, + exclusion, dependency, budget, and official conformance-fixture support. +- Pinned official Agent Skills validation in CI and every release check. + +### Changed + +- OWASP hardening now follows the 2025 Web Top 10, including Software Supply + Chain Failures and Mishandling of Exceptional Conditions. +- Specialist source contracts moved from `agents/` to `specialists/`, while + installed host contracts retain the portable `agents/` destination. +- Repository Pillars now use the normative eight-section body, `present` or + `stub` status, explicit cataloged absences, and new development, release, and + privacy context. +- Arc workflows select exactly one primary product form before applying domain + or regulatory overlays. + ## [5.4.0] - 2026-07-13 Godplans 1.1 interoperability release. This release recognizes the complete diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 50afb34..552997b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -114,7 +114,7 @@ competitor. If the sentence still reads true, it decides nothing. Rewrite. ## Adding a New Specialist Agent -1. Create `agents/god-.md` with required sections +1. Create `specialists/god-.md` with required sections 2. Add or update routing metadata if the agent is spawned by a command 3. Add to `bin/install.js` if it needs special install handling (rare) 4. Add CHANGELOG entry under [Unreleased] diff --git a/README.md b/README.md index ecf176c..34e5f9f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![CI](https://github.com/hannsxpeter/godpowers/actions/workflows/ci.yml/badge.svg)](https://github.com/hannsxpeter/godpowers/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) -[![Version](https://img.shields.io/badge/version-5.4.0-blue)](CHANGELOG.md) +[![Version](https://img.shields.io/badge/version-5.5.0-blue)](CHANGELOG.md) [![npm](https://img.shields.io/npm/v/godpowers.svg)](https://www.npmjs.com/package/godpowers) **Ship fast. Ship right. Ship everything. Ship accountably.** @@ -96,6 +96,8 @@ It fuses several disciplines into one workflow: - **Native project context** - every Godpowers project is a Pillars project: a root `AGENTS.md` plus routed `agents/*.md` files hold durable project truth before any command touches code. +- **Form-first execution** - one primary product form selects the vertical + slice before archetype, industry, or regulatory constraints are composed. - **Artifact discipline** - every sentence in every document is a labeled decision, hypothesis, or open question, with mechanically verified failure modes. @@ -106,6 +108,8 @@ It fuses several disciplines into one workflow: anything is called complete. - **Accountability** - the current state is on disk, the next action is derived from it, and every change traces back to a request. +- **Publication integrity** - public activation is bound to a fresh hardening + hash, timestamp, and Critical-finding policy. It is the builder in a three-part family: [godplans](https://github.com/hannsxpeter/godplans) plans everything up front (`.godplans/PLAN.mdx` plus its self-contained @@ -116,6 +120,10 @@ either one when it finds it, and ships. Its own artifacts live under `.godpowers/` as `.mdx`, human-readable and machine-parseable, with a legacy `.md` fallback for projects created before 4.0. +Godpowers also imports Arc-Ready 1.1 tier artifacts as read-only migration +evidence and writes progress back only through +`.arc-ready/GODPOWERS-SYNC.md`. + ### Two ways to drive **One-shot arc.** Type `/god-mode` and Godpowers runs every tier from idea to diff --git a/RELEASE.md b/RELEASE.md index 01d44a5..9860158 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,46 +1,42 @@ -# Godpowers 5.4.0 Release +# Godpowers 5.5.0 Release -> Status: Published +> Status: Release candidate > Date: 2026-07-13 -- [DECISION] Godpowers 5.4.0 is the Godplans 1.1 interoperability release. -- [DECISION] The public surface contains 122 slash commands, 40 agents, 13 workflows, and 44 recipes. -- [DECISION] The core package contains 98 runtime library modules and keeps zero production dependencies. -- [DECISION] The `@godpowers/mcp` companion remains read-only and shares version 5.4.0. +- [DECISION] Godpowers 5.5.0 is the Arc-Ready and Pillars conformance release. +- [DECISION] The public surface contains 122 slash commands, 40 specialist agents, 13 workflows, and 44 recipes. +- [DECISION] The core package contains 100 runtime library modules and keeps zero production dependencies. +- [DECISION] The `@godpowers/mcp` companion remains read-only and shares version 5.5.0. ## Changes -- [DECISION] `lib/sibling-artifacts.js` recognizes the Godplans 1.1 PLAN plus validator contract, mirrors its structural rules without executing repository-owned shell, and pins the official validator by exact SHA-256 identity. -- [DECISION] GP execution is blocked for planning, done, invalid, incomplete, unsupported-validator, non-executable, symlinked, and lifecycle-inconsistent contracts. -- [DECISION] Approved or executing plans expose only dependency-ready tasks, and parallel dispatch remains inside one wave with disjoint file ownership. -- [DECISION] `lib/planning-systems.js` preserves the complete GP task ledger, phases, waves, statuses, `Reuses`, `Verify`, story requirements, and domain requirements during migration. -- [DECISION] Godplans staleness covers PLAN content, validator content, and validator executable mode while ignoring Godpowers-owned sync companions. -- [DECISION] Legacy and incomplete plans remain readable as hypothesis-grade migration context but cannot become execution authority. -- [DECISION] Planning, migration, preflight, doctor, context, reconciliation, reconstruction, orchestration, routing, workflow, template, architecture, and reference documentation now describe the Godplans 1.1 contract. +- [DECISION] Product routing selects one of six forms before applying product archetype, industry, or regulatory overlays. +- [DECISION] Each product form carries a distinct vertical slice and completion-evidence contract, so web assumptions do not leak into API, CLI, mobile, data, or infrastructure work. +- [DECISION] OWASP hardening uses the 2025 Web Top 10 and routes supply-chain failures plus exceptional-condition handling as first-class checks. +- [DECISION] Public activation requires `.godpowers/launch/PREPUBLICATION.mdx`, bound to the exact hardening findings hash, authoritative hardening timestamp, and Critical count. +- [DECISION] Godpowers imports Arc-Ready 1.1 canonical tier artifacts as read-only migration evidence and writes sync-back only to `.arc-ready/GODPOWERS-SYNC.md`. +- [DECISION] Pillars 1.1 support includes path-derived identities, recursive sub-pillars, nested scopes, exact portable matching, local catalogs, exclusions, dependency depth, budgets, and all official routing fixtures. +- [DECISION] Specialist source contracts live under `specialists/`, while host installation still writes portable contracts to the host `agents/` registry. +- [DECISION] The pinned official Agent Skills validator runs in release checks and GitHub publication workflows. ## Validation -- [DECISION] `npm run release:check` passes on the final 5.4.0 release-candidate tree. -- [DECISION] Aggregate coverage is 94.65% lines, 79.28% branches, and 96.93% functions. -- [DECISION] Per-file line coverage is at least 70% across all 96 expected non-browser runtime modules. -- [DECISION] `npm run lint` passes all static release-sensitive checks. -- [DECISION] The sibling integration suite passes 59 checks, including official validator identity, structural parity, lifecycle gates, companion safety, staleness, large-plan reads, and full GP and requirement traceability. -- [DECISION] A live parity probe passes the same Godplans fixture through the official 1.1.0 validator and the Godpowers static mirror. -- [DECISION] Node 18, Node 20, Node 22, and the package check pass in GitHub Actions run `29233469337` for pull request 67. -- [DECISION] Repository documentation, repository surface, route quality, recipe coverage, and release surface detectors report no stale checks. -- [DECISION] Root package validation covers 577 files and MCP package validation covers 8 files. -- [DECISION] The self-project truth gate passes 141 checks and fails closed on stale source versions, generated state, artifact hashes, roadmap provenance, lifecycle status, and public surface claims. +- [DECISION] Product routing passes 11 focused tests across six forms and four composition axes. +- [DECISION] The pre-publication gate passes 12 focused tests for recording, hash drift, timestamp drift, Critical policy, malformed authority, and fail-closed behavior. +- [DECISION] Pillars passes 14 native behavior tests, all 6 official portable routing fixtures, and the official Pillars repository validator with 0 errors and 0 warnings. +- [DECISION] The official Agent Skills validator accepts the absolute Godpowers repository path. +- [DECISION] The complete release gate passes with 94.64 percent line coverage, 79.26 percent branch coverage, 96.77 percent function coverage, and at least 70 percent line coverage across 98 included runtime modules. +- [DECISION] The dependency audit reports 0 vulnerabilities and self-project truth passes 141 checks. +- [DECISION] Package verification records 582 files in `godpowers` and 8 files in `@godpowers/mcp`. +- [HYPOTHESIS] Pull-request CI and publication evidence will be recorded after the release candidate is merged and published. ## Upgrade -- [DECISION] Install with `npm install -g godpowers@5.4.0` or `npx godpowers@5.4.0`. -- [DECISION] Existing 5.x projects need no Godpowers artifact migration. -- [DECISION] Projects using Godplans 1.1 should keep `.godplans/PLAN.mdx` beside its emitted executable `.godplans/validate-plan.sh` companion. -- [DECISION] Re-run the installer for each host runtime so updated skills and runtime helpers replace installed copies. +- [DECISION] After publication, install with `npm install -g godpowers@5.5.0` or `npx godpowers@5.5.0`. +- [DECISION] Existing 5.x projects need no `.godpowers` artifact migration. +- [DECISION] Re-run the installer for each host runtime so updated skills, specialists, routes, references, and runtime helpers replace installed copies. +- [DECISION] Repository contributors should treat `agents/` as Pillars context and `specialists/` as portable specialist source contracts. ## Publication Evidence -- [DECISION] GitHub tag `v5.4.0` and the GitHub Release point to merged main commit `13c0ce2905b870846c8170673eaed5415e09b235`. -- [DECISION] GitHub Actions run `29234078146` verified release identity, passed the complete release gate, and published npm `godpowers@5.4.0` plus npm `@godpowers/mcp@5.4.0` with provenance. -- [DECISION] The 577-file root tarball and 8-file MCP tarball attached to the GitHub Release exactly match npm registry integrity, and `SHA256SUMS` records their GitHub asset digests. -- [DECISION] npm latest resolves both packages to 5.4.0, and isolated published verification passes for Quick Proof, read-only project inspection, dashboard, next route, Claude, Codex, and the MCP executable. +- [HYPOTHESIS] Git tag, GitHub Release, asset checksums, npm provenance, and isolated published-install verification are pending the merged release commit. diff --git a/SECURITY.md b/SECURITY.md index 919c6cc..17ef560 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -73,7 +73,8 @@ When using Godpowers in a sensitive context: | Version | Supported | |---------|-----------| -| 5.4.x | Yes | +| 5.5.x | Yes | +| 5.4.x | Security fixes only | | 5.3.x | Security fixes only | | 5.2.x | Security fixes only | | 5.1.x | Security fixes only | diff --git a/SKILL.md b/SKILL.md index e9cb0c6..b2bfa8e 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,6 +1,5 @@ --- name: godpowers -version: 2.2.0 description: | AI-powered development system that takes a project from raw idea to hardened production. Fuses artifact discipline, execution engine, quality enforcement, @@ -12,6 +11,13 @@ description: | "god review", "god smite", "godpowers", "start a project", "build this", "ship this", "take this from idea to production", "one-shot the whole thing", "autonomous build", "full arc", "idea to deploy" +license: MIT +compatibility: "Works with Agent Skills compatible file-system agents. Supported hosts include Claude Code, Codex, Cursor, Windsurf, Gemini, OpenCode, Copilot, Augment, Trae, Cline, Kilo, Antigravity, Qwen, CodeBuddy, and Pi." +metadata: + version: "5.5.0" + updated: "2026-07-13" + changelog: "CHANGELOG.md" + tier: "full-arc" --- # Godpowers @@ -96,6 +102,14 @@ answer a question, inspect first. When a term is resolved, record it in `.godpowers/domain/GLOSSARY.mdx` with canonical spelling, avoided aliases, relationships, and any unresolved ambiguity. +### 8.1 Product Form Before Domain +Select exactly one primary product form before product archetype, industry, or +regulatory guidance. Use `lib/product-routing.js`, +`references/building/PRODUCT-FORM-ROUTER.md`, and +`references/building/DOMAIN-COMPOSITION-REGISTRY.md`. Preserve this order: +product form, product archetype, industry overlay, regulatory overlay. Build +completion uses the selected form's evidence, not a web-only default. + ### 9. Next Commands Closeout When you answer with a recommendation, proposal, status report, diagnostic, audit, lifecycle view, reconciliation, or exploratory plan, end with @@ -287,8 +301,8 @@ Run these local runtime helpers automatically when their trigger is present: managed progress view refresh. - Lightweight reverse-sync or linkage scan after code or artifact edits. - Pillars sync planning after durable artifact truth changes. -- `lib/planning-systems.importPlanningContext` when legacy planning, BMAD, or - Superpowers planning context is detected during `/god-init` or +- `lib/planning-systems.importPlanningContext` when legacy planning, BMAD, + Superpowers, or Arc-Ready planning context is detected during `/god-init` or `/god-migrate`. - `lib/source-sync.run` when `state.json` records enabled `source-systems` entries and `/god-sync`, `/god-scan`, or `/god-migrate` closes a workflow. @@ -341,7 +355,7 @@ Spawn these agents only when the trigger is direct and scope is bounded: - `god-automation-engineer` after the user approves provider, template, cadence, and scope for multi-template, write-capable, background-agent, scriptable-scheduler, or provider-uncertain automation setup. -- `god-greenfieldifier` when imported legacy planning, BMAD, or Superpowers context has +- `god-greenfieldifier` when imported legacy planning, BMAD, Superpowers, or Arc-Ready context has low confidence, conflicting systems, or missing canonical Godpowers seed artifacts after local import. - `god-greenfieldifier` when feature-awareness detects unimported or imported @@ -462,7 +476,12 @@ Silence is not a status. Every tier must have an explicit entry. **Process**: 1. Elicit the user's vision through targeted questions (not open-ended) -2. Draft the PRD with these required sections: +2. Select one primary product form before applying product archetype, + industry, or regulatory guidance. Record an open question on ambiguity + instead of defaulting to a web application. +3. Compose and record the four domain axes in order, including explicit + none-evidenced values. +4. Draft the PRD with these required sections: - Problem statement (substitution-tested) - Target users (specific, not "developers") - Success metrics (measurable, time-bound) @@ -471,10 +490,10 @@ Silence is not a status. Every tier must have an explicit entry. - Scope and explicit no-gos - Appetite (time/resource constraints) - Open questions (with owners and due dates) -3. Run substitution test on every claim -4. Run three-label test on every sentence -5. Write to `.godpowers/prd/PRD.mdx` -6. Run `npx godpowers state advance --step=prd --status=done --project=.` +5. Run substitution test on every claim +6. Run three-label test on every sentence +7. Write to `.godpowers/prd/PRD.mdx` +8. Run `npx godpowers state advance --step=prd --status=done --project=.` **Have-nots (PRD fails if any are true)**: - Problem statement passes substitution test (reads the same for any product) @@ -594,23 +613,29 @@ Silence is not a status. Every tier must have an explicit entry. **Process**: 1. Read roadmap, select current milestone -2. Break milestone into vertical slices -3. For each slice, create a plan: +2. Load the ordered product route and the primary form's vertical-slice and + completion-evidence contract. +3. Break milestone into form-appropriate vertical slices. A CLI or SDK uses a + clean consumer round trip, an API uses a contract path, Data or ML uses a + reproducible pipeline, and Infrastructure or IaC uses plan, policy, + simulation, and rollback evidence. +4. For each slice, create a plan: - Files to create/modify (exact paths) - Tests to write FIRST - Implementation steps - Verification criteria -4. Detect dependencies between slices -5. Group independent slices into parallel waves -6. Execute waves: +5. Detect dependencies between slices +6. Group independent slices into parallel waves +7. Execute waves: - Each agent gets fresh context (full 200K budget) - Agent writes tests first (RED) - Agent implements until tests pass (GREEN) - Agent refactors (REFACTOR) - Two-stage review: spec compliance, then code quality - Atomic commit on pass -7. Record build verification evidence in `.godpowers/state.json` -8. Run `npx godpowers state advance --step=build --status=done --project=.` to regenerate the build state view +8. Verify the primary form's completion evidence and record it with the build + verification commands in `.godpowers/state.json`. +9. Run `npx godpowers state advance --step=build --status=done --project=.` to regenerate the build state view **TDD Enforcement**: - If a subagent writes implementation before tests, flag the violation @@ -673,6 +698,10 @@ Silence is not a status. Every tier must have an explicit entry. 4. Launch-day telemetry (source attribution on every signup) 5. D-7 to D+7 runbook 6. Record launch evidence in `.godpowers/state.json` and regenerate the launch state view +7. Immediately before any public release action, re-read hardening evidence, + record `.godpowers/launch/PREPUBLICATION.mdx` with its exact content hash, + and run `node /lib/prepublication-gate.js --check --project=.`. + Any later hardening change invalidates this gate. **Have-nots**: - Landing copy passes substitution test (reads generic) @@ -685,7 +714,9 @@ Silence is not a status. Every tier must have an explicit entry. **Runs in parallel with**: Launch prep (but gates launch completion) **Process**: -1. OWASP Top 10 walkthrough (not scanner output, actual review) +1. OWASP Web Top 10:2025 walkthrough using + `references/shipping/HARDEN-OWASP-2025-ROUTER.md` and reproducible manual + evidence for all ten current categories 2. Auth/authz boundary verification 3. Input validation audit 4. Dependency vulnerability scan diff --git a/USERS.md b/USERS.md index 51f29b1..d9d9d45 100644 --- a/USERS.md +++ b/USERS.md @@ -1,6 +1,6 @@ # Users and Community -The current source version is v5.4.0, and the latest published release is v5.4.0. +The current source version is v5.5.0, and the latest published release is v5.4.0. ## Track record diff --git a/agents/arch.md b/agents/arch.md index 76987fd..e462a27 100644 --- a/agents/arch.md +++ b/agents/arch.md @@ -1,6 +1,6 @@ --- pillar: arch -status: active +status: present always_load: false covers: [architecture, runtime model, state model, workflows, agents] triggers: [architecture, workflow, state, router, agent, runtime] @@ -12,6 +12,10 @@ see_also: [quality, deploy] - [DECISION] This pillar captures architectural context for Godpowers. +## Context + +- [DECISION] Runtime architecture is implemented by source-controlled skills, routes, workflows, specialist contracts, schemas, and dependency-free Node.js helpers. + ## Decisions - [DECISION] Godpowers uses a pure-skill runtime where slash-command skills spawn specialist agents inside the host AI coding tool. @@ -29,20 +33,36 @@ see_also: [quality, deploy] - [DECISION] Godplans 1.1 interoperability treats `.godplans/PLAN.mdx` plus the pinned executable `.godplans/validate-plan.sh` as one contract, mirrors structural validation without executing repository shell during import, blocks GP dispatch outside `approved` or `executing`, and requires the official validator to pass immediately before work. - [DECISION] The current executable audit status is fresh for repo surface, route quality, recipe coverage, and workflow planning. +## Rules + +(none) + +## Workflows + +(none) + ## Watchouts - [HYPOTHESIS] Runtime behavior depends on host AI tools exposing skill and agent capabilities consistently. - [HYPOTHESIS] Local helper work must stay visible in closeouts so automatic work does not become hidden orchestration. - [HYPOTHESIS] A future Godplans validator hash requires an explicit Godpowers compatibility update so new shell bytes cannot become trusted silently. +## Touchpoints + +- [DECISION] Architecture decisions synchronize from `.godpowers/arch/ARCH.mdx` through the managed section below. + +## Gaps + +(none) + -## Godpowers artifact sources +### Godpowers artifact sources - Sync mode: auto-applied by yolo. - Related artifact: `.godpowers/arch/ARCH.mdx`. - Rule: keep this pillar aligned when these artifacts change durable arch truth. -## Extracted durable signals +### Extracted durable signals From `.godpowers/arch/ARCH.mdx`: - [DECISION] A developer invokes Godpowers inside an AI coding host, which loads installed skills and specialist agents from the host-specific runtime directory. diff --git a/agents/auth.md b/agents/auth.md index 17360f7..ff0226e 100644 --- a/agents/auth.md +++ b/agents/auth.md @@ -41,13 +41,13 @@ see_also: [] - This pillar is a stub. Ask before making durable auth decisions. -## Godpowers artifact sources +### Godpowers artifact sources - Sync mode: auto-applied by yolo. - Related artifact: `.godpowers/harden/FINDINGS.mdx`. - Rule: keep this pillar aligned when these artifacts change durable auth truth. -## Extracted durable signals +### Extracted durable signals From `.godpowers/harden/FINDINGS.mdx`: - [DECISION] Date: 2026-07-13. diff --git a/agents/catalog.yaml b/agents/catalog.yaml new file mode 100644 index 0000000..98e3a3d --- /dev/null +++ b/agents/catalog.yaml @@ -0,0 +1,29 @@ +version: 1 +absent: + - identity: a11y + covers: [accessibility, wcag, assistive technology] + triggers: [a11y, accessibility, wcag, screen reader] + - identity: analytics + covers: [product events, user telemetry, key metrics] + triggers: [analytics, product event, telemetry, kpi] + - identity: async + covers: [background jobs, queues, schedules, events] + triggers: [background job, queue, scheduler, cron, async] + - identity: cache + covers: [caching, invalidation, time to live] + triggers: [cache, caching, invalidation, ttl] + - identity: compliance + covers: [regulatory requirements, audit controls, control mappings] + triggers: [compliance, soc2, hipaa, gdpr, pci, audit] + - identity: config + covers: [configuration, environment variables, feature flags, secrets] + triggers: [config, configuration, environment variable, feature flag, secret] + - identity: i18n + covers: [translation, locale, right-to-left layout, localization] + triggers: [i18n, translation, locale, rtl, localization] + - identity: integrations + covers: [third-party services, outbound contracts, webhooks] + triggers: [integration, third party, webhook, external api] + - identity: notifications + covers: [transactional email, sms, push notifications] + triggers: [notification, transactional email, sms, push] diff --git a/agents/context.md b/agents/context.md index 065e607..119dcc5 100644 --- a/agents/context.md +++ b/agents/context.md @@ -1,6 +1,6 @@ --- pillar: context -status: active +status: present always_load: true covers: [project identity, domain language, product promise, user outcomes] triggers: [godpowers, slash commands, specialist agents, product context, domain] @@ -15,57 +15,57 @@ see_also: [arch, quality, deploy] ## Context - [DECISION] Godpowers is an AI-powered development system delivered as slash commands and specialist agents inside AI coding tools. -- [DECISION] The package name is `godpowers`, and the current repository version is `5.4.0`. +- [DECISION] The package name is `godpowers`, and the current repository version is `5.5.0`. - [DECISION] The primary audience is solo founders and small engineering teams using AI coding tools who need accountable production workflow discipline without enterprise process. - [DECISION] The product promise is one slash-command arc from idea to hardened, observable, launch-ready software with traceable artifacts on disk. - [DECISION] Godpowers uses a pure-skill model where `npx godpowers` installs runtime files and in-tool slash commands perform work. - [DECISION] The native context layer is Pillars: root `AGENTS.md` plus routed `agents/*.md` files. - [DECISION] Workflow state lives in `.godpowers/` and is authoritative for Godpowers command resumes. +## Decisions + +(none) + ## Rules - [DECISION] Generated artifacts must label substantive sentences as `[DECISION]`, `[HYPOTHESIS]`, or `[OPEN QUESTION]`. - [DECISION] Generated text must avoid em dashes, en dashes, and emojis. - [DECISION] Claims must include Godpowers-specific evidence instead of generic AI tooling language. +## Workflows + +(none) + ## Watchouts - [HYPOTHESIS] User adoption risk concentrates around whether agent spawning, installed runtime metadata, and local validation behave the same across supported AI coding tools. - [HYPOTHESIS] Documentation drift risk is high because the public surface includes 122 slash commands, 40 specialist agents, 13 workflows, and 44 recipes. - [HYPOTHESIS] Adoption risk also concentrates around whether executable gates, dogfood, host guarantees, extension authoring, and suite release dry-runs behave consistently across supported hosts. +## Touchpoints + +- [DECISION] Durable product truth is synchronized from the PRD, roadmap, and authoritative state through the managed source section below. + ## Gaps -- [OPEN QUESTION] Which external messy repository should become the first full host-run adoption case study after `5.4.0`? Owner: maintainer. Due: before the next broad product proof claim. +- [OPEN QUESTION] Which external messy repository should become the first full host-run adoption case study after `5.5.0`? Owner: maintainer. Due: before the next broad product proof claim. -## Godpowers artifact sources +### Godpowers artifact sources - Sync mode: auto-applied by yolo. -- Related artifact: `.godpowers/prd/PRD.mdx`. -- Related artifact: `.godpowers/roadmap/ROADMAP.mdx`. -- Related artifact: `.godpowers/state.json`. +- Related artifact: `RELEASE.md`. - Rule: keep this pillar aligned when these artifacts change durable context truth. -## Extracted durable signals - -From `.godpowers/prd/PRD.mdx`: -- [DECISION] AI coding agents like Claude Code can write code, but a single prompt cannot carry a project from raw idea to hardened production without losing the plan, skipping review, or forgetting what was already decided across sessions. -- [DECISION] Teams that adopt Claude Code hit 3 recurring failures: the agent narrates progress it did not actually make, the agent re-asks questions it already answered, and the produced artifacts (PRD, architecture, code) drift out of sync with each other within days. -- [DECISION] Primary: solo founders and small engineering teams (1 to 5 people) who use Claude Code or a compatible agent CLI daily and want to ship a real product, not a prototype, without hiring a separate planning function. -- [DECISION] Secondary: engineers inheriting a brownfield repository who need to reconstruct planning artifacts, map technical debt, and onboard an AI agent onto existing code without rewriting it from scratch. -- [HYPOTHESIS] A disk-authoritative workflow that re-derives state from files on every turn, gates every artifact against named failure modes, and traces each requirement to the code that satisfies it will remove most of that drift. -- [DECISION] Within 30 minutes of a fresh install, a first-time user can run one command (`/god-mode`) and reach a committed, test-green vertical slice, measured on the shipped dogfood fixtures. -- [DECISION] Within 10 minutes after a build completes, at least 95 percent of declared requirements trace to implementing code, measured by the linkage coverage percentage that the Godpowers dashboard reports. -- [DECISION] For every release candidate, all release-gate checks reach zero failures within the 60-minute verification window before publication, measured by `scripts/run-tests.js` and `npm run release:check`. - -From `.godpowers/roadmap/ROADMAP.mdx`: -- [DECISION] Evidence generated at: `2026-07-13T08:08:49.000Z`. -- [DECISION] Source version: `5.4.0`. -- [DECISION] Source hash `package.json`: `sha256:b4408eb0bd0365433a55d2a29b23d45a52874117f7228caa7bbf487123dfa1f5`. -- [DECISION] Source hash `.godpowers/prd/PRD.mdx`: `sha256:239990ed2eb267c26d3de744bf318d6260bfd67463fec8e7ccccbc348fc1712c`. -- [DECISION] Source hash `.godpowers/arch/ARCH.mdx`: `sha256:ec90f0ec06d07fbc67c3b5ac22f3ae882a10d714ef230316f75823709e44642b`. -- [DECISION] Source hash `.godpowers/stack/DECISION.mdx`: `sha256:cc9e9227262d9d472fa7806fbafc9a83b8e621728c3652fae1a423a867989ce3`. -- [DECISION] Planning completion is backed by passing PRD, design not-required, architecture, roadmap, and stack gates. -- [DECISION] Build, shipping, steady-state, and advanced completion remain backed by the 33 linked requirements and the final release gate recorded in state. +### Extracted durable signals + +From `RELEASE.md`: +- [DECISION] Godpowers 5.5.0 is the Arc-Ready and Pillars conformance release. +- [DECISION] The public surface contains 122 slash commands, 40 specialist agents, 13 workflows, and 44 recipes. +- [DECISION] The core package contains 100 runtime library modules and keeps zero production dependencies. +- [DECISION] The `@godpowers/mcp` companion remains read-only and shares version 5.5.0. +- [DECISION] Product routing selects one of six forms before applying product archetype, industry, or regulatory overlays. +- [DECISION] Each product form carries a distinct vertical slice and completion-evidence contract, so web assumptions do not leak into API, CLI, mobile, data, or infrastructure work. +- [DECISION] OWASP hardening uses the 2025 Web Top 10 and routes supply-chain failures plus exceptional-condition handling as first-class checks. +- [DECISION] Public activation requires `.godpowers/launch/PREPUBLICATION.mdx`, bound to the exact hardening findings hash, authoritative hardening timestamp, and Critical count. diff --git a/agents/deploy.md b/agents/deploy.md index 28965a6..dda152d 100644 --- a/agents/deploy.md +++ b/agents/deploy.md @@ -1,6 +1,6 @@ --- pillar: deploy -status: active +status: present always_load: false covers: [ci, release, npm publish, package verification] triggers: [deploy, publish, release, npm, ci, provenance] @@ -12,7 +12,9 @@ see_also: [security, observe] - [DECISION] This pillar captures deployment and release context for Godpowers. -## Release Surface +## Context + +### Release Surface - [DECISION] Godpowers deploys as an npm package published from tag-triggered GitHub Actions when provenance is available. - [DECISION] `.github/workflows/ci.yml` runs the full matrix test suite and the Node 20 release gate on pushes and pull requests to `main`. @@ -20,20 +22,52 @@ see_also: [security, observe] - [DECISION] `.github/workflows/publish-pack.yml` runs `npm run release:check` before publishing first-party extension packs. - [DECISION] `package.json` exposes `bin.godpowers` at `./bin/install.js`. - [DECISION] Manual tarball publish is a fallback only when the tag-triggered workflow cannot run, and provenance is unavailable for that publish. -- [DECISION] Source version `5.4.0` is published through the identity-bound tag workflow from merged main commit `13c0ce2905b870846c8170673eaed5415e09b235`. -- [DECISION] npm `godpowers@5.4.0` and `@godpowers/mcp@5.4.0` are tagged `latest`, and their registry integrity values match the tarballs attached to the GitHub Release. +- [HYPOTHESIS] Source version `5.5.0` will publish through the identity-bound tag workflow after the release candidate merges to `main`. +- [HYPOTHESIS] npm `godpowers@5.5.0` and `@godpowers/mcp@5.5.0` will become `latest` only after registry and asset integrity verification passes. - [DECISION] Isolated published-install verification passes for Quick Proof, read-only project inspection, dashboard, next route, Claude, Codex, and the MCP executable. -- [DECISION] The prior `v5.3.1` tag remains the tested rollback reference. +- [DECISION] The prior `v5.4.0` tag remains the tested rollback reference. + +## Decisions + +(none) + +## Rules + +(none) + +## Workflows + +(none) ## Watchouts - [HYPOTHESIS] A release is incomplete until git tag, GitHub release, npm version, package tarball, README badges, CHANGELOG, RELEASE, and local install verification agree. - [HYPOTHESIS] Registry and published-install proof do not substitute for adoption evidence from an unaffiliated production user. +## Touchpoints + +- [DECISION] Release truth synchronizes from package metadata, GitHub workflows, npm registry evidence, and authoritative Godpowers state. + +## Gaps + +(none) + -## Godpowers artifact sources +### Godpowers artifact sources - Sync mode: auto-applied by yolo. -- Related artifact: `.godpowers/state.json`. +- Related artifact: `RELEASE.md`. - Rule: keep this pillar aligned when these artifacts change durable deploy truth. + +### Extracted durable signals + +From `RELEASE.md`: +- [DECISION] Godpowers 5.5.0 is the Arc-Ready and Pillars conformance release. +- [DECISION] The public surface contains 122 slash commands, 40 specialist agents, 13 workflows, and 44 recipes. +- [DECISION] The core package contains 100 runtime library modules and keeps zero production dependencies. +- [DECISION] The `@godpowers/mcp` companion remains read-only and shares version 5.5.0. +- [DECISION] Product routing selects one of six forms before applying product archetype, industry, or regulatory overlays. +- [DECISION] Each product form carries a distinct vertical slice and completion-evidence contract, so web assumptions do not leak into API, CLI, mobile, data, or infrastructure work. +- [DECISION] OWASP hardening uses the 2025 Web Top 10 and routes supply-chain failures plus exceptional-condition handling as first-class checks. +- [DECISION] Public activation requires `.godpowers/launch/PREPUBLICATION.mdx`, bound to the exact hardening findings hash, authoritative hardening timestamp, and Critical count. diff --git a/agents/development.md b/agents/development.md new file mode 100644 index 0000000..3aa53a5 --- /dev/null +++ b/agents/development.md @@ -0,0 +1,46 @@ +--- +pillar: development +status: present +always_load: false +covers: [local setup, developer workflow, debugging, generated artifacts] +triggers: [develop, development, local setup, bootstrap, debug] +must_read_with: [repo, quality] +see_also: [stack] +--- + +## Scope + +- [DECISION] This pillar captures the contributor inner loop for the Godpowers repository. + +## Context + +- [DECISION] Contributors use Node.js 18 or newer and npm from the repository root. +- [DECISION] Source-controlled commands, specialist contracts, routes, workflows, schemas, and runtime helpers are edited in place without a compilation step. +- [DECISION] Generated `.godpowers/PROGRESS.mdx` and tier state views derive from `.godpowers/state.json` and must not be edited directly. + +## Decisions + +- [DECISION] Focused tests run before `npm test`, while `npm run release:check` is reserved for complete release evidence because it includes coverage and package checks. + +## Rules + +- [DECISION] Preserve unrelated user changes in dirty worktrees. +- [DECISION] Add new runtime behavior in `lib/` and keep `bin/install.js` a thin dispatch surface. + +## Workflows + +1. [DECISION] Read the applicable Pillars load set and source-controlled route before changing a command. +2. [DECISION] Run the smallest focused test that exercises the change. +3. [DECISION] Run `npm test`, `npm run lint`, and relevant package checks before handoff. + +## Watchouts + +- [HYPOTHESIS] Direct edits to generated views can appear correct locally while leaving authoritative state stale. + +## Touchpoints + +- [DECISION] Development workflow touches `lib/`, `scripts/`, `skills/`, `specialists/`, `routing/`, `workflows/`, and `.godpowers/state.json`. + +## Gaps + +(none) diff --git a/agents/god-harden-auditor.md b/agents/god-harden-auditor.md deleted file mode 100644 index 25c3a05..0000000 --- a/agents/god-harden-auditor.md +++ /dev/null @@ -1,181 +0,0 @@ ---- -name: god-harden-auditor -description: | - Adversarial security reviewer. Manual OWASP Top 10 walkthrough, auth boundary - verification, input validation audit, dependency vulnerability scan, - rate-limiting check. Critical findings BLOCK launch. - - Spawned by: /god-harden, god-orchestrator -tools: Read, Bash, Grep, Glob, WebSearch -inputs: - - "codebase" - - ".godpowers/state.json deploy evidence" - - "optional org security standards" - - "references/shipping/HARDEN-OWASP-WORKSHEETS.md" - - "references/shipping/HARDEN-ANTIPATTERNS.md" -outputs: - - ".godpowers/harden/FINDINGS.mdx" -gates: - - "H-01 through H-11 have-nots" - - "Critical findings block launch" - - "manual adversarial review" -handoff: - - "return security findings and block launch on unresolved Critical issues" ---- - -# God Harden Auditor - -Adversarial security review. Not a scanner run. A manual walkthrough of how -the application can be broken. - -## Gate Check - -Build is complete. Code is in the repo. - -## Process - -Before reviewing, read `references/shipping/HARDEN-OWASP-WORKSHEETS.md` (the -per-category worksheets for the walkthrough below) and -`references/shipping/HARDEN-ANTIPATTERNS.md` (failure patterns to avoid). - -### 1. OWASP Top 10 Manual Walkthrough - -For each category, REVIEW THE CODE (not just run a tool): - -1. **A01 Broken Access Control** - - Map every endpoint to required permissions - - Verify each endpoint actually checks those permissions - - Test: unauth user hitting auth endpoints - - Test: low-privilege user hitting high-privilege endpoints - -2. **A02 Cryptographic Failures** - - Sensitive data encrypted at rest and in transit - - No hardcoded secrets (grep for common patterns) - - No weak algorithms (MD5, SHA1 for security, weak ciphers) - - Proper random number generation (crypto.randomBytes, not Math.random) - -3. **A03 Injection** - - SQL injection: parameterized queries, no string concat - - XSS: output encoding, CSP headers - - Command injection: never pass user input to shell - - Template injection: safe template engines, no eval - -4. **A04 Insecure Design** - - Business logic flaws (race conditions, TOCTOU) - - Rate limiting gaps - - Missing abuse prevention - -5. **A05 Security Misconfiguration** - - Default credentials removed - - Verbose errors disabled in prod - - Unnecessary features disabled - - Security headers present (CSP, HSTS, X-Frame-Options) - -6. **A06 Vulnerable Components** - - Run dependency audit (npm audit, pip-audit, etc.) - - Check for stale dependencies (>12 months old) - - Known CVEs - -7. **A07 Authentication Failures** - - Strong password policy - - MFA available for sensitive accounts - - Session fixation prevented - - Credential stuffing protection (rate limit, captcha) - -8. **A08 Data Integrity Failures** - - Updates signed/verified - - No unsafe deserialization - - Integrity checks on critical data - -9. **A09 Logging Failures** - - Security events logged (auth, authz, admin actions) - - No sensitive data in logs (passwords, tokens, PII) - - Alerts on suspicious activity - -10. **A10 SSRF** - - User-supplied URLs validated - - Internal services not reachable from user-facing endpoints - - Cloud metadata endpoints blocked - -### 2. Classification - -For each finding: - -| Severity | Definition | Launch Impact | -|----------|-----------|---------------| -| **Critical** | Exploitable now, data loss or unauthorized access | BLOCKS LAUNCH | -| **High** | Exploitable with moderate effort | Should fix before launch | -| **Medium** | Defense-in-depth gap | Fix in first sprint post-launch | -| **Low** | Best practice improvement | Backlog | - -## Output - -Use `templates/HARDEN-FINDINGS.mdx` (installed at -`/godpowers-templates/HARDEN-FINDINGS.mdx`) as the structural starting -point. Write `.godpowers/harden/FINDINGS.mdx`: - -```markdown -# Security Findings - -Date: [timestamp] -Reviewer: god-harden-auditor - -## Summary -| Severity | Count | -|----------|-------| -| Critical | N | -| High | N | -| Medium | N | -| Low | N | - -Launch gate: PASSED / BLOCKED - -## Findings - -### [CRITICAL-001] [Title] -- **Category**: OWASP A01 -- **Location**: src/api/users.ts:45 -- **Description**: ... -- **Impact**: ... -- **Reproduction**: ... -- **Remediation Options**: - - Option A: [time estimate] - - Option B: [time estimate] -``` - -## Critical-Finding Gate - -If ANY finding is Critical: -- `.godpowers/harden/FINDINGS.mdx` declares launch BLOCKED -- Return to orchestrator: it MUST pause for human resolution -- Launch agent must refuse to proceed - -## YOLO Handling (special rules) - -god-harden-auditor has a UNIQUE --yolo rule: - -**Critical findings are the ONE pause that --yolo CANNOT auto-resolve.** - -Even with --yolo: -- High/Medium/Low findings are documented and the build moves on -- Critical findings BLOCK launch and force the orchestrator to pause - -Rationale: shipping with a known Critical security vulnerability is a category -of risk that should never be auto-accepted. The `--yolo` flag means "I trust -the system's defaults"; it does NOT mean "I accept unknown security risk -without seeing it". - -If invoked with --yolo and Critical findings exist: -- Write FINDINGS.md as normal -- Mark launch gate as BLOCKED in the file -- Return a clear "PAUSE REQUIRED: Critical findings present" signal to - orchestrator -- The orchestrator will then pause regardless of --yolo - -## Have-Nots - -- Only scanner output, no manual review -- Auth boundaries not actually tested -- No input validation audit -- Findings have no severity classification -- Critical finding without remediation options diff --git a/agents/observe.md b/agents/observe.md index 4c968ce..506484c 100644 --- a/agents/observe.md +++ b/agents/observe.md @@ -1,6 +1,6 @@ --- pillar: observe -status: active +status: present always_load: false covers: [events, metrics, traces, checkpoints, logs] triggers: [observe, observability, events, checkpoint, trace, metrics, logs] @@ -12,7 +12,9 @@ see_also: [quality] - [DECISION] This pillar captures observability mechanisms inside Godpowers itself. -## Signals +## Context + +### Signals - [DECISION] `lib/events.js` writes hash-chained JSONL events under `.godpowers/runs//events.jsonl`. - [DECISION] `lib/checkpoint.js` writes `.godpowers/CHECKPOINT.mdx` as the durable orientation pin for future sessions. @@ -21,13 +23,33 @@ see_also: [quality] - [DECISION] `lib/dashboard.js` renders disk-derived project status, action brief, proactive checks, and host guarantees. - [DECISION] Event vocabulary includes local helper, dashboard, host capability, dogfood, source-system import, sync-back, repo-doc sync, and repo-surface sync events. +## Decisions + +(none) + +## Rules + +(none) + +## Workflows + +(none) + ## Watchouts - [HYPOTHESIS] Checkpoint drift can confuse future sessions if state changes without `lib/checkpoint.syncFromState`. - [HYPOTHESIS] Event vocabulary drift can break OTel export, dashboard closeouts, and recovery if schemas and runtime events diverge. +## Touchpoints + +- [DECISION] Observability context synchronizes from authoritative state through the managed section below. + +## Gaps + +(none) + -## Godpowers artifact sources +### Godpowers artifact sources - Sync mode: auto-applied by yolo. - Related artifact: `.godpowers/state.json`. diff --git a/agents/privacy.md b/agents/privacy.md new file mode 100644 index 0000000..e2d9b82 --- /dev/null +++ b/agents/privacy.md @@ -0,0 +1,43 @@ +--- +pillar: privacy +status: present +always_load: false +covers: [personal data, consent, retention, deletion, subject rights] +triggers: [privacy, personal data, pii, consent, retention, deletion] +must_read_with: [context, security] +see_also: [analytics] +--- + +## Scope + +- [DECISION] This pillar captures privacy boundaries for Godpowers project-local events, adoption metrics, connectors, and exported telemetry. + +## Context + +- [DECISION] Godpowers stores workflow state and evidence locally under `.godpowers/` unless a user explicitly configures an external connector or telemetry export. +- [DECISION] OTel export and connector actions are explicit capabilities rather than silent data collection. + +## Decisions + +- [DECISION] Local evidence should record operational facts without copying secrets, credentials, or unnecessary personal content. + +## Rules + +- [DECISION] Do not place API tokens, session values, raw credentials, or unnecessary personal data in state, events, logs, checkpoints, or sync-back files. +- [DECISION] External export requires explicit configuration and must remain visible in closeout evidence. + +## Workflows + +- [DECISION] Before adding a new external data path, inventory collected fields, purpose, destination, retention behavior, deletion path, and user control. + +## Watchouts + +- [HYPOTHESIS] User-authored artifact excerpts can contain personal data even when the runtime itself does not collect identity fields. + +## Touchpoints + +- [DECISION] Privacy concerns touch `lib/events.js`, `lib/otel-exporter.js`, connector configuration, logs, checkpoints, and source-system sync-back. + +## Gaps + +(none) diff --git a/agents/quality.md b/agents/quality.md index 946b2f0..229548d 100644 --- a/agents/quality.md +++ b/agents/quality.md @@ -1,6 +1,6 @@ --- pillar: quality -status: active +status: present always_load: false covers: [tests, linting, validation, release gates, artifact checks] triggers: [test, lint, validation, audit, release, package, check] @@ -12,43 +12,63 @@ see_also: [security, deploy] - [DECISION] This pillar captures quality gates for Godpowers changes. -## Commands +## Context + +### Commands - [DECISION] `npm test` is the required full verification command. - [DECISION] `npm run test:quick-proof` checks README, Quick Proof, release verification, runtime expectations, and adoption canary alignment. - [DECISION] `npm run test:audit` runs dependency audit, `git diff --check`, and documentation surface count tests. - [DECISION] `npm run pack:check` verifies the npm package contains required runtime files and excludes local-only files. -- [DECISION] `npm run release:check` combines per-file library coverage, the full test suite, audit checks, self-project truth checks, and package contents checks. +- [DECISION] `npm run release:check` combines official Agent Skills validation, Pillars 1.1 behavior and conformance fixtures, per-file library coverage, the full test suite, audit checks, self-project truth checks, and package contents checks. - [DECISION] `npm run test:self-truth` blocks stale version, public surface, lifecycle, artifact, requirement, generated progress, and roadmap provenance claims. - [DECISION] The full test suite includes quick proof docs, repo-doc sync, repo-surface sync, automation surface sync, host capabilities, extension authoring, dogfood, Mode D, installer smoke, workflow runner, OTel, and extension publish-readiness checks. - [DECISION] Sibling-artifact tests cover godaudits 2.x JSON authority, large canonical files, non-regular source rejection, legacy and generated MDX fallback, check and evidence ledgers, compliance, accepted risks, score caps, compiled coverage, typed GA dispatch, managed todo synchronization, MDX safety, canonical staleness, migration seeds, and remediation impact detection. - [DECISION] Sibling-artifact tests cover the Godplans 1.1 validator identity, two-artifact completeness, static structural preflight, lifecycle dispatch gates, full GP/R seed traceability, large-plan reads, and legacy hypothesis-grade fallback. +- [DECISION] Arc-Ready leverage tests cover six product forms, four-axis domain composition, Arc artifact import and sync-back, OWASP 2025, and hash-bound pre-publication invalidation. - [DECISION] Build and review agents enforce request-trace discipline: assumptions, public behavior, expected files, and verification command must be explicit before implementation. - [DECISION] Reviewers block speculative flexibility, unrelated cleanup, and diff churn that cannot be traced to the user request, slice plan, failing test, or implementation-caused cleanup. -## Standards +## Decisions + +(none) + +## Rules - [DECISION] Artifact linter checks must catch em or en dashes, emojis, unlabeled paragraphs, phantom references, future-dated body timestamps, and selected PRD or ARCH failures. - [DECISION] CI tests Node `18`, Node `20`, and Node `22`. - [DECISION] Full release work must keep `CHANGELOG.md`, `README.md`, `RELEASE.md`, package metadata, GitHub release notes, npm version, and local installed runtime aligned. +## Workflows + +(none) + ## Watchouts - [HYPOTHESIS] The full test suite is intentionally broad and can surface unrelated drift from docs, packaging, workflows, routing, and installer behavior. +## Touchpoints + +- [DECISION] Quality evidence synchronizes from roadmap and release artifacts through the managed section below. + +## Gaps + +(none) + -## Godpowers artifact sources +### Godpowers artifact sources - Sync mode: auto-applied by yolo. - Related artifact: `.godpowers/roadmap/ROADMAP.mdx`. +- Related artifact: `docs/ROADMAP.md`. - Rule: keep this pillar aligned when these artifacts change durable quality truth. -## Extracted durable signals +### Extracted durable signals From `.godpowers/roadmap/ROADMAP.mdx`: -- [DECISION] Evidence generated at: `2026-07-13T08:08:49.000Z`. -- [DECISION] Source version: `5.4.0`. -- [DECISION] Source hash `package.json`: `sha256:b4408eb0bd0365433a55d2a29b23d45a52874117f7228caa7bbf487123dfa1f5`. +- [DECISION] Evidence generated at: `2026-07-13T15:55:18.000Z`. +- [DECISION] Source version: `5.5.0`. +- [DECISION] Source hash `package.json`: `sha256:3cdde60011cd4891c7c6109bec611176d56d6d6c1c92d3bcc28d5bba9e810f5b`. - [DECISION] Source hash `.godpowers/prd/PRD.mdx`: `sha256:239990ed2eb267c26d3de744bf318d6260bfd67463fec8e7ccccbc348fc1712c`. - [DECISION] Source hash `.godpowers/arch/ARCH.mdx`: `sha256:ec90f0ec06d07fbc67c3b5ac22f3ae882a10d714ef230316f75823709e44642b`. - [DECISION] Source hash `.godpowers/stack/DECISION.mdx`: `sha256:cc9e9227262d9d472fa7806fbafc9a83b8e621728c3652fae1a423a867989ce3`. diff --git a/agents/release.md b/agents/release.md new file mode 100644 index 0000000..aa7a4e7 --- /dev/null +++ b/agents/release.md @@ -0,0 +1,48 @@ +--- +pillar: release +status: present +always_load: false +covers: [versioning, release preparation, publication, changelog policy] +triggers: [release, version, changelog, publish, semver] +must_read_with: [repo, quality, deploy] +see_also: [security] +--- + +## Scope + +- [DECISION] This pillar owns Godpowers version decisions, release readiness, artifacts, and publication truth. + +## Context + +- [DECISION] The root `godpowers` package and `@godpowers/mcp` workspace publish the same semantic version. +- [DECISION] GitHub releases attach both npm tarballs and a `SHA256SUMS` file. +- [DECISION] Tag-triggered GitHub Actions publish both npm packages with provenance. + +## Decisions + +- [DECISION] Backward-compatible routing, validation, and workflow capability additions use a minor release. +- [DECISION] A release is complete only after GitHub, npm, package integrity, and isolated installed behavior agree. + +## Rules + +- [DECISION] `README.md`, `CHANGELOG.md`, `RELEASE.md`, package metadata, lockfile metadata, project Pillars, and generated release evidence must identify the same version. +- [DECISION] Never publish from an unmerged task branch or a commit that has not passed `npm run release:check`. + +## Workflows + +1. [DECISION] Prepare version metadata and release notes on a release branch. +2. [DECISION] Pass local and pull-request release gates. +3. [DECISION] Merge, tag the merge commit, create checksummed assets, and let the provenance workflow publish npm packages. +4. [DECISION] Verify registry integrity and isolated installation before cleanup. + +## Watchouts + +- [HYPOTHESIS] Ambient globally installed binaries can contaminate published-package verification unless the exact tarball is installed into an isolated prefix. + +## Touchpoints + +- [DECISION] Release work touches `package.json`, `packages/mcp/package.json`, `package-lock.json`, `.github/workflows/`, `scripts/release.sh`, and public release documentation. + +## Gaps + +(none) diff --git a/agents/repo.md b/agents/repo.md index b33374c..0ef43d1 100644 --- a/agents/repo.md +++ b/agents/repo.md @@ -1,6 +1,6 @@ --- pillar: repo -status: active +status: present always_load: true covers: [repository layout, package scripts, test commands, release files] triggers: [repo, package, scripts, tests, release, installer, workflow] @@ -12,7 +12,9 @@ see_also: [quality, deploy, security] - [DECISION] This pillar captures repository structure and command conventions for Godpowers. -## Layout +## Context + +### Layout - [DECISION] `SKILL.md` is the main installed skill entry point. - [DECISION] `skills/` contains one slash-command skill markdown file per command. @@ -26,7 +28,7 @@ see_also: [quality, deploy, security] - [DECISION] `templates/` and `references/` contain artifact scaffolds and have-nots guidance. - [DECISION] `fixtures/dogfood/` contains deterministic messy-repo scenarios for release and autonomy readiness. -## Commands +### Commands - [DECISION] Use `npm test` for the full local suite. - [DECISION] Use `npm run test:audit` for audit, whitespace, and documentation surface checks. @@ -34,22 +36,43 @@ see_also: [quality, deploy, security] - [DECISION] Use `npm run pack:check` to verify npm package contents before release. - [DECISION] Use `npm run release:check` for the complete release gate. +## Decisions + +(none) + ## Rules - [DECISION] Do not add production dependencies unless the installer or runtime need them. - [DECISION] Keep the public operation model slash-command based. - [DECISION] Treat `bin/install.js` as the install and distribution surface, with only narrow operational helpers for status, next route, automation status, dogfood, and extension scaffolding. +## Workflows + +(none) + ## Watchouts - [HYPOTHESIS] Package contents can regress when files are added outside the `files` allowlist in `package.json`. - [HYPOTHESIS] Routing drift can regress direct command gates because `lib/router.js` loads `routing/*.yaml` at runtime. +## Touchpoints + +- [DECISION] README, reference docs, package metadata, and repository-surface checks are synchronized through the managed source section below. + +## Gaps + +(none) + -## Godpowers artifact sources +### Godpowers artifact sources -- Sync mode: proposed for review. +- Sync mode: auto-applied by yolo. - Related artifact: `README.md`. - Related artifact: `docs/reference.md`. - Rule: keep this pillar aligned when these artifacts change durable repo truth. + +### Extracted durable signals + +From `docs/reference.md`: +- [DECISION] Phase 5 uses [Surface Contraction Evidence](surface-contraction.md) to map proof-campaign command usage after installer defaults changed. diff --git a/agents/security.md b/agents/security.md index 1e2f948..46504ea 100644 --- a/agents/security.md +++ b/agents/security.md @@ -1,6 +1,6 @@ --- pillar: security -status: active +status: present always_load: false covers: [security review, dependency audit, command execution, release gates] triggers: [security, harden, audit, exec, shell, dependency, vulnerability] @@ -12,6 +12,14 @@ see_also: [deploy] - [DECISION] This pillar captures security boundaries for Godpowers runtime and release work. +## Context + +- [DECISION] Installer, bridge, shell-execution, dependency, and publication surfaces receive adversarial review before release. + +## Decisions + +(none) + ## Rules - [DECISION] Treat shell execution helpers and install target paths as security-sensitive code. @@ -20,25 +28,27 @@ see_also: [deploy] - [DECISION] Treat unresolved Critical harden findings as launch blockers. - [DECISION] `hooks/pre-tool-use.sh` blocks destructive state deletion, hard reset, force push, npm publish, and GitHub release creation until the user confirms the release gate context. +## Workflows + +(none) + ## Watchouts - [HYPOTHESIS] Installer and bridge code are the highest-risk surfaces because they write runtime files into multiple AI tool directories. - [HYPOTHESIS] Public publish actions are security-sensitive because a bad package or release note becomes externally visible immediately. +## Touchpoints + +- [DECISION] Security context synchronizes from hardening evidence through the managed section below. + +## Gaps + +(none) + -## Godpowers artifact sources +### Godpowers artifact sources - Sync mode: auto-applied by yolo. -- Related artifact: `.godpowers/harden/FINDINGS.mdx`. +- Related artifact: `SECURITY.md`. - Rule: keep this pillar aligned when these artifacts change durable security truth. - -## Extracted durable signals - -From `.godpowers/harden/FINDINGS.mdx`: -- [DECISION] Date: 2026-07-13. -- [DECISION] Reviewer: autonomous product trust hardening run. -- [DECISION] Scope: installer, host capability detection, Quick Proof, state reconciliation, release checks, package contents, and production dependencies. -- [DECISION] Launch gate: PASSED. -- [DECISION] No unresolved security finding remains in the reviewed scope. -- [HYPOTHESIS] External connector writes and publish credentials remain last-mile provider risks controlled by authenticated tooling and explicit user authority. diff --git a/agents/stack.md b/agents/stack.md index cb0274e..733da0d 100644 --- a/agents/stack.md +++ b/agents/stack.md @@ -1,6 +1,6 @@ --- pillar: stack -status: active +status: present always_load: false covers: [runtime stack, package manager, dependencies, tooling] triggers: [stack, node, npm, package, dependency, runtime] @@ -12,25 +12,47 @@ see_also: [quality, deploy] - [DECISION] This pillar captures technology choices for Godpowers. -## Stack +## Context + +### Stack - [DECISION] Godpowers uses Node.js with CommonJS runtime modules. - [DECISION] Godpowers uses npm as package manager and package distribution mechanism. - [DECISION] Runtime helpers intentionally avoid production dependencies. - [DECISION] GitHub Actions is the CI and publish automation surface. +## Decisions + +(none) + +## Rules + +(none) + +## Workflows + +(none) + ## Watchouts - [HYPOTHESIS] Adding a YAML dependency would simplify parsing but would increase package footprint and installation risk. +## Touchpoints + +- [DECISION] Stack decisions synchronize from `.godpowers/stack/DECISION.mdx` through the managed section below. + +## Gaps + +(none) + -## Godpowers artifact sources +### Godpowers artifact sources - Sync mode: auto-applied by yolo. - Related artifact: `.godpowers/stack/DECISION.mdx`. - Rule: keep this pillar aligned when these artifacts change durable stack truth. -## Extracted durable signals +### Extracted durable signals From `.godpowers/stack/DECISION.mdx`: - [DECISION] Candidates evaluated: Node.js CommonJS, Node.js ESM, and a compiled binary. diff --git a/docs/FUSION-ARCHITECTURE.md b/docs/FUSION-ARCHITECTURE.md index cb23d02..f6930ec 100644 --- a/docs/FUSION-ARCHITECTURE.md +++ b/docs/FUSION-ARCHITECTURE.md @@ -57,7 +57,7 @@ building toward. - **Verification today** is a mix: build tier genuinely enforces evidence via the gate; other tiers rest on artifact-existence + have-nots lint + reviewer-agent PROSE verdicts (`god-spec-reviewer`, `god-quality-reviewer`) returned to the - orchestrator. TDD is prompt-attested (`agents/god-executor.md:42-99`), not + orchestrator. TDD is prompt-attested (`specialists/god-executor.md:42-99`), not mechanically proven. ### Mythify (v3.6.2) diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 74d44a7..0207c8a 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -3,7 +3,7 @@ > Status: ACTIVE > Model: Pure-skill for durable work. CLI provides install plus read-only status helpers. > Last updated: 2026-07-13 -> Current source: v5.4.0. Latest published: v5.4.0. +> Current source: v5.5.0. Latest published: v5.4.0. This roadmap tracks releases, what's shipped, and what is frozen during the 3.x public adoption window. Everything user-facing remains slash-command based. @@ -45,6 +45,12 @@ quarterback, work report, reflections, memory, lessons, outcome loops, MCP read tools, and ledger importer) shipped across 3.1.0-3.11.0. What works today: +- **Arc-Ready 1.1 leverage**: six product forms, four-axis domain composition, + OWASP 2025 routing, hash-bound pre-publication checks, read-only tier-artifact + import, and managed `.arc-ready/GODPOWERS-SYNC.md` sync-back. +- **Pillars 1.1 conformance**: path identities, portable matching, nested + scopes, cataloged absences, exclusions, dependency and budget validation, + specialist-source separation, and all official routing fixtures. - **Godplans 1.1 interoperability**: PLAN plus pinned executable validator contract detection, non-executing structural preflight, lifecycle-safe GP routing, exact pre-execution validator gate, complete GP/R seed traceability, @@ -265,7 +271,8 @@ What works today: - **Bidirectional linkage map** with 7 stable ID types - **Reverse-sync** writing fenced "Implementation Linkage" footers - **Native Pillars project context**: `AGENTS.md` plus routed - `agents/*.md` pillar files created for every Godpowers project + `agents/*.md` pillar files created for every Godpowers project, with + Pillars 1.1 catalogs, nested scopes, portable matching, and sub-pillars - **Domain precision layer**: `.godpowers/domain/GLOSSARY.mdx` plus DG-01 through DG-05 linter checks for canonical terms, aliases, ambiguity, and relationships - **Existing-project Pillar-ization**: current `.godpowers` artifacts become diff --git a/docs/agent-specs.md b/docs/agent-specs.md index ab2dd38..16c62cd 100644 --- a/docs/agent-specs.md +++ b/docs/agent-specs.md @@ -706,7 +706,7 @@ added during the production-ready + design + linkage push. | Field | Value | |---|---| -| **File** | `agents/god-designer.md` | +| **File** | `specialists/god-designer.md` | | **Triggers** | `/god-design`, `/god-design teach`, `/god-design from `, `/god-design suggest`, `/god-design refresh`, `/god-design polish [...]`, `/god-mode` Tier 1 (when UI detected) | | **Inputs** | PRD.md (target users, register), ARCH.md (UI surface), STACK/DECISION.md (UI framework), state.json | | **Outputs** | `DESIGN.md` (project root, Google Labs spec), `PRODUCT.md` (when impeccable installed), `.godpowers/state.json` design evidence, generated `.godpowers/design/STATE.mdx` | @@ -719,7 +719,7 @@ added during the production-ready + design + linkage push. | Field | Value | |---|---| -| **File** | `agents/god-design-reviewer.md` | +| **File** | `specialists/god-design-reviewer.md` | | **Triggers** | Spawned by god-design-updater BEFORE impact analysis; spawned by god-orchestrator on mid-arc DESIGN/PRODUCT change detection | | **Inputs** | DESIGN.md diff (old vs new), PRODUCT.md (for register, brand, anti-references) | | **Outputs** | Verdict: PASS / WARN / BLOCK; appends to `.godpowers/design/REJECTED.mdx` on BLOCK | @@ -745,7 +745,7 @@ added during the production-ready + design + linkage push. | Field | Value | |---|---| -| **File** | `agents/god-browser-tester.md` | +| **File** | `specialists/god-browser-tester.md` | | **Triggers** | `/god-test-runtime`, `/god-build` (post-wave, optional), `/god-launch` (mandatory gate), `/god-harden` (a11y portion), `/god-design` (post-change runtime audit) | | **Inputs** | URL (live dev server, deploy preview, or production); DESIGN.md (for design audit); PRD.md (for acceptance criteria); project root | | **Outputs** | `.godpowers/runtime//audit-report.json` (design verification), `test-report.json` (functional verification), `screenshots/.png`, `summary.md` | @@ -758,7 +758,7 @@ added during the production-ready + design + linkage push. | Field | Value | |---|---| -| **File** | `agents/god-context-writer.md` | +| **File** | `specialists/god-context-writer.md` | | **Triggers** | `/god-context on/off/status`, `/god-init` (automatic quiet write), generic init triggers (one-time consent prompt, then quiet write), `/god-sync` (quiet auto-refresh unless never-ask) | | **Inputs** | state.json (project name, mode, scale, linkage state), DESIGN.md and PRODUCT.md presence, detected AI tools | | **Outputs** | Fenced sections in AGENTS.md (canonical), CLAUDE.md, GEMINI.md, .cursor/rules/godpowers.mdc, .windsurfrules, .github/copilot-instructions.md, .clinerules, .roo/, .continue/ (only when their tool is detected) | @@ -778,7 +778,7 @@ greenfieldification, and host-automation agents added after v0.11. | Field | Value | |---|---| -| **File** | `agents/god-coordinator.md` | +| **File** | `specialists/god-coordinator.md` | | **Triggers** | `/god-suite-init`, `/god-suite-status`, `/god-suite-sync`, `/god-suite-release`, `/god-suite-patch` | | **Inputs** | Suite manifest (`.godpowers/suite-config.yaml` at the hub), per-repo `state.json` files, suite operation request, optional `.godpowers/runs//COORDINATOR-HANDOFF.mdx` | | **Outputs** | Suite coordination state (`lib/suite-state.refreshFromRepos`), per-repo orchestrator handoff files, suite release or sync report | @@ -791,7 +791,7 @@ greenfieldification, and host-automation agents added after v0.11. | Field | Value | |---|---| -| **File** | `agents/god-storyteller.md` | +| **File** | `specialists/god-storyteller.md` | | **Triggers** | `/god-story`, `/god-feature --with-stories` | | **Inputs** | User story prompt or feature decomposition; PRD.md and ARCH.md for context; optional existing STORY-*.md files to chain into (deps) | | **Outputs** | `.godpowers/stories//STORY-.mdx` (user story, acceptance criteria, initial slice plan) | @@ -804,7 +804,7 @@ greenfieldification, and host-automation agents added after v0.11. | Field | Value | |---|---| -| **File** | `agents/god-greenfieldifier.md` | +| **File** | `specialists/god-greenfieldifier.md` | | **Triggers** | brownfield-arc and bluefield-arc workflows, god-orchestrator, `/god-migrate` (conditional spawn for low-confidence or conflicting imports) | | **Inputs** | `.godpowers/audit/GREENFIELD-SIMULATION.mdx`, `.godpowers/prep/INITIAL-FINDINGS.mdx` and `IMPORTED-CONTEXT.mdx` (when present), existing canonical artifacts, `.godpowers/state.json` | | **Outputs** | `.godpowers/audit/GREENFIELDIFY-PLAN.mdx` (written before any artifact edit), approved canonical artifact updates | @@ -817,7 +817,7 @@ greenfieldification, and host-automation agents added after v0.11. | Field | Value | |---|---| -| **File** | `agents/god-automation-engineer.md` | +| **File** | `specialists/god-automation-engineer.md` | | **Triggers** | `/god-automation-setup` (after the user approves provider, template ids, cadence, and scope) | | **Inputs** | Approved automation setup plan, host provider choice, `.godpowers/state.json`, existing `.godpowers/automations.json` | | **Outputs** | `.godpowers/automations.json` (successful automations only), host-native automation configuration | diff --git a/docs/design-md.md b/docs/design-md.md index 346bc24..066f2ff 100644 --- a/docs/design-md.md +++ b/docs/design-md.md @@ -206,7 +206,7 @@ Duplicates error. - `lib/design-spec.js` - parser + linter - `lib/awesome-design.js` - catalog - `lib/skillui-bridge.js` - SkillUI fallback -- `agents/god-designer.md` - lifecycle owner -- `agents/god-design-reviewer.md` - two-stage review gate +- `specialists/god-designer.md` - lifecycle owner +- `specialists/god-design-reviewer.md` - two-stage review gate - `references/design/DESIGN-ANATOMY.md` - what good DESIGN.md looks like - `references/design/DESIGN-ANTIPATTERNS.md` - what to avoid diff --git a/docs/phase-4-state-read-inventory.md b/docs/phase-4-state-read-inventory.md index 5775ec3..f945858 100644 --- a/docs/phase-4-state-read-inventory.md +++ b/docs/phase-4-state-read-inventory.md @@ -23,9 +23,9 @@ | Root progress ledger writer instructions | [DECISION] decision-read | `SKILL.md:440`, `SKILL.md:504`, `SKILL.md:539`, `SKILL.md:572`, `SKILL.md:595`, `SKILL.md:616`, `SKILL.md:640`, `skills/god-build.md:81`, `skills/god-deploy.md:32`, `skills/god-observe.md:31`, `skills/god-launch.md:32`, `skills/god-harden.md:26`, `skills/god-harden.md:27`, `skills/god-skip.md:35`, `skills/god-rollback.md:41` | [DECISION] Completed: direct writer instructions now use `godpowers state advance --step= --status= --project=.` or an owning command wrapper that regenerates the view. | | Design state gate | [DECISION] decision-read | `lib/artifact-map.js:12`, `lib/gate.js:52`, `skills/god-design.md:99`, `routing/god-design.yaml:40`, `scripts/test-gate.js:52` | [DECISION] Completed: design gate authority now requires `.godpowers/state.json` and `tier-1.design` complete status, while `.godpowers/design/STATE.mdx` is no longer a required gate artifact. | | Build state gate and verification evidence | [DECISION] decision-read | `lib/artifact-map.js:27`, `lib/gate.js:52`, `lib/gate.js:172`, `lib/gate.js:175`, `skills/god-build.md:64`, `skills/god-build.md:79`, `skills/god-deploy.md:16`, `skills/god-harden.md:16`, `scripts/test-gate.js:125`, `scripts/test-gate.js:138`, `scripts/test-gate.js:195` | [DECISION] Completed: build gate authority now reads `.godpowers/state.json` `tier-2.build.verification.commands` for passed and failed command evidence instead of parsing `.godpowers/build/STATE.mdx`. | -| Deploy state prerequisite and handoff context | [DECISION] decision-read | `skills/god-deploy.md:19`, `skills/god-deploy.md:24`, `skills/god-observe.md:16`, `skills/god-feature.md:60`, `routing/god-deploy.yaml:22`, `routing/god-reconcile.yaml:25`, `agents/god-observability-engineer.md:18`, `agents/god-launch-strategist.md:72` | [DECISION] Completed: deploy prerequisites, route handoffs, feature handoffs, and launch or observability inputs now use structured `.godpowers/state.json` deploy evidence, while `.godpowers/deploy/STATE.mdx` remains a generated view. | -| Observe state prerequisite and handoff context | [DECISION] decision-read | `skills/god-observe.md:18`, `skills/god-observe.md:23`, `routing/god-observe.yaml:22`, `routing/god-reconcile.yaml:26`, `agents/god-launch-strategist.md:74` | [DECISION] Completed: observe prerequisites and handoffs now use structured `.godpowers/state.json` observability evidence, while `.godpowers/observe/STATE.mdx` remains a generated view. | -| Launch state completion and reconciliation context | [DECISION] decision-read | `skills/god-launch.md:20`, `skills/god-launch.md:25`, `routing/god-launch.yaml:25`, `routing/god-reconcile.yaml:28`, `agents/god-reconciler.md:102` | [DECISION] Completed: launch completion and reconciliation context now use structured `.godpowers/state.json` launch evidence, while `.godpowers/launch/STATE.mdx` remains a generated view. | +| Deploy state prerequisite and handoff context | [DECISION] decision-read | `skills/god-deploy.md:19`, `skills/god-deploy.md:24`, `skills/god-observe.md:16`, `skills/god-feature.md:60`, `routing/god-deploy.yaml:22`, `routing/god-reconcile.yaml:25`, `specialists/god-observability-engineer.md:18`, `specialists/god-launch-strategist.md:72` | [DECISION] Completed: deploy prerequisites, route handoffs, feature handoffs, and launch or observability inputs now use structured `.godpowers/state.json` deploy evidence, while `.godpowers/deploy/STATE.mdx` remains a generated view. | +| Observe state prerequisite and handoff context | [DECISION] decision-read | `skills/god-observe.md:18`, `skills/god-observe.md:23`, `routing/god-observe.yaml:22`, `routing/god-reconcile.yaml:26`, `specialists/god-launch-strategist.md:74` | [DECISION] Completed: observe prerequisites and handoffs now use structured `.godpowers/state.json` observability evidence, while `.godpowers/observe/STATE.mdx` remains a generated view. | +| Launch state completion and reconciliation context | [DECISION] decision-read | `skills/god-launch.md:20`, `skills/god-launch.md:25`, `routing/god-launch.yaml:25`, `routing/god-reconcile.yaml:28`, `specialists/god-reconciler.md:102` | [DECISION] Completed: launch completion and reconciliation context now use structured `.godpowers/state.json` launch evidence, while `.godpowers/launch/STATE.mdx` remains a generated view. | | Workflow greenfieldification artifact lists | [DECISION] decision-read | `workflows/brownfield-arc.yaml:75`, `workflows/brownfield-arc.yaml:76`, `workflows/brownfield-arc.yaml:77`, `workflows/brownfield-arc.yaml:78`, `workflows/bluefield-arc.yaml:59`, `workflows/bluefield-arc.yaml:60`, `workflows/bluefield-arc.yaml:61`, `workflows/bluefield-arc.yaml:62`, `lib/workflow-runner.js:140` | [DECISION] Completed: brownfield and bluefield greenfieldifier workflow inputs now pass `.godpowers/state.json` plus canonical artifacts instead of generated per-tier state views. | | Pillars artifact sync | [DECISION] migration-read | `lib/pillars.js:99`, `lib/pillars.js:100`, `lib/pillars.js:112`, `lib/pillars.js:113`, `lib/pillars.js:451`, `lib/pillars.js:457`, `lib/pillars.js:594`, `lib/pillars.js:628` | [DECISION] Completed: Pillars artifact discovery now maps `.godpowers/state.json` to durable context, deploy, and observe concerns instead of reading generated deploy or observe state views. | | Source-system sync-back summary | [DECISION] display-read | `lib/source-sync.js:88`, `lib/source-sync.js:99`, `lib/source-sync.js:134` | [DECISION] Completed: source-system sync-back now summarizes `.godpowers/state.json` instead of `.godpowers/build/STATE.mdx`. | @@ -35,7 +35,7 @@ | Quick-proof and doc drift tests | [DECISION] display-read | `scripts/test-quick-proof.js:256`, `docs/quick-proof.md:112`, `README.md:214`, `README.md:481`, `docs/concepts.md:66`, `docs/command-flows.md:64`, `docs/command-flows.md:298`, `docs/command-flows.md:491` | [DECISION] Completed: proof, concept, reference, command-flow, and README examples now show `state.json` as authority and `PROGRESS.mdx` as a generated view. | | Legacy planning pointer preservation | [DECISION] legacy-source-read | `lib/source-sync.js:21`, `scripts/test-planning-systems.js:112`, `scripts/test-planning-systems.js:126` | [DECISION] Preserve `.planning/STATE.md` as a source-system pointer target and document it as an allowed static-check exception. | | Historical and reference docs | [DECISION] display-read | `ARCHITECTURE.md:973`, `ARCHITECTURE.md:977`, `ARCHITECTURE.md:980`, `ARCHITECTURE.md:1065`, `docs/RFC/0001-state-model-v1.md:81`, `docs/RFC/0001-state-model-v1.md:84`, `docs/agent-specs.md:38`, `docs/agent-specs.md:193`, `docs/agent-specs.md:205`, `docs/agent-specs.md:217`, `docs/agent-specs.md:281`, `docs/greenfield-coverage.md:31`, `docs/greenfield-coverage.md:40`, `docs/greenfield-coverage.md:41`, `docs/greenfield-coverage.md:42`, `docs/greenfield-coverage.md:44`, `docs/reference.md:347`, `docs/reference.md:365`, `docs/reference.md:366`, `docs/reference.md:367`, `docs/reference.md:368` | [DECISION] Update durable reference docs in the same release as the state migration, but preserve historical case-study facts unless they describe current behavior. | -| Specialist agent contracts found during defensive scan | [DECISION] decision-read | `agents/god-deploy-engineer.md:17`, `agents/god-observability-engineer.md:18`, `agents/god-greenfieldifier.md:32`, `agents/god-greenfieldifier.md:33`, `agents/god-greenfieldifier.md:34`, `agents/god-greenfieldifier.md:35`, `agents/god-launch-strategist.md:72`, `agents/god-launch-strategist.md:74`, `agents/god-reconciler.md:85`, `agents/god-reconciler.md:90`, `agents/god-reconciler.md:102` | [DECISION] Include specialist agent contract edits in the runtime migration even though the original Phase 4 inventory sentence named skills rather than agents. | +| Specialist agent contracts found during defensive scan | [DECISION] decision-read | `specialists/god-deploy-engineer.md:17`, `specialists/god-observability-engineer.md:18`, `specialists/god-greenfieldifier.md:32`, `specialists/god-greenfieldifier.md:33`, `specialists/god-greenfieldifier.md:34`, `specialists/god-greenfieldifier.md:35`, `specialists/god-launch-strategist.md:72`, `specialists/god-launch-strategist.md:74`, `specialists/god-reconciler.md:85`, `specialists/god-reconciler.md:90`, `specialists/god-reconciler.md:102` | [DECISION] Include specialist agent contract edits in the runtime migration even though the original Phase 4 inventory sentence named skills rather than agents. | ## State Schema Gaps diff --git a/docs/planning-system-migration.md b/docs/planning-system-migration.md index b13f40d..4c6e66f 100644 --- a/docs/planning-system-migration.md +++ b/docs/planning-system-migration.md @@ -16,8 +16,8 @@ Two kinds of prior planning are supported: `.godaudits/AUDIT.json` plus generated `.godaudits/AUDIT.mdx`, with `A--n` checks, `F--n` findings, compiled score and coverage, and typed `GA-` remediation tasks. -2. **Foreign planning systems** (evidence-based import): legacy planning, BMAD, - and Superpowers. +2. **Adjacent and foreign systems** (evidence-based import): Arc-Ready, legacy + planning, BMAD, and Superpowers. ## Why the siblings are different @@ -59,6 +59,7 @@ recomputes counts only for legacy MDX, and never writes to sibling files. | legacy planning | `.planning/`, `.legacy-planning/`, `LEGACY-PLANNING.md`, `legacy-planning*.md` | `PROJECT.md`, `REQUIREMENTS.md`, `ROADMAP.md`, `STATE.md`, phase files | evidence-based | | BMAD | `_bmad/`, `_bmad-output/`, `.bmad-core/`, `.bmad/`, `BMAD.md` | `PRD.md`, `architecture.md`, epics, stories, `sprint-status.yaml`, `project-context.md` | evidence-based | | Superpowers | `docs/superpowers/`, `.superpowers/`, `SUPERPOWERS.md`, project-local skills | specs, plans, TDD and review skill files | evidence-based | +| Arc-Ready | `.arc-ready/PROGRESS.md`, `.prd-ready/PRD.md`, `.architecture-ready/ARCH.md`, and other `.*-ready/` artifacts | stable per-tier artifact files, including prepublication and hardening evidence | high when a canonical marker exists | Detection is evidence-based for the foreign systems: marker folders raise confidence, but Godpowers also reads likely planning files and classifies them @@ -73,6 +74,7 @@ separately enforces the two-artifact and lifecycle gates. |---|---|---| | `.godplans/PLAN.mdx` plus validator | `/god-migrate` | verify contract identity and structure, then import complete GP/R traceability as tier seeds | | `.godaudits/AUDIT.json` | `/god-migrate` then `/god-audit` | consume validated prior audit state instead of re-deriving it | +| `.arc-ready/PROGRESS.md` plus tier artifacts | `/god-migrate` | import matching PRD, architecture, roadmap, stack, build-state, and harden seeds without modifying Arc-Ready canon | | an open finding | `/god-fix GA-` | dispatch the remediation task with its evidence and `Verify` command as the done-check | | an empty repo plus a complete approved PLAN contract | `/god-mode` | import tier seeds, run the plan validator, then execute in wave order | @@ -126,11 +128,12 @@ Sync-back writes a managed companion file per system: - legacy planning: `.planning/GODPOWERS-SYNC.md` or `.legacy-planning/GODPOWERS-SYNC.md` - BMAD: `_bmad-output/GODPOWERS-SYNC.md` or `.bmad/GODPOWERS-SYNC.md` - Superpowers: `docs/superpowers/GODPOWERS-SYNC.md` or `.superpowers/GODPOWERS-SYNC.md` +- Arc-Ready: `.arc-ready/GODPOWERS-SYNC.md` Companions in the sibling `.godplans/`/`.godaudits/` directories are `.mdx` (the sibling family convention); companions in foreign directories stay `.md`. The -`PLAN.mdx`, `validate-plan.sh`, `AUDIT.json`, and `AUDIT.mdx` are never -modified by sync-back. +`PLAN.mdx`, `validate-plan.sh`, `AUDIT.json`, `AUDIT.mdx`, and Arc-Ready +canonical artifacts are never modified by sync-back. ## Read-Only Boundary And Untrusted Commands diff --git a/docs/reference.md b/docs/reference.md index eb2540c..dabe464 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1,6 +1,6 @@ # Godpowers Reference -Complete command, agent, and artifact reference for v5.4.0. +Complete command, agent, and artifact reference for v5.5.0. ## Slash commands (122 total) @@ -93,7 +93,7 @@ recommendation signals. Longer runs use `/god-metrics`, `/god-trace`, and - `/god-automation-status` - Show host automation provider support. - `/god-automation-setup` - Prepare opt-in automation setup. - `/god-surface` - Preview or apply a runtime command surface profile after install. -- `/god-migrate` - Detect legacy planning, BMAD, Superpowers, godplans, and godaudits context, import seeds, and sync back progress. +- `/god-migrate` - Detect legacy planning, BMAD, Superpowers, Arc-Ready, godplans, and godaudits context, import seeds, and sync back progress. ### Installer CLI helpers - `godpowers status --project .` - Render the shared dashboard from disk state. @@ -208,7 +208,7 @@ diff churn that cannot be traced to the request or slice plan. - `/god-review-changes` - Walk REVIEW-REQUIRED.mdx interactively. - `/god-reconcile` - Comprehensive reconciliation across all impacted artifacts. - `/god-reconstruct` - Reverse-engineer planning artifacts from existing code. -- `/god-migrate` - Convert adjacent planning-system context (including the Godplans 1.1 PLAN plus pinned validator contract and canonical `.godaudits/AUDIT.json`) into Godpowers prep and seed artifacts, with lifecycle-safe GP routing and open GA tasks synchronized to managed todos. +- `/god-migrate` - Convert adjacent planning-system context (including Arc-Ready artifacts, the Godplans 1.1 PLAN plus pinned validator contract, and canonical `.godaudits/AUDIT.json`) into Godpowers prep and seed artifacts, with lifecycle-safe GP routing and open GA tasks synchronized to managed todos. ### Verification - `/god-lint` - Mechanical validation against have-nots catalog. @@ -357,11 +357,14 @@ First-party packs on npm: ## Native Pillars context Every Godpowers project is also a Pillars project. Commands load -`agents/context.md` and `agents/repo.md` first, then route task-specific -pillar files by frontmatter triggers, `must_read_with`, and `see_also`. +`agents/context.md` and `agents/repo.md` in every applicable scope, then route +task-specific pillar files with the Pillars 1.1 portable matcher. Primaries add +direct `must_read_with` dependencies at depth 1. `see_also` targets load only +when their own identity, triggers, or covers match the task. ``` AGENTS.md Pillars loading protocol plus Godpowers managed fence +agents/catalog.yaml Optional local inventory of known absent concerns agents/context.md Always-loaded project identity and invariants agents/repo.md Always-loaded repository layout and naming agents/stack.md Technology choices and version constraints @@ -373,8 +376,13 @@ agents/auth.md Identity, sessions, roles, and access control agents/quality.md Testing, errors, style, and naming agents/deploy.md Environments, promotion, rollback, and release process agents/observe.md Logs, metrics, tracing, alerts, and runbooks +agents//*.md Path-qualified sub-pillars such as auth/registration ``` +Nested scopes contain both `AGENTS.md` and `agents/`. Godpowers loads outer +scopes first, applies the nearest scope last, and respects local exclusions. +The repository release gate executes the official Pillars routing fixtures. + Existing `.godpowers` projects are Pillar-ized on resume and sync. Current Godpowers artifacts become managed source references in the relevant pillar files, with labeled decisions, hypotheses, and open questions extracted when diff --git a/docs/repo-doc-sync.md b/docs/repo-doc-sync.md index f4a4bd4..75fd8cf 100644 --- a/docs/repo-doc-sync.md +++ b/docs/repo-doc-sync.md @@ -27,7 +27,7 @@ - [DECISION] Repo documentation sync is an arc closeout concern because public docs, release notes, contribution rules, and badges are part of shipping readiness. - [DECISION] A greenfield, brownfield, bluefield, or migration arc is not complete until `/god-sync` has checked repo documentation drift. -- [DECISION] Imported legacy planning, BMAD, and Superpowers projects keep their source-system sync-back path, while repo documentation sync keeps the Godpowers-facing repository surface current. +- [DECISION] Imported legacy planning, BMAD, Superpowers, and Arc-Ready projects keep their source-system sync-back path, while repo documentation sync keeps the Godpowers-facing repository surface current. - [DECISION] When repo docs change durable project truth, Pillars updates are planned through `lib/pillars.planArtifactSync`. - [DECISION] Under explicit yolo policy, the same changed docs may be applied through `lib/pillars.applyArtifactSync`. diff --git a/docs/repo-surface-sync.md b/docs/repo-surface-sync.md index e901a1e..42d766f 100644 --- a/docs/repo-surface-sync.md +++ b/docs/repo-surface-sync.md @@ -18,7 +18,7 @@ - [DECISION] Routing surface sync checks that every `skills/god-*.md` command has matching `routing/god-*.yaml` metadata. - [DECISION] Package and installer sync checks `package.json.files`, package content checks, package lock version, and required runtime helper files. -- [DECISION] Agent contract sync checks that routed specialist spawns resolve to real `agents/god-*.md` files. +- [DECISION] Agent contract sync checks that routed specialist spawns resolve to real `specialists/god-*.md` source files. - [DECISION] Workflow and recipe graph sync checks parseable workflow metadata and recipe command routes. - [DECISION] Extension pack sync checks manifest validation, package name and version agreement, peer dependency agreement, and provided file existence. - [DECISION] Route quality sync checks atomic spawn tokens, routed agent resolution, typed contextual exits, standards coverage, and agent trace event coverage. diff --git a/fixtures/gate/harden-pass/.godpowers/harden/FINDINGS.mdx b/fixtures/gate/harden-pass/.godpowers/harden/FINDINGS.mdx index 5fc7417..8d55fdd 100644 --- a/fixtures/gate/harden-pass/.godpowers/harden/FINDINGS.mdx +++ b/fixtures/gate/harden-pass/.godpowers/harden/FINDINGS.mdx @@ -12,3 +12,18 @@ | Low | 0 | [DECISION] Launch gate: PASSED. + +## OWASP Web Top 10:2025 Coverage + +| Category | Manual procedure | Result | Evidence or finding | +|---|---|---|---| +| A01:2025 Broken Access Control | Probe authorization and internal-resource access in the fixture boundary | pass | fixture authorization probe | +| A02:2025 Security Misconfiguration | Exercise production configuration defaults and error behavior | pass | fixture configuration probe | +| A03:2025 Software Supply Chain Failures | Verify dependency and artifact identity | pass | npm audit fixture evidence | +| A04:2025 Cryptographic Failures | Verify current hashing and transport policy | pass | fixture cryptography review | +| A05:2025 Injection | Trace fixture input through interpreter boundaries | pass | fixture malformed-input probe | +| A06:2025 Insecure Design | Exercise abuse cases and secure defaults | pass | fixture design probe | +| A07:2025 Authentication Failures | Probe credential and session boundaries | Not Applicable, no authentication surface | fixture scope review | +| A08:2025 Software or Data Integrity Failures | Tamper with fixture data and verify rejection | pass | fixture integrity probe | +| A09:2025 Security Logging and Alerting Failures | Trigger and observe a controlled security event | pass | fixture alert exercise | +| A10:2025 Mishandling of Exceptional Conditions | Inject malformed state and dependency failure | pass | fixture failure-path test | diff --git a/hooks/pre-tool-use.sh b/hooks/pre-tool-use.sh index cf0bd5c..4671646 100755 --- a/hooks/pre-tool-use.sh +++ b/hooks/pre-tool-use.sh @@ -51,13 +51,15 @@ fi if matches 'npm +publish'; then echo "WARNING: npm publish is a public release action." echo "Confirm release checklist, repo-doc-sync, repo-surface-sync," - echo "release-surface-sync, package contents, and installer smoke first." + echo "release-surface-sync, package contents, installer smoke, and" + echo "the fresh hash-bound pre-publication gate first." exit 1 fi if matches 'gh +release +create'; then echo "WARNING: gh release create publishes public release notes." - echo "Confirm README, badges, CHANGELOG, RELEASE, package, tag, and npm version agree." + echo "Confirm README, badges, CHANGELOG, RELEASE, package, tag, npm version," + echo "and the fresh hash-bound pre-publication gate agree." exit 1 fi diff --git a/lib/README.md b/lib/README.md index d9058d0..21d85bf 100644 --- a/lib/README.md +++ b/lib/README.md @@ -98,6 +98,8 @@ package-level integrations. | `extension-authoring.js` | Scaffold publishable extension packs with manifest, package, README, skill, agent, and workflow files. | | `package-legitimacy.js` | Assess third-party package metadata for existence, typo risk, recency, and repository signals. | | `pillars.js` | Manage the Pillars project-context layer (`AGENTS.md` plus routed `agents/*.md`). | +| `product-routing.js` | Select product form before composing archetype, industry, and regulatory guidance. | +| `prepublication-gate.js` | Bind public activation to a fresh hardening hash and Critical-finding check. | | `connectors.js` | Registry, detection, and write-scope policy for external connectors (GitHub, Linear, Slack, Sentry, Notion) that loops act through by delegating to host MCP servers. | ## Repository and graph helpers diff --git a/lib/agent-refs.js b/lib/agent-refs.js index 90c9cd5..bc2217b 100644 --- a/lib/agent-refs.js +++ b/lib/agent-refs.js @@ -90,7 +90,7 @@ function knownGodNames(rootDir) { for (const f of fs.readdirSync(path.join(rootDir, 'skills'))) { if (f.endsWith('.md')) valid.add(f.replace(/\.md$/, '')); } - for (const f of fs.readdirSync(path.join(rootDir, 'agents'))) { + for (const f of fs.readdirSync(path.join(rootDir, 'specialists'))) { if (/^god-.*\.md$/.test(f)) valid.add(f.replace(/\.md$/, '')); } @@ -130,7 +130,7 @@ function findUnresolvedProseRefs(rootDir) { const valid = knownGodNames(rootDir); const unresolved = []; - for (const dir of ['skills', 'agents']) { + for (const dir of ['skills', 'specialists']) { const dirPath = path.join(rootDir, dir); for (const f of fs.readdirSync(dirPath)) { if (!f.endsWith('.md')) continue; diff --git a/lib/agent-validator.js b/lib/agent-validator.js index 4dd1a41..752c8cb 100644 --- a/lib/agent-validator.js +++ b/lib/agent-validator.js @@ -264,14 +264,11 @@ function crossValidate(agents, opts = {}) { } /** - * Walk agents/ and audit all shipped specialist agents. - * - * Godpowers projects may also have Pillars files under agents/ (for example - * agents/context.md and agents/repo.md). Those are project context, not - * specialist agent specs, so they are intentionally excluded here. + * Walk specialists/ and audit all shipped specialist agent source contracts. + * Installed host copies still live under each host's agents/ directory. */ function auditAll(projectRoot, opts = {}) { - const agentsDir = path.join(projectRoot, 'agents'); + const agentsDir = path.join(projectRoot, 'specialists'); if (!fs.existsSync(agentsDir)) { return { results: [], summary: { errors: 0, warnings: 0, infos: 0 } }; } diff --git a/lib/gate.js b/lib/gate.js index c46e6a7..bcb750d 100644 --- a/lib/gate.js +++ b/lib/gate.js @@ -354,6 +354,54 @@ function checkHardenCriticals(projectRoot, result) { )); } +const OWASP_2025_IDS = [ + 'A01:2025', 'A02:2025', 'A03:2025', 'A04:2025', 'A05:2025', + 'A06:2025', 'A07:2025', 'A08:2025', 'A09:2025', 'A10:2025' +]; + +function checkHardenOwasp2025(projectRoot, result) { + const mapped = artifactMap.requiredArtifactsForTier('harden')[0].path; + const relPath = syncFs.resolveArtifact(projectRoot, mapped); + const content = syncFs.readArtifactOrNull(projectRoot, mapped); + if (content === null) return; + + const rows = new Map(); + for (const line of content.split(/\r?\n/)) { + const match = line.match(/^\|\s*(A\d{2}:2025)\b[^|]*\|([^|]*)\|([^|]*)\|([^|]*)\|\s*$/i); + if (!match) continue; + rows.set(match[1].toUpperCase(), match.slice(2).map(value => value.trim())); + } + + const missing = OWASP_2025_IDS.filter(id => !rows.has(id)); + const incomplete = []; + for (const [id, cells] of rows.entries()) { + if (cells.some(value => !value || /^\s*(?:\[[^\]]*\]|todo|tbd|pending)\s*$/i.test(value))) incomplete.push(id); + } + const pass = missing.length === 0 && incomplete.length === 0; + if (!pass) { + const details = [ + missing.length > 0 ? `missing rows: ${missing.join(', ')}` : null, + incomplete.length > 0 ? `placeholder or empty evidence: ${incomplete.join(', ')}` : null + ].filter(Boolean).join('; '); + const finding = makeFinding( + 'harden-owasp-2025-evidence', + 'error', + relPath, + `Harden findings must record manual procedure, result, and evidence for all OWASP Web Top 10:2025 categories (${details}).` + ); + result.findings.push(finding); + addFindingSummary(result.summary, finding.severity); + } + result.checks.push(makeCheck( + 'harden-owasp-2025-evidence', + pass ? 'pass' : 'fail', + relPath, + pass + ? 'All ten OWASP Web Top 10:2025 categories record manual procedure, result, and evidence.' + : 'OWASP Web Top 10:2025 manual evidence is incomplete.' + )); +} + function finalize(result) { result.verdict = result.findings.some((finding) => finding.severity === 'error') ? 'fail' @@ -418,7 +466,10 @@ function check(opts = {}) { if (stepRef && evidence.EXECUTED_REQUIRED_SUBSTEPS.has(stepRef.subStepKey)) { checkExecutedEvidence(result, stateStep, tier); } - if (tier === 'harden') checkHardenCriticals(projectRoot, result); + if (tier === 'harden') { + checkHardenCriticals(projectRoot, result); + checkHardenOwasp2025(projectRoot, result); + } return finalize(result); } diff --git a/lib/installer-core.js b/lib/installer-core.js index 3cd847d..6d0fe87 100644 --- a/lib/installer-core.js +++ b/lib/installer-core.js @@ -150,7 +150,7 @@ function installSkills(srcDir, runtimeKey, runtime, opts = {}) { } function installAgents(srcDir, runtime) { - const agentsSrc = path.join(srcDir, 'agents'); + const agentsSrc = path.join(srcDir, 'specialists'); const agentsDest = path.join(runtime.configDir, 'agents'); if (!fs.existsSync(agentsSrc)) return; @@ -306,7 +306,7 @@ function countProfileSurface(srcDir, opts = {}) { const selected = selectedSkillNames(opts.profile, names); return { skills: selected.size, - agents: fs.readdirSync(path.join(srcDir, 'agents')).filter(f => /^god-.*\.md$/.test(f)).length + agents: fs.readdirSync(path.join(srcDir, 'specialists')).filter(f => /^god-.*\.md$/.test(f)).length }; } diff --git a/lib/installer-files.js b/lib/installer-files.js index 979b48e..46177a6 100644 --- a/lib/installer-files.js +++ b/lib/installer-files.js @@ -65,7 +65,7 @@ function copyRecursive(src, dest, root) { function copyRuntimeBundle(srcDir, destDir) { ensureDir(destDir); - for (const dir of ['bin', 'lib', 'routing', 'workflows', 'schema', 'templates', 'references']) { + for (const dir of ['bin', 'lib', 'routing', 'workflows', 'schema', 'templates', 'references', 'specialists']) { const src = path.join(srcDir, dir); if (fs.existsSync(src)) { copyRecursive(src, path.join(destDir, dir)); diff --git a/lib/pillars.js b/lib/pillars.js index 52d77c0..63d75eb 100644 --- a/lib/pillars.js +++ b/lib/pillars.js @@ -9,6 +9,7 @@ const fs = require('fs'); const path = require('path'); const frontmatterLib = require('./frontmatter'); +const { parseSimpleYaml } = require('./intent'); const syncFs = require('./sync-fs'); const PILLARS_FENCE_BEGIN = ''; @@ -45,9 +46,17 @@ const CORE_PILLARS = { covers: ['testing', 'error handling', 'code style', 'naming'], triggers: ['test', 'testing', 'lint', 'quality', 'error', 'style', 'refactor'] }, + development: { + covers: ['local setup', 'developer workflow', 'debugging', 'generated artifacts'], + triggers: ['develop', 'development', 'local setup', 'bootstrap', 'debug'] + }, + release: { + covers: ['versioning', 'release preparation', 'publication', 'changelog policy'], + triggers: ['release', 'version', 'changelog', 'publish', 'semver'] + }, deploy: { - covers: ['environments', 'promotion', 'rollback', 'release process'], - triggers: ['deploy', 'deployment', 'environment', 'release', 'rollback', 'ci'] + covers: ['environments', 'promotion', 'rollback', 'runtime delivery'], + triggers: ['deploy', 'deployment', 'environment', 'rollback', 'promotion', 'cutover'] }, observe: { covers: ['logging', 'metrics', 'tracing', 'alerts', 'runbooks'], @@ -69,12 +78,72 @@ const ALWAYS_PILLARS = { }; const COMMON_PILLARS = { + config: { + covers: ['configuration', 'environment variables', 'feature flags', 'secrets'], + triggers: ['config', 'configuration', 'environment variable', 'feature flag', 'secret'] + }, security: { covers: ['input validation', 'threat model', 'dependency risk', 'adversarial concerns'], triggers: ['security', 'threat', 'vulnerability', 'owasp', 'cve', 'validation'] + }, + privacy: { + covers: ['personal data', 'consent', 'retention', 'deletion', 'subject rights'], + triggers: ['privacy', 'personal data', 'pii', 'consent', 'retention', 'deletion'] + }, + compliance: { + covers: ['regulatory requirements', 'audit controls', 'control mappings'], + triggers: ['compliance', 'soc2', 'hipaa', 'gdpr', 'pci', 'audit'] + }, + i18n: { + covers: ['translation', 'locale', 'right-to-left layout', 'localization'], + triggers: ['i18n', 'translation', 'locale', 'rtl', 'localization'] + }, + a11y: { + covers: ['accessibility', 'wcag', 'assistive technology'], + triggers: ['a11y', 'accessibility', 'wcag', 'screen reader'] + }, + analytics: { + covers: ['product events', 'user telemetry', 'key metrics'], + triggers: ['analytics', 'product event', 'telemetry', 'kpi'] + }, + integrations: { + covers: ['third-party services', 'outbound contracts', 'webhooks'], + triggers: ['integration', 'third party', 'webhook', 'external api'] + }, + async: { + covers: ['background jobs', 'queues', 'schedules', 'events'], + triggers: ['background job', 'queue', 'scheduler', 'cron', 'async'] + }, + cache: { + covers: ['caching', 'invalidation', 'time to live'], + triggers: ['cache', 'caching', 'invalidation', 'ttl'] + }, + notifications: { + covers: ['transactional email', 'sms', 'push notifications'], + triggers: ['notification', 'transactional email', 'sms', 'push'] } }; +const REQUIRED_SECTIONS = [ + 'Scope', + 'Context', + 'Decisions', + 'Rules', + 'Workflows', + 'Watchouts', + 'Touchpoints', + 'Gaps' +]; + +const PILLAR_BUDGETS = { + alwaysWords: 1000, + alwaysBytes: 8 * 1024, + alwaysScopeWords: 2000, + alwaysScopeBytes: 16 * 1024, + routedWords: 2000, + routedBytes: 16 * 1024 +}; + const KNOWN_PILLARS = { ...ALWAYS_PILLARS, ...CORE_PILLARS, @@ -130,6 +199,37 @@ function stripQuotes(value) { const parseFrontmatter = (raw) => frontmatterLib.parse(raw, { strict: true }); +function normalizeSelector(value) { + return String(value || '') + .replace(/[A-Z]/g, (character) => character.toLowerCase()) + .replace(/[^a-z0-9]+/g, ' ') + .trim(); +} + +function selectorMatches(taskText, selector) { + const taskTokens = normalizeSelector(taskText).split(' ').filter(Boolean); + const selectorTokens = normalizeSelector(selector).split(' ').filter(Boolean); + if (selectorTokens.length === 0 || selectorTokens.length > taskTokens.length) return false; + for (let index = 0; index <= taskTokens.length - selectorTokens.length; index += 1) { + if (selectorTokens.every((token, offset) => taskTokens[index + offset] === token)) return true; + } + return false; +} + +function validIdentity(identity) { + const segment = /^[a-z0-9]+(?:-[a-z0-9]+)*$/; + const parts = String(identity || '').split('/'); + return parts.length >= 1 && parts.length <= 2 && parts.every((part) => segment.test(part)); +} + +function derivedIdentity(filePath, agentsRoot) { + return path.relative(agentsRoot, filePath).split(path.sep).join('/').replace(/\.md$/, ''); +} + +function countWords(value) { + return (String(value || '').match(/[A-Za-z0-9]+(?:['-][A-Za-z0-9]+)*/g) || []).length; +} + function walkMarkdown(dir) { if (!fs.existsSync(dir)) return []; const out = []; @@ -144,13 +244,17 @@ function walkMarkdown(dir) { return out.sort(); } -function parsePillarFile(filePath) { +function parsePillarFile(filePath, agentsRoot = path.dirname(filePath)) { const raw = fs.readFileSync(filePath, 'utf8'); - const frontmatter = parseFrontmatter(raw); + const parsed = frontmatterLib.split(raw, { strict: true, source: filePath, require: true }); + const frontmatter = parsed.frontmatter || {}; if (!frontmatter || !frontmatter.pillar) return null; + const identity = derivedIdentity(filePath, agentsRoot); return { path: filePath, - name: frontmatter.pillar, + name: identity, + identity, + leaf: frontmatter.pillar, status: frontmatter.status || 'present', always_load: frontmatter.always_load === true, covers: Array.isArray(frontmatter.covers) ? frontmatter.covers : [], @@ -158,17 +262,55 @@ function parsePillarFile(filePath) { must_read_with: Array.isArray(frontmatter.must_read_with) ? frontmatter.must_read_with : [], see_also: Array.isArray(frontmatter.see_also) ? frontmatter.see_also : [], frontmatter, - raw + raw, + body: parsed.body, + diagnostics: parsed.diagnostics }; } -function listPillars(projectRoot) { - const agentsDir = path.join(projectRoot, 'agents'); +function listPillars(scopeRoot) { + const agentsDir = path.join(scopeRoot, 'agents'); return walkMarkdown(agentsDir) - .map(file => parsePillarFile(file)) + .map(file => parsePillarFile(file, agentsDir)) .filter(Boolean); } +function isCompleteScope(scopeRoot) { + return fs.existsSync(path.join(scopeRoot, 'AGENTS.md')) && + fs.existsSync(path.join(scopeRoot, 'agents')) && + fs.statSync(path.join(scopeRoot, 'agents')).isDirectory(); +} + +function discoverScopes(projectRoot) { + const root = path.resolve(projectRoot); + const scopes = []; + const skip = new Set(['.git', '.claude', '.codex', 'node_modules', 'coverage', 'dist', 'build', 'vendor']); + function visit(directory) { + if (isCompleteScope(directory)) scopes.push(directory); + for (const entry of fs.readdirSync(directory, { withFileTypes: true })) { + if (!entry.isDirectory() || entry.isSymbolicLink() || skip.has(entry.name)) continue; + visit(path.join(directory, entry.name)); + } + } + visit(root); + return scopes.sort((a, b) => { + const depth = (value) => path.relative(root, value).split(path.sep).filter(Boolean).length; + return depth(a) - depth(b) || a.localeCompare(b); + }); +} + +function applicableScopes(projectRoot, target = '.') { + const root = path.resolve(projectRoot); + const resolved = path.resolve(root, target); + if (resolved !== root && !resolved.startsWith(`${root}${path.sep}`)) { + throw new Error(`Pillars target escapes project root: ${target}`); + } + const directory = fs.existsSync(resolved) && fs.statSync(resolved).isDirectory() + ? resolved + : path.dirname(resolved); + return discoverScopes(root).filter((scope) => scope === directory || directory.startsWith(`${scope}${path.sep}`)); +} + function readAgents(projectRoot) { const file = path.join(projectRoot, 'AGENTS.md'); if (!fs.existsSync(file)) return ''; @@ -184,36 +326,98 @@ function hasPillarsProtocol(projectRoot) { function readExclusions(projectRoot) { const content = readAgents(projectRoot); - const exclusions = new Set(); - const inline = content.match(/excluded:\s*\[([^\]]*)\]/); - if (inline) { - for (const item of inline[1].split(',')) { - const value = stripQuotes(item); - if (value) exclusions.add(value); + const exclusions = new Map(); + const fences = [...content.matchAll(/```ya?ml\s*\n([\s\S]*?)```/g)]; + const source = fences.map((match) => match[1]).find((block) => /(^|\n)excluded\s*:/.test(block)); + if (!source) return exclusions; + const parsed = parseSimpleYaml(source); + const items = Array.isArray(parsed.excluded) ? parsed.excluded : []; + for (const item of items) { + if (typeof item === 'string' && validIdentity(item)) exclusions.set(item, null); + if (item && typeof item === 'object' && validIdentity(item.name)) { + exclusions.set(item.name, typeof item.reason === 'string' ? item.reason : null); } } - const nameMatches = content.matchAll(/^\s*-\s*name:\s*([A-Za-z0-9_-]+)/gm); - for (const match of nameMatches) exclusions.add(match[1]); return exclusions; } +function readCatalog(scopeRoot) { + const file = path.join(scopeRoot, 'agents', 'catalog.yaml'); + if (!fs.existsSync(file)) return { version: 1, entries: new Map(), issues: [] }; + const parsed = parseSimpleYaml(fs.readFileSync(file, 'utf8')); + const issues = []; + const entries = new Map(); + if (parsed.version !== 1) issues.push('agents/catalog.yaml version must be 1'); + const absent = Array.isArray(parsed.absent) ? parsed.absent : []; + if (!Array.isArray(parsed.absent)) issues.push('agents/catalog.yaml absent must be a list'); + for (const entry of absent) { + if (!entry || typeof entry !== 'object' || !validIdentity(entry.identity)) { + issues.push('agents/catalog.yaml contains an invalid identity'); + continue; + } + if (!Array.isArray(entry.triggers) || entry.triggers.length === 0) { + issues.push(`catalog identity ${entry.identity} requires triggers`); + continue; + } + if (entries.has(entry.identity)) { + issues.push(`catalog identity ${entry.identity} is duplicated`); + continue; + } + entries.set(entry.identity, { + identity: entry.identity, + covers: Array.isArray(entry.covers) ? entry.covers : [], + triggers: entry.triggers + }); + } + return { version: parsed.version, entries, issues, path: file }; +} + function validatePillar(projectRoot, pillar) { const issues = []; const rel = path.relative(path.join(projectRoot, 'agents'), pillar.path); const expectedName = path.basename(rel, '.md'); - if (pillar.name !== expectedName) { + if (!validIdentity(pillar.identity)) { + issues.push(`invalid path-derived pillar identity for ${rel}`); + } + if (pillar.leaf !== expectedName) { issues.push(`frontmatter pillar does not match filename for ${rel}`); } + if (!['present', 'stub'].includes(pillar.status)) { + issues.push(`${rel} status must be present or stub`); + } if (!Array.isArray(pillar.covers) || pillar.covers.length === 0) { issues.push(`${rel} missing covers list`); } - if (!pillar.always_load && !Array.isArray(pillar.triggers)) { + if (!pillar.always_load && (!Array.isArray(pillar.triggers) || pillar.triggers.length === 0)) { issues.push(`${rel} missing triggers list`); } + const headings = [...pillar.body.matchAll(/^##\s+(.+?)\s*$/gm)].map((match) => match[1]); + if (headings.join('\n') !== REQUIRED_SECTIONS.join('\n')) { + issues.push(`${rel} must contain the eight Pillars sections in order`); + } + for (const field of ['covers', 'triggers']) { + const values = pillar[field]; + const normalized = new Set(); + for (const value of values) { + const key = normalizeSelector(value); + if (!key) issues.push(`${rel} ${field} contains an empty portable selector`); + if (normalized.has(key)) issues.push(`${rel} ${field} contains duplicate portable selectors`); + normalized.add(key); + } + } + for (const field of ['must_read_with', 'see_also']) { + const seen = new Set(); + for (const reference of pillar[field]) { + if (!validIdentity(reference)) issues.push(`${rel} ${field} contains invalid identity ${reference}`); + if (reference === pillar.identity) issues.push(`${rel} ${field} contains a self-reference`); + if (seen.has(reference)) issues.push(`${rel} ${field} contains duplicate identity ${reference}`); + seen.add(reference); + } + } return issues; } -function detect(projectRoot) { +function detect(projectRoot, opts = {}) { const agentsPath = path.join(projectRoot, 'AGENTS.md'); const agentsDir = path.join(projectRoot, 'agents'); const hasAgents = fs.existsSync(agentsPath); @@ -221,7 +425,10 @@ function detect(projectRoot) { const protocol = hasPillarsProtocol(projectRoot); const pillars = listPillars(projectRoot); const byName = new Map(pillars.map(p => [p.name, p])); + const exclusions = readExclusions(projectRoot); + const catalog = readCatalog(projectRoot); const issues = []; + const warnings = []; if (!hasAgents) issues.push('AGENTS.md missing'); if (!hasAgentsDir) issues.push('agents directory missing'); @@ -229,7 +436,8 @@ function detect(projectRoot) { for (const name of ['context', 'repo']) { if (!byName.has(name)) { - issues.push(`agents/${name}.md missing`); + if (exclusions.has(name)) warnings.push(`floor pillar ${name} is explicitly excluded`); + else issues.push(`agents/${name}.md missing`); } else if (!byName.get(name).always_load) { issues.push(`agents/${name}.md must set always_load: true`); } @@ -237,33 +445,76 @@ function detect(projectRoot) { for (const pillar of pillars) { issues.push(...validatePillar(projectRoot, pillar)); + if (pillar.must_read_with.length > 3) { + warnings.push(`${pillar.identity} must_read_with exceeds the recommended dependency fan-out`); + } } + issues.push(...catalog.issues); + for (const identity of byName.keys()) { + if (exclusions.has(identity)) issues.push(`${identity} is both present and excluded`); + if (catalog.entries.has(identity)) issues.push(`${identity} is both present and cataloged as absent`); + } + for (const identity of exclusions.keys()) { + if (catalog.entries.has(identity)) issues.push(`${identity} is both excluded and cataloged as absent`); + } + for (const pillar of pillars) { + for (const reference of pillar.must_read_with) { + if (!byName.has(reference) && !exclusions.has(reference)) { + issues.push(`${pillar.identity} must_read_with reference ${reference} is unresolved`); + } + } + for (const reference of pillar.see_also) { + if (!byName.has(reference) && !exclusions.has(reference) && !catalog.entries.has(reference)) { + issues.push(`${pillar.identity} see_also reference ${reference} is unresolved`); + } + } + } + + const always = pillars.filter((pillar) => pillar.always_load); + const alwaysWords = always.reduce((sum, pillar) => sum + countWords(pillar.raw), 0); + const alwaysBytes = always.reduce((sum, pillar) => sum + Buffer.byteLength(pillar.raw), 0); + for (const pillar of pillars) { + const words = countWords(pillar.raw); + const bytes = Buffer.byteLength(pillar.raw); + const wordBudget = pillar.always_load ? PILLAR_BUDGETS.alwaysWords : PILLAR_BUDGETS.routedWords; + const byteBudget = pillar.always_load ? PILLAR_BUDGETS.alwaysBytes : PILLAR_BUDGETS.routedBytes; + if (words > wordBudget) warnings.push(`${pillar.identity} exceeds the recommended ${wordBudget}-word budget`); + if (bytes > byteBudget) warnings.push(`${pillar.identity} exceeds the recommended ${byteBudget}-byte budget`); + } + if (alwaysWords > PILLAR_BUDGETS.alwaysScopeWords) warnings.push('always-loaded pillars exceed the scope word budget'); + if (alwaysBytes > PILLAR_BUDGETS.alwaysScopeBytes) warnings.push('always-loaded pillars exceed the scope byte budget'); + const hasAnySignal = hasAgents || hasAgentsDir || pillars.length > 0; - const valid = protocol && byName.has('context') && byName.has('repo') && - byName.get('context').always_load && byName.get('repo').always_load && - issues.filter(issue => issue.includes('frontmatter') || issue.includes('missing') || issue.includes('must set')).length === 0; + const valid = protocol && issues.length === 0 && + (byName.has('context') || exclusions.has('context')) && + (byName.has('repo') || exclusions.has('repo')); - return { + const result = { status: valid ? 'present' : (hasAnySignal ? 'partial' : 'absent'), valid, hasAgents, hasAgentsDir, protocol, pillars, - issues + issues, + warnings, + exclusions: [...exclusions.keys()].sort(), + catalog: [...catalog.entries.values()] }; -} - -function containsTerm(taskText, term) { - const task = taskText.toLowerCase(); - const normalized = String(term).toLowerCase().replace(/[-_]/g, ' '); - return task.includes(normalized) || task.includes(String(term).toLowerCase()); + if (opts.recursive) { + result.scopes = discoverScopes(projectRoot).map((scope) => ({ + root: scope, + detection: scope === path.resolve(projectRoot) ? result : detect(scope) + })); + result.valid = result.scopes.every((scope) => scope.detection.valid); + result.status = result.valid ? 'present' : 'partial'; + } + return result; } function matchesTask(pillar, taskText) { - const terms = [pillar.name, ...pillar.triggers, ...pillar.covers]; - return terms.some(term => containsTerm(taskText, term)); + return pillar.triggers.some((trigger) => selectorMatches(taskText, trigger)); } function addLoad(load, pillar, reason) { @@ -273,13 +524,15 @@ function addLoad(load, pillar, reason) { load.get(pillar.name).reasons.push(reason); } -function computeLoadSet(projectRoot, taskText) { - const pillars = listPillars(projectRoot); +function computeScopeLoad(scopeRoot, taskText) { + const pillars = listPillars(scopeRoot); const byName = new Map(pillars.map(p => [p.name, p])); - const excluded = readExclusions(projectRoot); + const excluded = readExclusions(scopeRoot); + const catalog = readCatalog(scopeRoot); const load = new Map(); const primaryNames = []; const missing = []; + const absent = []; for (const name of ['context', 'repo']) { if (!byName.has(name) && !excluded.has(name)) missing.push({ pillar: name, reason: 'floor pillar missing' }); @@ -298,6 +551,13 @@ function computeLoadSet(projectRoot, taskText) { } } + for (const entry of catalog.entries.values()) { + if (excluded.has(entry.identity)) continue; + if (entry.triggers.some((trigger) => selectorMatches(taskText, trigger))) { + absent.push({ pillar: entry.identity, reason: 'catalog trigger match' }); + } + } + for (const primaryName of primaryNames) { const primary = byName.get(primaryName); for (const dep of primary.must_read_with) { @@ -313,21 +573,18 @@ function computeLoadSet(projectRoot, taskText) { for (const item of [...load.values()]) { for (const soft of item.pillar.see_also) { if (excluded.has(soft)) continue; - if (containsTerm(taskText, soft)) { + const target = byName.get(soft) || catalog.entries.get(soft); + if (!target) continue; + const selectors = [soft, ...(target.triggers || []), ...(target.covers || [])]; + if (selectors.some((selector) => selectorMatches(taskText, selector))) { if (byName.has(soft)) addLoad(load, byName.get(soft), `see_also from ${item.pillar.name}`); - else missing.push({ pillar: soft, reason: `see_also from ${item.pillar.name}` }); + else absent.push({ pillar: soft, reason: `see_also from ${item.pillar.name}` }); } } } - for (const [name, meta] of Object.entries(CORE_PILLARS)) { - if (byName.has(name) || excluded.has(name)) continue; - if (matchesTask({ name, ...meta, must_read_with: [], see_also: [] }, taskText)) { - missing.push({ pillar: name, reason: 'relevant known pillar absent' }); - } - } - return { + scope: scopeRoot, loadSet: [...load.values()].map(item => ({ name: item.pillar.name, path: item.pillar.path, @@ -335,7 +592,50 @@ function computeLoadSet(projectRoot, taskText) { reasons: [...new Set(item.reasons)] })), missing: dedupeMissing(missing), - excluded: [...excluded].sort() + absent: dedupeMissing(absent), + primaries: [...new Set(primaryNames)].sort(), + excluded: [...excluded.keys()].sort() + }; +} + +function computeLoadSet(projectRoot, taskText, opts = {}) { + const scopes = applicableScopes(projectRoot, opts.target || '.'); + if (scopes.length === 0) { + return { loadSet: [], missing: [{ pillar: 'context', reason: 'no Pillars scope found' }], absent: [], excluded: [], scopes: [] }; + } + const local = scopes.map((scope) => computeScopeLoad(scope, taskText)); + const loadSet = []; + const missing = []; + const absent = []; + const excluded = []; + for (let index = 0; index < local.length; index += 1) { + const current = local[index]; + const scopeLabel = path.relative(path.resolve(projectRoot), current.scope) || 'root'; + const descendantExclusions = new Set(local.slice(index + 1).flatMap((entry) => entry.excluded)); + for (const item of current.loadSet) { + const pillar = listPillars(current.scope).find((candidate) => candidate.identity === item.name); + if (descendantExclusions.has(item.name) && pillar && !pillar.always_load) continue; + loadSet.push({ + ...item, + identity: item.name, + scope: current.scope, + scopeLabel + }); + } + missing.push(...current.missing.map((item) => ({ ...item, scope: current.scope, scopeLabel }))); + absent.push(...current.absent.map((item) => ({ ...item, scope: current.scope, scopeLabel }))); + excluded.push(...current.excluded.map((identity) => ({ identity, scope: current.scope, scopeLabel }))); + } + return { + loadSet, + missing: dedupeMissing(missing), + absent: dedupeMissing(absent), + excluded, + scopes: local.map((entry) => ({ + root: entry.scope, + scopeLabel: path.relative(path.resolve(projectRoot), entry.scope) || 'root', + primaries: entry.primaries + })) }; } @@ -343,7 +643,7 @@ function dedupeMissing(missing) { const seen = new Set(); const out = []; for (const item of missing) { - const key = `${item.pillar}:${item.reason}`; + const key = `${item.scope || ''}:${item.pillar}:${item.reason}`; if (seen.has(key)) continue; seen.add(key); out.push(item); @@ -358,14 +658,16 @@ function buildProtocolContent(exclusions = []) { lines.push('This is a Godpowers project. Godpowers uses the Pillars standard as its native project context layer.'); lines.push('Coding agents read project context from `./agents/*.md` before changing code, while `.godpowers/` remains the Godpowers workflow state and artifact layer.'); lines.push(''); + lines.push('This project follows Pillars 1.1.0. Coding agents read project pillar files before acting.'); + lines.push(''); lines.push('## At the start of any task'); lines.push(''); - lines.push('1. Load every pillar whose frontmatter has `always_load: true`.'); - lines.push('2. Scan remaining pillar frontmatter and select task-relevant primaries from `triggers` and `covers`.'); - lines.push('3. Add each primary pillar direct `must_read_with` dependencies, depth 1 only.'); - lines.push('4. Read every pillar body in the computed load set.'); - lines.push('5. Read `see_also` pillars only when the task explicitly touches that area.'); - lines.push('6. Follow Rules, apply Workflows, heed Watchouts, and ask before deciding open Gaps.'); + lines.push('1. Resolve scopes from repository root to the task target. A scope contains both `AGENTS.md` and `agents/`. Apply outer scopes first and let the nearest scope win conflicts.'); + lines.push('2. Inventory pillar frontmatter recursively, local exclusions, and optional `agents/catalog.yaml` absent concerns in each scope.'); + lines.push('3. Load every pillar whose frontmatter has `always_load: true`. Match remaining `triggers` with the Pillars portable ASCII token matcher to select primaries and absent concerns.'); + lines.push('4. Add each primary pillar direct `must_read_with` dependencies, depth 1 only. Path-qualified sub-pillars use identities such as `auth/agent-registration`.'); + lines.push('5. Add a selected pillar `see_also` target only when the task matches the target identity, triggers, or covers. Do not follow soft references recursively.'); + lines.push('6. Read every selected body. Follow Rules, apply Workflows, heed Watchouts, and ask before deciding open Gaps.'); lines.push(''); lines.push('## Handling missing pillars'); lines.push(''); @@ -373,10 +675,11 @@ function buildProtocolContent(exclusions = []) { lines.push('|---|---|'); lines.push('| `status: present` | Load and comply. |'); lines.push('| `status: stub` | Treat the concern as acknowledged but undecided. Ask before making domain decisions. |'); - lines.push('| Name in `excluded:` | Treat as intentionally not applicable. |'); - lines.push('| Relevant but absent | Infer from code, state the assumption, and recommend authoring the pillar. |'); + lines.push('| Name in `excluded:` | Treat as intentionally not applicable in that scope. |'); + lines.push('| Trigger matches local `agents/catalog.yaml` entry | Infer from code, state the assumption, and recommend authoring the pillar. |'); + lines.push('| No local file, exclusion, or catalog entry | Make no Pillars-specific claim about that concern. |'); lines.push(''); - lines.push('If `context.md` or `repo.md` is missing, pause and create stubs before continuing.'); + lines.push('If `context.md` or `repo.md` is missing and not explicitly excluded, pause and ask the human to create a stub or record an exclusion.'); lines.push(''); lines.push('## Excluded pillars'); lines.push(''); @@ -559,6 +862,35 @@ function ensurePillar(projectRoot, name, meta, opts = {}) { return { path: file, action: 'created' }; } +function catalogContent(identities) { + const lines = ['version: 1', 'absent:']; + for (const identity of identities) { + const meta = KNOWN_PILLARS[identity]; + if (!meta) continue; + lines.push(` - identity: ${identity}`); + lines.push(` covers: [${meta.covers.join(', ')}]`); + lines.push(` triggers: [${meta.triggers.join(', ')}]`); + } + if (lines.length === 2) lines[1] = 'absent: []'; + lines.push(''); + return lines.join('\n'); +} + +function ensureCatalog(projectRoot) { + const agentsDir = path.join(projectRoot, 'agents'); + const file = path.join(agentsDir, 'catalog.yaml'); + if (fs.existsSync(file)) return { path: file, action: 'kept' }; + const present = new Set(listPillars(projectRoot).map((pillar) => pillar.identity)); + const excluded = readExclusions(projectRoot); + const absent = Object.keys(KNOWN_PILLARS) + .filter((identity) => !['context', 'repo'].includes(identity)) + .filter((identity) => !present.has(identity) && !excluded.has(identity)) + .sort(); + fs.mkdirSync(agentsDir, { recursive: true }); + fs.writeFileSync(file, catalogContent(absent)); + return { path: file, action: 'created' }; +} + function init(projectRoot, opts = {}) { const agentsFile = path.join(projectRoot, 'AGENTS.md'); const exclusions = opts.exclusions || []; @@ -574,10 +906,12 @@ function init(projectRoot, opts = {}) { for (const name of coreNames) { results.push(ensurePillar(projectRoot, name, CORE_PILLARS[name])); } + const catalog = ensureCatalog(projectRoot); return { agentsFile, results, + catalog, detection: detect(projectRoot) }; } @@ -589,7 +923,7 @@ function buildPillarSyncContent(pillarName, artifactEntries, opts = {}) { ); const unique = [...new Set(entries.map(entry => entry.artifact))].sort(); const lines = []; - lines.push('## Godpowers artifact sources'); + lines.push('### Godpowers artifact sources'); lines.push(''); lines.push(`- Sync mode: ${mode}.`); for (const artifact of unique) { @@ -599,7 +933,7 @@ function buildPillarSyncContent(pillarName, artifactEntries, opts = {}) { const signalEntries = entries.filter(entry => entry.signals && entry.signals.length > 0); if (signalEntries.length > 0) { lines.push(''); - lines.push('## Extracted durable signals'); + lines.push('### Extracted durable signals'); for (const entry of signalEntries) { lines.push(''); lines.push(`From \`${entry.artifact}\`:`); @@ -709,15 +1043,25 @@ module.exports = { ALWAYS_PILLARS, COMMON_PILLARS, KNOWN_PILLARS, + REQUIRED_SECTIONS, + PILLAR_BUDGETS, parseFrontmatter, parsePillarFile, listPillars, + discoverScopes, + applicableScopes, + normalizeSelector, + selectorMatches, + validIdentity, readExclusions, + readCatalog, hasPillarsProtocol, detect, computeLoadSet, buildProtocolContent, pillarStub, + catalogContent, + ensureCatalog, init, artifactToPillars, sanitizeSignal, diff --git a/lib/planning-systems.js b/lib/planning-systems.js index c7e9d14..f49a4aa 100644 --- a/lib/planning-systems.js +++ b/lib/planning-systems.js @@ -1,8 +1,8 @@ /** * Planning System Migration * - * Detects legacy planning, BMAD, Superpowers, the Godplans PLAN plus validator - * contract, and Godaudits project artifacts, converts their useful signals + * Detects legacy planning, BMAD, Superpowers, Arc-Ready, the Godplans PLAN plus + * validator contract, and Godaudits project artifacts, converts useful signals * into Godpowers preparation * artifacts, and records source-system state so /god-sync can later write * progress back through lib/source-sync.js. @@ -111,6 +111,30 @@ const SYSTEMS = { fileRoots: ['docs/superpowers', '.superpowers', 'superpowers'], standalonePatterns: [/^SUPERPOWERS\.md$/i] }, + 'arc-ready': { + displayName: 'Arc-Ready', + markerPaths: [ + '.arc-ready/PROGRESS.md', + '.prd-ready/PRD.md', + '.architecture-ready/ARCH.md', + '.roadmap-ready/ROADMAP.md', + '.stack-ready/STACK.md' + ], + fileRoots: [ + '.arc-ready', + '.prd-ready', + '.architecture-ready', + '.roadmap-ready', + '.stack-ready', + '.repo-ready', + '.production-ready', + '.deploy-ready', + '.observe-ready', + '.launch-ready', + '.harden-ready' + ], + standalonePatterns: [] + }, godplans: { displayName: 'godplans', markerPaths: [siblingArtifacts.PLAN_PATH], @@ -259,6 +283,39 @@ function classifyFile(filePath, content) { const body = `${lower}\n${content.slice(0, 3000).toLowerCase()}`; const kinds = new Set(); + if (lower.startsWith('.prd-ready/')) { + kinds.add('requirements'); + kinds.add('product'); + } + if (lower.startsWith('.architecture-ready/')) { + kinds.add('architecture'); + kinds.add('technical'); + } + if (lower.startsWith('.roadmap-ready/')) { + kinds.add('roadmap'); + kinds.add('phase'); + } + if (lower.startsWith('.stack-ready/')) { + kinds.add('stack'); + kinds.add('technical'); + } + if (/^\.(?:repo|production|deploy|launch)-ready\//.test(lower)) { + kinds.add('plan'); + kinds.add('verification'); + } + if (lower.startsWith('.observe-ready/')) { + kinds.add('technical'); + kinds.add('verification'); + } + if (lower.startsWith('.harden-ready/') || lower === '.launch-ready/prepublication.md') { + kinds.add('audit'); + kinds.add('technical'); + } + if (lower.startsWith('.arc-ready/')) { + kinds.add('state'); + kinds.add('context'); + } + if (filePath === siblingArtifacts.PLAN_VALIDATOR_PATH) return ['validator']; // Sibling superskill id grammars are case-sensitive, so they match against @@ -481,7 +538,7 @@ function buildImportedContext(detection, projectRoot) { lines.push(''); if (detection.systems.length === 0) { - lines.push('- [DECISION] No legacy planning, BMAD, Superpowers, godplans, or godaudits planning context was detected.'); + lines.push('- [DECISION] No legacy planning, BMAD, Superpowers, Arc-Ready, godplans, or godaudits planning context was detected.'); } for (const system of detection.systems) { @@ -525,7 +582,7 @@ function buildImportedContext(detection, projectRoot) { lines.push('## Sync-Back Policy'); lines.push(''); lines.push('- [DECISION] Godpowers may write managed sync-back summaries only inside Godpowers-owned fences or companion files.'); - lines.push('- [DECISION] Godpowers must not rewrite legacy planning, BMAD, Superpowers, godplans, or godaudits source documents outside managed sync-back sections.'); + lines.push('- [DECISION] Godpowers must not rewrite legacy planning, BMAD, Superpowers, Arc-Ready, godplans, or godaudits source documents outside managed sync-back sections.'); lines.push('- [DECISION] Sync-back exists so a project can return to the prior planning system with current Godpowers progress visible.'); lines.push(''); diff --git a/lib/prepublication-gate.js b/lib/prepublication-gate.js new file mode 100644 index 0000000..e72f999 --- /dev/null +++ b/lib/prepublication-gate.js @@ -0,0 +1,302 @@ +/** + * Hash-bound pre-publication gate. + * + * A launch preparation result does not authorize publication. This module + * re-reads hardening evidence, records the exact findings hash, and rejects a + * gate after either the findings bytes or authoritative hardening timestamp + * changes. + */ + +const crypto = require('crypto'); +const fs = require('fs'); +const path = require('path'); + +const FINDINGS_FILE = '.godpowers/harden/FINDINGS.mdx'; +const STATE_FILE = '.godpowers/state.json'; +const GATE_FILE = '.godpowers/launch/PREPUBLICATION.mdx'; + +function sha256(content) { + return `sha256:${crypto.createHash('sha256').update(content).digest('hex')}`; +} + +function readText(projectRoot, relPath) { + try { + return fs.readFileSync(path.join(projectRoot, relPath), 'utf8'); + } catch (error) { + if (error.code === 'ENOENT') return null; + throw error; + } +} + +function readState(projectRoot) { + const text = readText(projectRoot, STATE_FILE); + if (text === null) return null; + try { + return JSON.parse(text); + } catch (_error) { + return null; + } +} + +function normalizedStatus(value) { + return String(value || '').trim().toLowerCase().replace(/[_.\s]+/g, '-'); +} + +function classifyStatus(value) { + const status = normalizedStatus(value); + if (['fixed', 'resolved', 'closed', 'verified'].includes(status)) return 'resolved'; + if (['accepted-risk', 'accepted'].includes(status)) return 'accepted'; + return 'unresolved'; +} + +function parseCriticalFindings(content) { + const text = String(content || ''); + const summary = text.match(/\|\s*Critical\s*\|\s*(\d+)\s*\|/i); + const summaryTotal = summary ? Number(summary[1]) : null; + const entries = []; + + const headingPattern = /^###\s+\[CRITICAL-[^\n]+\]([\s\S]*?)(?=^###\s+\[|(?![\s\S]))/gim; + let match; + while ((match = headingPattern.exec(text)) !== null) { + const status = match[1].match(/(?:\*\*)?Status(?:\*\*)?:\s*([^\n.]+)/i); + entries.push(classifyStatus(status ? status[1] : 'unknown')); + } + + const yamlPattern = /^severity:\s*critical\s*$([\s\S]*?)(?=^severity:\s*|(?![\s\S]))/gim; + while ((match = yamlPattern.exec(text)) !== null) { + const status = match[1].match(/^status:\s*([^\n#]+)/im); + entries.push(classifyStatus(status ? status[1] : 'unknown')); + } + + const entryTotal = entries.length; + const total = summaryTotal === null ? entryTotal : Math.max(summaryTotal, entryTotal); + const resolved = entries.filter(status => status === 'resolved').length; + const accepted = entries.filter(status => status === 'accepted').length; + const unclassified = Math.max(0, total - entries.length); + const unresolved = entries.filter(status => status === 'unresolved').length + accepted + unclassified; + return { total, resolved, accepted, unresolved }; +} + +function hardeningState(state) { + return state && state.tiers && state.tiers['tier-3'] && state.tiers['tier-3'].harden + ? state.tiers['tier-3'].harden + : null; +} + +function snapshot(projectRoot) { + const findings = readText(projectRoot, FINDINGS_FILE); + const state = readState(projectRoot); + const harden = hardeningState(state); + return { + findings, + revision: findings === null ? null : sha256(findings), + statePresent: state !== null, + hardeningStatus: harden && harden.status ? harden.status : null, + hardeningUpdatedAt: harden && harden.updated ? harden.updated : null, + criticals: parseCriticalFindings(findings), + explicitBlocked: findings !== null && /Launch gate(?:\*\*)?:\s*BLOCKED/i.test(findings) + }; +} + +function evaluateSnapshot(current) { + const reasons = []; + if (current.findings === null) reasons.push(`missing ${FINDINGS_FILE}`); + if (!current.statePresent) reasons.push(`missing or invalid ${STATE_FILE}`); + if (current.hardeningStatus !== 'done') reasons.push(`hardening status is ${current.hardeningStatus || 'missing'}, expected done`); + if (current.explicitBlocked) reasons.push('hardening findings record a blocked launch gate'); + if (current.criticals.unresolved > 0) reasons.push(`${current.criticals.unresolved} unresolved or accepted Critical finding(s)`); + return { + verdict: reasons.length === 0 ? 'pass' : 'block', + reasons + }; +} + +function frontmatterValue(value) { + if (value === null || value === undefined) return 'null'; + if (typeof value === 'number') return String(value); + return JSON.stringify(String(value)); +} + +function renderGate(record) { + const lines = [ + '---', + 'schema-version: 1', + `checked_at: ${frontmatterValue(record.checkedAt)}`, + `hardening_revision: ${frontmatterValue(record.hardeningRevision)}`, + `hardening_updated_at: ${frontmatterValue(record.hardeningUpdatedAt)}`, + `critical_total: ${record.criticals.total}`, + `critical_unresolved: ${record.criticals.unresolved}`, + `critical_accepted: ${record.criticals.accepted}`, + 'policy: "block-unresolved-critical"', + `verdict: ${frontmatterValue(record.verdict)}`, + '---', + '# Pre-Publication Gate', + '', + `- [DECISION] Checked at: ${record.checkedAt}.`, + `- [DECISION] Hardening revision: ${record.hardeningRevision || 'missing'}.`, + `- [DECISION] Hardening updated at: ${record.hardeningUpdatedAt || 'missing'}.`, + `- [DECISION] Critical findings: ${record.criticals.total} total, ${record.criticals.unresolved} unresolved or accepted.`, + `- [DECISION] Verdict: ${record.verdict}.`, + '- [DECISION] Any later hardening revision or hardening state update invalidates this gate.', + '' + ]; + if (record.reasons.length > 0) { + lines.push('## Blocking Reasons', ''); + for (const reason of record.reasons) lines.push(`- [DECISION] ${reason}.`); + lines.push(''); + } + return lines.join('\n'); +} + +function parseScalar(value) { + const trimmed = value.trim(); + if (trimmed === 'null') return null; + if (/^\d+$/.test(trimmed)) return Number(trimmed); + if (trimmed.startsWith('"')) { + try { + return JSON.parse(trimmed); + } catch (_error) { + return trimmed.slice(1, -1); + } + } + return trimmed; +} + +function parseGate(content) { + const match = String(content || '').match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/); + if (!match) return null; + const result = {}; + for (const line of match[1].split(/\r?\n/)) { + const field = line.match(/^([a-z0-9_-]+):\s*(.*)$/i); + if (field) result[field[1]] = parseScalar(field[2]); + } + return result; +} + +function record(projectRoot, opts = {}) { + const root = path.resolve(projectRoot || process.cwd()); + const current = snapshot(root); + const evaluation = evaluateSnapshot(current); + const checkedAt = opts.now || new Date().toISOString(); + if (!Number.isFinite(Date.parse(checkedAt))) throw new Error(`Invalid checked_at value: ${checkedAt}`); + const hardeningUpdatedAt = Date.parse(current.hardeningUpdatedAt); + if (Number.isFinite(hardeningUpdatedAt) && Date.parse(checkedAt) <= hardeningUpdatedAt) { + evaluation.reasons.push('pre-publication check is not later than the authoritative hardening update'); + evaluation.verdict = 'block'; + } + const result = { + projectRoot: root, + gateFile: GATE_FILE, + checkedAt, + hardeningRevision: current.revision, + hardeningUpdatedAt: current.hardeningUpdatedAt, + criticals: current.criticals, + verdict: evaluation.verdict, + reasons: evaluation.reasons + }; + const target = path.join(root, GATE_FILE); + fs.mkdirSync(path.dirname(target), { recursive: true }); + fs.writeFileSync(target, renderGate(result)); + return result; +} + +function check(projectRoot) { + const root = path.resolve(projectRoot || process.cwd()); + const gateText = readText(root, GATE_FILE); + const gate = parseGate(gateText); + const current = snapshot(root); + const evaluation = evaluateSnapshot(current); + const reasons = [...evaluation.reasons]; + + if (!gate) { + reasons.push(`missing or invalid ${GATE_FILE}`); + } else { + if (gate.verdict !== 'pass') reasons.push(`recorded gate verdict is ${gate.verdict || 'missing'}`); + if (gate.hardening_revision !== current.revision) reasons.push('hardening revision changed after the gate was recorded'); + if (gate.hardening_updated_at !== current.hardeningUpdatedAt) reasons.push('authoritative hardening update changed after the gate was recorded'); + if (gate.critical_unresolved !== current.criticals.unresolved) reasons.push('Critical finding counts changed after the gate was recorded'); + const checkedAt = Date.parse(gate.checked_at); + const updatedAt = Date.parse(current.hardeningUpdatedAt); + if (!Number.isFinite(checkedAt)) reasons.push('recorded checked_at is invalid'); + if (Number.isFinite(updatedAt) && (!Number.isFinite(checkedAt) || checkedAt <= updatedAt)) { + reasons.push('pre-publication check is not later than the authoritative hardening update'); + } + } + + return { + projectRoot: root, + gateFile: GATE_FILE, + verdict: reasons.length === 0 ? 'pass' : 'block', + reasons: [...new Set(reasons)], + checkedAt: gate ? gate.checked_at : null, + hardeningRevision: current.revision, + recordedRevision: gate ? gate.hardening_revision : null, + hardeningUpdatedAt: current.hardeningUpdatedAt, + criticals: current.criticals + }; +} + +function renderResult(result) { + const lines = [ + 'Godpowers Pre-Publication Gate', + '', + `Verdict: ${result.verdict}`, + `Hardening revision: ${result.hardeningRevision || 'missing'}`, + `Critical unresolved or accepted: ${result.criticals.unresolved}`, + `Artifact: ${result.gateFile}` + ]; + if (result.reasons.length > 0) { + lines.push('', 'Blocking reasons:'); + for (const reason of result.reasons) lines.push(`- ${reason}`); + } + return lines.join('\n'); +} + +function parseArgs(argv) { + const opts = { mode: 'check', projectRoot: process.cwd(), json: false }; + for (let i = 2; i < argv.length; i++) { + const arg = argv[i]; + if (arg === '--record') opts.mode = 'record'; + else if (arg === '--check') opts.mode = 'check'; + else if (arg === '--json') opts.json = true; + else if (arg.startsWith('--project=')) opts.projectRoot = arg.slice('--project='.length); + else if (arg === '--project' && argv[i + 1]) opts.projectRoot = argv[++i]; + else throw new Error(`Unknown argument: ${arg}`); + } + return opts; +} + +function main(argv = process.argv) { + let opts; + try { + opts = parseArgs(argv); + const result = opts.mode === 'record' ? record(opts.projectRoot) : check(opts.projectRoot); + if (opts.json) console.log(JSON.stringify(result, null, 2)); + else console.log(renderResult(result)); + if (result.verdict !== 'pass') process.exitCode = 1; + return result; + } catch (error) { + console.error(`Pre-publication gate error: ${error.message}`); + process.exitCode = 1; + return null; + } +} + +if (require.main === module) main(); + +module.exports = { + FINDINGS_FILE, + STATE_FILE, + GATE_FILE, + sha256, + parseCriticalFindings, + snapshot, + evaluateSnapshot, + renderGate, + parseGate, + record, + check, + renderResult, + parseArgs, + main +}; diff --git a/lib/product-routing.js b/lib/product-routing.js new file mode 100644 index 0000000..f068fbc --- /dev/null +++ b/lib/product-routing.js @@ -0,0 +1,214 @@ +/** + * Product-form and domain-composition routing. + * + * Product form is selected before product archetype, industry, or regulatory + * overlays. This keeps browser assumptions out of CLI, API, data, mobile, and + * infrastructure work while preserving one ordered routing contract. + */ + +const FORM_DEFINITIONS = Object.freeze([ + { + id: 'web-application', + label: 'Web application', + signals: ['browser ui', 'web app', 'saas app', 'authenticated portal', 'customer portal', 'admin console', 'dashboard'], + profiles: ['Web App (SaaS)'], + verticalSlice: 'user action -> permission boundary -> service or API -> real data -> UI states -> tests', + completionEvidence: [ + 'roadmap-grounded job crosses the real data boundary', + 'loading, empty, error, and success states are covered where applicable', + 'permission checks run at the server boundary', + 'accessibility, unit, integration, and browser checks pass' + ] + }, + { + id: 'api-or-service', + label: 'API or service', + signals: ['api service', 'public api', 'headless service', 'http service', 'rpc service', 'event consumer', 'microservice', 'worker service'], + profiles: ['API / Microservice'], + verticalSlice: 'contract -> validation and authorization -> domain operation -> dependency -> telemetry -> tests', + completionEvidence: [ + 'a real consumer fixture completes one contract path', + 'schema and error responses are tested', + 'retries are bounded and idempotent where required', + 'health, telemetry, contract, and integration checks pass' + ] + }, + { + id: 'cli-or-sdk', + label: 'CLI or SDK', + signals: ['command line', 'command-line', 'terminal command', 'cli tool', ' cli ', 'sdk', 'developer library', 'embeddable library', 'npm package'], + profiles: ['Library / SDK', 'CLI Tool'], + verticalSlice: 'public command or API -> parsing and validation -> domain operation -> output contract -> consumer fixture -> tests', + completionEvidence: [ + 'a clean consumer fixture installs the release artifact', + 'the primary job completes without repository internals', + 'invalid input returns documented errors and exit behavior', + 'examples, compatibility checks, and reproducible packaging pass' + ] + }, + { + id: 'mobile-or-desktop', + label: 'Mobile or desktop', + signals: ['mobile app', 'desktop app', 'app store', 'play store', 'native app', 'offline client', 'electron app', 'tauri app', 'signed installer'], + profiles: ['Mobile App', 'Desktop App'], + verticalSlice: 'native interaction -> local state -> sync boundary -> offline and recovery states -> platform tests', + completionEvidence: [ + 'a build runs on every declared platform class', + 'the primary job survives lifecycle and connectivity transitions', + 'secrets use platform storage', + 'accessibility, crash telemetry, device tests, and packaging pass' + ] + }, + { + id: 'data-or-ml', + label: 'Data or ML', + signals: ['data pipeline', 'dataset pipeline', 'analytics engineering', 'model training', 'inference service', 'feature pipeline', 'evaluation pipeline', 'machine learning', 'ml system'], + profiles: ['Data / ML'], + verticalSlice: 'versioned input -> validated transform or training -> reproducible output -> evaluation -> lineage checks', + completionEvidence: [ + 'a clean environment reproduces one pipeline or model artifact', + 'quality and evaluation thresholds are explicit and pass', + 'lineage identifies code, data, and configuration versions', + 'fixtures contain no unauthorized sensitive data' + ] + }, + { + id: 'infrastructure-or-iac', + label: 'Infrastructure or IaC', + signals: ['terraform module', 'opentofu module', 'infrastructure as code', 'iac module', 'kubernetes package', 'ansible automation', 'platform infrastructure'], + profiles: ['DevOps / IaC'], + verticalSlice: 'versioned configuration -> static validation -> plan -> policy check -> isolated apply or simulation -> rollback proof', + completionEvidence: [ + 'formatting and static validation pass', + 'an isolated plan and policy result are reviewed', + 'a sandbox apply or faithful simulation proves the main path', + 'destructive behavior, state, secrets, and rollback are verified' + ] + } +]); + +const ARCHETYPE_STACKS = Object.freeze({ + 'saas': 'SaaS / Multi-tenant', + 'multi-tenant': 'SaaS / Multi-tenant', + 'marketplace': 'Marketplace / Two-sided', + 'developer-platform': 'SaaS / Multi-tenant', + 'workflow-automation': 'SaaS / Multi-tenant', + 'internal-tool': 'Internal Tools / Back-office', + 'analytics-bi': 'Analytics / BI / Dashboards', + 'ai-ml-chat': 'AI / ML / LLM products' +}); + +const INDUSTRY_STACKS = Object.freeze({ + 'financial-fintech-accounting': 'Fintech / Financial', + 'healthcare-medical': 'Healthcare / Medical', + 'ecommerce-retail': 'E-commerce / Retail', + 'education-lms': 'Education / LMS', + 'marketing-crm-sales': 'CRM / Sales / Marketing', + 'customer-support': 'Customer Support / Helpdesk', + 'research-lab-lims': 'Internal Tools / Back-office', + 'manufacturing-mes': 'Internal Tools / Back-office', + 'cybersecurity-soc': 'Analytics / BI / Dashboards', + 'data-analytics-bi': 'Analytics / BI / Dashboards' +}); + +function normalizeText(value) { + return ` ${String(value || '').toLowerCase().replace(/[^a-z0-9+/-]+/g, ' ').replace(/\s+/g, ' ').trim()} `; +} + +function signalPresent(text, signal) { + const normalizedSignal = normalizeText(signal); + return text.includes(normalizedSignal); +} + +function selectProductForm(input) { + const text = normalizeText(typeof input === 'string' ? input : input && input.text); + const explicit = input && typeof input === 'object' ? input.form : null; + if (explicit) { + const definition = FORM_DEFINITIONS.find(item => item.id === explicit || item.label.toLowerCase() === String(explicit).toLowerCase()); + if (!definition) return { status: 'invalid', form: null, evidence: [], candidates: [] }; + return { status: 'selected', form: definition.id, evidence: ['explicit product form'], candidates: [{ form: definition.id, score: Number.MAX_SAFE_INTEGER }] }; + } + + const candidates = FORM_DEFINITIONS.map(definition => { + const evidence = definition.signals.filter(signal => signalPresent(text, signal)); + return { form: definition.id, score: evidence.length, evidence }; + }).filter(candidate => candidate.score > 0) + .sort((a, b) => b.score - a.score || a.form.localeCompare(b.form)); + + if (candidates.length === 0) return { status: 'undetermined', form: null, evidence: [], candidates: [] }; + if (candidates.length > 1 && candidates[0].score === candidates[1].score) { + return { status: 'ambiguous', form: null, evidence: candidates[0].evidence, candidates }; + } + return { status: 'selected', form: candidates[0].form, evidence: candidates[0].evidence, candidates }; +} + +function uniqueValues(value) { + const values = Array.isArray(value) ? value : value ? [value] : []; + return [...new Set(values.map(item => String(item).trim()).filter(Boolean))]; +} + +function formDefinition(form) { + return FORM_DEFINITIONS.find(item => item.id === form) || null; +} + +function composeDomain(input = {}) { + const form = formDefinition(input.form); + if (!form) throw new Error(`Unknown or missing product form: ${input.form || '(none)'}`); + + const archetypes = uniqueValues(input.archetype); + const industries = uniqueValues(input.industry); + const regulatory = uniqueValues(input.regulatory); + const primaryStack = archetypes.map(item => ARCHETYPE_STACKS[item]).find(Boolean) + || industries.map(item => INDUSTRY_STACKS[item]).find(Boolean) + || null; + const secondaryStacks = [...new Set([ + ...archetypes.map(item => ARCHETYPE_STACKS[item]), + ...industries.map(item => INDUSTRY_STACKS[item]) + ].filter(item => item && item !== primaryStack))]; + + return { + axes: { + form: form.id, + archetype: archetypes, + industry: industries, + regulatory + }, + profiles: form.profiles, + verticalSlice: form.verticalSlice, + completionEvidence: form.completionEvidence, + stackComposition: { + primary: primaryStack, + secondaryConstraints: secondaryStacks, + rule: 'Score the primary profile first, then add only hard constraints from secondary profiles.' + }, + loadOrder: [ + 'references/building/PRODUCT-FORM-ROUTER.md', + 'references/building/DOMAIN-COMPOSITION-REGISTRY.md' + ] + }; +} + +function renderRoute(route) { + if (!route || !route.axes) throw new Error('A composed domain route is required.'); + const definition = formDefinition(route.axes.form); + const lines = [ + `Product form: ${definition ? definition.label : route.axes.form}`, + `Product archetype: ${route.axes.archetype.join(', ') || 'none evidenced'}`, + `Industry overlay: ${route.axes.industry.join(', ') || 'none evidenced'}`, + `Regulatory overlay: ${route.axes.regulatory.join(', ') || 'none evidenced'}`, + `Vertical slice: ${route.verticalSlice}`, + 'Completion evidence:' + ]; + for (const item of route.completionEvidence) lines.push(`- ${item}`); + return lines.join('\n'); +} + +module.exports = { + FORM_DEFINITIONS, + ARCHETYPE_STACKS, + INDUSTRY_STACKS, + selectProductForm, + formDefinition, + composeDomain, + renderRoute +}; diff --git a/lib/repo-doc-sync.js b/lib/repo-doc-sync.js index 45120eb..d7cda43 100644 --- a/lib/repo-doc-sync.js +++ b/lib/repo-doc-sync.js @@ -37,7 +37,7 @@ function packageVersion(projectRoot) { function counts(projectRoot) { return { skills: countFiles(projectRoot, 'skills', /^god.*\.md$/), - agents: countFiles(projectRoot, 'agents', /^god.*\.md$/), + agents: countFiles(projectRoot, 'specialists', /^god.*\.md$/), workflows: countFiles(projectRoot, 'workflows', /\.yaml$/), recipes: countFiles(projectRoot, path.join('routing', 'recipes'), /\.yaml$/) }; diff --git a/lib/repo-surface-sync.js b/lib/repo-surface-sync.js index 7aa41f7..a6e9000 100644 --- a/lib/repo-surface-sync.js +++ b/lib/repo-surface-sync.js @@ -24,7 +24,7 @@ const LOG_PATH = '.godpowers/surface/REPO-SURFACE-SYNC.mdx'; const REQUIRED_PACKAGE_FILE_ENTRIES = [ 'bin/', 'skills/', - 'agents/god-*.md', + 'specialists/', 'templates/', 'references/', 'routing/', @@ -166,7 +166,7 @@ function parseRoute(projectRoot, routePath) { function agentChecks(projectRoot) { const checks = []; - const agents = new Set(listFiles(projectRoot, 'agents', /^god.*\.md$/) + const agents = new Set(listFiles(projectRoot, 'specialists', /^god.*\.md$/) .map((file) => path.basename(file, '.md'))); const routes = listFiles(projectRoot, 'routing', /^god.*\.yaml$/); const missing = new Set(); diff --git a/lib/route-quality-sync.js b/lib/route-quality-sync.js index 848205e..814810f 100644 --- a/lib/route-quality-sync.js +++ b/lib/route-quality-sync.js @@ -143,7 +143,7 @@ function isAtomicSpawn(token) { function detect(projectRoot) { const checks = []; const routes = listFiles(projectRoot, 'routing', /^god.*\.yaml$/); - const agents = new Set(listFiles(projectRoot, 'agents', /^god.*\.md$/) + const agents = new Set(listFiles(projectRoot, 'specialists', /^god.*\.md$/) .map((file) => path.basename(file, '.md'))); let symbolicCount = 0; let unresolvedCount = 0; diff --git a/lib/self-project-truth.js b/lib/self-project-truth.js index 52e26a7..050039b 100644 --- a/lib/self-project-truth.js +++ b/lib/self-project-truth.js @@ -110,7 +110,7 @@ function versionChecks(root, result, version) { function surfaceChecks(root, result, pkg) { const counts = { skills: countFiles(root, 'skills', (name) => name.endsWith('.md')), - agents: countFiles(root, 'agents', (name) => /^god-.*\.md$/.test(name)), + agents: countFiles(root, 'specialists', (name) => /^god-.*\.md$/.test(name)), workflows: countFiles(root, 'workflows', (name) => name.endsWith('.yaml')), recipes: countFiles(root, 'routing/recipes', (name) => name.endsWith('.yaml')) }; diff --git a/lib/source-sync.js b/lib/source-sync.js index 0c34c9c..217e920 100644 --- a/lib/source-sync.js +++ b/lib/source-sync.js @@ -1,8 +1,8 @@ /** * Source System Sync-Back * - * Writes Godpowers progress back to detected legacy planning, BMAD, and Superpowers - * projects through managed companion files and optional managed fences. + * Writes Godpowers progress back to detected source systems through managed + * companion files and optional managed fences. */ const fs = require('fs'); @@ -29,6 +29,10 @@ const SYSTEM_TARGETS = { companionCandidates: ['docs/superpowers/GODPOWERS-SYNC.md', '.superpowers/GODPOWERS-SYNC.md'], pointerCandidates: [] }, + 'arc-ready': { + companionCandidates: ['.arc-ready/GODPOWERS-SYNC.md'], + pointerCandidates: [] + }, // Sibling superskill directories are mdx-family, so their companions are // .mdx (unlike the legacy .md companions in foreign dirs). PLAN.mdx, // validate-plan.sh, AUDIT.json, and its generated AUDIT.mdx view remain @@ -149,7 +153,7 @@ function progressLines(projectRoot) { lines.push(''); lines.push('## Return Path'); lines.push(''); - lines.push('- [DECISION] If the project returns to legacy planning, BMAD, or Superpowers, use this file as a migration note rather than treating it as a native source-system artifact.'); + lines.push('- [DECISION] If the project returns to its prior source system, use this file as a migration note rather than treating it as a native source-system artifact.'); lines.push('- [OPEN QUESTION] Confirm which Godpowers decisions should be copied into native source-system documents before switching systems. Owner: user. Due: before switching systems.'); lines.push(''); return lines.join('\n'); diff --git a/lib/voice-lint.js b/lib/voice-lint.js index 563cef4..55c3bb8 100644 --- a/lib/voice-lint.js +++ b/lib/voice-lint.js @@ -12,7 +12,7 @@ * Used three ways: * - have-not U-14 in lib/have-nots-validator.js (flags generated artifacts), * - a self-dogfood check in scripts/static-check.js (the framework's own - * shipped skill and agent prose must not model the filler it forbids), + * shipped skill, specialist, and Pillars prose must not model the filler), * - a reusable check an agent can run on its own drafted output before sending. */ diff --git a/package-lock.json b/package-lock.json index 463339c..49d164c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "godpowers", - "version": "5.4.0", + "version": "5.5.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "godpowers", - "version": "5.4.0", + "version": "5.5.0", "license": "MIT", "workspaces": [ "packages/mcp" @@ -1796,7 +1796,7 @@ }, "packages/mcp": { "name": "@godpowers/mcp", - "version": "5.4.0", + "version": "5.5.0", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.29.0", diff --git a/package.json b/package.json index e3925df..0308db8 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,13 @@ { "name": "godpowers", - "version": "5.4.0", + "version": "5.5.0", "description": "AI-powered development system: 122 slash commands and 40 specialist agents that take a project from raw idea to hardened production, then run it as an autonomous loop. Runs inside Claude Code, Codex, Cursor, Windsurf, Gemini, and 10+ other AI coding tools.", "bin": { "godpowers": "./bin/install.js" }, "scripts": { "test": "node scripts/run-tests.js", - "prepublishOnly": "npm run release:check", + "prepublishOnly": "npm run release:check && npm run release:prepublication:check", "validate-skills": "node scripts/validate-skills.js", "test:surface": "node scripts/test-doc-surface-counts.js", "test:self-truth": "node scripts/check-self-project-truth.js", @@ -17,9 +17,14 @@ "smoke": "bash scripts/smoke.sh", "test:runtime": "node scripts/test-runtime.js", "test:router": "node scripts/test-router.js", + "test:product-routing": "node scripts/test-product-routing.js", + "test:prepublication": "node scripts/test-prepublication-gate.js", "test:recipes": "node scripts/test-recipes.js", "test:context": "node scripts/test-context-writer.js", "test:pillars": "node scripts/test-pillars.js", + "test:pillars-conformance": "node scripts/test-pillars-conformance.js", + "validate:official-skill": "node scripts/validate-official-skill.js", + "release:standards": "npm run validate:official-skill && npm run test:pillars && npm run test:pillars-conformance", "test:linter": "node scripts/test-artifact-linter.js", "test:diff": "node scripts/test-artifact-diff.js", "test:e2e": "node tests/integration/full-arc.test.js", @@ -29,7 +34,9 @@ "test:audit": "npm audit --omit=dev && git diff --check && npm run test:surface", "pack:check": "node scripts/check-package-contents.js", "pack:mcp:check": "npm --workspace @godpowers/mcp run pack:check", - "release:check": "npm run coverage:lib && node scripts/check-per-file-coverage.js && npm run test:audit && npm run test:self-truth && npm run pack:check && npm run pack:mcp:check", + "release:prepublication:record": "node lib/prepublication-gate.js --record --project=.", + "release:prepublication:check": "node lib/prepublication-gate.js --check --project=.", + "release:check": "npm run release:standards && npm run coverage:lib && node scripts/check-per-file-coverage.js && npm run test:audit && npm run test:self-truth && npm run pack:check && npm run pack:mcp:check", "lint": "node scripts/static-check.js" }, "workspaces": [ @@ -78,7 +85,7 @@ "files": [ "bin/", "skills/", - "agents/god-*.md", + "specialists/", "hooks/", "templates/", "references/", diff --git a/packages/mcp/package.json b/packages/mcp/package.json index 150ba09..b397f81 100644 --- a/packages/mcp/package.json +++ b/packages/mcp/package.json @@ -1,6 +1,6 @@ { "name": "@godpowers/mcp", - "version": "5.4.0", + "version": "5.5.0", "description": "Read-only MCP server for Godpowers runtime status, routing, gates, artifact linting, and requirement tracing.", "bin": { "godpowers-mcp": "./bin/godpowers-mcp.js" diff --git a/references/HAVE-NOTS.md b/references/HAVE-NOTS.md index f7d7ff8..f655f6d 100644 --- a/references/HAVE-NOTS.md +++ b/references/HAVE-NOTS.md @@ -468,7 +468,9 @@ No plan for D+1 to D+7 (responding to comments, gathering feedback, iterating). Fail. #### L-08 "We'll figure out marketing later" -Launch tier marked done with no actual launch artifacts. Fail. +Launch tier marked done with no actual launch artifacts. Public activation +without a fresh hash-bound `.godpowers/launch/PREPUBLICATION.mdx` pass also +fails. ### Harden Have-Nots @@ -485,7 +487,9 @@ User input paths not systematically reviewed. Fail. Rate limiting claimed but not tested with actual abuse simulation. Fail. #### H-05 OWASP categories skipped -A Top 10 category marked "N/A" without justification. Fail. +An OWASP Web Top 10:2025 category lacks a reproducible manual procedure and +result, or is marked Not Applicable without project-specific justification. +Fail. #### H-06 Findings without severity Finding exists but has no Critical/High/Medium/Low classification. Fail. diff --git a/references/building/DOMAIN-COMPOSITION-REGISTRY.md b/references/building/DOMAIN-COMPOSITION-REGISTRY.md new file mode 100644 index 0000000..6ac4c0e --- /dev/null +++ b/references/building/DOMAIN-COMPOSITION-REGISTRY.md @@ -0,0 +1,89 @@ +# Domain Composition Registry + +Compose domain guidance on four independent axes, in this order: + +1. Product form: delivery shape and Build completion gate. +2. Product archetype: product mechanics such as SaaS, marketplace, developer + platform, workflow automation, or internal tool. +3. Industry overlay: domain entities, operator expectations, and failure modes. +4. Regulatory overlay: only evidenced jurisdictions, data classes, and control + frameworks. + +Product form is selected through `references/building/PRODUCT-FORM-ROUTER.md`. +Regulatory and provider details are freshness-sensitive. Verify applicability, +effective date, jurisdiction, and current provider capabilities before making a +commitment. + +## Stack profile mappings + +| Domain profile | Axis role | Primary stack profile | Common product forms | +|---|---|---|---| +| SaaS / Multi-tenant | Product archetype | SaaS / Multi-tenant | Web application, API or service | +| Marketplace / Platform | Product archetype | Marketplace / Two-sided | Web application, mobile or desktop, API or service | +| Developer Platform / API / SDK | Product archetype | SaaS / Multi-tenant | API or service, CLI or SDK, web application | +| Workflow Automation / Integration | Product archetype | SaaS / Multi-tenant | Web application, API or service | +| Internal Tool / Back-office | Product archetype | Internal Tools / Back-office | Web application, API or service | +| Data / Analytics / BI | Product archetype | Analytics / BI / Dashboards | Data or ML, web application | +| AI / ML / Chat | Product archetype | AI / ML / LLM products | Web application, API or service, data or ML | +| E-commerce / Retail | Archetype and industry | E-commerce / Retail | Web application, mobile or desktop | +| Financial / Fintech / Accounting | Industry overlay | Fintech / Financial | Web application, API or service | +| Healthcare / Medical | Industry and regulatory overlay | Healthcare / Medical | Web application, mobile or desktop, API or service | +| Education / EdTech / LMS | Industry overlay | Education / LMS | Web application, mobile or desktop | +| Customer Support / Helpdesk | Product archetype | Customer Support / Helpdesk | Web application | +| Marketing / CRM / Sales | Product archetype | CRM / Sales / Marketing | Web application, API or service | +| Logistics / Supply Chain / Fleet | Industry overlay | Internal Tools / Back-office | Web application, mobile or desktop, data or ML | +| HR / People / Payroll | Industry overlay | SaaS / Multi-tenant | Web application | +| Project Management / Collaboration | Product archetype | SaaS / Multi-tenant | Web application, mobile or desktop | +| IoT / Device Management | Industry overlay | Internal Tools / Back-office | Web application, API or service, infrastructure or IaC | +| Travel / Hospitality / Booking | Industry overlay | Marketplace / Two-sided | Web application, mobile or desktop | +| Sports / Fitness | Industry overlay | SaaS / Multi-tenant | Web application, mobile or desktop | +| Real Estate / Property Management | Industry overlay | SaaS / Multi-tenant | Web application, mobile or desktop | +| Restaurant / Food Service | Industry overlay | E-commerce / Retail | Web application, mobile or desktop | +| Legal / Law Firm | Industry overlay | SaaS / Multi-tenant | Web application | +| Non-profit / Fundraising | Industry overlay | CRM / Sales / Marketing | Web application | +| Media / Streaming | Industry overlay | CMS / Content / Blog | Web application, mobile or desktop | +| Agriculture / Farm Management | Industry overlay | Internal Tools / Back-office | Mobile or desktop, data or ML | +| Entertainment / Events | Industry overlay | E-commerce / Retail | Web application, mobile or desktop | +| Gaming / Esports | Industry overlay | SaaS / Multi-tenant | Web application, API or service | +| Cybersecurity / SOC | Industry overlay | Analytics / BI / Dashboards | Web application, data or ML | +| Construction / Field Services | Industry overlay | Internal Tools / Back-office | Mobile or desktop, web application | +| Insurance / InsurTech | Industry overlay | Fintech / Financial | Web application, API or service | +| Telecommunications / ISP | Industry overlay | Internal Tools / Back-office | Web application, API or service, infrastructure or IaC | +| Energy / Utilities | Industry overlay | Analytics / BI / Dashboards | Web application, data or ML, infrastructure or IaC | +| Government / Public Sector | Industry and regulatory overlay | Internal Tools / Back-office | Web application, mobile or desktop | +| Recruiting / ATS | Product archetype and industry | SaaS / Multi-tenant | Web application | +| Co-working Space / Shared Office | Industry overlay | SaaS / Multi-tenant | Web application, mobile or desktop | +| Manufacturing / MES | Industry overlay | Internal Tools / Back-office | Web application, mobile or desktop, infrastructure or IaC | +| Research / Lab / LIMS | Industry overlay | Internal Tools / Back-office | Web application, data or ML | + +This registry selects the smallest directly applicable guidance set. When the +repository lacks a focused profile for the selected industry, infer constraints +from current project evidence, label the inference, and record the missing +profile as a context gap instead of loading unrelated industries. + +## Composition rules + +- A developer platform is a product archetype, not an industry. Add a customer + industry only when the platform itself encodes that industry's rules. +- SaaS and marketplace describe product mechanics. They can combine with + healthcare, manufacturing, research, or other industry overlays. +- Analytics or BI can be an archetype or a secondary capability. Do not force + OLAP infrastructure onto modest operational reporting. +- Research / Lab / LIMS remains an industry overlay because sample custody, + instrument provenance, and method versioning are stable constraints. + Clinical research adds healthcare and applicable regulatory overlays. +- When two stack profiles apply, score the primary profile first, then add only + hard constraints from the secondary profile. Do not average full matrices. +- Regulatory language is a routing signal, not legal advice. Record uncertain + applicability as an open question with an owner and due date. + +## Required route evidence + +Before Architecture, Stack, or Build closes, record: + +- Primary product form and its observable distribution channel. +- Product archetype or an explicit statement that none applies. +- Industry overlay or an explicit statement that none is evidenced. +- Regulatory overlay or an explicit statement that none is evidenced. +- Primary stack profile plus any secondary hard constraints. +- Form-specific vertical-slice definition and completion evidence. diff --git a/references/building/PRODUCT-FORM-ROUTER.md b/references/building/PRODUCT-FORM-ROUTER.md new file mode 100644 index 0000000..49ea48f --- /dev/null +++ b/references/building/PRODUCT-FORM-ROUTER.md @@ -0,0 +1,102 @@ +# Product Form Router + +Select one primary product form before applying product archetype, industry, +or regulatory guidance. Product form defines how users operate the software, +what a vertical slice means, and which completion evidence can close Build. + +## Routing procedure + +1. Inventory the primary user interaction and distribution channel. +2. Select one primary form. Record a secondary form only when it has its own + user, public contract, distribution path, and completion evidence. +3. Run `lib/product-routing.selectProductForm` when the available intent is + explicit enough for deterministic selection. Treat an ambiguous or + undetermined result as an open planning question. +4. Compose archetype, industry, and regulatory overlays through + `references/building/DOMAIN-COMPOSITION-REGISTRY.md`. +5. Use common Build discipline plus the form-specific gate below. + +Do not infer a web application from words such as product, platform, or tool. +Do not infer infrastructure from YAML files alone. A backend is required only +when the selected product form and architecture actually include one. + +## Common vertical-slice discipline + +| Product form | User-operable vertical slice | +|---|---| +| Web application | User action -> permission boundary -> service or API -> real data -> UI states -> tests | +| API or service | Contract -> validation and authorization -> domain operation -> dependency -> telemetry -> tests | +| CLI or SDK | Public command or API -> parsing and validation -> domain operation -> output contract -> consumer fixture -> tests | +| Mobile or desktop | Native interaction -> local state -> sync boundary -> offline and recovery states -> platform tests | +| Data or ML | Versioned input -> validated transform or training -> reproducible output -> evaluation -> lineage checks | +| Infrastructure or IaC | Versioned configuration -> static validation -> plan -> policy check -> isolated apply or simulation -> rollback proof | + +## Form-specific completion gates + +### Web application + +Use when the primary job is delivered through a browser UI, authenticated +portal, SaaS surface, or customer or admin console. + +Build closes only when one roadmap-grounded job crosses the real data boundary, +relevant loading, empty, error, and success states exist, permissions are +enforced at the server boundary, accessibility checks pass, and unit, +integration, and browser tests are green. + +### API or service + +Use for a headless HTTP or RPC contract, event consumer, worker, or internal +service. + +Build closes only when a real consumer fixture completes one contract path +against real dependencies or faithful local substitutes, schema and error +responses are tested, retries are bounded and idempotent where required, +health and telemetry are observable, and contract plus integration tests pass. + +### CLI or SDK + +Use for a terminal workflow, globally installed binary, package consumed by +developers, language SDK, or embeddable library. + +Build closes only when a clean consumer fixture installs the release artifact, +completes the primary job without repository internals, receives documented +errors for invalid input, executes or compiles the examples, passes supported +runtime or OS checks, and reproduces the release artifact. + +### Mobile or desktop + +Use for app-store distribution, native capabilities, offline clients, signed +installers, Electron, or Tauri. + +Build closes only when a build runs on every declared platform class, the +primary job survives lifecycle and connectivity transitions, secrets use +platform storage, accessibility and device checks pass, crash telemetry is +wired, and packaging is reproducible. + +### Data or ML + +Use for dataset pipelines, analytics engineering, training, inference, +feature pipelines, model evaluation, or notebook-centered delivery. + +Build closes only when a clean environment reproduces one pipeline or model +artifact from versioned inputs, explicit quality and evaluation thresholds +pass, lineage identifies code, data, and configuration versions, fixtures +contain no unauthorized sensitive data, and serving behavior is tested when +serving is in scope. + +### Infrastructure or IaC + +Use for Terraform or OpenTofu modules, Kubernetes packages, Ansible +automation, or cloud platform foundations. + +Build closes only when formatting and static validation pass, an isolated plan +is reviewed, policy checks pass, a sandbox apply or faithful simulation proves +the main path, destructive behavior is guarded, state and secrets are +protected, and rollback or destroy is exercised. + +## Secondary forms + +A web console with a public SDK or a data pipeline with a separate inference +API can have a secondary form. Keep one primary form for sequencing. Give each +secondary form a distinct user, contract, distribution path, and completion +gate instead of merging its evidence into the primary form. diff --git a/references/building/README.md b/references/building/README.md index c932626..012f60a 100644 --- a/references/building/README.md +++ b/references/building/README.md @@ -7,6 +7,8 @@ Per-tier reference content for Tier 2 (Building: Repo, Build). - `BUILD-ANTIPATTERNS.md`: failure modes for implementation planning and execution. - `BUILD-VERTICAL-SLICES.md`: guidance for slicing work into user-visible increments. - `BUILD-WAVES.md`: dependency-aware parallelism patterns for multi-agent work. +- `PRODUCT-FORM-ROUTER.md`: form-first vertical slices and completion evidence. +- `DOMAIN-COMPOSITION-REGISTRY.md`: ordered archetype, industry, regulatory, and stack-profile composition. ## Use diff --git a/references/orchestration/GOD-ORCHESTRATOR-RUNBOOK.md b/references/orchestration/GOD-ORCHESTRATOR-RUNBOOK.md index 6d027aa..e91cc5b 100644 --- a/references/orchestration/GOD-ORCHESTRATOR-RUNBOOK.md +++ b/references/orchestration/GOD-ORCHESTRATOR-RUNBOOK.md @@ -220,8 +220,9 @@ projectRoot)`. Missing prerequisites are authoritative even when the tier order suggests the command is structurally next. If `safe-sync-clear` fails, route to `/god-reconcile Release Truth And Safe Sync` before deploy, observe, harden, launch, broad migration, or resume work. If `no-critical-findings` -fails, launch remains blocked until harden is fixed and re-verified or risk is -explicitly accepted in writing. +fails, public activation remains blocked until harden is fixed and re-verified +or public activation is removed from scope. The pre-publication gate does not +treat accepted Critical risk as a pass. Between every tier, run god-standards-check on the produced artifact (if the routing config has a `standards` section). Standards check uses fresh @@ -300,6 +301,17 @@ changes artifacts, review items, blockers, or the next recommendation. ## Detection-Driven Tier 1 Routing +Before UI detection or domain-specific planning, select product form through +`lib/product-routing.selectProductForm`. Load +`references/building/PRODUCT-FORM-ROUTER.md`, then compose product archetype, +industry, and regulatory overlays through +`references/building/DOMAIN-COMPOSITION-REGISTRY.md`. Preserve that four-axis +order in PRD, Architecture, Stack, and Build handoffs. If the form is +ambiguous, record an open question instead of inferring a web application. +Build can close only with the selected form's completion evidence. + +After the product-form route is recorded, apply UI detection: + After PRD and before ARCH, branch on UI or product-experience presence: 1. Call `lib/design-detector.isUiProject(projectRoot)` to determine @@ -362,6 +374,23 @@ Everything else must first enter the autonomous repair loop below. A failed typecheck, lint, check, unit test, generated artifact lint, or have-nots pass is not a reason to declare the project run complete. It is work. +## Hash-Bound Public Activation Gate + +Launch assets may be prepared without authorizing an external write. After all +other release-readiness work and immediately before any public release action: + +1. Re-read `.godpowers/harden/FINDINGS.mdx` and authoritative hardening state. +2. Run `node /lib/prepublication-gate.js --record --project=.`. +3. Run `node /lib/prepublication-gate.js --check --project=.` in + the same release attempt. +4. Continue only on `verdict: pass`. + +The record binds `.godpowers/launch/PREPUBLICATION.mdx` to the exact hardening +findings hash, authoritative hardening timestamp, current Critical counts, and +check time. Any later hardening revision or state update invalidates it. Never +reuse a stale gate after a hardening rerun. CI publication workflows run the +check again after the release gate and before publishing. + ## Autonomous Repair Loop Godpowers full project run means: plan, build, verify, repair, ship, sync. Do not stop diff --git a/references/shipping/HARDEN-OWASP-2025-ROUTER.md b/references/shipping/HARDEN-OWASP-2025-ROUTER.md new file mode 100644 index 0000000..cb5aa27 --- /dev/null +++ b/references/shipping/HARDEN-OWASP-2025-ROUTER.md @@ -0,0 +1,26 @@ +# OWASP Web Top 10:2025 Router + +Use this order for current web hardening. Each category must produce one row in +`.godpowers/harden/FINDINGS.mdx` with a reproducible manual test, result, and +finding link or a project-specific Not Applicable justification. Scanner output +cannot satisfy a row by itself. + +| Current category | Required manual scope | +|---|---| +| A01:2025 Broken Access Control | Object and function authorization, SSRF, and internal-resource access | +| A02:2025 Security Misconfiguration | Application, framework, cloud, CORS, error, default, and debug configuration | +| A03:2025 Software Supply Chain Failures | Dependency provenance, CI identities, build integrity, signing, substitution, and distribution | +| A04:2025 Cryptographic Failures | Algorithms, key lifecycle, nonce or IV handling, password hashing, and transport policy | +| A05:2025 Injection | Untrusted input through every interpreter and output context | +| A06:2025 Insecure Design | Threat models, abuse cases, rate limits, step-up controls, and secure defaults | +| A07:2025 Authentication Failures | Credentials, sessions, MFA, recovery, rotation, revocation, and throttling | +| A08:2025 Software or Data Integrity Failures | Trust boundaries and integrity checks for code, updates, data, and serialized content | +| A09:2025 Security Logging and Alerting Failures | Detection, alert delivery, ownership, and exercised response | +| A10:2025 Mishandling of Exceptional Conditions | Fail-open paths, abnormal transitions, exhaustion, partial operations, rollback, and recovery | + +OWASP moved SSRF into A01 and introduced A10 for exceptional-condition +handling. Do not preserve the 2021 category ordering in a new hardening report. +Use `references/shipping/HARDEN-OWASP-WORKSHEETS.md` for the manual procedures. + +When standards freshness is material to a release, verify the current category +authority at `https://owasp.org/Top10/2025/` before recording the walkthrough. diff --git a/references/shipping/HARDEN-OWASP-WORKSHEETS.md b/references/shipping/HARDEN-OWASP-WORKSHEETS.md index a34cdea..3bb6afa 100644 --- a/references/shipping/HARDEN-OWASP-WORKSHEETS.md +++ b/references/shipping/HARDEN-OWASP-WORKSHEETS.md @@ -1,89 +1,101 @@ -# OWASP Top 10 Manual Walkthrough +# OWASP Web Top 10:2025 Manual Walkthrough -> Worksheets for each of the OWASP Top 10. Use during /god-harden. +Use during `/god-harden` after reading +`references/shipping/HARDEN-OWASP-2025-ROUTER.md`. Record the exact request, +fault injection, fixture, or reproduction procedure and observed result for +every applicable category. A code-read or scanner result can support evidence, +but cannot replace the manual procedure. -## A01: Broken Access Control +## A01:2025 Broken Access Control -For each protected endpoint: -- [ ] What permission is required? -- [ ] Is the permission check present and correct? -- [ ] Test: unauthenticated user hitting endpoint -> 401 -- [ ] Test: authenticated user without permission -> 403 -- [ ] Test: authenticated user WITH permission -> 200 +- [ ] Inventory object, function, tenant, and administrative authorization boundaries. +- [ ] Probe unauthenticated, wrong-user, wrong-tenant, and wrong-role access. +- [ ] Test user-controlled URLs against localhost, private networks, cloud metadata, redirects, and alternate IP encodings. +- [ ] Confirm denial occurs at the service boundary and leaves no unauthorized state change. -``` -Endpoint: GET /api/users/:id -Required: authenticated AND (user_id == :id OR role == admin) -Implementation: src/api/users.ts:45 (permission check is line 47) -Tested: yes (test_users_self_access, test_users_other_403, test_users_admin_other_200) -``` +## A02:2025 Security Misconfiguration -## A02: Cryptographic Failures +- [ ] Verify production framework, cloud, storage, CORS, proxy, and error configuration. +- [ ] Remove default accounts, sample data, debug endpoints, and unnecessary features. +- [ ] Exercise verbose errors and confirm sensitive internals are not returned. +- [ ] Verify security headers and environment separation where the form uses HTTP. -- [ ] All ePHI / PII / financial data encrypted at rest? (DB-level, not just app-level) -- [ ] All transmissions over TLS 1.2+? (verify with `nmap --script ssl-enum-ciphers`) -- [ ] No hardcoded secrets? (run `grep -ri "sk_live\|api_key\|secret" src/`) -- [ ] No weak algorithms? (no MD5, no SHA1 for security; AES-256 minimum for symmetric; RSA-2048 minimum for asymmetric) -- [ ] Random number generation cryptographically secure? (crypto.randomBytes, not Math.random) +## A03:2025 Software Supply Chain Failures -## A03: Injection +- [ ] Run the ecosystem dependency audit and classify every unresolved result. +- [ ] Verify lockfile or equivalent dependency identity and registry provenance. +- [ ] Inspect CI identities, action or image pinning, secret scope, and build isolation. +- [ ] Verify release artifact integrity, signing or provenance, package substitution defenses, and distribution identity. -For each input source (user form, URL param, header, file upload, third-party webhook): -- [ ] SQL: parameterized queries only? (no string concat) -- [ ] XSS: output encoded? CSP headers in place? -- [ ] Command injection: never pass user input to shell commands? -- [ ] Template injection: safe template engines? No `eval()` of user data? -- [ ] LDAP/XML/NoSQL injection: parameterized? +## A04:2025 Cryptographic Failures -``` -Input: req.body.email (signup endpoint) -Validation: src/auth/signup.ts:23 (zod schema) -Used in: SQL via Prisma (parameterized) - safe -``` +- [ ] Verify current algorithms, parameter sizes, password hashing, and random generation. +- [ ] Trace key creation, storage, rotation, revocation, backup, and destruction. +- [ ] Verify nonce or IV uniqueness and authenticated encryption where applicable. +- [ ] Verify transport policy and the handling of sensitive data at rest and in logs. -## A04: Insecure Design +## A05:2025 Injection -- [ ] Rate limiting on auth endpoints? -- [ ] Bulk operation safeguards (e.g., delete-all has confirmation)? -- [ ] Race condition risks? (TOCTOU on account balance, e.g.) -- [ ] Business logic flaws? (negative quantities, sign-up bypass, etc.) +- [ ] Inventory user, URL, header, file, webhook, queue, and imported-data inputs. +- [ ] Trace each untrusted value through SQL, shell, template, HTML, LDAP, XML, and other interpreters. +- [ ] Verify parameterization, contextual output encoding, schema validation, and command argument boundaries. +- [ ] Probe malformed, nested, oversized, and encoded payloads through the real boundary. -## A05: Security Misconfiguration +## A06:2025 Insecure Design -- [ ] Default credentials removed? -- [ ] Verbose error messages disabled in production? -- [ ] Security headers present? (CSP, HSTS, X-Frame-Options, X-Content-Type-Options) -- [ ] Unnecessary features disabled? (debug endpoints, sample data) -- [ ] Cloud bucket permissions? (no public-by-default S3) +- [ ] Map threat actors, trust boundaries, abuse cases, and high-impact state transitions. +- [ ] Exercise rate limits, anti-automation controls, bulk-operation safeguards, and step-up controls. +- [ ] Probe race conditions, negative values, repeated actions, and business-rule bypasses. +- [ ] Confirm secure defaults and failure behavior match the deployed architecture. -## A06: Vulnerable Components +## A07:2025 Authentication Failures -- [ ] `npm audit` (or equivalent) clean for high+critical? -- [ ] Dependencies updated within last 12 months? -- [ ] Pinned versions or version ranges? +- [ ] Probe credential stuffing, enumeration, throttling, lockout, and recovery paths. +- [ ] Verify session fixation defense, expiry, rotation, revocation, logout, and concurrent-session policy. +- [ ] Verify MFA and step-up behavior for sensitive accounts or operations where required. +- [ ] Confirm tokens are scoped, time-bound, securely stored, and invalid after revocation. -## A07: Authentication Failures +## A08:2025 Software or Data Integrity Failures -- [ ] Strong password policy? -- [ ] MFA available for sensitive accounts? -- [ ] Session fixation prevented? (rotate session ID on login) -- [ ] Credential stuffing protection? (rate limit, account lockout, captcha) -- [ ] Forgot-password flow secure? (token expiry, single-use) +- [ ] Identify code, update, artifact, serialized-content, webhook, and critical-data trust boundaries. +- [ ] Verify signatures, hashes, MACs, allowlists, or equivalent integrity checks at those boundaries. +- [ ] Probe unsafe deserialization, unsigned updates, replay, and tampered import data. +- [ ] Confirm integrity failure blocks the operation and produces actionable evidence. -## A08: Data Integrity Failures +## A09:2025 Security Logging and Alerting Failures -- [ ] Updates signed/verified? (e.g., software updates from upstream) -- [ ] No unsafe deserialization? (no `pickle.loads(user_input)` or equivalent) -- [ ] Critical data has integrity checks? (HMAC, signature) +- [ ] Verify authentication, authorization, administrative, integrity, and abuse events are recorded. +- [ ] Confirm logs exclude secrets and unauthorized sensitive data. +- [ ] Trigger one controlled suspicious event through the production-equivalent telemetry path. +- [ ] Verify detection, alert delivery, owner acknowledgment, and the linked response procedure. -## A09: Logging Failures +## A10:2025 Mishandling of Exceptional Conditions -- [ ] Security events logged? (auth, authz failures, admin actions) -- [ ] No sensitive data in logs? (no passwords, no full tokens, no PII unless required and redacted) -- [ ] Alerts on suspicious activity? (e.g., 100 failed logins in 5 min) +Inventory every external dependency, state transition, asynchronous job, +transaction boundary, parser, and resource limit. Exercise applicable cases: -## A10: SSRF +1. Timeout, connection reset, malformed response, and dependency unavailability. +2. Partial success across a multi-step write, including retry and duplicate delivery. +3. Disk, memory, queue, connection-pool, file-descriptor, and request-size exhaustion. +4. Unexpected enum values, nulls, empty collections, oversized values, and invalid transitions. +5. Authorization, policy, or validation dependency failure. +6. Rollback failure and recovery after restart between steps. -- [ ] User-supplied URLs validated? (no localhost, no internal IPs) -- [ ] Internal services not reachable from user-facing endpoints? -- [ ] Cloud metadata endpoints blocked? (169.254.169.254 in AWS, etc.) +A pass requires secure failure, bounded resource use, no unauthorized state +transition, no sensitive error leakage, idempotent or compensating recovery +where required, and an observable alert for operator action. A catch-all that +returns success, silently drops work, or bypasses a control is a finding. + +## Completion evidence + +The walkthrough passes only when all ten 2025 rows contain: + +- The exact manual procedure or justified Not Applicable scope. +- The observed result and evidence location. +- A linked finding when the result does not pass. +- A reviewer and review timestamp. + +For non-web forms, retain the current 2025 category names and adapt the manual +boundary to the product form. For example, test command arguments and package +distribution for a CLI or SDK, pipeline inputs and lineage for Data or ML, and +plan, state, provider, and policy boundaries for Infrastructure or IaC. diff --git a/references/shipping/README.md b/references/shipping/README.md index 50c9860..54559e9 100644 --- a/references/shipping/README.md +++ b/references/shipping/README.md @@ -9,7 +9,8 @@ Per-tier reference content for Tier 3 (Deploy, Observe, Launch, Harden). - `OBSERVE-SLO-EXAMPLES.md`: SLO, alerting, and error-budget examples. - `OBSERVE-ANTIPATTERNS.md`: observability gaps, noisy alerts, and weak signals. - `LAUNCH-ANTIPATTERNS.md`: launch readiness, messaging, and adoption failure modes. -- `HARDEN-OWASP-WORKSHEETS.md`: security review worksheets based on OWASP categories. +- `HARDEN-OWASP-2025-ROUTER.md`: current OWASP Web Top 10:2025 category order and evidence contract. +- `HARDEN-OWASP-WORKSHEETS.md`: reproducible manual procedures for the current ten categories. - `HARDEN-ANTIPATTERNS.md`: hardening gaps and security theater patterns. ## Use diff --git a/requirements/skills-ref.txt b/requirements/skills-ref.txt new file mode 100644 index 0000000..394cc35 --- /dev/null +++ b/requirements/skills-ref.txt @@ -0,0 +1,2 @@ +# Official Agent Skills validator pinned to the reviewed upstream commit. +git+https://github.com/agentskills/agentskills.git@38a2ff82958afee88dadf4831509e6f7e9d8ef4e#subdirectory=skills-ref diff --git a/routing/god-build.yaml b/routing/god-build.yaml index 4aeb06a..d97958b 100644 --- a/routing/god-build.yaml +++ b/routing/god-build.yaml @@ -18,6 +18,9 @@ prerequisites: execution: spawns: [god-planner] context: fresh + reads: + - references/building/PRODUCT-FORM-ROUTER.md + - references/building/DOMAIN-COMPOSITION-REGISTRY.md secondary-spawns: [god-executor, god-spec-reviewer, god-quality-reviewer] writes: - .godpowers/build/PLAN.mdx diff --git a/routing/god-launch.yaml b/routing/god-launch.yaml index 373f2e5..989373a 100644 --- a/routing/god-launch.yaml +++ b/routing/god-launch.yaml @@ -23,6 +23,7 @@ execution: context: fresh writes: - .godpowers/state.json + - .godpowers/launch/PREPUBLICATION.mdx - landing copy - OG cards - launch runbook diff --git a/routing/god-migrate.yaml b/routing/god-migrate.yaml index 31161b8..c2cdeed 100644 --- a/routing/god-migrate.yaml +++ b/routing/god-migrate.yaml @@ -2,7 +2,7 @@ apiVersion: godpowers/v1 kind: CommandRouting metadata: command: /god-migrate - description: Detect and migrate legacy planning, BMAD, Superpowers, godplans, and godaudits planning context + description: Detect and migrate legacy planning, BMAD, Superpowers, Arc-Ready, godplans, and godaudits planning context tier: 0 family: start @@ -21,6 +21,17 @@ execution: - _bmad-output/** - .bmad/** - docs/superpowers/** + - .arc-ready/** + - .prd-ready/** + - .architecture-ready/** + - .roadmap-ready/** + - .stack-ready/** + - .repo-ready/** + - .production-ready/** + - .deploy-ready/** + - .observe-ready/** + - .launch-ready/** + - .harden-ready/** - .godplans/** - .godaudits/AUDIT.json - .godaudits/AUDIT.mdx @@ -38,6 +49,7 @@ execution: - _bmad-output/GODPOWERS-SYNC.md - .bmad/GODPOWERS-SYNC.md - docs/superpowers/GODPOWERS-SYNC.md + - .arc-ready/GODPOWERS-SYNC.md - .godplans/GODPOWERS-SYNC.mdx - .godaudits/GODPOWERS-SYNC.mdx local-runtime: diff --git a/scripts/check-package-contents.js b/scripts/check-package-contents.js index 1427e64..9956b97 100644 --- a/scripts/check-package-contents.js +++ b/scripts/check-package-contents.js @@ -20,14 +20,19 @@ const REQUIRED_FILES = [ 'bin/install.js', 'skills/god.md', 'skills/god-mode.md', - 'agents/god-orchestrator.md', - 'agents/god-pm.md', + 'specialists/god-orchestrator.md', + 'specialists/god-pm.md', 'templates/DOMAIN-GLOSSARY.mdx', 'templates/PRD.mdx', 'references/HAVE-NOTS.md', 'references/planning/PRD-ANATOMY.md', + 'references/building/PRODUCT-FORM-ROUTER.md', + 'references/building/DOMAIN-COMPOSITION-REGISTRY.md', + 'references/shipping/HARDEN-OWASP-2025-ROUTER.md', 'lib/adoption-metrics.js', 'lib/command-families.js', + 'lib/product-routing.js', + 'lib/prepublication-gate.js', 'lib/frontmatter.js', 'lib/workflow-runner.js', 'lib/workflow-helper-groups.js', @@ -113,9 +118,7 @@ function main() { if (pack.name !== 'godpowers') { throw new Error(`expected package name godpowers, got ${pack.name}`); } - const nonSpecialistAgents = [...files].filter(file => - file.startsWith('agents/') && !/^agents\/god-.*\.md$/.test(file) - ); + const packagedProjectPillars = [...files].filter(file => file.startsWith('agents/')); if (pack.entryCount < 400) { throw new Error(`expected at least 400 package entries, got ${pack.entryCount}`); } @@ -125,8 +128,8 @@ function main() { if (forbidden.length > 0) { throw new Error(`package includes local-only files:\n - ${forbidden.join('\n - ')}`); } - if (nonSpecialistAgents.length > 0) { - throw new Error(`package includes non-specialist agent files:\n - ${nonSpecialistAgents.join('\n - ')}`); + if (packagedProjectPillars.length > 0) { + throw new Error(`package includes repository-local Pillars files:\n - ${packagedProjectPillars.join('\n - ')}`); } console.log(` + package contents verified: ${pack.entryCount} files`); diff --git a/scripts/reconstruct-self-ledger.js b/scripts/reconstruct-self-ledger.js index 2bbffb8..4a2bd6e 100644 --- a/scripts/reconstruct-self-ledger.js +++ b/scripts/reconstruct-self-ledger.js @@ -27,16 +27,16 @@ const ROOT = path.resolve(__dirname, '..'); // Requirement id -> the real file(s) that implement it. Kept deliberately small // (the primary implementing surface), not an exhaustive file list. const MAP = { - 'P-MUST-01': ['agents/god-orchestrator.md'], + 'P-MUST-01': ['specialists/god-orchestrator.md'], 'P-MUST-02': ['lib/state.js'], 'P-MUST-03': ['lib/multi-repo-detector.js'], - 'P-MUST-04': ['agents/god-pm.md'], - 'P-MUST-05': ['agents/god-architect.md'], - 'P-MUST-06': ['agents/god-roadmapper.md'], - 'P-MUST-07': ['agents/god-stack-selector.md'], - 'P-MUST-08': ['agents/god-repo-scaffolder.md'], - 'P-MUST-09': ['agents/god-executor.md', 'agents/god-planner.md'], - 'P-MUST-10': ['agents/god-spec-reviewer.md', 'agents/god-quality-reviewer.md'], + 'P-MUST-04': ['specialists/god-pm.md'], + 'P-MUST-05': ['specialists/god-architect.md'], + 'P-MUST-06': ['specialists/god-roadmapper.md'], + 'P-MUST-07': ['specialists/god-stack-selector.md'], + 'P-MUST-08': ['specialists/god-repo-scaffolder.md'], + 'P-MUST-09': ['specialists/god-executor.md', 'specialists/god-planner.md'], + 'P-MUST-10': ['specialists/god-spec-reviewer.md', 'specialists/god-quality-reviewer.md'], 'P-MUST-11': ['lib/have-nots-validator.js'], 'P-MUST-12': ['lib/artifact-linter.js'], 'P-MUST-13': ['lib/linkage.js'], @@ -48,18 +48,18 @@ const MAP = { 'P-MUST-19': ['lib/requirements.js', 'skills/god-progress.md'], 'P-MUST-20': ['lib/checkpoint.js'], 'P-MUST-21': ['lib/installer-core.js', 'bin/install.js'], - 'P-MUST-22': ['agents/god-harden-auditor.md'], - 'P-SHOULD-01': ['agents/god-deploy-engineer.md'], - 'P-SHOULD-02': ['agents/god-observability-engineer.md'], - 'P-SHOULD-03': ['agents/god-launch-strategist.md'], - 'P-SHOULD-04': ['agents/god-updater.md'], + 'P-MUST-22': ['specialists/god-harden-auditor.md'], + 'P-SHOULD-01': ['specialists/god-deploy-engineer.md'], + 'P-SHOULD-02': ['specialists/god-observability-engineer.md'], + 'P-SHOULD-03': ['specialists/god-launch-strategist.md'], + 'P-SHOULD-04': ['specialists/god-updater.md'], 'P-SHOULD-05': ['lib/host-capabilities.js'], 'P-SHOULD-06': ['lib/runtime-test.js'], 'P-SHOULD-07': ['lib/source-sync.js'], - 'P-COULD-01': ['agents/god-coordinator.md'], - 'P-COULD-02': ['agents/god-automation-engineer.md'], + 'P-COULD-01': ['specialists/god-coordinator.md'], + 'P-COULD-02': ['specialists/god-automation-engineer.md'], 'P-COULD-03': ['lib/otel-exporter.js'], - 'P-COULD-04': ['agents/god-spike-runner.md'] + 'P-COULD-04': ['specialists/god-spike-runner.md'] }; function fail(msg) { diff --git a/scripts/run-tests.js b/scripts/run-tests.js index 6696671..640ec0d 100644 --- a/scripts/run-tests.js +++ b/scripts/run-tests.js @@ -25,9 +25,12 @@ const TEST_COMMANDS = [ [node, ['scripts/test-agent-refs.js']], [node, ['scripts/test-sync-fs-resolver.js']], [node, ['scripts/test-router.js']], + [node, ['scripts/test-product-routing.js']], + [node, ['scripts/test-prepublication-gate.js']], [node, ['scripts/test-recipes.js']], [node, ['scripts/test-context-writer.js']], [node, ['scripts/test-pillars.js']], + [node, ['scripts/test-pillars-conformance.js']], [node, ['scripts/test-artifact-linter.js']], [node, ['scripts/test-voice-lint.js']], [node, ['scripts/test-artifact-diff.js']], diff --git a/scripts/smoke.sh b/scripts/smoke.sh index b66647f..4032cbf 100755 --- a/scripts/smoke.sh +++ b/scripts/smoke.sh @@ -51,17 +51,17 @@ done # 3. All specialist agent files have frontmatter, name, description. # Project Pillars may also live under agents/ (context.md, repo.md, etc.), # but those are context files, not spawnable specialist agents. -for agent in "$ROOT/agents/"/god-*.md; do +for agent in "$ROOT/specialists/"/god-*.md; do name="$(basename "$agent")" if head -1 "$agent" | grep -q "^---"; then - pass "agents/$name has frontmatter" + pass "specialists/$name has frontmatter" else - fail "agents/$name missing frontmatter" + fail "specialists/$name missing frontmatter" fi if grep -q "^name:" "$agent"; then - pass "agents/$name has name field" + pass "specialists/$name has name field" else - fail "agents/$name missing name field" + fail "specialists/$name missing name field" fi done @@ -88,7 +88,7 @@ for path in [sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]]: if '\u2013' in line or '\u2014' in line: hits.append(f'{fp}:{i}') print('\n'.join(hits)) -" "$ROOT/SKILL.md" "$ROOT/skills" "$ROOT/agents" "$ROOT/README.md" 2>/dev/null)" +" "$ROOT/SKILL.md" "$ROOT/skills" "$ROOT/specialists" "$ROOT/agents" "$ROOT/README.md" 2>/dev/null)" if [ -n "$DASH_HITS" ]; then echo "$DASH_HITS" @@ -147,7 +147,7 @@ god-update-deps:god-deps-auditor while IFS=: read -r skill_name agent_name; do [ -z "$skill_name" ] && continue skill_file="$ROOT/skills/${skill_name}.md" - agent_file="$ROOT/agents/${agent_name}.md" + agent_file="$ROOT/specialists/${agent_name}.md" if [ -f "$skill_file" ] && grep -q "$agent_name" "$skill_file"; then pass "skills/${skill_name}.md spawns ${agent_name}" @@ -156,9 +156,9 @@ while IFS=: read -r skill_name agent_name; do fi if [ -f "$agent_file" ]; then - pass "agents/${agent_name}.md exists" + pass "specialists/${agent_name}.md exists" else - fail "agents/${agent_name}.md missing" + fail "specialists/${agent_name}.md missing" fi done < { +test('shipped skill, specialist, and Pillars prose has no sycophancy filler (U-14 self-dogfood)', () => { const voiceLint = require('../lib/voice-lint'); const offenders = []; - for (const dir of ['skills', 'agents']) { + for (const dir of ['skills', 'specialists', 'agents']) { const base = path.join(ROOT, dir); for (const file of fs.readdirSync(base).filter(name => name.endsWith('.md')).sort()) { for (const hit of voiceLint.scan(fs.readFileSync(path.join(base, file), 'utf8'))) { @@ -410,7 +410,7 @@ test('prompts do not direct-edit generated STATE views', () => { const files = [ path.join(ROOT, 'SKILL.md'), ...walkMatching(path.join(ROOT, 'skills'), file => file.endsWith('.md')), - ...walkMatching(path.join(ROOT, 'agents'), file => file.endsWith('.md')) + ...walkMatching(path.join(ROOT, 'specialists'), file => file.endsWith('.md')) ]; const offenders = []; for (const file of files) { @@ -456,7 +456,7 @@ test('god-mode delegates long-form runbook content', () => { test('agent prompts delegate oversized runbook content', () => { const maxBytes = 20000; - const agentsDir = path.join(ROOT, 'agents'); + const agentsDir = path.join(ROOT, 'specialists'); const agentFiles = fs.readdirSync(agentsDir) .filter(file => /^god-.*\.md$/.test(file)) .map(file => path.join(agentsDir, file)); @@ -465,7 +465,7 @@ test('agent prompts delegate oversized runbook content', () => { throw new Error(`oversized agent prompts: ${oversized.map(file => path.relative(ROOT, file)).join(', ')}`); } - const orchestrator = fs.readFileSync(path.join(ROOT, 'agents', 'god-orchestrator.md'), 'utf8'); + const orchestrator = fs.readFileSync(path.join(ROOT, 'specialists', 'god-orchestrator.md'), 'utf8'); const runbook = path.join(ROOT, 'references', 'orchestration', 'GOD-ORCHESTRATOR-RUNBOOK.md'); if (!fs.existsSync(runbook)) { throw new Error('God orchestrator runbook reference missing'); @@ -498,7 +498,7 @@ test('legacy roadmap reconciliation delegates to god-reconciler', () => { throw new Error('/god-roadmap-check must spawn god-reconciler'); } - const adapter = fs.readFileSync(path.join(ROOT, 'agents', 'god-roadmap-reconciler.md'), 'utf8'); + const adapter = fs.readFileSync(path.join(ROOT, 'specialists', 'god-roadmap-reconciler.md'), 'utf8'); if (!adapter.includes('compatibility adapter') || !adapter.includes('god-reconciler')) { throw new Error('god-roadmap-reconciler must remain a compatibility adapter'); } @@ -536,13 +536,13 @@ test('dashboard contract stays shared between status and next', () => { } }); -test('skills and agents use shared locking pointer without inline sections', () => { +test('skills, specialists, and Pillars use shared locking pointer without inline sections', () => { const locking = path.join(ROOT, 'references', 'shared', 'LOCKING.md'); if (!fs.existsSync(locking)) { throw new Error('shared locking reference missing'); } - const markdownFiles = ['skills', 'agents'] + const markdownFiles = ['skills', 'specialists', 'agents'] .flatMap(dir => walkMatching(path.join(ROOT, dir), file => file.endsWith('.md'))); const sectionOffenders = markdownFiles.filter(file => /^#{2,}\s+Locking\b/m.test(fs.readFileSync(file, 'utf8'))); if (sectionOffenders.length > 0) { diff --git a/scripts/test-agent-validator.js b/scripts/test-agent-validator.js index 5d8e89a..4ccd1d1 100644 --- a/scripts/test-agent-validator.js +++ b/scripts/test-agent-validator.js @@ -20,9 +20,9 @@ function mkAgent(content) { function mkAgentsDir(agents) { const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'godpowers-agent-dir-')); - fs.mkdirSync(path.join(tmp, 'agents'), { recursive: true }); + fs.mkdirSync(path.join(tmp, 'specialists'), { recursive: true }); for (const [name, content] of Object.entries(agents)) { - fs.writeFileSync(path.join(tmp, 'agents', name + '.md'), content); + fs.writeFileSync(path.join(tmp, 'specialists', name + '.md'), content); } return tmp; } @@ -364,7 +364,7 @@ description: r if (unresolved.length !== 0) throw new Error('false positive'); }); -test('auditAll ignores Pillars files in agents directory', () => { +test('auditAll ignores non-specialist files in specialists directory', () => { const tmp = mkAgentsDir({ 'context': '# Context\n\nProject context, not a specialist agent.\n', 'repo': '# Repo\n\nRepository context, not a specialist agent.\n', @@ -388,7 +388,7 @@ test('non-god-mode orchestrator entrypoints use display-safe handoffs', () => { ['skills/god-suite-init.md', 'COORDINATOR-HANDOFF.md'], ['skills/god-suite-release.md', 'COORDINATOR-HANDOFF.md'], ['skills/god-suite-patch.md', 'COORDINATOR-HANDOFF.md'], - ['agents/god-coordinator.md', 'COORDINATOR-ORCHESTRATOR-HANDOFF.md'], + ['specialists/god-coordinator.md', 'COORDINATOR-ORCHESTRATOR-HANDOFF.md'], ]; for (const [relPath, marker] of checks) { const text = readProjectFile(relPath); @@ -409,24 +409,24 @@ test('hygiene route does not spawn orchestrator directly', () => { }); // ============================================================================ -// auditAll on real godpowers/agents +// auditAll on real godpowers/specialists // ============================================================================ -test('auditAll on real godpowers/agents passes (no errors)', () => { +test('auditAll on real godpowers/specialists passes (no errors)', () => { const result = validator.auditAll('.'); if (result.summary.errors > 0) { throw new Error(`expected 0 errors, got ${result.summary.errors}`); } }); -test('auditAll on real godpowers/agents covers 30+ agents', () => { +test('auditAll on real godpowers/specialists covers 30+ agents', () => { const result = validator.auditAll('.'); if (result.summary.agentCount < 30) { throw new Error(`expected 30+ agents, got ${result.summary.agentCount}`); } }); -test('auditAll on real godpowers/agents has structured contracts for every shipped agent', () => { +test('auditAll on real godpowers/specialists has structured contracts for every shipped agent', () => { const result = validator.auditAll('.'); if (result.summary.agentCount !== 40) { throw new Error(`expected 40 agents, got ${result.summary.agentCount}`); diff --git a/scripts/test-automation-surface-sync.js b/scripts/test-automation-surface-sync.js index c246345..0aa8e85 100644 --- a/scripts/test-automation-surface-sync.js +++ b/scripts/test-automation-surface-sync.js @@ -42,11 +42,11 @@ function fixture() { "'lib/recipe-coverage-sync.js'", "'lib/release-surface-sync.js'" ].join('\n')); - writeRel(tmp, 'agents/god-planner.md', '---\nname: god-planner\n---\n'); - writeRel(tmp, 'agents/god-executor.md', '---\nname: god-executor\n---\n'); - writeRel(tmp, 'agents/god-spec-reviewer.md', '---\nname: god-spec-reviewer\n---\n'); - writeRel(tmp, 'agents/god-quality-reviewer.md', '---\nname: god-quality-reviewer\n---\n'); - writeRel(tmp, 'agents/god-writer.md', '---\nname: god-writer\n---\n'); + writeRel(tmp, 'specialists/god-planner.md', '---\nname: god-planner\n---\n'); + writeRel(tmp, 'specialists/god-executor.md', '---\nname: god-executor\n---\n'); + writeRel(tmp, 'specialists/god-spec-reviewer.md', '---\nname: god-spec-reviewer\n---\n'); + writeRel(tmp, 'specialists/god-quality-reviewer.md', '---\nname: god-quality-reviewer\n---\n'); + writeRel(tmp, 'specialists/god-writer.md', '---\nname: god-writer\n---\n'); writeRel(tmp, 'routing/god-story-build.yaml', [ 'apiVersion: godpowers/v1', 'kind: CommandRouting', diff --git a/scripts/test-doc-surface-counts.js b/scripts/test-doc-surface-counts.js index b181b84..54b9a9b 100644 --- a/scripts/test-doc-surface-counts.js +++ b/scripts/test-doc-surface-counts.js @@ -29,7 +29,7 @@ function assertIncludes(rel, expected) { const counts = { skills: countFiles('skills', /^god.*\.md$/), - agents: countFiles('agents', /^god.*\.md$/), + agents: countFiles('specialists', /^god.*\.md$/), workflows: countFiles('workflows', /\.yaml$/), recipes: countFiles(path.join('routing', 'recipes'), /\.yaml$/), libModules: countFiles('lib', /\.js$/), diff --git a/scripts/test-gate.js b/scripts/test-gate.js index e1a15c0..82521e6 100644 --- a/scripts/test-gate.js +++ b/scripts/test-gate.js @@ -204,7 +204,20 @@ test('harden gate passes with no criticals and an executed pass', () => { '|---|---:|', '| Critical | 0 |', '', - '[DECISION] Launch gate: PASSED.' + '[DECISION] Launch gate: PASSED.', + '', + '| Category | Manual procedure | Result | Evidence or finding |', + '|---|---|---|---|', + '| A01:2025 Broken Access Control | authorization probe | pass | test evidence |', + '| A02:2025 Security Misconfiguration | configuration probe | pass | test evidence |', + '| A03:2025 Software Supply Chain Failures | supply-chain probe | pass | test evidence |', + '| A04:2025 Cryptographic Failures | cryptography probe | pass | test evidence |', + '| A05:2025 Injection | injection probe | pass | test evidence |', + '| A06:2025 Insecure Design | abuse-case probe | pass | test evidence |', + '| A07:2025 Authentication Failures | authentication scope review | Not Applicable, no auth surface | test evidence |', + '| A08:2025 Software or Data Integrity Failures | integrity probe | pass | test evidence |', + '| A09:2025 Security Logging and Alerting Failures | alert exercise | pass | test evidence |', + '| A10:2025 Mishandling of Exceptional Conditions | failure injection | pass | test evidence |' ].join('\n')); initState(project, (current) => { current.tiers['tier-3'].harden = { diff --git a/scripts/test-golden-artifacts.js b/scripts/test-golden-artifacts.js index 69cca8e..0ffb634 100644 --- a/scripts/test-golden-artifacts.js +++ b/scripts/test-golden-artifacts.js @@ -7,7 +7,7 @@ * The premise: the 1500+ tests we have today cover lib/ logic * (validators, linkage, drift) but never assert anything about actual * agent artifacts (PRD.md, ARCH.md, DESIGN.md, ROADMAP.md, STACK - * DECISION.md). If a future change to agents/god-pm.md prompt produces + * DECISION.md). If a future change to specialists/god-pm.md prompt produces * lower-quality PRDs, no test catches it. * * This suite runs the same have-nots / artifact-linter / linkage diff --git a/scripts/test-install-smoke.js b/scripts/test-install-smoke.js index 769347d..b0ee37e 100644 --- a/scripts/test-install-smoke.js +++ b/scripts/test-install-smoke.js @@ -48,7 +48,7 @@ const RUNTIME_SURFACES = { }; function godAgentSourceFiles() { - return fs.readdirSync(path.join(ROOT, 'agents')).filter(f => /^god-.*\.md$/.test(f)); + return fs.readdirSync(path.join(ROOT, 'specialists')).filter(f => /^god-.*\.md$/.test(f)); } console.log('\n Install + init smoke test\n'); @@ -217,6 +217,8 @@ test('installer wrote runtime bundle with lib next to workflow data', () => { assert(fs.existsSync(path.join(runtimeDir, 'lib', 'router.js')), 'runtime lib/router.js missing'); assert(fs.existsSync(path.join(runtimeDir, 'routing', 'god-mode.yaml')), 'runtime routing missing'); assert(fs.existsSync(path.join(runtimeDir, 'workflows', 'full-arc.yaml')), 'runtime workflow missing'); + assert(fs.existsSync(path.join(runtimeDir, 'specialists', 'god-orchestrator.md')), + 'runtime specialist source missing'); assert(fs.existsSync(path.join(runtimeDir, 'package.json')), 'runtime package.json missing'); }); diff --git a/scripts/test-pillars-conformance.js b/scripts/test-pillars-conformance.js new file mode 100644 index 0000000..5c78d01 --- /dev/null +++ b/scripts/test-pillars-conformance.js @@ -0,0 +1,50 @@ +#!/usr/bin/env node +/** + * Execute the Pillars 1.1 portable routing conformance fixtures. + */ + +const fs = require('fs'); +const path = require('path'); + +const { parseSimpleYaml } = require('../lib/intent'); +const pillars = require('../lib/pillars'); +const { test, report, assert } = require('./test-harness'); + +const fixturePath = path.resolve(__dirname, '..', 'tests', 'pillars-conformance', 'fixtures.yaml'); +const fixtureRoot = path.dirname(fixturePath); +const fixture = parseSimpleYaml(fs.readFileSync(fixturePath, 'utf8')); + +function normalized(values) { + return [...values].sort((left, right) => left.localeCompare(right)); +} + +function assertSame(actual, expected, label) { + const left = normalized(actual); + const right = normalized(expected); + assert( + JSON.stringify(left) === JSON.stringify(right), + `${label}: expected ${JSON.stringify(right)}, got ${JSON.stringify(left)}` + ); +} + +console.log('\n Pillars 1.1 conformance tests\n'); + +for (const fixtureCase of fixture.cases || []) { + test(fixtureCase.name, () => { + const projectRoot = path.resolve(fixtureRoot, fixtureCase.project); + const result = pillars.computeLoadSet(projectRoot, fixtureCase.task, { + target: fixtureCase.target + }); + const load = result.loadSet.map((item) => `${item.scopeLabel}::${item.identity}`); + const primaries = result.scopes.flatMap((scope) => + scope.primaries.map((identity) => `${scope.scopeLabel}::${identity}`) + ); + const absent = result.absent.map((item) => `${item.scopeLabel}::${item.pillar}`); + + assertSame(load, fixtureCase.expected.load, 'load'); + assertSame(primaries, fixtureCase.expected.primaries, 'primaries'); + assertSame(absent, fixtureCase.expected.absent, 'absent'); + }); +} + +report(); diff --git a/scripts/test-pillars.js b/scripts/test-pillars.js index ba45696..f0c42c5 100644 --- a/scripts/test-pillars.js +++ b/scripts/test-pillars.js @@ -22,10 +22,10 @@ function write(filePath, content) { console.log('\n Pillars tests\n'); -test('detect does not treat Godpowers specialist agents as pillars', () => { +test('detect keeps specialist source contracts outside the Pillars scope', () => { const tmp = mkTmp(); write(path.join(tmp, 'AGENTS.md'), '# Godpowers\n'); - write(path.join(tmp, 'agents', 'god-pm.md'), `--- + write(path.join(tmp, 'specialists', 'god-pm.md'), `--- name: god-pm description: Product manager agent. --- @@ -62,7 +62,7 @@ test('init creates native Pillars protocol and floor pillars', () => { test('computeLoadSet loads always pillars and task-routed dependencies', () => { const tmp = mkTmp(); - pillars.init(tmp, { corePillars: [] }); + pillars.init(tmp, { corePillars: ['auth'] }); write(path.join(tmp, 'agents', 'auth.md'), `--- pillar: auth status: present @@ -155,6 +155,54 @@ Secrets live in env vars. } }); +test('portable matcher uses contiguous ASCII tokens without substring matches', () => { + assert(pillars.selectorMatches('Apply a schema-change safely', 'Schema change')); + assert(!pillars.selectorMatches('Improve capitalization', 'api')); + assert(!pillars.selectorMatches('Change the schema migration', 'schema change')); +}); + +test('local catalog reports task-relevant absent concerns', () => { + const tmp = mkTmp(); + pillars.init(tmp, { corePillars: [] }); + const load = pillars.computeLoadSet(tmp, 'Add privacy retention and deletion controls'); + assert(load.absent.some((item) => item.pillar === 'privacy'), JSON.stringify(load)); +}); + +test('path-qualified sub-pillars load through hard dependencies', () => { + const tmp = mkTmp(); + pillars.init(tmp, { corePillars: [] }); + write(path.join(tmp, 'agents', 'auth', 'agent-registration.md'), pillars.pillarStub( + 'agent-registration', + { covers: ['agent registration protocol'], triggers: ['agent registration'] }, + { status: 'present', must_read_with: ['auth'] } + )); + write(path.join(tmp, 'agents', 'auth.md'), pillars.pillarStub( + 'auth', + { covers: ['identity and access'], triggers: ['auth'] }, + { status: 'present' } + )); + const listed = pillars.listPillars(tmp); + assert(listed.some((item) => item.identity === 'auth/agent-registration')); + const load = pillars.computeLoadSet(tmp, 'Update the agent registration protocol'); + assert(load.loadSet.some((item) => item.identity === 'auth/agent-registration'), JSON.stringify(load)); + assert(load.loadSet.some((item) => item.identity === 'auth'), JSON.stringify(load)); +}); + +test('nested scopes preserve ancestor always pillars and nearest-scope routing', () => { + const tmp = mkTmp(); + pillars.init(tmp, { corePillars: ['ui'] }); + const child = path.join(tmp, 'packages', 'web'); + pillars.init(child, { corePillars: ['ui'] }); + const load = pillars.computeLoadSet(tmp, 'Update the UI component layout', { + target: 'packages/web/src/page.js' + }); + const labels = load.loadSet.map((item) => `${item.scopeLabel}::${item.identity}`); + assert(labels.includes('root::context'), JSON.stringify(labels)); + assert(labels.includes('packages/web::context'), JSON.stringify(labels)); + assert(labels.includes('root::ui'), JSON.stringify(labels)); + assert(labels.includes('packages/web::ui'), JSON.stringify(labels)); +}); + test('planArtifactSync proposes by default and auto-applies under yolo', () => { const tmp = mkTmp(); pillars.init(tmp, { corePillars: ['arch'] }); diff --git a/scripts/test-planning-systems.js b/scripts/test-planning-systems.js index 3e3d314..577dbf9 100644 --- a/scripts/test-planning-systems.js +++ b/scripts/test-planning-systems.js @@ -80,6 +80,29 @@ test('detect finds Superpowers specs and plans', () => { assert(superpowers.files.some((file) => file.path.includes('plans')), 'plan missing'); }); +test('detect and import preserve Arc-Ready canonical artifact evidence', () => { + const tmp = mkProject(); + write(path.join(tmp, '.arc-ready', 'PROGRESS.md'), '# Progress\n\nCurrent tier: build\n'); + write(path.join(tmp, '.prd-ready', 'PRD.md'), '# PRD\n\n## Acceptance criteria\n'); + write(path.join(tmp, '.architecture-ready', 'ARCH.md'), '# Architecture\n\n## Trust boundaries\n'); + write(path.join(tmp, '.roadmap-ready', 'ROADMAP.md'), '# Roadmap\n\n## Phase 1\n'); + write(path.join(tmp, '.stack-ready', 'STACK.md'), '# Stack\n\n## Runtime\n'); + write(path.join(tmp, '.harden-ready', 'FINDINGS.md'), '# Findings\n\n## Critical\n'); + + const detection = planningSystems.detect(tmp); + const arcReady = detection.systems.find((system) => system.id === 'arc-ready'); + assert(arcReady, 'Arc-Ready not detected'); + assert(arcReady.confidence === 'high', `unexpected confidence: ${arcReady.confidence}`); + assert(arcReady.files.some((file) => file.path === '.prd-ready/PRD.md'), 'Arc-Ready PRD missing'); + + const result = planningSystems.importPlanningContext(tmp, { detection }); + assert(result.writtenArtifacts.includes('prd/PRD.mdx'), 'Arc-Ready PRD seed missing'); + assert(result.writtenArtifacts.includes('arch/ARCH.mdx'), 'Arc-Ready architecture seed missing'); + assert(result.writtenArtifacts.includes('roadmap/ROADMAP.mdx'), 'Arc-Ready roadmap seed missing'); + assert(result.writtenArtifacts.includes('stack/DECISION.mdx'), 'Arc-Ready stack seed missing'); + assert(result.writtenArtifacts.includes('harden/FINDINGS.mdx'), 'Arc-Ready findings seed missing'); +}); + test('importPlanningContext writes prep context and Godpowers seed artifacts', () => { const tmp = mkProject(); write(path.join(tmp, '.planning', 'REQUIREMENTS.md'), '# Requirements\n\n## Login\n'); @@ -142,4 +165,20 @@ test('sourceSync is idempotent', () => { assert(count === 1, `expected one fence, got ${count}`); }); +test('sourceSync writes an Arc-Ready companion without changing canonical artifacts', () => { + const tmp = mkProject(); + const progress = '# Arc-Ready Progress\n\nCanonical progress stays here.\n'; + write(path.join(tmp, '.arc-ready', 'PROGRESS.md'), progress); + write(path.join(tmp, '.prd-ready', 'PRD.md'), '# PRD\n\n## Outcome\n'); + planningSystems.importPlanningContext(tmp); + + const result = sourceSync.run(tmp); + const synced = result.results.find((entry) => entry.system === 'arc-ready'); + assert(synced, 'Arc-Ready sync result missing'); + assert(synced.companion === '.arc-ready/GODPOWERS-SYNC.md', 'wrong Arc-Ready companion'); + assert(synced.pointers.length === 0, 'Arc-Ready must not receive pointer edits'); + assert(fs.readFileSync(path.join(tmp, '.arc-ready', 'PROGRESS.md'), 'utf8') === progress, + 'Arc-Ready canonical progress was changed'); +}); + report(); diff --git a/scripts/test-prepublication-gate.js b/scripts/test-prepublication-gate.js new file mode 100644 index 0000000..8f860cc --- /dev/null +++ b/scripts/test-prepublication-gate.js @@ -0,0 +1,220 @@ +#!/usr/bin/env node + +const fs = require('fs'); +const os = require('os'); +const path = require('path'); + +const gate = require('../lib/prepublication-gate'); +const { test, assert, report } = require('./test-harness'); + +console.log('\n Pre-publication gate tests\n'); + +function project(name = 'godpowers-prepublication-') { + return fs.mkdtempSync(path.join(os.tmpdir(), name)); +} + +function write(root, relPath, content) { + const target = path.join(root, relPath); + fs.mkdirSync(path.dirname(target), { recursive: true }); + fs.writeFileSync(target, content); +} + +function findings(opts = {}) { + const count = opts.count === undefined ? 0 : opts.count; + const launch = opts.launch || (count === 0 ? 'PASSED' : 'BLOCKED'); + const sections = opts.sections || ''; + return [ + '# Security Findings', + '', + '| Severity | Count |', + '|---|---:|', + `| Critical | ${count} |`, + '', + `[DECISION] Launch gate: ${launch}.`, + '', + sections + ].join('\n'); +} + +function ready(root, updated = '2026-07-13T10:00:00.000Z', content = findings()) { + write(root, gate.FINDINGS_FILE, content); + write(root, gate.STATE_FILE, JSON.stringify({ + tiers: { + 'tier-3': { + harden: { status: 'done', updated } + } + } + }, null, 2)); +} + +test('records and verifies a fresh hash-bound pass', () => { + const root = project(); + ready(root); + const recorded = gate.record(root, { now: '2026-07-13T10:00:01.000Z' }); + assert(recorded.verdict === 'pass', JSON.stringify(recorded)); + assert(recorded.hardeningRevision.startsWith('sha256:'), recorded.hardeningRevision); + assert(fs.existsSync(path.join(root, gate.GATE_FILE)), 'gate artifact missing'); + const checked = gate.check(root); + assert(checked.verdict === 'pass', JSON.stringify(checked)); + assert(checked.recordedRevision === checked.hardeningRevision, JSON.stringify(checked)); +}); + +test('invalidates the gate when findings bytes change', () => { + const root = project(); + ready(root); + gate.record(root, { now: '2026-07-13T10:00:01.000Z' }); + fs.appendFileSync(path.join(root, gate.FINDINGS_FILE), '\n[DECISION] A later hardening note changed the reviewed bytes.\n'); + const checked = gate.check(root); + assert(checked.verdict === 'block', JSON.stringify(checked)); + assert(checked.reasons.includes('hardening revision changed after the gate was recorded'), JSON.stringify(checked.reasons)); +}); + +test('invalidates the gate when authoritative hardening state changes', () => { + const root = project(); + ready(root); + gate.record(root, { now: '2026-07-13T10:00:01.000Z' }); + ready(root, '2026-07-13T10:00:02.000Z'); + const checked = gate.check(root); + assert(checked.verdict === 'block', JSON.stringify(checked)); + assert(checked.reasons.includes('authoritative hardening update changed after the gate was recorded'), JSON.stringify(checked.reasons)); + assert(checked.reasons.includes('pre-publication check is not later than the authoritative hardening update'), JSON.stringify(checked.reasons)); +}); + +test('records a blocked artifact when the timestamp is stale', () => { + const root = project(); + ready(root, '2026-07-13T10:00:02.000Z'); + const recorded = gate.record(root, { now: '2026-07-13T10:00:01.000Z' }); + assert(recorded.verdict === 'block', JSON.stringify(recorded)); + assert(recorded.reasons.some(reason => reason.includes('not later')), JSON.stringify(recorded.reasons)); + const parsed = gate.parseGate(fs.readFileSync(path.join(root, gate.GATE_FILE), 'utf8')); + assert(parsed.verdict === 'block', JSON.stringify(parsed)); +}); + +test('blocks unresolved and accepted Critical findings', () => { + const open = gate.parseCriticalFindings(findings({ + count: 1, + sections: '### [CRITICAL-001] Auth bypass\n- **Status**: Open' + })); + assert(open.total === 1 && open.unresolved === 1, JSON.stringify(open)); + + const accepted = gate.parseCriticalFindings(findings({ + count: 1, + launch: 'PASSED', + sections: '### [CRITICAL-001] Auth bypass\n- **Status**: Accepted-Risk' + })); + assert(accepted.accepted === 1 && accepted.unresolved === 1, JSON.stringify(accepted)); + + const root = project(); + ready(root, '2026-07-13T10:00:00.000Z', findings({ + count: 1, + sections: '### [CRITICAL-001] Auth bypass\n- **Status**: Open' + })); + const result = gate.record(root, { now: '2026-07-13T10:00:01.000Z' }); + assert(result.verdict === 'block', JSON.stringify(result)); + assert(result.reasons.some(reason => reason.includes('Critical')), JSON.stringify(result.reasons)); +}); + +test('recognizes fixed Critical entries and YAML finding shape', () => { + const fixed = gate.parseCriticalFindings(findings({ + count: 1, + launch: 'PASSED', + sections: '### [CRITICAL-001] Fixed issue\n- Status: Verified.' + })); + assert(fixed.resolved === 1 && fixed.unresolved === 0, JSON.stringify(fixed)); + + const yaml = gate.parseCriticalFindings('severity: critical\nstatus: resolved\n\nseverity: critical\nstatus: wip\n'); + assert(yaml.total === 2 && yaml.resolved === 1 && yaml.unresolved === 1, JSON.stringify(yaml)); + + const missingEntry = gate.parseCriticalFindings('| Critical | 2 |\n### [CRITICAL-001] One\n- Status: Fixed'); + assert(missingEntry.total === 2 && missingEntry.unresolved === 1, JSON.stringify(missingEntry)); +}); + +test('fails closed on missing, invalid, or incomplete authority', () => { + const missing = project(); + const missingSnapshot = gate.snapshot(missing); + const missingEvaluation = gate.evaluateSnapshot(missingSnapshot); + assert(missingEvaluation.verdict === 'block', JSON.stringify(missingEvaluation)); + assert(missingEvaluation.reasons.some(reason => reason.includes(gate.FINDINGS_FILE)), JSON.stringify(missingEvaluation)); + + const invalid = project(); + write(invalid, gate.FINDINGS_FILE, findings()); + write(invalid, gate.STATE_FILE, '{bad json'); + const invalidResult = gate.check(invalid); + assert(invalidResult.verdict === 'block', JSON.stringify(invalidResult)); + assert(invalidResult.reasons.some(reason => reason.includes(gate.STATE_FILE)), JSON.stringify(invalidResult.reasons)); + + const pending = project(); + ready(pending); + const state = JSON.parse(fs.readFileSync(path.join(pending, gate.STATE_FILE), 'utf8')); + state.tiers['tier-3'].harden.status = 'pending'; + write(pending, gate.STATE_FILE, JSON.stringify(state)); + const pendingResult = gate.record(pending, { now: '2026-07-13T10:00:01.000Z' }); + assert(pendingResult.verdict === 'block', JSON.stringify(pendingResult)); +}); + +test('fails closed on a missing or malformed gate artifact', () => { + const root = project(); + ready(root); + const missing = gate.check(root); + assert(missing.reasons.includes(`missing or invalid ${gate.GATE_FILE}`), JSON.stringify(missing.reasons)); + write(root, gate.GATE_FILE, '# no frontmatter'); + const malformed = gate.check(root); + assert(malformed.verdict === 'block', JSON.stringify(malformed)); + assert(gate.parseGate('not a gate') === null, 'invalid gate should return null'); +}); + +test('parses and renders stable gate artifacts', () => { + const rendered = gate.renderGate({ + checkedAt: '2026-07-13T10:00:01.000Z', + hardeningRevision: gate.sha256('findings'), + hardeningUpdatedAt: null, + criticals: { total: 1, unresolved: 1, accepted: 0 }, + verdict: 'block', + reasons: ['one blocker'] + }); + const parsed = gate.parseGate(rendered); + assert(parsed['schema-version'] === 1, JSON.stringify(parsed)); + assert(parsed.hardening_updated_at === null, JSON.stringify(parsed)); + assert(parsed.critical_unresolved === 1, JSON.stringify(parsed)); + assert(rendered.includes('## Blocking Reasons'), rendered); +}); + +test('renders a concise operator result', () => { + const text = gate.renderResult({ + verdict: 'block', + hardeningRevision: null, + criticals: { unresolved: 2 }, + gateFile: gate.GATE_FILE, + reasons: ['stale revision'] + }); + assert(text.includes('Verdict: block'), text); + assert(text.includes('- stale revision'), text); +}); + +test('parses command arguments and rejects unknown flags', () => { + const first = gate.parseArgs(['node', 'gate', '--record', '--project=/tmp/example', '--json']); + assert(first.mode === 'record' && first.projectRoot === '/tmp/example' && first.json === true, JSON.stringify(first)); + const second = gate.parseArgs(['node', 'gate', '--check', '--project', '/tmp/two']); + assert(second.mode === 'check' && second.projectRoot === '/tmp/two', JSON.stringify(second)); + let message = ''; + try { + gate.parseArgs(['node', 'gate', '--unknown']); + } catch (error) { + message = error.message; + } + assert(message.includes('Unknown argument'), message); +}); + +test('record rejects an invalid checked_at value', () => { + const root = project(); + ready(root); + let message = ''; + try { + gate.record(root, { now: 'not-a-date' }); + } catch (error) { + message = error.message; + } + assert(message.includes('Invalid checked_at'), message); +}); + +report('Pre-publication gate tests'); diff --git a/scripts/test-product-routing.js b/scripts/test-product-routing.js new file mode 100644 index 0000000..0f7c182 --- /dev/null +++ b/scripts/test-product-routing.js @@ -0,0 +1,100 @@ +#!/usr/bin/env node + +const routing = require('../lib/product-routing'); +const { test, assert, report } = require('./test-harness'); + +console.log('\n Product routing tests\n'); + +test('selects CLI or SDK before a secondary public API signal', () => { + const result = routing.selectProductForm('Build a cross-platform CLI tool and TypeScript SDK for our public API.'); + assert(result.status === 'selected', JSON.stringify(result)); + assert(result.form === 'cli-or-sdk', JSON.stringify(result)); + assert(result.evidence.some(item => /cli|sdk/.test(item)), JSON.stringify(result.evidence)); +}); + +test('does not infer web or infrastructure from generic product language', () => { + const result = routing.selectProductForm('Build a useful product platform from this tool and its YAML configuration.'); + assert(result.status === 'undetermined', JSON.stringify(result)); + assert(result.form === null, JSON.stringify(result)); +}); + +test('returns ambiguity instead of silently choosing a tied form', () => { + const result = routing.selectProductForm('The web app calls an API service.'); + assert(result.status === 'ambiguous', JSON.stringify(result)); + assert(result.form === null, JSON.stringify(result)); + assert(result.candidates.length === 2, JSON.stringify(result)); +}); + +test('accepts an explicit form and rejects an unknown explicit form', () => { + const selected = routing.selectProductForm({ form: 'Data or ML', text: 'pipeline' }); + assert(selected.status === 'selected' && selected.form === 'data-or-ml', JSON.stringify(selected)); + const invalid = routing.selectProductForm({ form: 'dashboard-ish', text: 'dashboard' }); + assert(invalid.status === 'invalid' && invalid.form === null, JSON.stringify(invalid)); +}); + +test('form definitions expose form-specific completion evidence', () => { + const definition = routing.formDefinition('api-or-service'); + assert(definition.profiles.includes('API / Microservice'), JSON.stringify(definition)); + assert(definition.completionEvidence.some(item => item.includes('consumer fixture')), JSON.stringify(definition)); + assert(routing.formDefinition('missing') === null, 'unknown form should be null'); +}); + +test('composes the four axes in form-first order without averaging stack profiles', () => { + const result = routing.composeDomain({ + form: 'web-application', + archetype: ['saas', 'saas'], + industry: 'research-lab-lims', + regulatory: ['healthcare-clinical', 'healthcare-clinical'] + }); + assert(Object.keys(result.axes).join(',') === 'form,archetype,industry,regulatory', JSON.stringify(result.axes)); + assert(result.axes.form === 'web-application', JSON.stringify(result.axes)); + assert(result.axes.archetype.length === 1, JSON.stringify(result.axes)); + assert(result.stackComposition.primary === 'SaaS / Multi-tenant', JSON.stringify(result.stackComposition)); + assert(result.stackComposition.secondaryConstraints.includes('Internal Tools / Back-office'), JSON.stringify(result.stackComposition)); + assert(result.stackComposition.rule.includes('hard constraints'), result.stackComposition.rule); +}); + +test('uses an industry stack when no archetype mapping exists', () => { + const result = routing.composeDomain({ form: 'api-or-service', industry: 'financial-fintech-accounting' }); + assert(result.stackComposition.primary === 'Fintech / Financial', JSON.stringify(result.stackComposition)); + assert(result.axes.archetype.length === 0 && result.axes.regulatory.length === 0, JSON.stringify(result.axes)); +}); + +test('allows an evidenced route with no mapped stack profile', () => { + const result = routing.composeDomain({ form: 'mobile-or-desktop', archetype: 'custom', industry: 'custom-sector' }); + assert(result.stackComposition.primary === null, JSON.stringify(result.stackComposition)); + assert(result.stackComposition.secondaryConstraints.length === 0, JSON.stringify(result.stackComposition)); +}); + +test('rejects domain composition before product-form selection', () => { + let message = ''; + try { + routing.composeDomain({ archetype: 'saas' }); + } catch (error) { + message = error.message; + } + assert(message.includes('Unknown or missing product form'), message); +}); + +test('renders an ordered route for specialist handoff', () => { + const result = routing.composeDomain({ form: 'infrastructure-or-iac', industry: [] }); + const text = routing.renderRoute(result); + assert(text.startsWith('Product form: Infrastructure or IaC'), text); + assert(text.includes('Product archetype: none evidenced'), text); + assert(text.includes('Completion evidence:\n- formatting and static validation pass'), text); + let threw = false; + try { + routing.renderRoute({}); + } catch (_error) { + threw = true; + } + assert(threw, 'render should reject an uncomposed route'); +}); + +test('the catalog defines six distinct product forms', () => { + assert(routing.FORM_DEFINITIONS.length === 6, JSON.stringify(routing.FORM_DEFINITIONS.map(item => item.id))); + assert(Object.keys(routing.ARCHETYPE_STACKS).length >= 8, 'archetype stack mappings missing'); + assert(Object.keys(routing.INDUSTRY_STACKS).length >= 10, 'industry stack mappings missing'); +}); + +report('Product routing tests'); diff --git a/scripts/test-repo-doc-sync.js b/scripts/test-repo-doc-sync.js index 6cd6563..2e9cc1a 100644 --- a/scripts/test-repo-doc-sync.js +++ b/scripts/test-repo-doc-sync.js @@ -31,8 +31,8 @@ function mkFixture() { }, null, 2)); writeRel(tmp, 'skills/god-one.md', '# one\n'); writeRel(tmp, 'skills/god-two.md', '# two\n'); - writeRel(tmp, 'agents/god-alpha.md', '# alpha\n'); - writeRel(tmp, 'agents/god-beta.md', '# beta\n'); + writeRel(tmp, 'specialists/god-alpha.md', '# alpha\n'); + writeRel(tmp, 'specialists/god-beta.md', '# beta\n'); writeRel(tmp, 'workflows/full.yaml', 'name: full\n'); writeRel(tmp, 'routing/recipes/green.yaml', 'name: green\n'); writeRel(tmp, 'README.md', diff --git a/scripts/test-repo-surface-sync.js b/scripts/test-repo-surface-sync.js index 9cc40bc..e710a73 100644 --- a/scripts/test-repo-surface-sync.js +++ b/scripts/test-repo-surface-sync.js @@ -27,7 +27,7 @@ function fixture() { writeRel(tmp, 'package.json', JSON.stringify({ name: 'godpowers', version: '7.0.0', - files: ['bin/', 'skills/', 'agents/god-*.md', 'routing/', 'workflows/', 'schema/', 'lib/', 'extensions/', 'RELEASE.md', 'SKILL.md', 'AGENTS.md', 'CHANGELOG.md', 'LICENSE'], + files: ['bin/', 'skills/', 'specialists/', 'routing/', 'workflows/', 'schema/', 'lib/', 'extensions/', 'RELEASE.md', 'SKILL.md', 'AGENTS.md', 'CHANGELOG.md', 'LICENSE'], scripts: { test: 'node scripts/test-repo-surface-sync.js' } }, null, 2)); writeRel(tmp, 'package-lock.json', JSON.stringify({ name: 'godpowers', version: '7.0.0' }, null, 2)); @@ -37,7 +37,7 @@ function fixture() { writeRel(tmp, 'skills/god-beta.md', '---\nname: god-beta\ndescription: |\n Triggers on: beta\n---\n# beta\n'); writeRel(tmp, 'routing/god-alpha.yaml', 'apiVersion: godpowers/v1\nkind: CommandRouting\nmetadata:\n command: /god-alpha\nexecution:\n spawns: [god-missing]\n'); - writeRel(tmp, 'agents/god-alpha-agent.md', '---\nname: god-alpha-agent\ndescription: x\ntools: Read\n---\n'); + writeRel(tmp, 'specialists/god-alpha-agent.md', '---\nname: god-alpha-agent\ndescription: x\ntools: Read\n---\n'); writeRel(tmp, 'docs/agent-specs.md', 'god-alpha-agent\n'); writeRel(tmp, 'workflows/full-arc.yaml', 'apiVersion: godpowers/v1\nname: full-arc\n'); writeRel(tmp, 'routing/recipes/demo.yaml', 'apiVersion: godpowers/v1\ncommands:\n - /god-alpha\n'); diff --git a/scripts/test-self-project-truth.js b/scripts/test-self-project-truth.js index 111e200..d751f0a 100644 --- a/scripts/test-self-project-truth.js +++ b/scripts/test-self-project-truth.js @@ -16,7 +16,7 @@ function validProject() { })); writeRel(root, 'skills/god.md', 'one'); writeRel(root, 'skills/god-mode.md', 'two'); - writeRel(root, 'agents/god-orchestrator.md', 'agent'); + writeRel(root, 'specialists/god-orchestrator.md', 'agent'); writeRel(root, 'workflows/full.yaml', 'name: full'); writeRel(root, 'routing/recipes/start.yaml', 'name: start'); const counts = '2 slash commands, 1 agents, 1 workflows, 1 recipes'; diff --git a/scripts/test-sibling-artifacts.js b/scripts/test-sibling-artifacts.js index a9ed7b3..27cad49 100644 --- a/scripts/test-sibling-artifacts.js +++ b/scripts/test-sibling-artifacts.js @@ -1185,7 +1185,7 @@ test('IMPORTED-CONTEXT enumeration covers godplans/godaudits when nothing found' state.init(tmp, 'sibling-empty-test'); planningSystems.importPlanningContext(tmp); const imported = fs.readFileSync(path.join(tmp, '.godpowers', 'prep', 'IMPORTED-CONTEXT.mdx'), 'utf8'); - assert(imported.includes('No legacy planning, BMAD, Superpowers, godplans, or godaudits planning context was detected.'), + assert(imported.includes('No legacy planning, BMAD, Superpowers, Arc-Ready, godplans, or godaudits planning context was detected.'), 'updated enumeration string missing'); assert(imported.includes('No godplans master plan was detected.'), 'plan absence line missing'); }); diff --git a/scripts/test-voice-lint.js b/scripts/test-voice-lint.js index 351b9bc..a333447 100644 --- a/scripts/test-voice-lint.js +++ b/scripts/test-voice-lint.js @@ -81,9 +81,9 @@ test('U-14 is registered as a universal check', () => { assert(validator.UNIVERSAL_CHECKS.some((c) => c.code === 'U-14'), 'U-14 in UNIVERSAL_CHECKS'); }); -test('shipped skill and agent prose is already clean (self-dogfood)', () => { +test('shipped skill, specialist, and Pillars prose is already clean (self-dogfood)', () => { const offenders = []; - for (const dir of ['skills', 'agents']) { + for (const dir of ['skills', 'specialists', 'agents']) { const base = path.join(ROOT, dir); for (const file of fs.readdirSync(base).filter((name) => name.endsWith('.md'))) { for (const hit of voiceLint.scan(fs.readFileSync(path.join(base, file), 'utf8'))) { diff --git a/scripts/validate-official-skill.js b/scripts/validate-official-skill.js new file mode 100644 index 0000000..d670e6d --- /dev/null +++ b/scripts/validate-official-skill.js @@ -0,0 +1,24 @@ +#!/usr/bin/env node +/** + * Run the pinned official Agent Skills validator against this repository. + */ + +const path = require('path'); +const { spawnSync } = require('child_process'); + +const projectRoot = path.resolve(__dirname, '..'); +const executable = process.env.SKILLS_REF_BIN || 'skills-ref'; +const result = spawnSync(executable, ['validate', projectRoot], { + cwd: projectRoot, + encoding: 'utf8', + stdio: 'inherit' +}); + +if (result.error) { + console.error('Official Agent Skills validator is required for release checks.'); + console.error('Install requirements/skills-ref.txt in an isolated Python environment,'); + console.error('then set SKILLS_REF_BIN to that environment skills-ref executable.'); + process.exit(1); +} + +process.exit(result.status || 0); diff --git a/skills/god-agent-audit.md b/skills/god-agent-audit.md index 94fe138..3c58261 100644 --- a/skills/god-agent-audit.md +++ b/skills/god-agent-audit.md @@ -1,7 +1,7 @@ --- name: god-agent-audit description: | - Validates every `agents/god-*.md` against the agent contract: + Validates every `specialists/god-*.md` source contract: required frontmatter, structured contract frontmatter, recommended sections (Have-Nots, Inputs, Outputs, Handoff), hand-off targets exist, no dual-ownership of output paths. Lenient by design: most issues are diff --git a/skills/god-build.md b/skills/god-build.md index fb6cae5..c8946df 100644 --- a/skills/god-build.md +++ b/skills/god-build.md @@ -23,6 +23,10 @@ Orchestrate the build via specialist agents. `lib/pillars.computeLoadSet(projectRoot, taskText)`. Always load `agents/context.md` and `agents/repo.md`, then pass only task-relevant pillars into each planner or executor context. +4. Load `references/building/PRODUCT-FORM-ROUTER.md` and the ordered product + route from PRD or Architecture. Select one primary form before domain + overlays and pass its vertical-slice definition plus completion evidence to + the planner, executors, and both reviewers. ## Orchestration @@ -80,8 +84,13 @@ After all waves: 5. Record the exact verification commands that passed in `.godpowers/state.json` under `tiers.tier-2.build.verification.commands` 6. Run `npx godpowers gate --tier=build --project=.` and do not proceed on a non-zero exit -7. Run `npx godpowers state advance --step=build --status=done --project=.` to update `state.json` and regenerate `.godpowers/PROGRESS.mdx` plus `.godpowers/build/STATE.mdx`. -8. If the build plan or implementation establishes durable conventions, plan +7. Verify the primary form's completion evidence. A generic test pass cannot + replace a clean consumer install for CLI or SDK, contract evidence for API, + browser and accessibility evidence for web, platform evidence for mobile or + desktop, reproducibility and lineage for data or ML, or plan, policy, + simulation, and rollback evidence for infrastructure or IaC. +8. Run `npx godpowers state advance --step=build --status=done --project=.` to update `state.json` and regenerate `.godpowers/PROGRESS.mdx` plus `.godpowers/build/STATE.mdx`. +9. If the build plan or implementation establishes durable conventions, plan pillar updates through `lib/pillars.planArtifactSync`. Under `/god-mode --yolo`, apply those updates immediately and log the decision. diff --git a/skills/god-design.md b/skills/god-design.md index 3156c0b..de1234c 100644 --- a/skills/god-design.md +++ b/skills/god-design.md @@ -242,8 +242,8 @@ vendored. If SkillUI isn't installed, the bridge returns - `lib/design-spec.js` - Google Labs format parser and linter - `lib/impeccable-bridge.js` - command dispatch layer - `lib/awesome-design.js` - 71-site catalog + lookup + fetch -- `agents/god-designer.md` - lifecycle owner -- `agents/god-design-reviewer.md` - two-stage review gate +- `specialists/god-designer.md` - lifecycle owner +- `specialists/god-design-reviewer.md` - two-stage review gate - `references/design/DESIGN-ANATOMY.md` - what good DESIGN.md looks like - `references/design/DESIGN-ANTIPATTERNS.md` - what to avoid - [awesome-design-md](https://github.com/VoltAgent/awesome-design-md) - upstream catalog diff --git a/skills/god-harden.md b/skills/god-harden.md index 3883a7c..84c16c3 100644 --- a/skills/god-harden.md +++ b/skills/god-harden.md @@ -14,18 +14,28 @@ Spawn the **god-harden-auditor** agent in a fresh context via the host platform' ## Setup 1. Verify build is complete through `.godpowers/state.json` `tier-2.build.status == done`. -2. Spawn god-harden-auditor with full code access. -3. The agent writes `.godpowers/harden/FINDINGS.mdx`. +2. Read `references/shipping/HARDEN-OWASP-2025-ROUTER.md` and + `references/shipping/HARDEN-OWASP-WORKSHEETS.md`. Use the current 2025 + category order, including supply-chain failures and mishandling of + exceptional conditions. SSRF is covered within A01:2025. +3. Spawn god-harden-auditor with full code access and the selected product + form. Adapt manual boundaries for non-web forms without renaming the ten + current categories. +4. The agent writes `.godpowers/harden/FINDINGS.mdx` with one reproducible + procedure, observed result, evidence or finding link, reviewer, and + timestamp for every category. Scanner output alone cannot close a row. ## Verification After god-harden-auditor returns: 1. Verify FINDINGS.md exists on disk -2. Record the executed security check as evidence so the gate has a passing +2. Treat every existing `.godpowers/launch/PREPUBLICATION.mdx` as invalid + until the hash-bound gate is recorded again after this hardening update. +3. Record the executed security check as evidence so the gate has a passing verification record, for example: `npx godpowers verify "npm audit --omit=dev" --substep tier-3.harden --claim "dependency audit clean" --project=.` -3. Run `npx godpowers gate --tier=harden --project=.` and do not proceed on a non-zero exit -4. Read findings classification: +4. Run `npx godpowers gate --tier=harden --project=.` and do not proceed on a non-zero exit +5. Read findings classification: - If any Critical: run `npx godpowers state advance --step=harden --status=failed --project=.` and keep launch BLOCKED - If only High/Medium/Low: run `npx godpowers state advance --step=harden --status=done --project=.` @@ -33,6 +43,7 @@ After god-harden-auditor returns: Hardening FAILS if: - Only automated scanner output, no manual review +- Any OWASP Web Top 10:2025 row lacks a reproducible manual procedure and result - Auth boundaries not tested (just code-read) - No input validation audit - Rate limiting not verified @@ -46,7 +57,10 @@ If ANY finding is Critical: 2. Present finding to user using pause format 3. Launch remains BLOCKED until: - Critical finding is fixed and re-verified, OR - - User explicitly accepts the risk in writing + - Public activation is removed from scope + +The hash-bound pre-publication gate does not treat accepted risk as a passing +Critical. Resolve and re-verify the finding before public activation. ## On Completion diff --git a/skills/god-launch.md b/skills/god-launch.md index 43d5cd1..130a962 100644 --- a/skills/god-launch.md +++ b/skills/god-launch.md @@ -13,11 +13,22 @@ Spawn the **god-launch-strategist** agent in a fresh context via the host platfo ## Setup -1. Verify `.godpowers/harden/FINDINGS.mdx` exists with NO unresolved Critical findings. -2. If Critical findings exist: REFUSE to proceed. Tell user to resolve or - explicitly accept the risk first. +1. Verify `.godpowers/harden/FINDINGS.mdx` exists with NO unresolved or + accepted Critical findings. +2. If Critical findings exist, REFUSE public activation. Launch asset work may + remain complete, but a Critical must be resolved and re-verified or public + activation must be removed from scope. 3. Spawn god-launch-strategist with PRD path and harden FINDINGS.md path. 4. The agent returns structured launch evidence for `.godpowers/state.json` plus landing copy artifacts; the generated `.godpowers/launch/STATE.mdx` view refreshes after state mutation. +5. Immediately before any public release action, run: + `node /lib/prepublication-gate.js --record --project=.` + followed by: + `node /lib/prepublication-gate.js --check --project=.` + The first command records `.godpowers/launch/PREPUBLICATION.mdx` against the + exact hardening findings hash and authoritative hardening update. The second + command must pass in the same release attempt. +6. If hardening changes after the record, the revision or timestamp check + fails. Re-run hardening as needed, then record and check a fresh gate. ## Verification @@ -29,7 +40,9 @@ After god-launch-strategist returns: - launch target is live and smoke checked - local launch-readiness harness passed and external access bundle is the only missing item -5. Run `npx godpowers state advance --step=launch --status=done --project=.` +5. For public activation, verify the pre-publication gate after every other + release-readiness check and immediately before the external write. +6. Run `npx godpowers state advance --step=launch --status=done --project=.` only when live launch or explicit local launch-readiness scope is complete. If external access is missing, record the waiting artifact path in launch state through the owning command wrapper rather than editing the generated diff --git a/skills/god-migrate.md b/skills/god-migrate.md index 1407ecc..be1c0cb 100644 --- a/skills/god-migrate.md +++ b/skills/god-migrate.md @@ -1,13 +1,14 @@ --- name: god-migrate description: | - Detect legacy planning, BMAD, Superpowers, godplans, and godaudits planning + Detect legacy planning, BMAD, Superpowers, Arc-Ready, godplans, and godaudits planning systems, migrate useful context into Godpowers prep and seed artifacts, and sync Godpowers progress back to the prior system through managed companion files. Triggers on: "god migrate", "/god-migrate", "migrate from legacy-planning", "migrate from bmad", "migrate from superpowers", "migrate from godplans", + "migrate from arc-ready", "sync back to arc-ready", "import the plan", "import the audit", "sync back to legacy-planning", "sync back to bmad", "sync back to superpowers", "sync back to godplans", "sync back to godaudits" @@ -23,6 +24,8 @@ Detect and migrate adjacent planning systems into Godpowers. - A project already has BMAD `_bmad/`, `_bmad-output/`, `.bmad-core/`, or `.bmad/` context. - A project already has Superpowers specs, plans, or project-local skills. +- A project already has Arc-Ready canonical artifacts such as + `.arc-ready/PROGRESS.md`, `.prd-ready/PRD.md`, or `.architecture-ready/ARCH.md`. - A project already has a Godplans master plan at `.godplans/PLAN.mdx`, with `.godplans/validate-plan.sh` for a complete Godplans 1.1 emission. - A project already has canonical godaudits state at `.godaudits/AUDIT.json` @@ -34,7 +37,7 @@ Detect and migrate adjacent planning systems into Godpowers. ## Auto-Invoke Contract `/god-init` auto-invokes the import path when it detects legacy planning, BMAD, -Superpowers, godplans, or godaudits context. It shows this concise note when +Superpowers, Arc-Ready, godplans, or godaudits context. It shows this concise note when import writes happen: ``` @@ -73,7 +76,7 @@ lib/planning-systems.importPlanningContext(projectRoot, { ``` This: -- detects legacy planning, BMAD, Superpowers, godplans, and godaudits sources +- detects legacy planning, BMAD, Superpowers, Arc-Ready, godplans, and godaudits sources - writes `.godpowers/prep/IMPORTED-CONTEXT.mdx` - writes missing Godpowers seed artifacts when enough source evidence exists - marks those seed artifacts as `imported` in `state.json` @@ -120,12 +123,15 @@ This: | legacy planning variant | `.legacy-planning/` files | prep context and seeds when source files are readable | `.legacy-planning/GODPOWERS-SYNC.md` | | BMAD | `_bmad-output/planning-artifacts/PRD.md`, `architecture.md`, epics, stories, sprint status | prep context, PRD seed, arch seed, roadmap seed | `_bmad-output/GODPOWERS-SYNC.md` | | Superpowers | `docs/superpowers/specs/*.md`, `docs/superpowers/plans/*.md`, project-local skills | prep context, PRD seed, roadmap seed, build-state seed | `docs/superpowers/GODPOWERS-SYNC.md` | +| Arc-Ready | `.arc-ready/PROGRESS.md` and canonical `.*-ready/*.md` tier artifacts | prep context plus matching PRD, architecture, roadmap, stack, build-state, and harden seeds | `.arc-ready/GODPOWERS-SYNC.md` | | godplans | `.godplans/PLAN.mdx` plus executable `.godplans/validate-plan.sh` for 1.1 | prep context, PRD seed, arch seed, roadmap seed, stack seed, `.godpowers/prep/IMPORTED-BUILD-STATE.mdx` (all applicable GP task ids, lifecycle fields, Verify commands, and R ids preserved) | `.godplans/GODPOWERS-SYNC.mdx` | | godaudits | `.godaudits/AUDIT.json` (legacy `.godaudits/AUDIT.mdx` fallback) | prep context, harden/FINDINGS seed, compiled coverage, open GA remediation tasks routed to todos/backlog with Verify commands preserved | `.godaudits/GODPOWERS-SYNC.mdx` | ## Guardrails -- Do not delete, move, or rewrite legacy planning, BMAD, or Superpowers files. +- Do not delete, move, or rewrite legacy planning, BMAD, Superpowers, or Arc-Ready files. +- Arc-Ready canonical artifacts are read-only. Godpowers writes only + `.arc-ready/GODPOWERS-SYNC.md` for sync-back. - `.godplans/` and `.godaudits/` artifacts are read-only for Godpowers except when Godpowers executes plan or audit tasks. A godaudits 2.x completion updates reciprocal state in AUDIT.json, validates with `--write`, and diff --git a/skills/god-prd.md b/skills/god-prd.md index 606fdb7..d8f3fe4 100644 --- a/skills/god-prd.md +++ b/skills/god-prd.md @@ -16,13 +16,22 @@ Spawn the **god-pm** agent in a fresh context via the host platform's native age 1. If `.godpowers/state.json` does not exist: tell the user to run `/god-init` first. 2. Read `.godpowers/prep/INITIAL-FINDINGS.mdx` if present. 3. Read `.godpowers/prep/IMPORTED-CONTEXT.mdx` if present. -4. Spawn god-pm with the user's project description from `state.json`, +4. Select the primary product form before applying domain assumptions. Use + `lib/product-routing.selectProductForm` with the durable intent, then load + `references/building/PRODUCT-FORM-ROUTER.md` and + `references/building/DOMAIN-COMPOSITION-REGISTRY.md`. If the result is + ambiguous, record an open question instead of defaulting to a web app. +5. Compose the route in this order: product form, product archetype, industry + overlay, regulatory overlay. Record an explicit none-evidenced value for an + empty axis and verify freshness-sensitive regulatory claims. +6. Spawn god-pm with the user's project description from `state.json`, `.godpowers/intent.yaml`, and any prep artifacts. Prep artifacts are - context, not source of truth. -5. The agent writes `.godpowers/prd/PRD.mdx` -6. The agent runs have-nots checks before declaring done -7. If god-pm pauses for a human question: relay to user using pause format -8. If prep artifacts or the PRD show UI or product-experience signals, route + context, not source of truth. Include the ordered product route and the + selected form-specific completion evidence. +7. The agent writes `.godpowers/prd/PRD.mdx` +8. The agent runs have-nots checks before declaring done +9. If god-pm pauses for a human question: relay to user using pause format +10. If prep artifacts or the PRD show UI or product-experience signals, route to `/god-design` next so DESIGN.md can shape architecture. Otherwise route to `/god-arch`. diff --git a/skills/god-stack.md b/skills/god-stack.md index 3fbc7e0..e0c29b8 100644 --- a/skills/god-stack.md +++ b/skills/god-stack.md @@ -14,8 +14,16 @@ Spawn the **god-stack-selector** agent in a fresh context via the host platform' ## Setup 1. Verify `.godpowers/arch/ARCH.mdx` exists. If not, tell user to run `/god-arch` first. -2. Spawn god-stack-selector with the ARCH path. -3. The agent writes `.godpowers/stack/DECISION.mdx`. +2. Read the product route recorded by PRD or Architecture. If absent, select + the product form before applying archetype, industry, or regulatory + guidance through `lib/product-routing`. +3. Load `references/building/DOMAIN-COMPOSITION-REGISTRY.md`. Score the primary + stack profile first, then add only hard constraints from secondary + profiles. Do not average complete profile matrices. +4. Verify current regulatory obligations and provider capabilities before + making a freshness-sensitive commitment. +5. Spawn god-stack-selector with the ARCH path and ordered product route. +6. The agent writes `.godpowers/stack/DECISION.mdx`. ## Verification diff --git a/skills/god-test-runtime.md b/skills/god-test-runtime.md index dbb298b..237f0d4 100644 --- a/skills/god-test-runtime.md +++ b/skills/god-test-runtime.md @@ -163,4 +163,4 @@ Headless launch only (`headless: true` enforced by bridge). - `lib/agent-browser-driver.js` - vercel-labs/agent-browser CLI wrapper - `lib/runtime-audit.js` - design verification on rendered DOM (backend-aware) - `lib/runtime-test.js` - PRD acceptance to user-flow assertions (backend-aware) -- `agents/god-browser-tester.md` - lifecycle owner of runtime checks +- `specialists/god-browser-tester.md` - lifecycle owner of runtime checks diff --git a/agents/god-archaeologist.md b/specialists/god-archaeologist.md similarity index 100% rename from agents/god-archaeologist.md rename to specialists/god-archaeologist.md diff --git a/agents/god-architect.md b/specialists/god-architect.md similarity index 100% rename from agents/god-architect.md rename to specialists/god-architect.md diff --git a/agents/god-auditor.md b/specialists/god-auditor.md similarity index 100% rename from agents/god-auditor.md rename to specialists/god-auditor.md diff --git a/agents/god-automation-engineer.md b/specialists/god-automation-engineer.md similarity index 100% rename from agents/god-automation-engineer.md rename to specialists/god-automation-engineer.md diff --git a/agents/god-browser-tester.md b/specialists/god-browser-tester.md similarity index 100% rename from agents/god-browser-tester.md rename to specialists/god-browser-tester.md diff --git a/agents/god-context-writer.md b/specialists/god-context-writer.md similarity index 100% rename from agents/god-context-writer.md rename to specialists/god-context-writer.md diff --git a/agents/god-coordinator.md b/specialists/god-coordinator.md similarity index 100% rename from agents/god-coordinator.md rename to specialists/god-coordinator.md diff --git a/agents/god-debt-assessor.md b/specialists/god-debt-assessor.md similarity index 100% rename from agents/god-debt-assessor.md rename to specialists/god-debt-assessor.md diff --git a/agents/god-debugger.md b/specialists/god-debugger.md similarity index 100% rename from agents/god-debugger.md rename to specialists/god-debugger.md diff --git a/agents/god-deploy-engineer.md b/specialists/god-deploy-engineer.md similarity index 100% rename from agents/god-deploy-engineer.md rename to specialists/god-deploy-engineer.md diff --git a/agents/god-deps-auditor.md b/specialists/god-deps-auditor.md similarity index 100% rename from agents/god-deps-auditor.md rename to specialists/god-deps-auditor.md diff --git a/agents/god-design-reviewer.md b/specialists/god-design-reviewer.md similarity index 100% rename from agents/god-design-reviewer.md rename to specialists/god-design-reviewer.md diff --git a/agents/god-designer.md b/specialists/god-designer.md similarity index 100% rename from agents/god-designer.md rename to specialists/god-designer.md diff --git a/agents/god-docs-writer.md b/specialists/god-docs-writer.md similarity index 100% rename from agents/god-docs-writer.md rename to specialists/god-docs-writer.md diff --git a/agents/god-executor.md b/specialists/god-executor.md similarity index 100% rename from agents/god-executor.md rename to specialists/god-executor.md diff --git a/agents/god-explorer.md b/specialists/god-explorer.md similarity index 100% rename from agents/god-explorer.md rename to specialists/god-explorer.md diff --git a/agents/god-greenfieldifier.md b/specialists/god-greenfieldifier.md similarity index 100% rename from agents/god-greenfieldifier.md rename to specialists/god-greenfieldifier.md diff --git a/specialists/god-harden-auditor.md b/specialists/god-harden-auditor.md new file mode 100644 index 0000000..fb0d24b --- /dev/null +++ b/specialists/god-harden-auditor.md @@ -0,0 +1,178 @@ +--- +name: god-harden-auditor +description: | + Adversarial security reviewer. Manual OWASP Web Top 10:2025 walkthrough, auth boundary + verification, input validation audit, dependency vulnerability scan, + rate-limiting check. Critical findings BLOCK launch. + + Spawned by: /god-harden, god-orchestrator +tools: Read, Bash, Grep, Glob, WebSearch +inputs: + - "codebase" + - ".godpowers/state.json deploy evidence" + - "optional org security standards" + - "selected product form and domain composition" + - "references/shipping/HARDEN-OWASP-2025-ROUTER.md" + - "references/shipping/HARDEN-OWASP-WORKSHEETS.md" + - "references/shipping/HARDEN-ANTIPATTERNS.md" +outputs: + - ".godpowers/harden/FINDINGS.mdx" +gates: + - "H-01 through H-11 have-nots" + - "unresolved or accepted Critical findings block public activation" + - "manual evidence for all ten 2025 categories" +handoff: + - "return security findings and block launch on unresolved Critical issues" +--- + +# God Harden Auditor + +Adversarial security review. Not a scanner run. A manual walkthrough of how +the application can be broken. + +## Gate Check + +Build is complete. Code is in the repo. + +## Process + +Before reviewing, read `references/shipping/HARDEN-OWASP-2025-ROUTER.md`, +`references/shipping/HARDEN-OWASP-WORKSHEETS.md` (the per-category worksheets +for the walkthrough below), and +`references/shipping/HARDEN-ANTIPATTERNS.md` (failure patterns to avoid). +Read the selected product form and adapt the test boundary for non-web forms +without changing the current category names. + +### 1. OWASP Web Top 10:2025 Manual Walkthrough + +For each category, review code and execute a reproducible manual probe or fault +injection. Record the exact procedure, observed result, evidence location, and +finding link or project-specific Not Applicable justification. Scanner output +alone cannot close a row. + +1. **A01:2025 Broken Access Control** + - Probe object, function, tenant, and administrative authorization. + - Probe SSRF and internal-resource access where user-controlled URLs exist. + +2. **A02:2025 Security Misconfiguration** + - Exercise application, framework, cloud, CORS, error, default, and debug configuration. + +3. **A03:2025 Software Supply Chain Failures** + - Verify dependency provenance, CI identities, build isolation, artifact integrity, signing or provenance, and package substitution defenses. + +4. **A04:2025 Cryptographic Failures** + - Verify current algorithms, key lifecycle, nonce or IV handling, password hashing, random generation, and transport policy. + +5. **A05:2025 Injection** + - Trace untrusted input through every interpreter and output context, then probe malformed and encoded payloads through the real boundary. + +6. **A06:2025 Insecure Design** + - Exercise threat scenarios, abuse cases, rate limits, step-up controls, race conditions, and secure defaults against deployed design. + +7. **A07:2025 Authentication Failures** + - Probe credentials, sessions, MFA, recovery, token rotation and revocation, enumeration, and throttling. + +8. **A08:2025 Software or Data Integrity Failures** + - Probe integrity boundaries for code, software, data, updates, webhooks, and serialized content. + +9. **A09:2025 Security Logging and Alerting Failures** + - Trigger a controlled suspicious event and exercise detection, alert delivery, ownership, and response. + +10. **A10:2025 Mishandling of Exceptional Conditions** + - Inject timeouts, malformed responses, partial writes, duplicate delivery, resource exhaustion, invalid transitions, and rollback or restart failure where applicable. + - Require secure failure, bounded resource use, no unauthorized transition, no sensitive leakage, recoverability, and an operator-visible alert. + +### 2. Classification + +For each finding: + +| Severity | Definition | Launch Impact | +|----------|-----------|---------------| +| **Critical** | Exploitable now, data loss or unauthorized access | BLOCKS LAUNCH | +| **High** | Exploitable with moderate effort | Should fix before launch | +| **Medium** | Defense-in-depth gap | Fix in first sprint post-launch | +| **Low** | Best practice improvement | Backlog | + +## Output + +Use `templates/HARDEN-FINDINGS.mdx` (installed at +`/godpowers-templates/HARDEN-FINDINGS.mdx`) as the structural starting +point. Write `.godpowers/harden/FINDINGS.mdx`: + +```markdown +# Security Findings + +Date: [timestamp] +Reviewer: god-harden-auditor + +## Summary +| Severity | Count | +|----------|-------| +| Critical | N | +| High | N | +| Medium | N | +| Low | N | + +Launch gate: PASSED / BLOCKED + +## Findings + +## OWASP Web Top 10:2025 Coverage + +| Category | Manual procedure | Result | Evidence or finding | +|---|---|---|---| +| A01:2025 through A10:2025 | one row per category | pass, fail, or justified Not Applicable | exact artifact, log, command, or finding | + +### [CRITICAL-001] [Title] +- **Category**: OWASP A01:2025 +- **Location**: src/api/users.ts:45 +- **Description**: ... +- **Impact**: ... +- **Reproduction**: ... +- **Observed Result**: ... +- **Evidence**: ... +- **Reviewed At**: ... +- **Remediation Options**: + - Option A: [time estimate] + - Option B: [time estimate] +``` + +## Critical-Finding Gate + +If ANY finding is Critical: +- `.godpowers/harden/FINDINGS.mdx` declares launch BLOCKED +- Return to orchestrator: it MUST pause for human resolution +- Launch agent must refuse public activation +- Existing `.godpowers/launch/PREPUBLICATION.mdx` is stale until a fresh + hash-bound gate is recorded after the finding is resolved and re-verified + +## YOLO Handling (special rules) + +god-harden-auditor has a UNIQUE --yolo rule: + +**Critical findings are the ONE pause that --yolo CANNOT auto-resolve.** + +Even with --yolo: +- High/Medium/Low findings are documented and the build moves on +- Critical findings BLOCK launch and force the orchestrator to pause + +Rationale: shipping with a known Critical security vulnerability is a category +of risk that should never be auto-accepted. The `--yolo` flag means "I trust +the system's defaults"; it does NOT mean "I accept unknown security risk +without seeing it". + +If invoked with --yolo and Critical findings exist: +- Write FINDINGS.md as normal +- Mark launch gate as BLOCKED in the file +- Return a clear "PAUSE REQUIRED: Critical findings present" signal to + orchestrator +- The orchestrator will then pause regardless of --yolo + +## Have-Nots + +- Only scanner output, no manual review +- Any 2025 category lacks a reproducible manual procedure and result +- Auth boundaries not actually tested +- No input validation audit +- Findings have no severity classification +- Critical finding without remediation options diff --git a/agents/god-incident-investigator.md b/specialists/god-incident-investigator.md similarity index 100% rename from agents/god-incident-investigator.md rename to specialists/god-incident-investigator.md diff --git a/agents/god-launch-strategist.md b/specialists/god-launch-strategist.md similarity index 82% rename from agents/god-launch-strategist.md rename to specialists/god-launch-strategist.md index 5b45ee5..9c1d3d3 100644 --- a/agents/god-launch-strategist.md +++ b/specialists/god-launch-strategist.md @@ -14,12 +14,14 @@ inputs: - "references/shipping/LAUNCH-ANTIPATTERNS.md" outputs: - ".godpowers/state.json launch evidence" + - ".godpowers/launch/PREPUBLICATION.mdx before public activation" - "landing copy and channel messaging" - "D-7 to D+7 launch runbook" gates: - "L-01 through L-08 have-nots" - "no unresolved Critical harden findings" - "launch state evidence is complete" + - "hash-bound pre-publication gate passes immediately before public activation" handoff: - "return launch evidence and pause only for human-only brand choices" --- @@ -30,9 +32,10 @@ Put the product in front of users. ## Gate Check -`.godpowers/harden/FINDINGS.mdx` exists with NO unresolved Critical findings. -If Critical findings are unresolved, REFUSE to proceed and tell orchestrator -to pause for human resolution. +`.godpowers/harden/FINDINGS.mdx` exists with NO unresolved or accepted Critical +findings. If Critical findings remain, launch asset preparation may stay +complete but public activation is refused. Tell the orchestrator to pause for +resolution and re-verification or remove public activation from scope. Confirm all P-MUST requirements show done in `.godpowers/REQUIREMENTS.mdx` before launch. @@ -112,6 +115,21 @@ For each channel: `STAGING_APP_URL=` only when the user requests staging or final project sign-off begins. +### 7. Hash-Bound Public Activation + +After every other launch and release-readiness check, and immediately before +an external public write: + +1. Re-read hardening findings and authoritative hardening state from disk. +2. Run `node /lib/prepublication-gate.js --record --project=.`. +3. Run `node /lib/prepublication-gate.js --check --project=.`. +4. Continue only when the second command returns `verdict: pass`. + +The recorded `.godpowers/launch/PREPUBLICATION.mdx` binds publication to the +exact hardening findings hash, hardening update timestamp, Critical counts, +and check time. Any later hardening change invalidates the record. Accepted +Critical risk does not pass this gate. Never publish from a stale record. + ## Output Return launch evidence for `.godpowers/state.json`; `lib/state-views.js` generates `.godpowers/launch/STATE.mdx` with the launch artifact summary. @@ -130,6 +148,7 @@ Return launch evidence for `.godpowers/state.json`; `lib/state-views.js` generat - Requests launch or provider credentials before the live staging smoke check proves they are needed - Invents or guesses launch, staging, or production domains +- Publishes without a fresh hash-bound pre-publication pass ## Pause Conditions diff --git a/agents/god-migration-strategist.md b/specialists/god-migration-strategist.md similarity index 100% rename from agents/god-migration-strategist.md rename to specialists/god-migration-strategist.md diff --git a/agents/god-observability-engineer.md b/specialists/god-observability-engineer.md similarity index 100% rename from agents/god-observability-engineer.md rename to specialists/god-observability-engineer.md diff --git a/agents/god-orchestrator.md b/specialists/god-orchestrator.md similarity index 100% rename from agents/god-orchestrator.md rename to specialists/god-orchestrator.md diff --git a/agents/god-org-context-loader.md b/specialists/god-org-context-loader.md similarity index 100% rename from agents/god-org-context-loader.md rename to specialists/god-org-context-loader.md diff --git a/agents/god-planner.md b/specialists/god-planner.md similarity index 100% rename from agents/god-planner.md rename to specialists/god-planner.md diff --git a/agents/god-pm.md b/specialists/god-pm.md similarity index 100% rename from agents/god-pm.md rename to specialists/god-pm.md diff --git a/agents/god-quality-reviewer.md b/specialists/god-quality-reviewer.md similarity index 100% rename from agents/god-quality-reviewer.md rename to specialists/god-quality-reviewer.md diff --git a/agents/god-reconciler.md b/specialists/god-reconciler.md similarity index 100% rename from agents/god-reconciler.md rename to specialists/god-reconciler.md diff --git a/agents/god-reconstructor.md b/specialists/god-reconstructor.md similarity index 100% rename from agents/god-reconstructor.md rename to specialists/god-reconstructor.md diff --git a/agents/god-repo-scaffolder.md b/specialists/god-repo-scaffolder.md similarity index 100% rename from agents/god-repo-scaffolder.md rename to specialists/god-repo-scaffolder.md diff --git a/agents/god-retrospective.md b/specialists/god-retrospective.md similarity index 100% rename from agents/god-retrospective.md rename to specialists/god-retrospective.md diff --git a/agents/god-roadmap-reconciler.md b/specialists/god-roadmap-reconciler.md similarity index 97% rename from agents/god-roadmap-reconciler.md rename to specialists/god-roadmap-reconciler.md index 8bb1f84..5b5fe79 100644 --- a/agents/god-roadmap-reconciler.md +++ b/specialists/god-roadmap-reconciler.md @@ -82,4 +82,4 @@ Reconciliation FAILS if: ## When to skip reconciliation -Follow the skip policy in `agents/god-reconciler.md`. +Follow the skip policy in `specialists/god-reconciler.md`. diff --git a/agents/god-roadmap-updater.md b/specialists/god-roadmap-updater.md similarity index 100% rename from agents/god-roadmap-updater.md rename to specialists/god-roadmap-updater.md diff --git a/agents/god-roadmapper.md b/specialists/god-roadmapper.md similarity index 100% rename from agents/god-roadmapper.md rename to specialists/god-roadmapper.md diff --git a/agents/god-spec-reviewer.md b/specialists/god-spec-reviewer.md similarity index 100% rename from agents/god-spec-reviewer.md rename to specialists/god-spec-reviewer.md diff --git a/agents/god-spike-runner.md b/specialists/god-spike-runner.md similarity index 100% rename from agents/god-spike-runner.md rename to specialists/god-spike-runner.md diff --git a/agents/god-stack-selector.md b/specialists/god-stack-selector.md similarity index 100% rename from agents/god-stack-selector.md rename to specialists/god-stack-selector.md diff --git a/agents/god-standards-check.md b/specialists/god-standards-check.md similarity index 100% rename from agents/god-standards-check.md rename to specialists/god-standards-check.md diff --git a/agents/god-storyteller.md b/specialists/god-storyteller.md similarity index 100% rename from agents/god-storyteller.md rename to specialists/god-storyteller.md diff --git a/agents/god-updater.md b/specialists/god-updater.md similarity index 100% rename from agents/god-updater.md rename to specialists/god-updater.md diff --git a/templates/HARDEN-FINDINGS.mdx b/templates/HARDEN-FINDINGS.mdx index 60f8ed5..fa27282 100644 --- a/templates/HARDEN-FINDINGS.mdx +++ b/templates/HARDEN-FINDINGS.mdx @@ -17,31 +17,34 @@ Scope: [What was reviewed: code, config, dependencies, deploy pipeline] If any Critical: BLOCKED. Launch cannot proceed until resolved or risk explicitly accepted. -## OWASP Top 10 Coverage - -| Category | Status | Notes | -|----------|--------|-------| -| A01 Broken Access Control | Reviewed | [findings ref] | -| A02 Cryptographic Failures | Reviewed | [findings ref] | -| A03 Injection | Reviewed | [findings ref] | -| A04 Insecure Design | Reviewed | [findings ref] | -| A05 Security Misconfiguration | Reviewed | [findings ref] | -| A06 Vulnerable Components | Reviewed | [findings ref] | -| A07 Authentication Failures | Reviewed | [findings ref] | -| A08 Data Integrity Failures | Reviewed | [findings ref] | -| A09 Logging Failures | Reviewed | [findings ref] | -| A10 SSRF | Reviewed | [findings ref] | +## OWASP Web Top 10:2025 Coverage + +| Category | Manual procedure | Result | Evidence or finding | +|----------|------------------|--------|---------------------| +| A01:2025 Broken Access Control | [exact probe or justified Not Applicable] | [pass/fail] | [evidence or finding ref] | +| A02:2025 Security Misconfiguration | [exact probe or justified Not Applicable] | [pass/fail] | [evidence or finding ref] | +| A03:2025 Software Supply Chain Failures | [exact probe or justified Not Applicable] | [pass/fail] | [evidence or finding ref] | +| A04:2025 Cryptographic Failures | [exact probe or justified Not Applicable] | [pass/fail] | [evidence or finding ref] | +| A05:2025 Injection | [exact probe or justified Not Applicable] | [pass/fail] | [evidence or finding ref] | +| A06:2025 Insecure Design | [exact probe or justified Not Applicable] | [pass/fail] | [evidence or finding ref] | +| A07:2025 Authentication Failures | [exact probe or justified Not Applicable] | [pass/fail] | [evidence or finding ref] | +| A08:2025 Software or Data Integrity Failures | [exact probe or justified Not Applicable] | [pass/fail] | [evidence or finding ref] | +| A09:2025 Security Logging and Alerting Failures | [exact probe or justified Not Applicable] | [pass/fail] | [evidence or finding ref] | +| A10:2025 Mishandling of Exceptional Conditions | [exact fault injection or justified Not Applicable] | [pass/fail] | [evidence or finding ref] | No category may be marked "N/A" without explicit justification. ## Findings ### [CRITICAL-001] [Short title] -- **Category**: OWASP A01 Broken Access Control +- **Category**: OWASP A01:2025 Broken Access Control - **Location**: [file:line] - **Description**: [What the vulnerability is] - **Impact**: [What happens if exploited] - **Reproduction**: [Step-by-step] +- **Observed Result**: [What happened] +- **Evidence**: [Artifact, log, test, or command] +- **Reviewed At**: [ISO 8601 timestamp] - **Remediation Options**: - **Option A**: [Approach] -- Estimated: [time] - **Option B**: [Approach] -- Estimated: [time] @@ -64,6 +67,6 @@ No category may be marked "N/A" without explicit justification. - [ ] Auth boundaries actively tested (not just code-read) - [ ] Input validation audited - [ ] Rate limiting verified on auth endpoints -- [ ] All OWASP categories reviewed (no skips without justification) +- [ ] All OWASP Web Top 10:2025 categories have reproducible manual evidence or justified Not Applicable scope - [ ] Every finding has a severity classification - [ ] Every Critical finding has remediation options diff --git a/tests/pillars-conformance/fixtures.yaml b/tests/pillars-conformance/fixtures.yaml new file mode 100644 index 0000000..b6bdea7 --- /dev/null +++ b/tests/pillars-conformance/fixtures.yaml @@ -0,0 +1,55 @@ +version: 1 +cases: + - name: hard dependency stays depth one + project: projects/routing + task: Change the database schema for workspace invitations + target: services/api/src/invitations.py + expected: + load: [root::auth, root::context, root::data, root::repo] + primaries: [root::data] + absent: [] + + - name: covers can activate see also + project: projects/routing + task: Update the request contract used by this database query + target: services/api/src/query.py + expected: + load: [root::api, root::auth, root::context, root::data, root::repo] + primaries: [root::data] + absent: [] + + - name: sub-pillar identity is path qualified + project: projects/routing + task: Add agent registration credential rotation + target: services/api/src/agents.py + expected: + load: [root::auth, root::auth/agent-registration, root::context, root::repo] + primaries: [root::auth/agent-registration] + absent: [] + + - name: nested scopes inherit and override + project: projects/routing + task: Fix the UI component spacing + target: packages/web/src/card.tsx + expected: + load: [root::context, root::repo, root::ui, packages/web::context, packages/web::repo, packages/web::ui] + primaries: [root::ui, packages/web::ui] + absent: [] + + - name: child exclusion suppresses inherited routed pillar + project: projects/routing + task: Add a monitoring alert for the web package + target: packages/web/src/card.tsx + expected: + load: [root::context, root::repo, packages/web::context, packages/web::repo] + primaries: [root::observe] + absent: [] + + - name: local catalog exposes absent concern + project: projects/routing + task: Prepare the release checklist + target: services/api/src/version.py + expected: + load: [root::context, root::repo] + primaries: [] + absent: [root::release] diff --git a/tests/pillars-conformance/projects/routing/AGENTS.md b/tests/pillars-conformance/projects/routing/AGENTS.md new file mode 100644 index 0000000..221a816 --- /dev/null +++ b/tests/pillars-conformance/projects/routing/AGENTS.md @@ -0,0 +1,9 @@ +# Fixture Pillars Protocol + +This fixture follows Pillars 1.1.0 and exists only for deterministic conformance testing. + +## Excluded pillars + +```yaml +excluded: [] +``` diff --git a/tests/pillars-conformance/projects/routing/agents/api.md b/tests/pillars-conformance/projects/routing/agents/api.md new file mode 100644 index 0000000..ce58608 --- /dev/null +++ b/tests/pillars-conformance/projects/routing/agents/api.md @@ -0,0 +1,41 @@ +--- +pillar: api +status: present +always_load: false +covers: [request contract] +triggers: [api, endpoint, route] +must_read_with: [] +see_also: [] +--- + +## Scope + +This pillar covers fixture API contracts. + +## Context + +Request contracts are a soft data touchpoint. + +## Decisions + +(none) + +## Rules + +(none) + +## Workflows + +(none) + +## Watchouts + +(none) + +## Touchpoints + +(none) + +## Gaps + +(none) diff --git a/tests/pillars-conformance/projects/routing/agents/auth.md b/tests/pillars-conformance/projects/routing/agents/auth.md new file mode 100644 index 0000000..deb3c39 --- /dev/null +++ b/tests/pillars-conformance/projects/routing/agents/auth.md @@ -0,0 +1,41 @@ +--- +pillar: auth +status: present +always_load: false +covers: [identity and access] +triggers: [auth, login, permission] +must_read_with: [] +see_also: [] +--- + +## Scope + +This pillar covers fixture auth. + +## Context + +Data changes require auth context. + +## Decisions + +(none) + +## Rules + +(none) + +## Workflows + +(none) + +## Watchouts + +(none) + +## Touchpoints + +(none) + +## Gaps + +(none) diff --git a/tests/pillars-conformance/projects/routing/agents/auth/agent-registration.md b/tests/pillars-conformance/projects/routing/agents/auth/agent-registration.md new file mode 100644 index 0000000..e82e576 --- /dev/null +++ b/tests/pillars-conformance/projects/routing/agents/auth/agent-registration.md @@ -0,0 +1,41 @@ +--- +pillar: agent-registration +status: present +always_load: false +covers: [agent credentials] +triggers: [agent registration] +must_read_with: [auth] +see_also: [] +--- + +## Scope + +This pillar covers agent registration. + +## Context + +The identity is path-qualified. + +## Decisions + +(none) + +## Rules + +(none) + +## Workflows + +(none) + +## Watchouts + +(none) + +## Touchpoints + +- `must_read_with: [auth]` + +## Gaps + +(none) diff --git a/tests/pillars-conformance/projects/routing/agents/catalog.yaml b/tests/pillars-conformance/projects/routing/agents/catalog.yaml new file mode 100644 index 0000000..3e16ed7 --- /dev/null +++ b/tests/pillars-conformance/projects/routing/agents/catalog.yaml @@ -0,0 +1,5 @@ +version: 1 +absent: + - identity: release + covers: [version publication] + triggers: [release, publish] diff --git a/tests/pillars-conformance/projects/routing/agents/context.md b/tests/pillars-conformance/projects/routing/agents/context.md new file mode 100644 index 0000000..7db624f --- /dev/null +++ b/tests/pillars-conformance/projects/routing/agents/context.md @@ -0,0 +1,41 @@ +--- +pillar: context +status: present +always_load: true +covers: [fixture identity] +triggers: [] +must_read_with: [] +see_also: [] +--- + +## Scope + +This pillar identifies the routing fixture. + +## Context + +This project exists only to test deterministic loading. + +## Decisions + +(none) + +## Rules + +(none) + +## Workflows + +(none) + +## Watchouts + +(none) + +## Touchpoints + +(none) + +## Gaps + +(none) diff --git a/tests/pillars-conformance/projects/routing/agents/data.md b/tests/pillars-conformance/projects/routing/agents/data.md new file mode 100644 index 0000000..e2c3ed6 --- /dev/null +++ b/tests/pillars-conformance/projects/routing/agents/data.md @@ -0,0 +1,42 @@ +--- +pillar: data +status: present +always_load: false +covers: [database storage] +triggers: [database, schema, query] +must_read_with: [auth] +see_also: [api] +--- + +## Scope + +This pillar covers fixture data. + +## Context + +Data work needs auth context and may touch request contracts. + +## Decisions + +(none) + +## Rules + +(none) + +## Workflows + +(none) + +## Watchouts + +(none) + +## Touchpoints + +- `must_read_with: [auth]` +- `see_also: [api]` + +## Gaps + +(none) diff --git a/tests/pillars-conformance/projects/routing/agents/observe.md b/tests/pillars-conformance/projects/routing/agents/observe.md new file mode 100644 index 0000000..f2c4386 --- /dev/null +++ b/tests/pillars-conformance/projects/routing/agents/observe.md @@ -0,0 +1,41 @@ +--- +pillar: observe +status: present +always_load: false +covers: [system health] +triggers: [monitoring, alert] +must_read_with: [] +see_also: [] +--- + +## Scope + +This pillar covers root monitoring. + +## Context + +The nested web scope explicitly excludes this concern. + +## Decisions + +(none) + +## Rules + +(none) + +## Workflows + +(none) + +## Watchouts + +(none) + +## Touchpoints + +(none) + +## Gaps + +(none) diff --git a/tests/pillars-conformance/projects/routing/agents/repo.md b/tests/pillars-conformance/projects/routing/agents/repo.md new file mode 100644 index 0000000..559c90f --- /dev/null +++ b/tests/pillars-conformance/projects/routing/agents/repo.md @@ -0,0 +1,41 @@ +--- +pillar: repo +status: present +always_load: true +covers: [fixture layout] +triggers: [] +must_read_with: [] +see_also: [] +--- + +## Scope + +This pillar describes the fixture layout. + +## Context + +The fixture has a root scope and a nested web scope. + +## Decisions + +(none) + +## Rules + +(none) + +## Workflows + +(none) + +## Watchouts + +(none) + +## Touchpoints + +(none) + +## Gaps + +(none) diff --git a/tests/pillars-conformance/projects/routing/agents/ui.md b/tests/pillars-conformance/projects/routing/agents/ui.md new file mode 100644 index 0000000..a31718b --- /dev/null +++ b/tests/pillars-conformance/projects/routing/agents/ui.md @@ -0,0 +1,41 @@ +--- +pillar: ui +status: present +always_load: false +covers: [shared interface] +triggers: [ui, component] +must_read_with: [] +see_also: [] +--- + +## Scope + +This pillar covers shared UI guidance. + +## Context + +Nested UI guidance may refine these facts. + +## Decisions + +(none) + +## Rules + +(none) + +## Workflows + +(none) + +## Watchouts + +(none) + +## Touchpoints + +(none) + +## Gaps + +(none) diff --git a/tests/pillars-conformance/projects/routing/packages/web/AGENTS.md b/tests/pillars-conformance/projects/routing/packages/web/AGENTS.md new file mode 100644 index 0000000..2cb8542 --- /dev/null +++ b/tests/pillars-conformance/projects/routing/packages/web/AGENTS.md @@ -0,0 +1,11 @@ +# Nested Fixture Protocol + +This package inherits the root Pillars 1.1 protocol and refines the fixture guidance for the web scope. + +## Excluded pillars + +```yaml +excluded: + - name: observe + reason: The fixture web package has no operational surface +``` diff --git a/tests/pillars-conformance/projects/routing/packages/web/agents/context.md b/tests/pillars-conformance/projects/routing/packages/web/agents/context.md new file mode 100644 index 0000000..389b779 --- /dev/null +++ b/tests/pillars-conformance/projects/routing/packages/web/agents/context.md @@ -0,0 +1,41 @@ +--- +pillar: context +status: present +always_load: true +covers: [web package identity] +triggers: [] +must_read_with: [] +see_also: [] +--- + +## Scope + +This pillar identifies the nested web package. + +## Context + +Nearest-scope facts win conflicts. + +## Decisions + +(none) + +## Rules + +(none) + +## Workflows + +(none) + +## Watchouts + +(none) + +## Touchpoints + +(none) + +## Gaps + +(none) diff --git a/tests/pillars-conformance/projects/routing/packages/web/agents/repo.md b/tests/pillars-conformance/projects/routing/packages/web/agents/repo.md new file mode 100644 index 0000000..2924930 --- /dev/null +++ b/tests/pillars-conformance/projects/routing/packages/web/agents/repo.md @@ -0,0 +1,41 @@ +--- +pillar: repo +status: present +always_load: true +covers: [web package layout] +triggers: [] +must_read_with: [] +see_also: [] +--- + +## Scope + +This pillar describes nested package placement. + +## Context + +Web package files live under `packages/web/src`. + +## Decisions + +(none) + +## Rules + +(none) + +## Workflows + +(none) + +## Watchouts + +(none) + +## Touchpoints + +(none) + +## Gaps + +(none) diff --git a/tests/pillars-conformance/projects/routing/packages/web/agents/ui.md b/tests/pillars-conformance/projects/routing/packages/web/agents/ui.md new file mode 100644 index 0000000..dbbeaed --- /dev/null +++ b/tests/pillars-conformance/projects/routing/packages/web/agents/ui.md @@ -0,0 +1,41 @@ +--- +pillar: ui +status: present +always_load: false +covers: [web components] +triggers: [ui, component] +must_read_with: [] +see_also: [] +--- + +## Scope + +This pillar refines UI guidance for the web package. + +## Context + +Package-specific spacing rules override root UI conflicts. + +## Decisions + +(none) + +## Rules + +(none) + +## Workflows + +(none) + +## Watchouts + +(none) + +## Touchpoints + +(none) + +## Gaps + +(none) diff --git a/workflows/bluefield-arc.yaml b/workflows/bluefield-arc.yaml index 3015e14..4d79550 100644 --- a/workflows/bluefield-arc.yaml +++ b/workflows/bluefield-arc.yaml @@ -64,6 +64,8 @@ jobs: tier: 1 needs: greenfieldify-artifacts uses: god-pm@^1.0.0 + with: + routing-order: [product-form, product-archetype, industry, regulatory] arch: tier: 1 @@ -83,6 +85,7 @@ jobs: uses: god-stack-selector@^1.0.0 with: respect-org-context: true + domain-composition: primary-profile-then-secondary-hard-constraints repo: tier: 2 @@ -93,6 +96,8 @@ jobs: tier: 2 needs: [roadmap, repo] uses: god-planner@^1.0.0 + with: + completion-gate: selected-product-form review: stages: - uses: god-spec-reviewer@^1.0.0 diff --git a/workflows/feature-arc.yaml b/workflows/feature-arc.yaml index 25b72ed..c0f1f6f 100644 --- a/workflows/feature-arc.yaml +++ b/workflows/feature-arc.yaml @@ -21,6 +21,7 @@ jobs: with: mode: feature-only template: PRD.md + routing-order: [product-form, product-archetype, industry, regulatory] feature-arch: tier: 1 @@ -34,6 +35,8 @@ jobs: tier: 2 needs: feature-prd uses: god-planner@^1.0.0 + with: + completion-gate: selected-product-form review: stages: - uses: god-spec-reviewer@^1.0.0 diff --git a/workflows/full-arc.yaml b/workflows/full-arc.yaml index a5b9675..7ec7c15 100644 --- a/workflows/full-arc.yaml +++ b/workflows/full-arc.yaml @@ -48,6 +48,7 @@ jobs: uses: god-pm@^1.0.0 with: template: PRD.md + routing-order: [product-form, product-archetype, industry, regulatory] arch: tier: 1 @@ -69,6 +70,7 @@ jobs: uses: god-stack-selector@^1.0.0 with: template: STACK-DECISION.md + domain-composition: primary-profile-then-secondary-hard-constraints repo: tier: 2 @@ -79,6 +81,8 @@ jobs: tier: 2 needs: [roadmap, repo] uses: god-planner@^1.0.0 + with: + completion-gate: selected-product-form review: stages: - uses: god-spec-reviewer@^1.0.0