Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .charter/patterns/adf-patterns.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
}
24 changes: 24 additions & 0 deletions .charter/patterns/oss-patterns.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
}
14 changes: 14 additions & 0 deletions .charter/patterns/testing-patterns.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
}
115 changes: 115 additions & 0 deletions .charter/policies/governance-policy.md
Original file line number Diff line number Diff line change
@@ -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: <policy-section>` | Breaking changes, architecture decisions, OSS API mutations |
| `Resolves-Request: <issue-url>` | 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 |
10 changes: 5 additions & 5 deletions .github/workflows/governance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading