# Monorepo / Multi-Activity Constitution (v1)

Derived from first principles. Paste into `.specify/memory/constitution.md` via
`/speckit.constitution`. Preserve the exact phrasing of each principle; do not
paraphrase into generalities.

This template is **activity-scoped**, not path-scoped. It is designed to be
applied before the file structure exists (Spec-Kit order: constitution first,
plan later). Rules fire on what the agent is doing (writing a network handler,
designing a data boundary, adding telemetry), not on which folder the file
eventually lands in.

Source: https://daita.io/blog/spec_kit_constitution_first_principles

## How To Apply

- **Core** rules apply to every file, every plan, every diff.
- **Activity** rules apply whenever the current work matches the activity. The
  agent must check the activity list at the start of each plan step and at
  the start of each file it writes. Multiple activities can apply at once
  (for example, a service with UI and telemetry is in three activities
  simultaneously).
- Ignore activities your project does not engage in. Deleting an activity
  section is preferable to leaving it dormant.

## Core (applies always)

### C1. Optimize for deletion, not extension

A module must be small enough that one engineer can delete and rewrite it in
a day. Reject speculative abstractions. Inline until it hurts, then extract.
Duplication below three occurrences is cheaper than the wrong abstraction.

### C2. Make dependencies explicit

No hidden coupling, no implicit global state, no import-time side effects.
A reader must be able to see every dependency of a function in its signature
or at the top of its file. Dependency injection over singletons.

### C3. Test the transformation, not the plumbing

Unit tests cover pure transformation logic. Integration tests cover the
boundaries. Do not mock what you own; do mock what you do not. A green CI
without a failing test for the bug you just fixed is not green.

### C4. Commands are discoverable; local dev matches CI

Every repeatable action (build, test, lint, migrate, deploy, seed) is a
single named command listed in one place and runnable with no hidden
arguments. The command a developer runs locally is the same command CI
runs. If a new contributor cannot list every command in 30 seconds, the
interface is broken.

### C5. Recovery over prevention

Every change must be revertible in under five minutes without a code change.
Feature flags gate risky paths. Migrations are expand-then-contract.
Rollback is tested as part of the deploy, not assumed.

### C6. Value is realized at the user, not at merge

A PR is not done until the change is in the hands of users, observable, and
revertible. "Shipped" means deployed, instrumented, and monitored, not
merged.

## Activity: designing a process, service, or deployable

### A1. Do not distribute by default

Vertical scaling and a single deployable is the starting point. A new
process, service, or queue requires a written justification tied to one of:
working-set overflow, genuinely independent compute, geographic latency, or
organizational independence. Coordination is a cost measured in round trips,
not milliseconds.

## Activity: defining a producer/consumer boundary (HTTP, queue, file, database)

### A2. Contract at the boundary, not in the middle

Every boundary has a schema with a version. No shared mutable schemas. The
contract is defined before the pipe is built.

### A3. Semantic reconciliation at the boundary

Shared column or field names do not imply shared meaning. Reconciliation
(unit conversion, timezone normalization, identity resolution) happens at
the boundary owned by the party that understands both sides.

## Activity: writing UI code

### A4. Accessibility is a correctness property

Keyboard navigation, focus order, ARIA roles, and color contrast are not
polish. Every interactive element must be reachable by keyboard and
announced by a screen reader. No `<div onClick>` in new code.

### A5. Render what you can prove

No loading spinner without a timeout. No error state without a retry path.
No empty state without copy. A component that can render "nothing" must
render a deliberate "nothing", not a blank frame.

### A6. Measure what users feel

Core Web Vitals (LCP, INP, CLS) are the latency budget. Regressions are
treated like test failures. Bundle size is tracked per route; new
dependencies that push over budget require a written justification.

### A7. State lives at the edge it is needed

URL state is URL state. Server state is server state (cache, not store).
Form state is local. Global client state is the last resort.

## Activity: writing a data transformation

### A8. Contract before pipeline

Every producer output and consumer input is a versioned schema before the
transformation is written. Schema changes are expand-then-contract.

### A9. Provenance is non-negotiable

Every row has a traceable origin: source system, ingest time, pipeline
version, upstream record id. Walking backward from a wrong downstream row
to the originating record must take minutes, not days.

### A10. Idempotency is a correctness property

Every job is safe to re-run on the same inputs and produce the same
outputs. Upserts over inserts. Deterministic partitioning. No side effects
outside the declared outputs.

### A11. Collect with purpose

Only ingest data with an identified consumer and use case. "Collect
everything in case we need it" is rejected. Unused tables are deleted.

## Activity: designing a CLI command

### A12. Stable, versioned interface; exit codes are contracts

Every command has a documented, versioned interface. Exit codes are
meaningful (0 success, distinct non-zero codes for distinct failure
classes). Breaking flag changes require a major version bump.

### A13. Fail loudly, exit predictably

Errors print to stderr, results print to stdout. Never swallow errors into
"operation completed" messages. A non-zero exit is always paired with a
human-readable stderr message.

### A14. Composability over features

New behavior composes with Unix tools (pipes, stdin, stdout, exit codes)
before becoming a new flag. If `mytool list | grep foo` works, do not add
`mytool list --filter foo` without a written justification.

### A15. Startup is fast, help is instant

`--help` returns in under 100ms. No network calls on startup. No "updating
metadata" banners without an explicit opt-in.

## Activity: integrating an LLM or agent

### A16. Evals before features

No prompt, tool, or agent flow ships without an eval that would have failed
before the change and passes after it. Every change carries its regression
case into the eval set.

### A17. Context is a budget

Tokens in context are a scarce, billed resource. Every prompt, tool schema,
and memory injection is justified against its cost. Cache-friendly ordering
(stable prefix, volatile suffix) is a correctness property.

### A18. Tools are typed contracts

Every tool has a JSON schema, a documented side-effect profile, and a
deterministic error taxonomy. Tool descriptions are prompts.

### A19. Deterministic where possible, probabilistic where necessary

Parsing, formatting, retrieval, and routing are deterministic code. Use the
model only for the irreducibly probabilistic step (generation, classification
without ground truth, judgment). A regex beats a prompt for structured input.

### A20. Separate agent authority from side-effect blast radius

Destructive tools (delete, send, pay, deploy) require human confirmation or
a signed pre-approval token. Agent permissions scale with eval coverage, not
with demo needs.

## Activity: adding telemetry

### A21. Emit structured events, derive everything else

Logs, metrics, and traces are projections of one primitive: the structured
event. High-cardinality fields (user id, request id, tenant id, feature
flag state) are required, not optional. No unstructured log lines in new
code.

### A22. Attention is finite

Every alert corresponds to a user-visible symptom and a runbook. Dashboards
are saved queries, not decoration. Delete signals that have not fired a
useful page in 90 days.
