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
44 changes: 28 additions & 16 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

`interfacectl` is a command-line tool for managing interface contracts in the Surfaces ecosystem. It validates, compares, and enforces compliance between defined interface contracts and actual implementation artifacts across multiple surfaces.

## Generation-time gating

`interfacectl validate` is the canonical command for contract compliance. Use it to gate changes before merge or deployment. For deterministic, category-based exit codes, use `--exit-codes v2` or set `INTERFACECTL_EXIT_CODES=v2`. The command `enforce --mode fail` runs a structural diff and applies a policy threshold. It is optional and useful when you want to block on diff severity separately from compliance. For the minimal contract format and where contract semantics live in the repo, see [docs/contract-baseline.md](docs/contract-baseline.md).

## Commands

### `validate`
Expand Down Expand Up @@ -79,7 +83,7 @@ Performs comprehensive validation of surface implementations against an interfac
{
"code": "string",
"severity": "error | warning",
"category": "E0 | E1 | E2 | E3",
"category": "E0 | E1 | E2",
"surface": "string",
"message": "string",
"expected": "unknown",
Expand Down Expand Up @@ -139,8 +143,8 @@ Performs a structural comparison between the contract definition and observed su
**Note:** E3 (non-blocking drift) only exists in v2 and requires policy-driven severity downgrades to `info`. v1 always exits `1` if any entries exist, regardless of severity. A deprecation warning is printed in v1 mode when diffs exist.

**Diff Entry Types:**
- `added`: Path exists in contract but not in observed
- `removed`: Path exists in observed but not in contract
- `added`: Path exists in observed but not in contract
- `removed`: Path exists in contract but not in observed
- `modified`: Path exists in both but values differ
- `renamed`: Path was renamed (detected via similarity threshold)

Expand Down Expand Up @@ -242,8 +246,8 @@ interfacectl enforce [options]

**Description:**
Applies enforcement policies to interface contracts through three modes:
- **fail**: Validates compliance and exits with error code on violations
- **fix**: Automatically applies safe, mechanical fixes to non-compliant code
- **fail**: Runs a structural diff and exits with an error code when differences exceed the policy threshold
- **fix**: Applies safe, mechanical fixes based on policy rules
- **pr**: Generates patches for review (unified diff or JSON patch format)

**Options:**
Expand All @@ -266,10 +270,10 @@ Applies enforcement policies to interface contracts through three modes:
**Enforcement Modes:**

1. **fail** (default):
- Checks for contract violations
- Exits with error code if violations exceed policy threshold
- Runs a structural diff between the contract and observed descriptors
- Exits with an error code if differences exceed the policy threshold
- Does not modify files
- Suitable for CI/CD validation
- Suitable for CI when you want policy-based blocking on diff severity

2. **fix**:
- Automatically applies safe fixes matching autofix rules
Expand All @@ -293,15 +297,15 @@ Applies enforcement policies to interface contracts through three modes:
**v2 (new contract, opt-in via `--exit-codes v2` or `INTERFACECTL_EXIT_CODES=v2`):**
- `0`: Enforcement passed (no violations or fixes applied successfully)
- `10`: E0 - Artifact invalid (config/policy load failures, internal errors)
- `30`: E2 - Violations remaining (does not distinguish E1 vs E2 for exit codes)
- `30`: E2 - Differences exceed policy threshold (does not distinguish E1 vs E2 for exit codes)

**Note:** enforce does not distinguish E1 (token policy) vs E2 (interface contract) violations for exit codes - both return `30` in v2. However, JSON findings still carry `category: "E1"` or `category: "E2"` so downstream tools can see what happened. A deprecation warning is printed in v1 mode when violations exist.

**Output Format (JSON):**
```json
{
"schemaVersion": "1.0.0",
"mode": "fix | pr",
"mode": "fail | fix | pr",
"policy": {
"version": "string",
"fingerprint": "string"
Expand Down Expand Up @@ -385,7 +389,7 @@ Enforcement policies define:
- Rename detection via similarity thresholds
- Drift risk identification and reporting

### Policy Enforcement
### Policy-based enforcement
- Rule-based autofix system
- Safety level enforcement (only mechanical changes)
- Confidence scoring for applied fixes
Expand All @@ -405,14 +409,22 @@ Enforcement policies define:

## Integration Examples

### CI/CD Validation
### CI/CD Validation (canonical gate)

Use validate with v2 exit codes for contract compliance in CI:

```bash
interfacectl validate --root . --contract ./contracts/ui.contract.json --format json
interfacectl validate --root . --contract ./contracts/ui.contract.json --format json --exit-codes v2
```

### Pre-commit Hook
Or set the environment variable: `INTERFACECTL_EXIT_CODES=v2`.

### Pre-commit Hook (optional: policy-on-diff)

To block on structural diff severity in addition to validate:

```bash
interfacectl enforce --mode fail --strict
interfacectl enforce --mode fail
```

### Automated Fixing
Expand Down Expand Up @@ -455,7 +467,7 @@ When using `--exit-codes v2` or `INTERFACECTL_EXIT_CODES=v2`:
**enforce v2**: 0 / 10 / 30
- `0`: Enforcement passed (no violations or fixes applied successfully)
- `10`: E0 - Artifact invalid
- `30`: E2 - Violations remaining (does not distinguish E1 vs E2)
- `30`: E2 - Differences exceed policy threshold (does not distinguish E1 vs E2 for exit codes)

**Note on v1 internal errors:** v1 internal errors may be `2` or `3` depending on command (diff uses `3` if it currently does); v2 unifies to `10`.

Expand Down
25 changes: 18 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

Interface contract tooling for the Surfaces ecosystem. Validates, compares, and enforces compliance between defined interface contracts and actual implementation artifacts across multiple surfaces.

## Planning

All feature work must align with docs/plans/contract-first-enforcement-alignment.md.

## Feature planning requirement

Before planning or implementing any feature, read "docs/strategy.md" and produce a short "Feature Plan" that explicitly maps the work to the strategy decision filter and enforcement model.

See "docs/feature-plan.template.md".

This repository contains two packages:

- **`@surfaces/interfacectl-validator`** — Core validation library with TypeScript types, schema validation, and bundled contract schema definitions. Provides the foundation for contract validation.
Expand Down Expand Up @@ -53,14 +63,16 @@ interfacectl diff [options]

### `enforce`

Enforces policy on interface contracts using configurable enforcement modes: `fail` (validate and exit on violations), `fix` (automatically apply safe fixes), or `pr` (generate patches for review).
Enforces policy on interface contracts using configurable enforcement modes: `fail` (run diff and exit when policy threshold is exceeded), `fix` (automatically apply safe fixes), or `pr` (generate patches for review).

```bash
interfacectl enforce [options]
```

For complete command documentation with all options, exit codes, and output formats, see [API.md](API.md).

**Generation-time gating:** `interfacectl validate` is the canonical command for contract compliance. Use it to gate changes before merge or deployment. For local use and CI, run validate with your contract path and, for deterministic exit codes, use `--exit-codes v2`. The command `enforce --mode fail` is optional; it runs a structural diff then applies a policy threshold and is useful when you want to block on diff severity separately from compliance.

## Usage Examples

### Validation
Expand Down Expand Up @@ -132,6 +144,7 @@ Configuration options can be set via environment variables:
- `SURFACES_ROOT` — Project root directory (defaults to current working directory)
- `SURFACES_CONTRACT` — Path to contract JSON file (defaults to `contracts/surfaces.web.contract.json`)
- `SURFACES_CONFIG` — Path to interfacectl config JSON file (defaults to `interfacectl.config.json`)
- `INTERFACECTL_EXIT_CODES` — Exit code version (`v1` or `v2`, default: `v1`). Use `v2` in CI for stable category-based exit codes.

**Precedence:** CLI flags > environment variables > defaults

Expand All @@ -152,7 +165,7 @@ The config file tells interfacectl where to find surface descriptors in your cod

## CI/CD Integration

Example GitHub Actions workflow:
**Recommended:** Use `interfacectl validate` with `--exit-codes v2` as the contract compliance gate. Example GitHub Actions workflow:

```yaml
- uses: pnpm/action-setup@v4
Expand All @@ -163,14 +176,12 @@ Example GitHub Actions workflow:
node-version: 20
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm exec interfacectl validate --root . --contract contracts/ui.contract.json --format json
- run: pnpm exec interfacectl validate --root . --contract contracts/ui.contract.json --format json --exit-codes v2
```

For enforcement in CI, use:
You can set `INTERFACECTL_EXIT_CODES=v2` in the job environment instead of passing `--exit-codes v2` if you prefer.

```yaml
- run: pnpm exec interfacectl enforce --mode fail --strict
```
Optional: to block on structural diff severity (policy-on-diff), run `interfacectl enforce --mode fail` in addition to or instead of validate, depending on your workflow.

## Development

Expand Down
52 changes: 52 additions & 0 deletions docs/contract-baseline.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Contract baseline

This document describes the minimal authoritative interface contract used by interfacectl. It lets you understand what the contract requires without reading the JSON schema file alone. For the exact schema, see the schema location below.

## Required top-level fields

Every contract must include:

- **contractId** (string, non-empty): Identifier for the contract. Used for traceability.
- **version** (string): Semantic version. Must match the pattern `X.Y.Z` (e.g. `1.0.0`).
- **surfaces** (array, at least one item): List of surfaces (apps or UIs) that the contract governs. Each surface has its own required and allowed values.
- **sections** (array, at least one item): List of sections that surfaces can implement. Each section has an id, intent, and description.
- **constraints** (object): Global constraints. Today the only required part is **motion**: an object with **allowedDurationsMs** (array of integers, milliseconds) and **allowedTimingFunctions** (array of strings).

## Per-surface required fields

Each entry in **surfaces** must have:

- **id** (string): Lowercase alphanumeric and hyphens only. Must match the key used in `interfacectl.config.json` surfaceRoots.
- **displayName** (string, non-empty): Human-readable name.
- **type** (string): Either `"web"` or `"cli"`.
- **requiredSections** (array): Section ids that this surface must implement. Section id pattern: `a-z0-9` and dots (e.g. `main.hero`).
- **allowedFonts** (array, at least one string): Font family values that the surface may use. Implementations are checked against this list.
- **layout** (object): Must include **maxContentWidth** (number, minimum 1). Optionally **requiredContainers** (array of strings) and **pageFrame** (containerSelector, containerMaxWidthPx, paddingXpx, and optional alignment and enforcement).

## Per-section required fields

Each entry in **sections** must have:

- **id** (string): Matches the pattern used in surface requiredSections.
- **intent** (string, non-empty): Purpose of the section. Not yet used as an enforcement hook; documented for clarity.
- **description** (string, non-empty): Human-readable description.

## Optional: color policy

The top-level **color** object is optional. When present it can include:

- **sourceOfTruth**: If `type` is `"tokens"`, you must provide **tokenNamespaces** (array of strings). Used to allow or disallow CSS variable namespaces for colors.
- **rawValues**: **policy** is required (`"off"`, `"warn"`, or `"strict"`). Optional **allowlist** and **denylist** arrays of color values. Controls whether raw color literals (hex, rgb, hsl) are allowed.
- **semantics**: Optional **roles** (accent, text, background, border) each with **enforcement** (`"off"`, `"warn"`, `"strict"`).
- **consistency**: Optional **acrossSurfaces** with **enforcement** and **signals**.

## Deprecated fields

- **allowedColors** (per-surface): Deprecated. The schema still accepts it for compatibility. Prefer the top-level **color** policy with **sourceOfTruth** and **rawValues**. Migration: move per-surface color allowlists into **color.sourceOfTruth** (e.g. token namespaces) or **color.rawValues** (allowlist/denylist). The CLI emits a deprecation warning when allowedColors is present.

## Where contract semantics live in the repo

- **Schema file:** `packages/interfacectl-validator/src/schema/surfaces.web.contract.schema.json`. This is the authoritative JSON Schema. The CLI uses a bundled copy; you can override with `--schema <path>`.
- **Structure validation:** The function **validateContractStructure** in `packages/interfacectl-validator/src/index.ts` loads the schema and validates contract JSON (via AJV). It returns errors or the parsed contract.
- **Compliance evaluation:** The function **evaluateContractCompliance** in the same file takes a validated contract and a list of surface descriptors. It returns a validation summary with per-surface reports and violations. Compliance rules (fonts, colors, layout, motion, sections, pageFrame) are implemented in **evaluateSurfaceCompliance** in that file.
- **CLI entry point:** The validate command is implemented in `packages/interfacectl-cli/src/commands/validate.ts`. It calls **collectSurfaceDescriptors** (in `packages/interfacectl-cli/src/descriptors/static-analysis.ts`) to gather descriptors from the codebase, then passes the contract and descriptors to **evaluateContractCompliance**. The CLI maps violation types to stable codes (e.g. `font.disallowed`) in that command file.
39 changes: 39 additions & 0 deletions docs/feature-plan.template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Feature Plan

## Summary
Describe the feature in 2 to 4 sentences.

## Strategy alignment
Explain how this work strengthens the decision filter sentence from "docs/strategy.md". Be specific.

Decision filter sentence
"When an agent proposes a change to the user experience, Surfaces determines whether that change is allowed, under what conditions it may proceed, and blocks or corrects it if it violates intent."

## Contract impact
1. Contract definition
What contract fields or semantics are added or changed. Include intent, invariants, allowed change surface, contextual conditions.

2. Enforcement timing
Which enforcement points apply. Generation time, runtime, or both.

3. Violation handling
What happens on violation. Blocked, corrected, constrained, or signaled.

## Surface impact
Which surface this affects and why.
- surfaces.systems
- surfaceops.ai
- interfacectl

## Non-goals
List what this explicitly does not do to avoid scope drift.

## Acceptance criteria
Write 5 to 10 testable criteria.

## Risks and drift checks
List the top 3 ways this could drift into observability-only, design tooling, prompt tooling, or orchestration.
Add one mitigation per risk.

## Implementation outline
List the smallest steps that can ship value.
Loading