event-modeling

v1.9.0

Event Modeling Skill - Guidelines for creating Event Models on prooph board. Covers event-first modeling strategy, command eligibility tests, element types, anti-patterns, and self-validation.

Author prooph software GmbH
License MIT
Category modeling
Element Types command, event, information, ui, automation, hotspot

Event Modeling

Core guidelines for creating Event Models on prooph board.

Overview

Event Modeling is a visual technique for mapping out business information flow and domain state changes. This skill teaches AI agents the fundamental rules of building valid Event Models on prooph board — from element types and slice structure to command eligibility and anti-patterns.

Think of this skill as the foundation. When you need detailed patterns for specific elements (like example data or ASCII mockups), install the dedicated skills alongside it.

Why Event Modeling

  • Shared understanding — Visual models that business stakeholders and developers can both read
  • Domain clarity — Forces you to think about what actually happens in the business, not how it's technically implemented
  • Early risk detection — Uncovers missing requirements and ambiguous rules before development starts

When to Use

✅ Use Event Modeling ❌ Don't Use It
Mapping business processes Technical architecture diagrams
Exploring domain complexity UI wireframing or interaction design
Aligning stakeholders on workflows Database schema design
Identifying missing requirements API endpoint documentation

Usage

Once installed, your AI agent will understand the rules for:

  • Commands — Business actions that change persistent state
  • Events — Facts that became true
  • Information — Data read from the system
  • UI — Screens and views
  • Automation — Automated actors
  • Hot Spots — Open questions and uncertainties

Examples

Related Skills

Skill Purpose
example-data Adding concrete YAML examples to element descriptions
ascii-mockups Creating text-based UI mockups in element descriptions
slice-scenarios Writing Given-When-Then scenarios for slice documentation

Install these alongside Event Modeling for richer element descriptions.

nameevent-modeling
descriptionEvent Modeling Skill - Core guidelines for creating Event Models on prooph board. Covers event-first modeling strategy, command eligibility tests, element types, lane and slice structure, anti-patterns, and self-validation. Use this skill to understand the rules of Event Modeling on prooph board.

Event Modeling — Guidelines

These guidelines describe how to create Event Models on a prooph board.

Event Modeling visualizes business information flow and domain state changes inside a system.

You are a Software Architect and Domain Modeler.

Your responsibility is to model business processes using Event Modeling with a strong focus on:

  • domain correctness
  • clear causality
  • business language (not technical language)

You think in terms of real-world behavior before software.


Modes

Modeling Mode

Use this mode to create or extend an Event Model.

  • Focus on exploration and structure
  • Do not over-correct early
  • Capture the process as completely as possible

Critic Mode

Use this mode to review an existing model.

  • Apply all rules strictly
  • Identify violations, gaps, and inconsistencies
  • Suggest concrete improvements
  • Create Hotspots where assumptions were made

Do NOT mix both modes.


Core Concepts

Chapter

A chapter represents a single user journey or business process path.

Rules:

  • chapters flow in one direction
  • alternative paths use separate chapters

Alternative Paths vs. Conditional Outcomes

Do not confuse a divergent journey with a conditional outcome of one step:

  • Alternative path → separate chapter. The actor makes a different choice that leads to a genuinely different journey (e.g. "Checkout with saved card" vs. "Checkout as guest").
  • Conditional outcome → sibling slices in the SAME chapter. A single trigger — a command's decision or an automation's rule — resolves to one of several mutually-exclusive results. Model each result as its own slice in the same chapter and name the slices for the outcome (see Slice Naming). Example: a sync automation whose precedence rule writes either System A → System B or System B → System A — two Write slices, one chapter, both triggered by the same automation.

Model Structure

Lanes

Lane Type Purpose Elements Allowed
User Role User perspective UI, Automation
Information Flow Commands entering system and information leaving system Command, Information
System Context Which system handles commands Event

The Information Flow lane must not be renamed.


Slices

Slices represent steps in the process.

Each slice is one of four types:

Read Slice

Also called a State View slice.

Contains:

Information → UI (optional)

The read model is projected from previously recorded events — those events are its inputs, and
placing them in the slice is how the model shows what it projects from.

Rules:

  • one or more information elements in Information Flow lane (required)
  • UI element in User Role lane (typical, but optional — omit when the information is consumed downstream rather than displayed)
  • the source events the read model projects from may be placed in the slice's System Context lane
  • commands are NOT allowed
  • new events are NOT allowed — a Read slice consumes events that already exist and never records a state change
  • automation is NOT allowed

A Read Slice represents data read from the system, normally displayed to users on a screen. The Information is the required element; the UI is its usual companion.

Source events are inputs, not outputs. The test is not "no event stickies" but no state change: a Read slice never emits an event. Showing the source events beside the read model documents the dependency; it is not a claim about wiring. On prooph board the arrow is derived from slice order — an event in a slice before the read reaches the Information in the following read slice, while an event placed in the same slice as its Information draws no arrow. Both placements are legal; only one draws.


Write Slice

Contains:

UI (optional) -> Command → Event

Rules:

  • exactly one command in Information Flow lane — the board tools enforce this per cell, so a
    move_element into a cell that already holds a command is rejected, and swapping two slices'
    contents needs a temporary holding slice
    rather than two moves
  • one or more events in System Context lane
  • information is NOT allowed
  • automation is NOT allowed

A Write Slice represents a business action that changes system state.


Automation Slice

Contains:

Information (optional) → Automation

Rules:

  • information in the Information Flow lane is optional (zero or more elements allowed)
  • automation element in User Role lane
  • commands are NOT allowed
  • events are NOT allowed
  • UI is NOT allowed

An Automation Slice represents automated decision-making or scheduled processing.

The automation reads information from the system and triggers commands in subsequent Write Slices.

Important: Events are NOT placed in automation slices directly.

  • If an event triggers an automation: place the event in a previous Write Slice, then the automation in the next slice
  • If an automation triggers a command that produces an event: place a Write Slice (Command → Event) AFTER the automation slice

Event Reaction Slice

Contains:

Event → Automation

Rules:

  • one or more events in System Context lane
  • one automation in User Role lane
  • commands are NOT allowed
  • information is NOT allowed
  • UI is NOT allowed

An Event Reaction Slice models the pattern where an event directly triggers an automation in the same slice. This is the only valid case where an event and an automation coexist in the same slice.

Use the add_event_reaction tool to add elements to an Event Reaction Slice. The regular add_element tool will reject this combination to prevent accidental mismodeling.

Example: Order Placed (event) → Fraud Detection Service (automation)


Elements

Structure

Each element has a name — pass a bare &, not an entity: the tools escape names, so & lands
on the card literally.

Also write a short description of 2-3 sentences or bullet points. Do not write to element
details while exploring.
They are the long-form specification — where a storage or transport
concern belongs instead of a command or an event — and where an amendment appends. Both cases are
below in Description vs. Details and Amending a Chapter That Already Shipped.

Description vs. Details

An element documents itself in two places, and they are not interchangeable.

The description is the card. It describes the information flow in condensed form — what this
step does, in the business's own words — and it is what people read while walking the model. Keep
it short; this is where concrete examples and sample data earn their place. Markdown is supported
(lists, links, images, code fences, Mermaid diagrams).

The details are the sidebar (Ctrl+D, the Documentation tab). This is the long-form
specification: database schema, configuration, API endpoints, rules — whatever the element needs
and a card cannot hold. It has an auto-generated table of contents (built from #/##/###
headings), the same extended Markdown as the description, and element references (:::element)
that link to the element they name.

They differ in scope, not only in length:

Description Details
Scope The slice this placement sits in The element, at every placement
Shared No — per placement Yes — all similar elements (name + type + context) share one
Written for This step: concrete examples The element: what is true everywhere

One consequence follows: a similar element in another slice may carry a different description —
that is where a step-specific example belongs. Put it in details instead and it shows at every
placement.

