Skip to content

Design Contracts

Oleksandr Geronime edited this page Jul 16, 2026 · 1 revision

Design Contracts

Session summaries (.serp/ai/summaries/**) are working notes an AI session keeps for itself and its children — useful, but not durable, not user-approved, and nothing gates implementation on them. Design Contracts are the durable layer above summaries: specs/**/*.design.yaml files, checked into the repo next to the .sidl/.suml files whose meaning they document, holding blocks with an explicit approval lifecycle. They're what lets an approved design — not just a chat transcript — be the thing that authorizes an AI session to write code, across as many services as a project has.

draft → proposed → approved / rejected / needs_update       (approval)
not_started → generated → implemented → validated / stale / blocked   (implementation)

Rule: an AI session may create draft/proposed blocks and propose changes, but only the user moves a block to approved — that's a human action a session must never take on itself, no exception. Marking a block generated/implemented/validated is looser: it's refused only for a draft/rejected block (a deliberate exception lets this also apply to a proposed block — see Design Sync below, where code can legitimately predate a design contract ever being reviewed). Evidence (which files implement a block) is optional, not required — the agent is trusted to have actually read the code, not mechanically forced to attach a fixed structure.


File layout

Design files follow spec ownership, not session kind — an interface's design file is named after the interface, not the service that implements it. A sequence/scenario has no design file of its own: its behavior is a block inside the owning service's design file.

Scope Path
Root / project specs/serp.design.yaml
Common/shared type specs/common/<module>.design.yaml
Service specs/services/<group>/<service>/<service>.design.yaml
Interface specs/services/<group>/<service>/<interface>.design.yaml
HMI component same tree as a service
Deployment specs/deployments/<deployment>.design.yaml
Sequence/scenario no file of its own — a block inside the owning service's design file

A design file, taken from a real generated example (AudioFocusService.design.yaml):

schema: serp.design.v1
scope:
  kind: service
  name: AudioFocusService
  spec: specs/services/system/AudioFocusService/AudioFocusService.sidl
blocks:
  - id: SVC-AudioFocusService
    approval: proposed
    description: "The AudioFocusService is the sole arbiter of audio focus for the
      MultimediaPlayer system. It maintains which owner currently holds focus,
      whether audio is being ducked by navigation, and which media source last
      held focus — and it fires notifications as those states change. ..."
    implementation_refs:
      files:
        - src/services/system/AudioFocusService/AudioFocusService.cpp
        - src/services/system/AudioFocusService/AudioFocusService.hpp
      symbols:
        - MultimediaPlayer::AudioFocusService

Approval and implementation status are split into a separate file, <same-name>.state.yaml, so an approved design and its current implementation truth don't fight over the same lines in review:

schema: serp.state.v1
scope:
  kind: service
  name: AudioFocusService
  spec: services/system/AudioFocusService/AudioFocusService.sidl
blocks:
  SVC-AudioFocusService:
    implementation: implemented
    refs:
      files:
        - src/services/system/AudioFocusService/AudioFocusService.cpp
        - src/services/system/AudioFocusService/AudioFocusService.hpp
      symbols:
        - MultimediaPlayer::AudioFocusService
    design_hash: sha256:cb63a1f9...
    updated_at: 2026-07-15T15:57:13.111Z
    updated_by:
      role: service
      session_id: service::system/AudioFocusService@mrm9e5f8q42q

design_hash is what lets tooling notice a block's design changed underneath an already-implemented state (see Implementation Runs, which is built directly on this file pair).

Edits go through serp.design.patchBlock (and the approve/reject/propose tools, thin wrappers around it), never a raw file write — it mutates only the target block's fields in place and writes atomically, so every other block and every untouched comment survives byte-for-byte. A design file is meant to be reviewed as a diff.


Working with design contracts in the editor

Right-click a service/HMI/Architecture node in the SERP AI panel for:

  • Open Design Contract — opens the *.design.yaml file directly
  • Approve / Reject / Request Changes Design Block… — prompts for a block, then copies a ready-to-paste @serp design instruction for you to hand to a session (the extension itself never talks to the MCP server — same pattern as Sync Session)
  • Show Design Diff — HEAD vs. working tree, in the built-in diff editor

A N stale / design drift: N badge can appear on Architecture/service/HMI nodes once a Sync Design or Show Design Drift run has populated the index — see below.

Pending decisions (serp.design.requestDecision/answerDecision) are for questions that genuinely need your input before a block can move forward. A decision raised inside a session's workflow also gets recorded as a critical workflow question, so the session can't advance past it silently.

Six validators back all of this: design_schema, design_approval_gate, design_status_consistency (catches impossible combinations, e.g. rejected + implemented), design_context_staleness, design_coverage (flags services/interfaces/HMI components with no design file yet), and design_reference_integrity.


Design Sync / Reconciliation

Design Contracts assume greenfield order — design, then specs, then code. A project that already has specs and code before adopting this feature needs the reverse. Sync Design — one command, on the Architecture/service/HMI/sequence tree nodes (also a visible inline icon, not just right-click) — scans what already exists and proposes design blocks from it. Inferred design is never auto-approved: every block it writes starts at approval: proposed.

Running it on a single node syncs just that component. Running it on Architecture is a global sync — every component under specs/services/ plus the root project block, in one review.

The block a sync creates is a deliberately minimal skeleton — just an id, proposed, not_started — no guessed title, no guessed implementation status. Deciding what a block is for, and whether it's genuinely implemented, is left to a real read of the code, not a regex. That's the next step:

Design Draft

Right after you accept a Sync Design proposal ("Apply as Proposed"), the extension groups the newly created blocks by service/interface and spawns one headless AI session per scope to do the part a script can't: write a description in its own words (why the thing exists, how it behaves, notable specifics), and decide — from actually reading the code — whether each block is genuinely implemented, calling markImplemented/markGenerated itself when confident. It's explicitly forbidden from touching approval or approveBlock (a human decision, never the agent's), from creating/deleting blocks, or from editing anything outside its own scope.

These sessions are invisible under their own service node by construction (a distinct design-draft:: id prefix keeps them out of the service's session list) but visible in the Temp branch of the SERP AI tree while they run, plus a status-bar spinner (Drafting design text (N)). They disappear once finished — no history kept. A completion toast fires per scope. Disable auto-spawn with the serp.ai.design.autoDraftText setting.

Intake

Intake is a lightweight session kind for greenfield or pre-code work: discussing what you want at the domain level and proposing initial design contracts before any .sidl/.suml/source file exists. Its write scope is specs/**/*.design.yaml only.

Drift detection

Show Design Drift cross-references specs/design/code evidence and opens a markdown report on demand — this is a filesystem scan, so it's not run on every session's context load, only explicitly. A cheap advisory line ("Design contract is missing or stale for this scope — use Sync Design first") is added to session context from whatever the index last computed, without blocking anything.

Stale detection only covers "the member no longer exists" — a member whose signature changed while keeping its name (e.g. DoubleFloat) isn't separately flagged; re-running Sync Design will pick it up as part of the normal scan.


Related Pages

  • SERP AI Sessions — session kinds, MCP tools, the Configuration and Settings panels
  • Implementation Runs — turns non-implemented/needs_update design blocks into spawned implementation sessions, project-wide
  • AI-Driven Development — how this fits into the overall spec → design → implementation flow

Clone this wiki locally