From 38592523e76dcaf994e4a8d324b78b722a6f3c63 Mon Sep 17 00:00:00 2001 From: Mike Long Date: Fri, 30 Jan 2026 22:05:19 -0800 Subject: [PATCH] docs: Phase 0 and Phase 1 contract-first gating documentation - Phase 0: Add docs/contract-baseline.md with minimal contract format, required fields, optional color policy, deprecated allowedColors, schema path, and validation entry points - Phase 1: Update README and API to state validate is canonical gate; CI examples use --exit-codes v2; document INTERFACECTL_EXIT_CODES; position enforce --mode fail as optional policy-on-diff - Add docs/strategy.md and docs/feature-plan.template.md (README refs) - Add docs/plans/contract-first-enforcement-alignment.md and phase-0-1-execution-plan.md Refs: docs/plans/phase-0-1-execution-plan.md Co-authored-by: Cursor --- API.md | 44 +++-- README.md | 25 ++- docs/contract-baseline.md | 52 +++++ docs/feature-plan.template.md | 39 ++++ .../contract-first-enforcement-alignment.md | 145 ++++++++++++++ docs/plans/phase-0-1-execution-plan.md | 123 ++++++++++++ docs/strategy.md | 180 ++++++++++++++++++ 7 files changed, 585 insertions(+), 23 deletions(-) create mode 100644 docs/contract-baseline.md create mode 100644 docs/feature-plan.template.md create mode 100644 docs/plans/contract-first-enforcement-alignment.md create mode 100644 docs/plans/phase-0-1-execution-plan.md create mode 100644 docs/strategy.md diff --git a/API.md b/API.md index 94c4e90..cd8ce66 100644 --- a/API.md +++ b/API.md @@ -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` @@ -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", @@ -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) @@ -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:** @@ -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 @@ -293,7 +297,7 @@ 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. @@ -301,7 +305,7 @@ Applies enforcement policies to interface contracts through three modes: ```json { "schemaVersion": "1.0.0", - "mode": "fix | pr", + "mode": "fail | fix | pr", "policy": { "version": "string", "fingerprint": "string" @@ -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 @@ -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 @@ -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`. diff --git a/README.md b/README.md index 7eba14f..e219c50 100644 --- a/README.md +++ b/README.md @@ -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. @@ -53,7 +63,7 @@ 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] @@ -61,6 +71,8 @@ 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 @@ -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 @@ -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 @@ -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 diff --git a/docs/contract-baseline.md b/docs/contract-baseline.md new file mode 100644 index 0000000..c9c8b00 --- /dev/null +++ b/docs/contract-baseline.md @@ -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 `. +- **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. diff --git a/docs/feature-plan.template.md b/docs/feature-plan.template.md new file mode 100644 index 0000000..01e885d --- /dev/null +++ b/docs/feature-plan.template.md @@ -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. \ No newline at end of file diff --git a/docs/plans/contract-first-enforcement-alignment.md b/docs/plans/contract-first-enforcement-alignment.md new file mode 100644 index 0000000..61c9358 --- /dev/null +++ b/docs/plans/contract-first-enforcement-alignment.md @@ -0,0 +1,145 @@ +# Feature Plan +Interfacectl — Contract-First Enforcement Alignment + +## Summary +Evolve interfacectl into a contract-first enforcement CLI that gates agent-driven interface changes at generation time and produces runtime-consumable enforcement artifacts. The repo already provides deterministic contract validation (`validate`), contract-vs-observed diff (`diff`), and policy-based enforcement (`enforce` with fail/fix/pr). Missing pieces: a single gating workflow that teams can adopt (e.g. `gate` or a clear recommendation), runtime bundle compilation (`compile`), and violation explainability (`explain`). The plan aligns existing behavior with the strategy and adds only what is needed for contract-first gating and runtime consumption. Interfacectl does not generate UI, act as a linter without contracts, or function as an observability tool. + +--- + +## Strategy Alignment + +This feature strengthens the Surfaces decision filter sentence by making it executable in developer workflows. + +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." + +Interfacectl enforces this by: +- validating contracts that define intent and invariants, +- gating proposed changes during development and CI, +- producing deterministic outputs that runtime systems can enforce without reinterpretation. + +--- + +## Contract Impact + +### 1. Contract definition +The authoritative contract schema lives in `packages/interfacectl-validator/src/schema/surfaces.web.contract.schema.json`. Contracts are JSON files (default path `contracts/surfaces.web.contract.json` or `SURFACES_CONTRACT`). The schema already includes: +- **Version and scope:** `contractId`, `version` (semver pattern). +- **Surfaces:** per-surface `requiredSections`, `allowedFonts`, `layout` (maxContentWidth, requiredContainers, optional pageFrame), deprecated `allowedColors`. +- **Sections:** `id`, `intent`, `description` (intent is present but not yet a first-class enforcement hook). +- **Constraints:** global `motion` (allowedDurationsMs, allowedTimingFunctions). +- **Color policy:** optional `color` (sourceOfTruth, rawValues, semantics, consistency). + +Missing or implicit today: +- No explicit "allowed change surface" or "contextual conditions" as top-level contract concepts; they are implied by surfaces and sections. +- Contract changes are not yet classified as breaking vs non-breaking; diff entries have severity but no formal breaking classification. + +Migration: `allowedColors` is deprecated in favor of `color.sourceOfTruth` and `color.rawValues`; existing contracts may need a one-time migration. New schema fields should remain additive where possible. + +### 2. Enforcement timing +- **Generation time:** Today gating is achieved by running `interfacectl validate` or `interfacectl enforce --mode fail`. Validate checks contract compliance against descriptors collected from the codebase; enforce fail runs diff then evaluates against policy. CI does not yet run interfacectl; adding a step is repo-specific. +- **Runtime:** No compiled bundles yet. `interfacectl compile` (or equivalent) does not exist; runtime consumers would need a defined bundle format and output location. + +### 3. Violation handling +- Violations are reported and, when used as a gate, cause non-zero exit codes (v1: 1/2; v2: 10/20/30 by category). +- Each violation already has a stable code (e.g. `font.disallowed`, `section.missing`) and maps to a category (E0/E1/E2). The validator emits `DriftViolation` with `type`, `message`, and optional `details` (including `jsonPointer` for some checks). +- There is no `interfacectl explain` today; human-readable text is in command output and in the `message` field of JSON findings. Adding a dedicated explain command would centralize violation-code documentation. +- Fail mode is the default for enforce; no silent failures. Advisory-only would require an explicit policy or flag, not the default. + +--- + +## Surface Impact + +- **interfacectl** + Primary execution and gating surface for contracts in local development and CI. + +- **surfaces.systems** + Source of canonical contract definitions consumed by interfacectl. + +- **surfaceops.ai** + Downstream consumer of structured violation signals emitted by interfacectl. No dashboards or reporting added to the CLI. + +--- + +## Non-Goals + +- Generating UI, code, or prompts. +- Acting as a general-purpose linter. +- Performing visual diffs or screenshot comparisons. +- Providing dashboards, analytics, or reporting interfaces. +- Making probabilistic or heuristic-based judgments. + +--- + +## Acceptance Criteria + +1. **Contract validation:** Running `interfacectl validate` with a valid contract and compliant descriptors exits 0; with schema or compliance errors it exits non-zero and prints clear errors. Verifiable via existing validator tests and CLI integration tests. +2. **Gating:** A run that detects violations (validate with violations, or enforce --mode fail with policy threshold exceeded) exits non-zero so CI or pre-commit can block. Verifiable by running against fixtures in `packages/interfacectl-cli/test/fixtures` and asserting exit codes. +3. **Violation mapping:** Every finding in validate/diff/enforce JSON output includes a stable `code` and, where applicable, `category` (E0/E1/E2/E3). Violation types in `DriftViolationType` and the code map in `validate.ts` (e.g. `font.disallowed`) remain the single source of truth. +4. **Runtime bundle (new):** A command (e.g. `interfacectl compile`) produces a versioned artifact (format TBD) that runtime or edge systems can consume. Verifiable by running the command and checking output exists and passes a minimal schema check. +5. **Semantics consistency:** The same contract schema and compliance logic in `@surfaces/interfacectl-validator` are used for validate and for any future compile output; no duplicate semantics. +6. **Output:** All current commands support `--format json` and text; any new commands (gate, compile, explain) must support both where applicable. +7. **Fail fast:** Contract load failure, schema validation failure, or config load failure exits immediately with E0 (e.g. exit 10 in v2); no partial success. Already true in validate and enforce; preserve in new code. + +--- + +## Risks and Drift Checks + +1. **Generic lint drift:** interfacectl could drift toward generic lint behavior. + Mitigation: Every check must be backed by the contract schema or a contract-backed rule (e.g. diff entries tied to contract paths). Existing violation types in `violation-classifier.ts` and the validator are already contract-scoped. + +2. **Observability creep:** Dashboards or aggregation could be added to the CLI. + Mitigation: Emit structured JSON only; no aggregation or visualization in interfacectl. Diff and validate already emit machine-readable findings; keep it that way. + +3. **Design-only rules:** Aesthetic or non-behavioral rules could be added. + Mitigation: Enforce only what the contract declares (surfaces, sections, constraints, color policy). Existing checks (fonts, colors, layout, motion, pageFrame) are all contract-defined. + +4. **Command surface sprawl:** New commands could duplicate or blur semantics. + Mitigation: Keep core surface to validate, diff, enforce, and any new gate/compile/explain. Document in API.md which command to use for gating (validate vs enforce --mode fail) so "gate" is either an alias or a single recommended workflow. + +5. **Repo-specific: two gating paths.** Validate runs contract compliance against descriptors; enforce --mode fail runs diff then policy. They can disagree (e.g. validate passes but diff has entries). + Mitigation: Decide and document the canonical gating workflow (e.g. "use validate for compliance; use enforce for policy-on-diff") and, if adding `gate`, make it a thin wrapper that calls one or both explicitly. + +6. **Repo-specific: v1 exit codes default.** v2 exit codes (10/20/30) are opt-in via `--exit-codes v2` or `INTERFACECTL_EXIT_CODES=v2`. CI and docs may assume v1. + Mitigation: When adding CI steps, use v2 explicitly. Plan for v2 as default in a future major release; keep v1 behavior until then. + +7. **Repo-specific: CI does not run interfacectl.** `.github/workflows/ci.yml` runs verify, build, test only. + Mitigation: Adding a contract check to CI is out of scope for this plan but should be a follow-up (e.g. optional job that runs `interfacectl validate` or `interfacectl enforce --mode fail` against a fixture or repo contract). + +--- + +## Implementation Outline + +### Phase 0. Contract baseline (mostly done; align and document) +- **Reuse:** Contract schema is in `packages/interfacectl-validator/src/schema/surfaces.web.contract.schema.json`. Validation is `validateContractStructure` in `packages/interfacectl-validator/src/index.ts` (AJV). Error taxonomy is `DriftViolationType` and the code map in `packages/interfacectl-cli/src/commands/validate.ts` (e.g. `font.disallowed`). +- **New/minimal:** Document the minimal authoritative contract (required fields, optional color policy, deprecated allowedColors). Optionally add a short "contract concepts" section to API.md or docs. No schema change required unless adding breaking/non-breaking metadata later. + +### Phase 1. Generation-time gating (map to existing commands; optional alias) +- **Reuse:** Gating today is `interfacectl validate` (compliance) or `interfacectl enforce --mode fail` (diff + policy). Both support `--root`, `--contract`, `--config`, `--surface`, `--format json`, and v2 exit codes. Dry-run for fix mode exists (`enforce --mode fix --dry-run`). +- **New:** Either (a) add `interfacectl gate` as an alias that runs validate (and optionally enforce fail) with a fixed set of options, or (b) document in README/API.md the recommended gating command (e.g. "for CI, run `interfacectl validate --exit-codes v2`"). If adding `gate`, wire it in `packages/interfacectl-cli/src/index.ts` and keep it thin (no duplicate logic). +- **CI:** Out of scope for this plan; follow-up can add an optional CI job that runs validate or enforce against a repo contract. + +### Phase 2. Drift-relevant enforcement (already present; tighten semantics) +- **Reuse:** Contract-backed checks exist in `evaluateSurfaceCompliance` (validator) and in diff (contract vs observed descriptors). Structured violation signals are already emitted: validate/diff/enforce JSON output with `code`, `category`, `findings`/`entries`. Drift risks are in `DiffOutput.driftRisks`. +- **New/minimal:** Ensure every diff entry that affects enforcement has a `rule` or contract path where possible (already in types; some entries may leave `rule` unset). No new checks unless they are deterministic and contract-backed. + +### Phase 3. Runtime compilation (new work) +- **New:** Implement a command (e.g. `interfacectl compile`) in `packages/interfacectl-cli`. Input: contract path (and optionally config). Output: a versioned bundle (e.g. JSON or a small artifact) that runtime or edge systems can load. Reuse: load contract and schema via same paths as validate; reuse `validateContractStructure` so only valid contracts compile. +- **Scope:** Define bundle format (e.g. contract + metadata, no new semantics). One target initially; "multiple runtime targets" can be a later phase if needed. +- **Location:** New command in `src/commands/compile.ts`, registered in `src/index.ts`. Validator may expose a small helper (e.g. "canonical contract shape for runtime") if useful; no duplicate compliance logic. + +### Phase 4. Ergonomics and explainability (new and small improvements) +- **New:** Add `interfacectl explain ` (or similar) that prints a short description and remediation for a violation code. Data can live in a static map (code to text) in the CLI or in a small JSON file; no network call. Register in `src/index.ts`. +- **Optional:** Contract diffing with explicit breaking vs non-breaking classification would require defining rules (e.g. removal of required section = breaking) and adding a classification step to diff output; can be a follow-up. +- **Reuse:** Failure messages already exist in validator (`DriftViolation.message`) and in validate text output; improve only where unclear (e.g. add one-line remediation for common codes in explain). + +--- + +## Builder Checklist + +Before implementation begins: +- **Contract location:** Canonical schema is `packages/interfacectl-validator/src/schema/surfaces.web.contract.schema.json`. Contract files are project-specific (default `contracts/surfaces.web.contract.json` or `SURFACES_CONTRACT`). Ownership is repo; surfaces.systems is the intended source of canonical definitions per strategy. +- **Generation-time gating:** Current CI (`.github/workflows/ci.yml`) runs verify, build, test only. Gating fits as an optional job (e.g. `interfacectl validate` or `enforce --mode fail` against a repo contract). Confirm with maintainers where to add it (e.g. on PR, on main, or as an optional job). +- **Runtime consumers:** No runtime consumers for compiled bundles exist yet. Before implementing `compile`, confirm at least one consumer or a concrete bundle format requirement; otherwise defer or define a minimal format and document it for future consumers. + +If any of these are unclear, stop and resolve before coding. \ No newline at end of file diff --git a/docs/plans/phase-0-1-execution-plan.md b/docs/plans/phase-0-1-execution-plan.md new file mode 100644 index 0000000..c6e2a47 --- /dev/null +++ b/docs/plans/phase-0-1-execution-plan.md @@ -0,0 +1,123 @@ +# Phase 0 and Phase 1 Execution Plan + + +## Purpose and scope + +_Approval note:_ This section is approved as written. Scope is intentionally constrained to documentation and alias-level changes to prevent premature expansion. + +This document defines the scope of Phase 0 and Phase 1 from docs/plans/contract-first-enforcement-alignment.md. It records the chosen gating workflow, exit code decision, and testable acceptance criteria so implementation PRs can be reviewed against a single source of truth. + +**In scope:** Phase 0 (contract baseline documentation and alignment) and Phase 1 (generation-time gating documentation and optional alias). No new enforcement logic; only documentation and, if chosen, a thin gate command. + +**Out of scope for this plan:** Phase 2 (drift-relevant enforcement tightening), Phase 3 (runtime compile), Phase 4 (explain, contract diff breaking classification). Any code that implements compile, explain, or new validation rules is out of scope until a follow-up plan is approved. + +--- + + +## Chosen gating option: "validate is the gate" (Option A) + +_Approval note:_ Decision is approved. "validate" correctly represents contract compliance, distinct from diff-plus-policy enforcement. Treat "canonical gate" as stable language going forward. + +**Decision:** The canonical generation-time gating workflow is **validate**. For local use and CI, the recommended command is `interfacectl validate` with explicit contract and root. No separate `gate` command is required; documentation will state that validate is the gate. No `gate` command will be added in Phase 0 or Phase 1. `validate` remains the only canonical gate during these phases. If a `gate` command is considered later, it must be introduced under a separate approved plan and must be an alias only with no new behavior. + +**Reasoning:** Validate is the only command that directly checks contract compliance. It loads the contract, collects surface descriptors from the codebase via static analysis, and runs the validator's `evaluateContractCompliance`. The result answers "do implementations comply with the contract?" with deterministic exit codes. Enforce --mode fail runs diff (contract vs observed structure) then applies policy; it answers a different question ("do structural diffs exceed the policy threshold?") and depends on a policy file. Strategy says "Validate UI produced by designers, systems, or agents" and "Prevent invalid or out-of-bounds output from existing." That aligns with validate, not with diff-plus-policy. + +**What we lose by not choosing the other options:** + +- **Not choosing B (enforce --mode fail as gate):** We do not make diff-plus-policy the single recommended gate. Teams that want to block on structural diff severity can still run `interfacectl enforce --mode fail` explicitly; it remains documented in API.md and README. We accept that the canonical gate is compliance (validate), and policy-on-diff is an optional second step. + +- **Not choosing C (gate wraps one or both):** We do not add a `gate` subcommand. We avoid maintaining an alias and avoid defining what "gate" runs by default. If we later add a `gate` command, it will run validate only (thin wrapper) and will be documented as such. + +--- + +## Recommended commands + +**Local use (development):** + +```bash +interfacectl validate --root . --contract [--surface ...] [--format text|json] +``` + +Use `--format json` when piping or saving output. Use `--surface` to limit to specific surfaces. + +**CI use:** + +```bash +interfacectl validate --root . --contract --exit-codes v2 [--format json] +``` + +_Review note:_ Environment variable names are intentionally left open in Phase 0 and Phase 1. They must be confirmed and locked before any implementation work begins. + +Contract path and root may be set via environment variables supported by interfacectl. Confirm the exact names in code and document only the real ones here. Update this section once env var names are confirmed. + +--- + + +## Exit code decision: use v2 in CI + +_Approval note:_ Use v2 exit codes as the documentation default even if the binary default remains v1. This avoids future churn and keeps CI behavior deterministic. + +**Decision:** For CI and for any new documentation examples, use **v2** exit codes. Set explicitly via `--exit-codes v2` or `INTERFACECTL_EXIT_CODES=v2`. + +**Reasoning:** v2 gives stable, category-based exit codes (0, 10, 20, 30) so scripts can distinguish E0 (artifact invalid), E1 (token policy), and E2 (interface contract). v1 uses 0/1/2 and prints a deprecation warning when violations occur. The plan states v2 will become the default in a future major release. Using v2 in CI now avoids churn when the default flips and makes failure handling deterministic. + +**Exact flags or env vars:** + +- CLI: `--exit-codes v2` +- Environment: `INTERFACECTL_EXIT_CODE_VERSION=v2` + +CI workflow examples in README and API.md should show `--exit-codes v2` for validate (and for enforce when documented). + +--- + + +## Acceptance criteria (Phase 0 and Phase 1) + +_Approval note:_ Acceptance criteria are approved as written. They are testable, scoped, and explicitly prevent early implementation of Phase 2+ features. + +**Phase 0 (testable in this repo):** + +1. A section or doc exists (in API.md or docs/) that describes the minimal authoritative contract: required fields (contractId, version, surfaces, sections, constraints), optional color policy, and deprecated allowedColors. A reader can identify what the schema requires without reading the JSON schema file alone. +2. The contract schema path and the validation entry point (validateContractStructure, evaluateContractCompliance) are named in documentation so implementors know where contract semantics live. +3. No schema or validator code changes are required for Phase 0 unless they are documentation-only (e.g. comments). + +**Phase 1 (testable in this repo):** + +1. README or API.md states clearly that **validate** is the recommended command for generation-time gating (local and CI). The exact recommended command for CI includes `--exit-codes v2`. +2. README CI example(s) show `interfacectl validate ... --exit-codes v2` (and optionally `INTERFACECTL_EXIT_CODE_VERSION=v2`). +3. If a `gate` command is added: it is implemented as a thin wrapper that invokes validate with fixed or passed-through options; it does not duplicate validation logic; it is registered in the CLI command registration entry point. +4. Running `interfacectl validate --root . --contract --exit-codes v2` from the repo against an existing fixture (e.g. packages/interfacectl-cli/test/fixtures/minimal-project) exits 0 when the fixture is compliant and non-zero when the fixture is non-compliant or missing. Verify this behavior locally and ensure docs and examples match it. + +--- + + +## Out of scope (Phase 2 and beyond) + +_Guardrail:_ Do not soften or bypass this list. Any work that falls into Phase 2 or beyond requires a separate, approved plan. + +The following are explicitly out of scope for Phase 0 and Phase 1: + +- Implementing `interfacectl compile` or any runtime bundle output. +- Implementing `interfacectl explain` or a violation code lookup table. +- Adding or changing validation rules, violation types, or contract schema (beyond documentation). +- Adding a CI job in .github/workflows that runs interfacectl (optional follow-up; not part of Phase 1). +- Defining breaking vs non-breaking contract diff classification. +- Changing enforce --mode fail behavior or making it the default gate. +- Any code change in packages/interfacectl-validator except comments or doc-only edits. +- Adding a `gate` command or changing command semantics without an explicitly approved follow-up plan. + +--- + + +## Review checklist for implementation PRs + +_Review guidance:_ Use this checklist instead of intuition when reviewing PRs. If an item fails, the PR should not merge. + +Use this checklist when reviewing PRs that implement Phase 0 or Phase 1: + +1. **Plan alignment:** Does the PR only change documentation and/or add a thin gate command? Does it avoid implementing compile, explain, or new validation logic? +2. **Gating:** If documentation was updated, does it state that validate is the recommended gate and show the recommended command(s) for local and CI? +3. **Exit codes:** Do any new or updated CI examples use `--exit-codes v2` (or `INTERFACECTL_EXIT_CODE_VERSION=v2`)? +4. **Phase 0:** If contract documentation was added, does it describe required fields, optional color policy, and deprecated allowedColors? Does it point to the schema and validator entry points? +5. **Phase 1 gate (if applicable):** If a `gate` command was added, does it only call validate (or delegate to validate) with no duplicate compliance logic? Is it registered in the CLI command registration entry point? +6. **Living constraint:** Is the README constraint ("All feature work must align with docs/plans/contract-first-enforcement-alignment.md") still present and unchanged? diff --git a/docs/strategy.md b/docs/strategy.md new file mode 100644 index 0000000..44747f3 --- /dev/null +++ b/docs/strategy.md @@ -0,0 +1,180 @@ +# Surfaces Platform — Strategy Artifacts + +This document contains three aligned artifacts: +1. A one-page strategy snapshot. +2. A builder-facing execution plan. +3. Explicit product principles and anti-principles. + +These are designed to be copied, shared, and used as working constraints. + +--- + +## 1. One-Page Strategy Snapshot + +### Purpose +Surfaces exists to ensure AI- and system-driven interfaces remain understandable, predictable, and accountable as agents increasingly shape user experience. + +The core problem is unbounded agent behavior expressed through interfaces. +UI drift is a failure mode, not the system. + +--- + +### Core Thesis +As decision-making shifts from humans to agents, interfaces become the primary surface where agent behavior is exposed, trusted, or rejected. + +Without constraints: +- adaptation becomes unpredictable, +- intent erodes, +- accountability breaks down. + +Surfaces treats interfaces as systems governed by executable contracts, not artifacts governed by guidelines. + +--- + +### What Surfaces Does +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. + +This happens before users experience failure. + +--- + +### How It Works +- Interface contracts define intent, allowed change, and invariants. +- Contracts are enforced at generation time and runtime. +- Feedback from live systems improves contracts over time. +- One contract model compiles once and applies across multiple enforcement surfaces. + +--- + +### What Surfaces Is Not +- Not a design system. +- Not an analytics or observability tool. +- Not a prompt library or copilot. +- Not a UI generator. + +Surfaces governs behavioral correctness, not creative output. + +--- + +### Strategic Focus +- Hold category clarity around enforcement. +- Treat contracts as gates, not documentation. +- Prefer fewer guarantees with stronger enforcement. + +--- + +## 2. Builder-Facing Execution Plan + +### Objective +Implement Surfaces as a contract-first enforcement layer that governs agent-driven interface behavior at generation time and runtime. + +--- + +### Core Artifact +The interface contract is the primary artifact. +Everything else exists to define, enforce, or refine it. + +Each contract must specify: +1. Intent and invariants. +2. Allowed change surface. +3. Contextual conditions. + +--- + +### Enforcement Points + +#### Generation Time +- Validate UI produced by designers, systems, or agents. +- Prevent invalid or out-of-bounds output from existing. + +#### Runtime +- Evaluate agent-proposed adaptations. +- Block, correct, or constrain changes before users see them. + +Observability feeds back into contract refinement. It does not replace enforcement. + +--- + +### System Surfaces +All surfaces use the same contract model. + +- surfaces.systems + Define and version interface contracts. + +- surfaceops.ai + Collect signals from live systems to refine contracts. + +- interfacectl.com + Execute, validate, and gate contracts in code and pipelines. + +Different surfaces, same enforcement semantics. + +--- + +### Implementation Rules +- Every feature must strengthen contract definition or enforcement. +- No enforcement-free pathways. +- No post-hoc-only guarantees. +- Runtime and edge enforcement are first-class, not optional. + +--- + +### Builder Check +Before shipping anything, answer: +- What contract does this rely on? +- When is it enforced? +- What happens on violation? + +If the answer is unclear, stop. + +--- + +## 3. Product Principles and Anti-Principles + +### Product Principles + +1. Contracts over conventions + If behavior matters, it must be enforceable. + +2. Gates before feedback + Prevent failure before observing it. + +3. Adaptation is expected + Unbounded adaptation is not. + +4. Same contract, many surfaces + Enforcement context may vary. Semantics must not. + +5. Trust is a system property + It emerges from guarantees, not review. + +--- + +### Anti-Principles + +1. No guidelines without enforcement + Documentation alone is insufficient. + +2. No observability without control + Metrics do not equal safety. + +3. No design-first framing + Surfaces governs behavior, not aesthetics. + +4. No prompt-level guarantees + Constraints must be deterministic. + +5. No silent violations + Every breach must be blocked, corrected, or surfaced as a signal. + +--- + +### Non-Negotiable Filter + +If a feature, integration, or message does not clearly strengthen this sentence, it is out of scope: + +“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.” + +--- + +End of document. \ No newline at end of file