docs(plan-rollout): compress SYSTEM_MD.md (215 → 129 lines, -40%)

Trim ceremonial prose. Keep load-bearing content: intro, schema, field
reference (now a table), example, "how /plan-rollout uses it", out-of-scope.
Drop redundant "what it is / what it isn't" expansion, "relationship to
other declarative files" table, separate scaffolding section.

No semantic change to the schema or the skill's contract with it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Manas Srivastava 2026-05-11 11:33:41 +05:30
parent 2684677b97
commit 9c4ab6fe6e
1 changed files with 56 additions and 144 deletions

View File

@ -1,41 +1,16 @@
# SYSTEM.md — the semantic contract graph
`SYSTEM.md` is a declarative file at the repo root describing what each
component *is*, what it *owns*, and the role-level contracts it has with
other components. Its consumer is `/plan-rollout`, which uses it to slice
a single large change into an ordered PR stack with reader guides and
deploy-edge awareness.
`SYSTEM.md` is an optional repo-root file declaring what each component
*is*, what it *owns*, and the role-level contracts between components.
Its consumer is `/plan-rollout`. The skill reads it to sharpen slice
ordering and surface coordinated-deploy edges; it falls back to path
heuristics when absent.
`SYSTEM.md` is optional. `/plan-rollout` works without it — falling back
to path heuristics + import-graph discovery — and improves materially
when present.
## What SYSTEM.md is NOT
It is not a package manifest. It does not list:
- Import graphs or symbol-level callers
- npm / Cargo / Gem / Go module versions
- Build dependencies or linker flags
- Test framework wiring
Everything mechanical is discovered at runtime (AST, grep, package manifests).
Declaring it here would go stale within a week.
## What SYSTEM.md IS
The **semantic contract graph**: the relationships between components that
only a human knows.
| Kind | Example | Lives where |
|------|---------|-------------|
| Role/contract dep | "auth mints session tokens middleware enforces; format change without middleware redeploy breaks sessions" | SYSTEM.md |
| Package/import dep | "`auth.ts` imports `crypto-utils`; `middleware.ts` calls `auth.verify()`" | Discovered (NOT here) |
`/plan-rollout` reads both. Declared contracts give the *why* (what breaks
under coordinated deploy). Discovered imports give the *what* (which files
move together). Disagreements surface in the decomposition output for human
resolution rather than being silently resolved either way.
Not a package manifest. Not an import graph. Those are discovered at
runtime (AST, grep, manifests) and would go stale within a week if
declared. SYSTEM.md captures only what a human knows: "auth mints
session tokens middleware enforces; session-format change without
middleware redeploy breaks sessions."
## Schema (v1 — intra-repo)
@ -44,75 +19,41 @@ resolution rather than being silently resolved either way.
version: 1
components:
- name: <unique identifier>
path: <repo-relative path to the component root>
kind: component # or: leaf-util | types-only (optional; defaults to 'component')
role: <one-line description of the component's job>
path: <repo-relative path>
kind: component # or: leaf-util | types-only (default: component)
role: <one-line job description>
owns:
- <data surface, table, API, or feature this component is source-of-truth for>
- <data surface, table, API, or feature this component owns>
contracts:
- with: <other component name>
nature: <what the relationship is in plain English>
breaks-if: <what human action causes the contract to break>
nature: <plain-English relationship>
breaks-if: <specific human action that violates the contract>
rollout-edge: <hard | soft>
note: <optional; 'runtime-only' | 'types-only' | 'legacy' | free text>
rollout-order: <integer; lower ships first; same number can ship in parallel>
note: <runtime-only | types-only | legacy | free text> # optional
rollout-order: <integer; lower ships first; equal = parallel>
---
# System Map
<Free-form markdown narrative: component stability, anti-patterns, deploy-edge
semantics the team has learned from incidents. This section is for humans, not
for parsers.>
<Free-form human notes: stability, anti-patterns, deploy-edge lessons
from past incidents. Not parsed.>
```
### Field reference
**`name`** — unique identifier used by other artifacts to reference this
component. Keep it short and stable. Renames cascade to every contract
reference.
**`path`** — where the component lives in the repo. Can be a file or
directory. Used for component-membership lookups (is `src/auth/session.ts`
in the `auth` component? yes).
**`kind`** — defaults to `component`. Use:
- `leaf-util` for shared utility dirs (`src/utils/`, `src/helpers/`) that
components import freely without declaring contracts. The skill skips
these when reconciling.
- `types-only` for pure type/interface modules. Skipped likewise.
**`role`** — one sentence describing what this component is FOR. Not what
it contains, not how it's built. What it does in the system.
**`owns`** — data surfaces, tables, APIs, or features this component is
the single source of truth for. Two components claiming ownership of the
same surface is a design smell.
**`contracts`** — the heart of SYSTEM.md. Each contract declares a
role-level relationship with another component.
- **`with`** — the other component's name. Must match a declared component.
- **`nature`** — plain-English description of the relationship.
- **`breaks-if`** — the specific human action that violates the contract.
This is what `/plan-rollout` reads. "Session payload schema changes
without middleware redeploy" tells the skill these two PRs must ship
as a coordinated stage.
- **`rollout-edge`**:
- `hard` = must deploy together (e.g., a session format change). The
skill places both sides of a hard edge in the same slice or marks
the slice "coordinated deploy required."
- `soft` = can lag (e.g., a logging metric addition). Noted but not
enforced.
- **`note`** (optional):
- `runtime-only` — coupling via DB, message bus, HTTP, or filesystem;
no code-level import edge exists. Suppresses the "contract without
imports" reconcile flag.
- `types-only` — TypeScript types only, not runtime values.
- `legacy` — contract exists but is being phased out.
**`rollout-order`** — integer. Components with lower numbers ship first.
Equal numbers can ship in parallel. Used as the default ordering for
PR-stack decomposition; users can override per-call.
| Field | Meaning |
|-------|---------|
| `name` | Unique identifier referenced by other components' contracts. Renames cascade. |
| `path` | File or dir under the repo root. Used for component-membership lookups. |
| `kind` | `component` (default), `leaf-util` (utils dirs, no contracts), `types-only` (interfaces, no runtime). leaf/types are skipped during reconciliation. |
| `role` | One sentence: what this component does in the system. Not what it contains. |
| `owns` | Data surfaces / tables / APIs / features this component is source-of-truth for. Dual ownership is a design smell. |
| `contracts[].with` | Other component's name. Must match a declared component. |
| `contracts[].nature` | Plain-English description of the relationship. |
| `contracts[].breaks-if` | Specific human action that violates the contract. This is what `/plan-rollout` reads to detect coordinated-deploy stages. |
| `contracts[].rollout-edge` | `hard` = must deploy together. `soft` = can lag. |
| `contracts[].note` | `runtime-only` (DB/HTTP/bus coupling — no import edge expected), `types-only`, `legacy`, or free text. |
| `rollout-order` | Integer. Lower ships first. Equal values can ship in parallel. |
## Example
@ -123,10 +64,7 @@ components:
- name: auth
path: src/auth
role: authentication + session lifecycle
owns:
- user table
- session table
- JWT minting
owns: [user table, session table, JWT minting]
contracts:
- with: middleware
nature: middleware enforces session tokens auth mints
@ -137,8 +75,7 @@ components:
- name: middleware
path: src/middleware
role: request routing + auth enforcement
owns:
- request context shape
owns: [request context shape]
contracts:
- with: gateway
nature: gateway consumes req.user set by middleware
@ -149,8 +86,7 @@ components:
- name: gateway
path: src/gateway
role: external HTTP surface
owns:
- public API schema
owns: [public API schema]
contracts: []
rollout-order: 3
@ -165,53 +101,29 @@ components:
# System Map
auth and middleware are the security boundary. Any change to session format
or the user-context shape is a coordinated deploy (rollout-edge: hard). We
learned this after the Feb 2025 incident where a session serializer change
shipped 40 minutes ahead of middleware and logged everyone out.
utils is declared `leaf-util` so the skill doesn't flag the many imports
into it from other components as missing contracts.
auth and middleware are the security boundary. Session-format or
user-context shape changes are coordinated deploys (rollout-edge: hard).
We learned this in Feb 2025 when a session serializer change shipped
40 minutes ahead of middleware and logged everyone out.
```
## How /plan-rollout uses it
`/plan-rollout` reads `SYSTEM.md` (if present) at the start of every run
and applies it three ways:
1. **File → component mapping.** Changed files are bucketed into the
slice for their component (matched by `path`, longest-match wins).
Without SYSTEM.md, the skill falls back to top-level-dir bucketing.
2. **Slice ordering.** Slices are sorted by `rollout-order`. `leaf-util`
and `types-only` components float to slice 0.
3. **Hard-edge enforcement.** When a changed-file set spans both sides
of a `rollout-edge: hard` contract, those files merge into one slice
tagged "coordinated deploy required — \<breaks-if reason\>".
4. **Reconciliation flags (informational).** Mismatches between declared
contracts and discovered imports surface in the output:
`import-without-contract`, `contract-without-imports`,
`rollout-order-inversion`. Never blocking.
1. **File-to-component mapping** — when bucketing changed files into PR
slices, files matching a component's `path` join that component's
slice. No SYSTEM.md ⇒ slices fall back to top-level path heuristics
(one slice per top-level dir of changes).
2. **Slice ordering** — slices are ordered by their components'
`rollout-order`, lowest first. Files in `leaf-util` or `types-only`
components float to slice 0 (foundational; no contracts to honor).
3. **Hard-edge enforcement** — if changed files span both sides of a
`rollout-edge: hard` contract, the skill either merges those slices
into a single coordinated stage or annotates the decomposition with
a deploy-coordination warning.
## Out of scope (v1)
Reconciliation is informational in v1. The skill prints flagged
mismatches between declared contracts and discovered imports
(`import-without-contract`, `contract-without-imports`,
`rollout-order-inversion`) so the human can resolve them, but does not
gate output on them.
## Scaffolding
`/plan-rollout` does NOT scaffold `SYSTEM.md` for you in v1. Scaffolding
(walking top-level dirs, classifying each, inferring `role` from
README/package.json) is a v2 follow-up. For v1, write the file by hand
or copy the example above and edit it.
## Relationship to other declarative files
| File | Purpose | Who writes it |
|------|---------|---------------|
| `CLAUDE.md` | Project-specific instructions for Claude (routing rules, test commands) | Human |
| `CODEOWNERS` | Who reviews changes to which paths | Human |
| `SYSTEM.md` | Semantic contract graph (this file's schema) | Human |
| `decomposition.md` | Per-change PR stack | `/plan-rollout` |
SYSTEM.md is the long-lived, repo-wide truth. `decomposition.md` is a
per-change artifact that references it.
No scaffolder. Write SYSTEM.md by hand or copy the example. Scaffolding
that walks top-level dirs and infers `role` from README/`package.json`
is a v2 follow-up.