Rewriting a description is therefore cheap and rewriting details is not (see Amending a Chapter
That Already Shipped): a correction moves out of the description and into details, never the
other way, and never into a second description-shaped field.

Command

Color: Blue (#26C0E7)

Represents a business action that changes system state.

Commands must:

  • express business intent
  • modify persistent state
  • cause at least one event

Naming:

  • imperative
  • title case
  • business language

Examples:

Register User
Place Order
Cancel Subscription

Invalid:

Load Orders
Fetch Data
Open Dialog


Event

Color: Orange (#FF9F4B)

Represents a business fact that became true.

Events must:

  • represent meaningful domain outcomes
  • use past tense
  • be understandable by business stakeholders

Naming:

  • past tense
  • title case
  • business language

Examples:

User Registered
Order Placed
Payment Authorized

Invalid:

Sidebar Opened
Request Completed
API Called


Information

Color: Green (#73dd8e)

Represents data read from the system.

Naming:

  • noun phrase
  • title case
  • business language

Name the data, not the machinery that produces it. Order Summary, never
OrderSummaryProjector — a class suffix on the board is an implementation
detail leaking into the model.

Examples:

User Profile
Order Summary
Invoice List

Invalid:

OrderSummaryProjector
UserProfileReadModel
InvoiceListRepository

Queries produce information, not events.


UI

Color: Light Gray

Represents screens or views.

Naming:

  • title case
  • display name, as a user would refer to the screen

Words describing what the user is looking at — Page, Screen, Grid,
Panel, Form — belong here. They are what a stakeholder would say, unlike a
class suffix such as Projector.

Examples:

Dashboard
Order Overview Page
User Profile Page

UI elements represent screens, not interactions.

UI interactions must be described in element details, not commands.

What the card itself carries is the action the actor takes, then a mockup of what they see — an
HTML block in the card, not a paragraph describing the screen. Consecutive UI cards of the same page
differ by exactly what the slice between them changed (an empty table → one row → the same row with
the field the next write set), so the delta between two cards is the story, and it is the fastest
thing a reader can scan. Rules, entry points, landings and the reason behind a gesture belong in the
slice's details, which can change without rewriting a card that renders at several placements.


Automation

Color: Purple (#EABFF1)

Represents automated actors.

Examples:

Billing Scheduler
Email Notification Service


Hot Spot

Color: Red (#f31d30)

Used to highlight:

  • missing requirements
  • unclear business rules
  • open questions
  • modeling concerns

Hot Spots should contain questions and explanations.

DO NOT WRITE INTO HOT SPOT DETAILS! Always use the element description so that all people can view the questions/concerns.

Two kinds of Hot Spot

The same red element is used for two different things, and conflating them makes a board hard to
read. Both are legitimate; be deliberate about which you are creating.

Open question Failure / skip state
Means We have not decided this yet We decided: this is what happens when it goes wrong
Written by Modeling and Critic mode slice-scenarios, as the Then of a failure or rejection scenario
Content A question, the options, and what blocks on it A named outcome with its payload — reason, ids, outcome code
Lifecycle Resolved, then retired — the ruling moves into the slice's details Permanent — it is part of the specified behavior
Blocks the gate? Yes, until resolved No — its existence is what passing looks like

A failure-state Hot Spot is not an unresolved question and must not be counted as one when
reporting completeness. Conversely, an open question dressed up with a payload looks decided when
it is not.

Resolving an open question retires the element. A red card on a finished model reads as "still
broken", which is not what a ruling looks like. Move the ruling and its rejected alternatives into
the owning slice's details.md as a dated section (### Ruled decisions) and remove the element;
a behavioural ruling also earns a Given/When/Then, which that section cannot replace. Only where
the history lives changes. A failure/skip state is never retired this way.

Reusing Elements Across Chapters (Sync)

The same command, event, or information often appears in several chapters — the chapter where it
originates, and chapters that consume it (automations, read models, other journeys). Do not re-type
it. prooph board treats elements with the same name, type, and context as one element: every copy
is synchronized, and editing one updates all of them.

Rules:

  • An element is identified by its name, type, and context. Two elements sharing all three are
    one synchronized element across every chapter; a command and an event of the same name are
    two different elements.
  • An element's context defaults to its chapter's context at creation time. The chapter context
    is a default, not a cage — elements can carry a different context than their chapter. Both are
    editable after creation: update_element accepts context, and update_chapter re-contexts
    the chapter, which cascades to the elements that shared the old chapter context.
  • A context is a bounded context — the part of the system that owns the state. Never an actor
    name (Human, Agent) and never a UI area or feature nickname.
  • To reuse an element that already exists in another chapter, copy it — never re-create it
    from scratch. Re-typed duplicates drift silently. copy_element defaults the copy to the
    source element's context, so a cross-chapter copy lands in the intended bounded context by
    itself; pass context: only when you deliberately want the copy to become a different element.
    Contexts are matched by exact string (Accounts ≠ accounts).
  • Alignment is asynchronous. copy_element returns a contentless skeleton that fills in a
    moment later (in the changelog it is an element-config-changed, not a details change).
  • details is shared; description is not. Elements sharing name + type + context synchronise
    their details field — writing it on any placement writes it everywhere — while description is
    per-placement and never shared. A copy inherits the shared details of the matching element
    already in that context
    , so the pre-existing placement's text is what survives; do not rely on
    a details: value passed to the copy. Keep slice-specific behaviour in the slice details:
    an element's details holds only what is true at every placement.
  • If two same-named elements are NOT synchronized, check their context (and type) first — a
    differing context is the cause. Repair it by aligning the context, not by re-copying:
    update_element(context:) for a single element, or update_chapter(context:) when a whole
    chapter is wrong — it cascades to every element sharing the old chapter context, and leaves an
    element that deliberately carries a different context alone.

Anti-Patterns (DO NOT MODEL)

UI Interaction Flow

Incorrect:

UI: Top Menu
Command: Open Sidebar
Event: Sidebar Opened

Reason: only UI state changes.


Data Loading as Commands

Incorrect:

Command: Load Orders
Event: Orders Loaded

Reason: reading data is a query.


Technical Events

Incorrect:

Event: API Called
Event: Response Received

Events must represent business facts.


Lane Naming

Default lane names MUST be replaced with domain-specific names.

Rules:

  • Rename User Role lane → actual actor
  • Rename System Context lane → bounded context or system name
  • Information Flow lane MUST NOT be renamed

Flow & Causality

Model causality, not strict sequence.

Rules:

  • A process MUST start with a READ or AUTOMATION slice
  • Every WRITE slice MUST have a clear trigger
  • A WRITE slice MUST NOT follow another WRITE without a trigger

Valid flows:

  • READ → WRITE
  • WRITE → READ
  • WRITE → AUTOMATION
  • AUTOMATION → WRITE
  • AUTOMATION → READ
  • WRITE → EVENT REACTION (an event triggers an automation in an Event Reaction slice)

WRITE → READ means the read that renders what that write wrote. A write slice is followed
immediately by the read slice whose read model folds its event: that adjacency is what draws the
event into a read model that actually consumes it. A write whose next read belongs to a different
page has no visible result — the operator makes a change, cannot see it, and the model cannot say
where they landed. The result read is its own slice, even when it renders the same page as an
earlier slice: two cards of one page, differing by exactly the change.

Every command must be traceable to:

  • a user decision (READ), or
  • a system reaction (AUTOMATION)

READ Slice Rules

Every READ slice MUST include:

  1. At least one Information

Event → Multiple Consecutive Read Slices

An event in a Write Slice connects to the Information element in the next slice.

If that next slice is a Read Slice (contains Information, no Event), and the slice after it is also a Read Slice, the same event connects to the Information in that following slice as well.

This chaining continues for as long as consecutive Read Slices follow one another without a new Event appearing.

The chain stops when:

  • a slice contains an Event, or
  • a slice contains no Information

Example:

Slice 1 (Write):  Order Placed (event)
Slice 2 (Read):   Order List (information)      ← event connects here
Slice 3 (Read):   Order Detail (information)    ← event also connects here
Slice 4 (Read):   Order Summary (information)   ← event also connects here
Slice 5 (Write):  Update Order (command) → Order Updated (event)  ← chain stops

Modeling rule: When a single event is the data source for multiple independent read views, place each view in its own Read Slice immediately after the Write Slice. Do not introduce a new event just to bridge read slices.


Write Slice Rules

Command → Multiple Consecutive Event-Only Slices

A Command connects to the Event in the same Write Slice.

If the next slice contains an Event but no new Command, the same Command connects to that Event as well.

This chaining continues for as long as consecutive slices contain an Event without a new Command.

The chain stops when:

  • a slice contains a Command, or
  • a slice contains no Event

Example:

Slice 1 (Write):  Place Order (command) → Order Placed (event)    ← command connects here
Slice 2:          Stock Reserved (event)                          ← command also connects here
Slice 3:          Payment Charged (event)                         ← command also connects here
Slice 4 (Write):  Ship Order (command) → Order Shipped (event)    ← chain stops

Modeling rule: When a single command produces multiple domain events as side effects, place each event in its own slice without adding a new Command. The Command from the originating slice will automatically connect to all of them.


UI/Automation → Multiple Consecutive Write Slices

A UI or Automation connects to the Command in the same slice (or the next slice if the current slice has no Command).

If the slice after that is also a Write Slice (contains a Command, no new UI or Automation), the same UI or Automation connects to that Command as well.

This chaining continues for as long as consecutive Write Slices follow one another without a new UI or Automation appearing.

The chain stops when:

  • a slice contains a UI or Automation, or
  • a slice contains no Command

Example:

Slice 1 (Write):  User Action (ui) → Place Order (command)          ← ui connects here
Slice 2 (Write):  Reserve Stock (command)                           ← ui also connects here
Slice 3 (Write):  Charge Payment (command)                          ← ui also connects here
Slice 4 (Write):  Confirm Screen (ui) → Send Confirmation (command) ← chain stops

Modeling rule: When a single user action triggers a sequence of commands with no intermediate user interaction, place each command in its own Write Slice without adding a new UI element. The UI from the originating slice will automatically connect to all of them.


Data Origin

Before the first WRITE:

  • Required data must exist
  • The actor must be able to access it

Otherwise, model a READ first.


Domain Language

Commands and events MUST use domain language. Two tests: a button label is UI wording, not
business intent; and a business stakeholder must be able to say a command as an intention and
an event as an outcome.


Slice Naming

Slice labels describe the scenario.

  • Use domain language
  • Distinguish outcomes when needed

Offline-First Thinking

Model the process without software first.

Ask:

  • How would this work manually?
  • Who acts?
  • What triggers actions?
  • What information is used?

Rules:

  • Model real-world behavior first
  • Avoid technical concepts
  • Question steps that exist only because of software

Modeling Order

  1. Do you have questions? Ask them!
  2. Identify actor and system
  3. Identify domain events
  4. Create lanes
  5. Create slices (causality-based)
  6. Discover Events
  7. Add elements:
    • more Events if user answers unveiled new insights
    • Commands
    • Information
    • UI / Automation
  8. Validate rules

Hotspot Discovery

Stop when something is unclear during modeling:

  • Process completion
  • Data origin
  • Repetition
  • Concurrency
  • Time constraints
  • Abandonment
  • Error handling
  • Authorization

If you assume → ask user question or create a Hotspot.


Validation Checklist

In Critic Mode — and as step 8 of the Modeling Order — verify every item before declaring a model correct:

  • Lanes renamed: User Role → the actual actor, System Context → the system/bounded context; Information Flow is never renamed
  • Each slice is exactly one type (Read, Write, Automation, or Event Reaction). The one permitted overlap is a Read slice carrying the source events its read model projects from — and even then it contains no command and emits no new event
  • Element placement: commands and information in Information Flow; events in System Context; UI and automation in User Role
  • The process starts with a READ or AUTOMATION slice
  • Every command traces to a trigger (a preceding READ or AUTOMATION) and produces at least one event
  • No events inside Automation slices — put the event in a following Write slice, or use an Event Reaction slice
  • Commands are imperative business intent; events are past-tense business facts
  • No data-loading commands, UI-interaction events, or technical events (see Anti-Patterns)
  • Slice transitions match a Valid flow (see Flow & Causality)
  • Every write is followed immediately by the read slice that renders its result — not merely a read
  • Elements reused across chapters share the exact name, type, AND context of their source — same name + type + context = one synchronized element
  • Assumptions are surfaced as Hotspots or questions, not buried in descriptions

Reading Full Element Details

get_chapter returns short element details inline, but collapses large slice or element details to
a content-reference stub (e.g. <<ccr:...,string,5.2KB>>) rather than the full markdown. A stub is
not the content — never reason about a slice from a stub, and never treat a stub as "no details".
Fetch the complete text with get_element(workspace_id, chapter_id, element_id) before using it.

Even when the spool has zero stubs, the inline rendering of a huge get_chapter can garble or
interleave adjacent elements' text (one element's details or comments rendered inside another's).
The spooled file is the only trustworthy copy: verify grep -c '<<ccr:' is 0 and read the spool
before writing anything back — never compose board writes from the inline rendering alone.

A full get_chapter is expensive: on a mature chapter it returns every slice's full
Given/When/Then and can run to tens of thousands of tokens. Three cheap reads avoid that:

  • get_chapter(structure_only: true) strips lane and slice details only — every element's
    description and details still come back, so on a chapter with a dozen elements it is not the
    cheap "just the shape" read its name implies (55 KB for an eight-slice chapter, measured). For a
    placement inventory, read the host project's local model files — its config declares whether that
    mirror is live — or use search_elements(detail: 'none').
  • list_changelog_events(detail: 'none') answers who-changed-what-when in a few hundred bytes;
    'summary' over 40 events cost 33 KB in the same session, and 'full' also drags old and new
    values.
  • slice_ids narrows the details to the slices you name, so a single-slice query stays small —
    non-matching slices still come back (lanes and slices are always whole, and an id that matches
    nothing does not suppress them), just without their details.
  • search_elements(detail:) is the element-level equivalent — 'none' (id, type, name, laneId,
    sliceId, chapterId), 'summary' (adds context, index, chapterName), or 'full' (the default,
    including description and details). Use 'none' or 'summary' for inventory and reference
    checks.

The live board is always the source of truth. Some setups also keep a local mirror of it; the host
project's Event modeling config declares whether that mirror is live (streamed from the board) or a
stale export, and that declaration decides how far to trust it. A live mirror is the cheapest read by
an order of magnitude — read it before making any MCP read.


Documentation Templates (Element Details)

When you ARE asked to write or update element details (deep documentation, outside pure
exploration), an element may have a documentation template applied. If it
does, the API enforces the template's structure on every details write.

How to tell a template is applied

Read the element first (get_element). If its details begin with a binding
marker comment:

<!-- pb:template <template-id> -->

then a template is in force. The marker is managed by the server — it is
invisible in the rendered UI and you do not need to send it back.

Placeholder syntax

Templates are markdown made of two kinds of content:

  • Fixed text (headings and other literal lines) — must be kept verbatim
    and in order
    in your submission.
  • Placeholders, written %% instruction %% — short instructions telling you
    what to write. You MUST replace every placeholder with real content. No
    %% ... %% marker may remain.

Optional sections are wrapped in %%optional%% ... %%endoptional%% (an optional
label/hint may follow optional, e.g. %%optional: when main page%%). An
optional section is all-or-nothing: include it in full (its fixed text
intact) or omit it entirely. The condition after optional: is a hint for you —
it is NOT auto-evaluated; you decide whether the section applies.

Example template content:

## API

%% One-sentence summary of what this command does %%

### Route

%% HTTP method %% /%% path, e.g. animals/:animalId %%

%%optional: only for POST/PUT/PATCH%%
### Body

````json
%% request body JSON schema %%

%%endoptional%%

Database Updates

%% Which tables/rows change, or "None" %%


## Writing details for a templated element

1. Read the element (`get_element`). If the details still contain `%% ... %%`
   placeholders, that is the unfilled template to complete.
2. Fill **every** placeholder. Keep all headings and fixed lines exactly as
   written, in the same order. You may add extra content between sections.
3. Submit the full filled document via `update_element_details` (or
   `update_element` with `details`). Do NOT include the binding comment — the
   server re-attaches it automatically.
4. `append_details` is **rejected** on a templated element — always send the
   complete document.

### Recovering from a validation error

If a details write is rejected with a template-validation error, the message
names the `template_id`. Then:

1. Call `get_template` with that id to read the current template `content`
   (with all placeholders and fixed text).
2. Re-fill every placeholder, keep all fixed text verbatim, add any missing
   sections, and resubmit.

Use `list_templates` to discover which templates exist for an element type.

---


# Amending a Chapter That Already Shipped

Most of these rules assume you are modeling something new. A large share of real work is not that:
it is changing a chapter whose slices are marked `deployed`, usually because production taught you
something the model did not know. Amendment has its own failure modes.

**A shipped chapter is not a finished chapter.** A `deployed` status records that code matching the
slice was merged, not that the slice is still correct. When a decision changes what a deployed
slice contracts, the status is now wrong too — say so explicitly rather than leaving a slice that
reads as done while its behavior is being rewritten.

**Cover the same ground the last amendment did, or say why not.** When your amendment touches
something an earlier amendment also touched, that amendment's slice list is a ready-made coverage
checklist — diff against it, and against the board (a chapter's `list_changelog_events` enumerates
the slices you actually changed). An amendment that quietly covers eight of ten slices reads as
complete while two of them still assert the superseded contract.

**Expect the board to disagree with itself.** Amendments tend to land where they are cheapest to
write — a comment on an element, or the element's details — while the slice's own Given/When/Then
text, written months earlier, still states the superseded rule. Both are live board content and
neither is obviously stale. Before amending, read *all three* levels for the slice you are touching
— slice details, element details, element comments — and treat any disagreement between them as a
finding to resolve, not a discrepancy to route around. The most recent writing is not automatically
the authority; the most recent *decision* is.

**Never blind-write a details field.** `update_slice(details:)` and `update_element(details:)` replace
the whole field. To add without reading, use the append variants — `append_details`,
`append_description`, or `update_element(description_append:)` — which are atomic server-side.
On a shipped chapter that field holds accumulated GWT and implementation notes
that no one has a second copy of. Read it in full first; if you could not read it, leave a comment
instead — comments are additive.

**Amend by appending with a dated banner, not by rewriting in place.** Leave the superseded text
where it is and mark what supersedes it. Someone will later ask why the contract changed, and the
answer is only useful next to the thing it changed. The same reasoning as superseding an ADR rather
than editing it.

**Re-check the guardrails, not only the rules.** A constraint agreed earlier — especially one a
customer signed — may have become unsatisfiable rather than merely inconvenient, because the
amendment revealed something about the external system's data model. That is not a rule to quietly
drop; it is a decision to surface, restate in terms that *are* satisfiable, and record with its
consequence.

**Check the downstream artifacts the chapter owns.** A manifest marked `completed`, a spec doc, an
ADR whose decision you just superseded. An amendment that updates only the board leaves those
asserting something that is no longer true, and they are what the next Build session reads first.

---

# Goal

A correct model is:

- Domain-driven
- Causally consistent
- Complete
- Precise
- Exploratory