diff --git a/.charter/patterns/adf-patterns.json b/.charter/patterns/adf-patterns.json new file mode 100644 index 0000000..4c56f73 --- /dev/null +++ b/.charter/patterns/adf-patterns.json @@ -0,0 +1,24 @@ +{ + "patterns": [ + { + "id": "adf-mutation-review", + "name": "ADF Module Mutation Review", + "category": "GOVERNANCE", + "status": "ACTIVE", + "blessed_solution": "Run `charter doctor` before merging any change to .ai/*.adf files. Include output in PR description.", + "rationale": "ADF modules are load-bearing context files that route AI agent behavior. Silent mutations break agent routing without visible test failures.", + "anti_patterns": "Merging .adf edits without running charter doctor. Editing DEFAULT_LOAD entries without updating dependent module triggers. Removing SENSITIVITY blocks without an explicit architecture decision.", + "created_at": "2026-05-23T00:00:00.000Z" + }, + { + "id": "adf-manifest-pointer-integrity", + "name": "ADF Manifest Pointer Integrity", + "category": "GOVERNANCE", + "status": "ACTIVE", + "blessed_solution": "Every module path listed in manifest.adf DEFAULT_LOAD or ON_DEMAND must resolve to an existing .adf file. Use `charter doctor` to validate before merge.", + "rationale": "Broken manifest pointers cause silent context loss for AI agents — the agent loads fewer modules than expected with no error surface.", + "anti_patterns": "Listing module paths in manifest.adf that do not exist on disk. Renaming .adf files without updating manifest.adf references.", + "created_at": "2026-05-23T00:00:00.000Z" + } + ] +} diff --git a/.charter/patterns/oss-patterns.json b/.charter/patterns/oss-patterns.json new file mode 100644 index 0000000..6d2e0c8 --- /dev/null +++ b/.charter/patterns/oss-patterns.json @@ -0,0 +1,24 @@ +{ + "patterns": [ + { + "id": "oss-additive-only-api", + "name": "OSS Additive-Only Public API", + "category": "API", + "status": "ACTIVE", + "blessed_solution": "Add new exports freely. To rename or remove a public export: bump major version, add a deprecation notice in the prior minor, and document the migration path in CHANGELOG.md.", + "rationale": "Charter packages are public infrastructure. Consumers pin exact versions; breaking changes without a major bump silently break downstream builds.", + "anti_patterns": "Removing or renaming an exported function without a major version bump. Changing a function signature in a backward-incompatible way in a patch or minor release. Deleting exported types that appear in @stackbilt/types.", + "created_at": "2026-05-23T00:00:00.000Z" + }, + { + "id": "oss-no-product-logic", + "name": "No Product Logic in OSS Packages", + "category": "ARCHITECTURE", + "status": "ACTIVE", + "blessed_solution": "Keep packages to framework patterns and generic utilities. If a feature requires knowledge of Stackbilt product internals, it belongs in a private package, not here.", + "rationale": "This is a public infrastructure package. Embedding product logic would expose Stackbilt architecture and violate the OSS policy.", + "anti_patterns": "Importing Stackbilt-internal constants or types directly in OSS package source. Adding cloud-API calls that require Stackbilt auth tokens. Hardcoding product-specific behavior such as tenant routing in generic utilities.", + "created_at": "2026-05-23T00:00:00.000Z" + } + ] +} diff --git a/.charter/patterns/testing-patterns.json b/.charter/patterns/testing-patterns.json new file mode 100644 index 0000000..9706777 --- /dev/null +++ b/.charter/patterns/testing-patterns.json @@ -0,0 +1,14 @@ +{ + "patterns": [ + { + "id": "tests-travel-with-exports", + "name": "Tests Travel with Public Exports", + "category": "TESTING", + "status": "ACTIVE", + "blessed_solution": "Every new public export added to a @stackbilt/* package must have at minimum one test exercising it as a callable function. Add the test in the same PR as the export.", + "rationale": "Silent export removal is the primary regression vector in OSS packages. A test that imports and calls the function will fail loudly if the export disappears.", + "anti_patterns": "Merging a new exported function with no corresponding test. Adding a type-only export without a runtime test that imports it. Testing implementation details instead of the exported surface.", + "created_at": "2026-05-23T00:00:00.000Z" + } + ] +} diff --git a/.charter/policies/governance-policy.md b/.charter/policies/governance-policy.md new file mode 100644 index 0000000..25f0e14 --- /dev/null +++ b/.charter/policies/governance-policy.md @@ -0,0 +1,115 @@ +# Charter Kit Governance Policy + +This document defines the engineering governance policy for the `Stackbilt-dev/charter` OSS monorepo. +It is the authoritative reference for commit standards, change classification, exception handling, +and escalation paths. + +--- + +## Commit Trailers + +All commits to `main` that touch public-facing behavior must include at least one governance trailer. + +### Required Trailers + +| Trailer | When required | +|---------|--------------| +| `Governed-By: ` | Breaking changes, architecture decisions, OSS API mutations | +| `Resolves-Request: ` | Any change linked to a tracked GitHub issue | + +### Trailer Format + +``` +feat(adf): add STACK field to manifest parser + +Parses and exposes the STACK key from manifest.adf sections. + +Governed-By: oss-additive-only-api +Resolves-Request: https://github.com/Stackbilt-dev/charter/issues/160 +``` + +Trailers must appear after the blank line following the commit body. The `charter validate` command +enforces trailer format on CI. Coverage is reported by `charter audit`. + +### Commit Trailer Coverage Target + +- New repos: ≥50% of commits on `main` must carry trailers within 30 days of onboarding +- Established repos: ≥67% coverage earns full trailer score in `charter audit` + +--- + +## Change Classification + +Every PR should be classified using Charter's three-tier change model before merge: + +| Class | Definition | Review requirement | +|-------|-----------|-------------------| +| `SURFACE` | Docs, comments, copy, rename with no behavior change | Author self-review | +| `LOCAL` | Bug fix or feature within a single package boundary | Standard PR review | +| `CROSS_CUTTING` | API contract change, inter-package dependency, CI workflow, ADF schema | Architecture review required | + +Run `charter setup --detect-only` to get a suggested classification. For cross_cutting changes, +include the output in the PR description. + +### Classification Tags in PR Titles + +Append `[SURFACE]`, `[LOCAL]`, or `[CROSS_CUTTING]` to PR titles for cross-cutting changes when +the conventional commit prefix doesn't make the scope obvious. + +--- + +## Exception Path + +Exceptions to this policy require explicit approval and documentation. + +### Valid Exception Conditions + +- **Emergency hotfix**: Production incident requiring immediate merge without full governance coverage. + Must be followed within 24 hours by a follow-up commit adding missing trailers. +- **Waiver request**: Engineering lead approves an exception for a specific PR via a GitHub issue + comment with the label `governance-waiver`. +- **Override for tooling PRs**: Automated dependency updates (Dependabot, Renovate) are exempt from + trailer requirements but must still pass all CI checks. + +### Documenting an Exception + +Add an `Exception:` trailer to any commit that knowingly bypasses a policy requirement: + +``` +chore(deps): bump vitest to 5.0.0 + +Exception: automated dependency update — trailer waiver per governance-policy.md §Exception Path +``` + +Exceptions are surfaced in `charter audit --format json` under `git.governedByRefs`. + +--- + +## Escalation and Approval + +### When to Escalate + +Escalate to an architectural review when: + +- A PR changes a type exported from `@stackbilt/types` +- A PR removes or renames a public export from any OSS package +- A PR modifies `.ai/manifest.adf` DEFAULT_LOAD entries +- A PR adds a new inter-package dependency +- The `charter setup --detect-only` output flags `CROSS_CUTTING` with `HIGH` confidence + +### Escalation Process + +1. Open a GitHub issue tagged `architecture-review` describing the change and its rationale +2. Link the issue in the PR description and add the `Governed-By:` trailer referencing the issue +3. Request explicit approval from `@Stackbilt-dev/charter-maintainers` before merge +4. Record the architectural decision in `.ai/state.adf` under the `DECISIONS` section if it + changes the module's long-term direction + +### Approval Authority + +| Change type | Approval required from | +|-------------|----------------------| +| Public API removal | Two maintainer reviews | +| Major version bump | Engineering lead sign-off | +| ADF manifest restructure | Architecture review (GitHub issue + `architecture-review` label) | +| CI/CD pipeline changes | DevOps + one maintainer | diff --git a/.github/workflows/governance.yml b/.github/workflows/governance.yml index 7b81a9b..0b9f88c 100644 --- a/.github/workflows/governance.yml +++ b/.github/workflows/governance.yml @@ -44,25 +44,25 @@ jobs: run: pnpm run build - name: Validate Commits - run: npx charter validate --ci --format text + run: node packages/cli/dist/bin.js validate --ci --format text continue-on-error: true - name: Drift Scan - run: npx charter drift --ci --format text + run: node packages/cli/dist/bin.js drift --ci --format text if: hashFiles('.charter/patterns/*.json') != '' - name: ADF Wiring & Pointer Integrity - run: npx charter doctor --adf-only --ci --format text + run: node packages/cli/dist/bin.js doctor --adf-only --ci --format text if: hashFiles('.ai/manifest.adf') != '' continue-on-error: true - name: ADF Evidence - run: npx charter adf evidence --auto-measure --ci --format text + run: node packages/cli/dist/bin.js adf evidence --auto-measure --ci --format text if: hashFiles('.ai/manifest.adf') != '' continue-on-error: true - name: Audit Report - run: npx charter audit --format json > /tmp/audit.json || true + run: node packages/cli/dist/bin.js audit --format json > /tmp/audit.json || true if: always() - name: Post Summary