System Instructions
This prompt is divided into three sections:
- System Instructions (this section) — structural orientation only. Do not treat this
section as task input.
- Input Context — begins with the heading
# Input Context. All blocks are wrapped in
<pblock> tags. Two block types:
- File blocks:
<pblock filename="<name>" role="<role>" guidance="...">— optional
guidance attribute carries context-specific instructions; content is in a fenced block.
- Metadata/section blocks:
<pblock label="<label>" kind="<kind>">— job parameters,
rules, instructions, or group headers.
- Agent Task — begins with the heading
# Agent Task. Defines your persona, constraints,
and required outputs. Read all input context before acting on this section.
Input Context
<pblock label="Planning job" kind="job">
Planning job
- TARGET: ReadingList
- BLUEPRINT_PATH: /mnt/c/Users/barlo/projects/drydock/uat/ReadingList/runs/20260815.171255/workspace/targets/ReadingList/blueprint
- DATE: 2026-08-15
- SYSTEM_SHAPE: unknown
- ANALYSIS_QUALITY: Questions
</pblock>
<pblock filename="COMPASS.md" role="compass" path="/mnt/c/Users/barlo/projects/drydock/uat/ReadingList/runs/20260815.171255/workspace/targets/ReadingList/COMPASS.md" guidance="Important: This is the core project intent, constraints, and guardrails. It should have presecedence in conflicts.">
# COMPASS: ReadingList
## Compass
ReadingList is a small web application for readers who want to maintain a personal, ordered list of books to read. A reader can add a book with its title and author, review books in insertion order, and remove books when they are no longer needed.
## Constraints
- The application must run as a web application.
- Book submissions require both a title and an author.
- Books must be shown in the order they were added.
- `bin/test.sh` must be POSIX-compatible and run from the application root.
- The complete automated test suite must pass for `bin/test.sh` to exit zero.
## Guardrails
- Never accept or store a submission with an empty title or author.
- Never reorder books relative to their addition order.
- Never report the test command as successful when any automated test fails.
- Always provide a clear reason when rejecting incomplete input.
<!-- drydock:build-write-guardrail:start -->
## Build Write Guardrail
- Authorized build directory: `/mnt/c/Users/barlo/projects/drydock/uat/ReadingList/runs/20260815.171255/build/ReadingList`
- Authorized Target directory: `/mnt/c/Users/barlo/projects/drydock/uat/ReadingList/runs/20260815.171255/workspace/targets/ReadingList`
- Build agents have permission to create, modify, and remove files required by the active build block inside these authorized directories.
- No path outside these authorized directories may be modified.
- Protected Drydock artifacts:
- `/mnt/c/Users/barlo/projects/drydock/uat/ReadingList/runs/20260815.171255/workspace/targets/ReadingList/blueprint/`
- `/mnt/c/Users/barlo/projects/drydock/uat/ReadingList/runs/20260815.171255/workspace/targets/ReadingList/MANIFEST.md`
- `/mnt/c/Users/barlo/projects/drydock/uat/ReadingList/runs/20260815.171255/workspace/targets/ReadingList/COMPASS.md`
- `/mnt/c/Users/barlo/projects/drydock/uat/ReadingList/runs/20260815.171255/workspace/targets/ReadingList/QuarterDeck/`
- `/mnt/c/Users/barlo/projects/drydock/uat/ReadingList/runs/20260815.171255/workspace/targets/ReadingList/evidence/`
<!-- drydock:build-write-guardrail:end -->
</pblock>
<pblock filename="TECHNOLOGY_STACK.md" role="technology stack" path="/mnt/c/Users/barlo/projects/drydock/uat/ReadingList/runs/20260815.171255/workspace/targets/ReadingList/TECHNOLOGY_STACK.md" guidance="Edit freely. Adding a technology never requires a matching Rigging file, and this file never blocks planning.">
# Technology Stack
**Approved:** 2026-08-10
Technology decisions of record for this Target. One row per technology, naming the
Rigging best-practice file that governs building it.
A `—` in the Rigging column means no Rigging guidance exists for that technology; the
builder applies general best practice instead. Adding a row never requires a matching
Rigging file.
This file is owned by the UAT kit. It is seeded into the Target before `analyze`, which
never overwrites it, and `drydock plan` reads it to assign per-story `stack:` guidance.
| Technology | Rigging | Notes |
|---|---|---|
| Python | python.md | Implementation language; the source is silent. |
| Flask | flask.md | Web framework for the described web application. |
| SQLite | sqlite.md | Local persistence store; the source names no database. |
| pytest | python.md | Test runner for the required automated tests. |
| HTML/CSS | — | Browser interface implied by the web application; styling is unspecified. |
</pblock>
<pblock filename="ANALYSIS.md" role="planning basis" path="/mnt/c/Users/barlo/projects/drydock/uat/ReadingList/runs/20260815.171255/workspace/targets/ReadingList/ANALYSIS.md" guidance="A list of Agile Stories suggested by an earlier analysis of the raw input.">
# Blueprint Analysis: ReadingList
## Commander Expectations
- assert readers can maintain an ordered list of books to read through a web application
- assert empty titles and authors are rejected with clear reasons
- assert the complete automated test suite is runnable through `sh bin/test.sh`
## Crew
| Crew | Charge |
|---|---|
| Commander | Defines intent and decides what done means. |
| Team Lead | Confirms epic completeness and stakeholder expectations. |
| Planning Crew | Authors atomic specifications and the ordered Manifest. |
| Shipyard Crew | Builds the tickets without synchronous Commander access. |
## Story List
### Feature: Book List Management
| ID | Story | High-level AC |
|---|---|---|
| BOOKS-001 | Add a book with title and author | A submitted title and author are stored and shown in the list. |
| BOOKS-002 | View books in order added | The list displays books in the same order in which they were added, including an understandable empty-list state. |
| BOOKS-003 | Remove a book | Removing a book causes it to be omitted on the next list read. |
| BOOKS-004 | Reject incomplete book submissions | Empty titles or authors are rejected and the reason is clearly reported. |
### Feature: Application Verification
| ID | Story | High-level AC |
|---|---|---|
| VERIFY-001 | Run the complete automated test suite | `sh bin/test.sh` runs from the application root and exits zero only when every automated test passes. |
| VERIFY-002 | Cover all book-list behaviors with automated tests | Automated tests cover adding, ordered listing, removal, and rejection of empty title or author. |
## Surfaced Acceptance Criteria
| ID | Story ID | Criterion |
|---|---|---|
| AC-001 | BOOKS-001 | The primary web entry point provides a first-time reader with a direct path to submit a title and author. |
| AC-002 | BOOKS-002 | When no books exist, the application presents a clear empty-list state. |
| AC-003 | BOOKS-004 | Submission errors identify that the title or author is required. |
| AC-004 | BOOKS-002 | Interactive list operations provide a usable response while the request is in progress and a clear error state if the operation fails. |
## Source Inventory
| Path | Content kind | Disposition | Reason |
|---|---|---|---|
| `sources/reading-list.md` | markdown | analyzed | readable UTF-8 |
## Relationship Model
| Source or group | Relationship type | Related source or group | Evidence | Delivery implication |
|---|---|---|---|---|
| `sources/reading-list.md` | instruction-to-test | `BOOKS-001` through `BOOKS-004` | The source defines add, ordered viewing, removal, and validation behaviors. | Implementation stories must preserve these user-visible behaviors. |
| `sources/reading-list.md` | instruction-to-test | `VERIFY-002` | The source explicitly requires automated tests for each behavior. | Tests must cover every listed book-list behavior. |
| `sources/reading-list.md` | instruction-to-test | `VERIFY-001` | The source requires a POSIX-compatible `bin/test.sh` and complete-suite execution. | The terminal verification story must provide and run the project test command. |
## Source Roles
| Path | Role | Plan disposition | Build disposition |
|---|---|---|---|
| `sources/reading-list.md` | author intent | compass | prompt-only |
## Planning Instructions
### Delivery Shape
A small web application accepts book title and author input, stores books, renders them in insertion order, and supports removal. The application includes automated behavior tests and a root-level POSIX test launcher. The primary flow is submit, view the ordered list, and remove an item.
### Story Realization Map
| Story ID | Blueprint scope | Evidence | Related files | Delivery kind |
|---|---|---|---|---|
| BOOKS-001 | Book creation flow and persistence | `sources/reading-list.md` | Web entry point, book model/store, add-book tests | capability, persistence, test |
| BOOKS-002 | Ordered list rendering and empty state | `sources/reading-list.md` | List view, ordered query/read path, list tests | capability, test |
| BOOKS-003 | Book removal flow | `sources/reading-list.md` | Remove route/action, persistence deletion, removal tests | capability, test |
| BOOKS-004 | Input validation and error presentation | `sources/reading-list.md` | Validation boundary, form error display, rejection tests | capability, test |
| VERIFY-001 | Complete test launcher | `sources/reading-list.md` | `bin/test.sh`, test-runner configuration | acceptance contract, build gate |
| VERIFY-002 | Behavior test coverage | `sources/reading-list.md` | Automated test modules for all book behaviors | test harness |
### Test and Acceptance Strategy
Each book-management story owns focused tests for its behavior. `VERIFY-002` confirms coverage across adding, ordered listing, removal, and invalid submissions. `VERIFY-001` is the terminal verification story and runs the complete suite through `sh bin/test.sh`; its acceptance assertion uses `Suite: full`. The complete-suite requirement is a proof gate, not a numeric release threshold.
### Sequencing and Dependencies
Establish the application foundation and persistence boundary before the book-management stories. Implement creation and ordered reads before removal and validation refinements. Keep focused story tests scoped to the owning behavior. Implement the test launcher and complete-suite verification after the behavior tests are available.
### Source Conflicts and Gaps
No conflicting source definitions were found. The source does not name a framework, language, persistence engine, or deployment target; conventional implementation choices are proposed in `TECHNOLOGY_STACK.md`. No external service, authentication model, or sensitive-data requirement is stated.
## Analysis Notes
generated: 2026-08-15
blueprint: /mnt/c/Users/barlo/projects/drydock/uat/ReadingList/runs/20260815.171255/workspace/targets/ReadingList/blueprint
Quality: Questions
blockers: 0
questions: 1
features: 2
stories: 6
stack: proposed Python, Flask, SQLite, pytest, POSIX sh
display_name: ReadingList
short_description: A web application for maintaining an ordered list of books to read.
None.
</pblock>
<pblock filename="SEA_TRIALS.md" role="project acceptance contract" path="/mnt/c/Users/barlo/projects/drydock/uat/ReadingList/runs/20260815.171255/workspace/targets/ReadingList/SEA_TRIALS.md">
# Sea Trials: ReadingList
## Policy
| Consequence | On FAIL | On INCONCLUSIVE |
|---|---|---|
| blocks | fail | attest |
| scores | score | score |
| attests | report | report |
## st-001: Test suite passes
Type: technical
Required: yes
Criterion: The application shall provide a POSIX-compatible bin/test.sh that exits zero when every automated test passes.
Testability: deterministic
Consequence: blocks
Verification: proof
Pattern: ubiquitous
## st-002: A book can be added
Type: behavioral
Required: yes
Criterion: When a reader submits a title and an author, the application shall store the book and show it in the list.
Testability: deterministic
Consequence: blocks
Verification: proof
Pattern: event
## st-003: Books appear in the order added
Type: behavioral
Required: yes
Criterion: The application shall present books in the order they were added.
Testability: deterministic
Consequence: blocks
Verification: proof
Pattern: ubiquitous
## st-004: A book can be removed
Type: behavioral
Required: yes
Criterion: When a reader removes a book, the application shall omit it from the list on the next read.
Testability: deterministic
Consequence: blocks
Verification: proof
Pattern: event
## st-005: Empty fields are rejected
Type: behavioral
Required: yes
Criterion: If a submission carries an empty title or an empty author, then the application shall reject it and report the reason.
Testability: deterministic
Consequence: blocks
Verification: proof
Pattern: unwanted
## st-006: Every behavior is covered by a test
Type: technical
Required: yes
Criterion: The application shall carry automated tests for adding a book, listing books in the order added, removing a book, rejecting an empty title or author
Testability: deterministic
Consequence: blocks
Verification: proof
Pattern: ubiquitous
</pblock>
<pblock label="Answered questionnaire header" kind="section">
Answered questionnaires (consume these decisions)
</pblock>
<pblock filename="discovery-identity.json" role="questionnaire" path="/mnt/c/Users/barlo/projects/drydock/uat/ReadingList/runs/20260815.171255/workspace/targets/ReadingList/QuarterDeck/questionnaires/discovery-identity.json" guidance="Discovery/Questions and possible user answers.">
{
"id": "discovery-identity",
"title": "Discovery: Project Identity",
"purpose": "Confirm the proposed display name and short description before planning.",
"questions": [
{
"id": "display_name",
"label": "Display Name",
"prompt": "The display name Drydock will use for this project. Edit to override the proposal.",
"input": "text",
"proposed": "ReadingList",
"answer": "ReadingList"
},
{
"id": "short_description",
"label": "Short Description",
"prompt": "One-sentence description of what this project does. Edit to override the proposal.",
"input": "textarea",
"proposed": "A web application for maintaining an ordered list of books to read.",
"answer": "A web application for maintaining an ordered list of books to read."
}
]
}
</pblock>
<pblock filename="MANIFEST_CONTRACT.md" role="contract" path="/mnt/c/Users/barlo/projects/drydock/prompts/MANIFEST_CONTRACT.md" guidance="MANIFEST output contract. Follow it exactly.">
---
name: Manifest Contract
description: Contract governing the format, story types, field semantics, lifecycle states, block grouping, and execution rules for `MANIFEST.md` — the single generated executable build plan for a Drydock Target.
version: 20260801 V14
---
## Overview
`MANIFEST.md` is the single generated execution view of the Blueprint. It determines build order,
selects required context, keeps work within useful context limits, identifies stale work, and
preserves unaffected accepted work. It is not a second product definition.
**Location:** `$DRYDOCK_WORKSPACE/targets/<Target>/MANIFEST.md`
The Manifest manages the full product lifecycle:
- specifications for individual components can be changed, resulting in context-minimized
incremental builds
- new files (such as change tickets) can be discovered and applied
---
## Plan Header
```markdown
# MANIFEST: {ProjectName}
updated: 2026-06-08T12:00:00
plan_hash: abc123456789
applied_specs: |
DATABASE.md sha256=<content_sha256> commit=<file_commit_sha> applied_by=foundation applied_at=2026-06-26T14:22:00Z
planning_feedback: |
decision-0123456789abcdef applied FEATURE-CATALOG.md
decision-fedcba9876543210 retained
```
Build execution evidence lives in the execution log. The Manifest preamble carries build-state
provenance required to detect stale previously applied Blueprint Specifications. `applied_specs`
records one line per Blueprint Specification file applied by a successful story. The path
is relative to `blueprint/`. `sha256` is the authoritative dirty signal. `commit` is the latest git
commit that touched that file, or `-` when unavailable. `applied_by` identifies the story
that last applied the file. `applied_at` is the UTC application timestamp.
---
## Story Types
The Manifest is a list of stories. A `type` field is the only variation.
| Type | Contains | Runs |
|---|---|---|
| `foundational` | Foundation and scaffolding | Early; work depends on it |
| `service` | Everything that does work | Reorderable |
| `feature` | Acceptance criteria plus assembly and intent; no implementation instructions | After its members |
Foundational work is structure and scaffolding. Standing up S3 and proving the connection is
architecture. Everything S3 subsequently does is a service. Everything that is not architecture is
a service, and services are reorderable because they carry no structural debt. Much of what source
material labels architecture is service work: the web server and the database are foundation; a
voice service interpreter is a service wearing an architecture filename.
Foundation status derives from the dependency graph, not from a filename prefix. The rule is
*build the foundation that is needed*, not *build all foundation first*.
There is no fourth type. A "foundational service" — voice-to-text, for example — is foundational to
whatever depends on it, which the edges already state more precisely than a label could.
`spike` is not a story type. Research questions are handled by questionnaires before Plan and by the
owning story's `## Questions` section after. `ac` is not a story type: Programmatic Acceptance is
verification the build runs to prove a story is complete. A story is not "built and failed" — it is
built or it is not, so acceptance is a field the story owns and passing is part of the story's own
state transition.
### Feature is an assembly story
A feature is a story that depends on its member stories, carries acceptance criteria, and carries
assembly and intent instructions instead of implementation instructions. Same node, same execution
path, different content shape. When its member stories complete, the feature story runs and is made
to pass like any other story, so integration testing is a real build step rather than an implicit
hope. A feature story is preferably placed in the same block as its members.
### Story
```markdown
## story N: {Name}
id: foundation
summary: One-line description.
type: foundational
kind: capability
phase: 1
block: 1
implements: ARCHITECTURE.md
covers: CATALOG-001
accepts: st-001
context: DATABASE.md
stack: common.md, python.md, fastapi.md
stack_mode: builder
provides: GET /health
consumes:
instructions: |
Stand up the application factory and health check.
acceptance: yes
depends:
state: pending
```
**Field reference:**
| Field | Required | Authored by | Description |
|-------|----------|-------------|-------------|
| `id` | Yes | Model | Stable unique slug within the Manifest |
| `summary` | Yes | Model | One-line description |
| `origin` | No | `drydock refit` | Provenance of a story authored from a source change, as `<source>@<commit>`. Absent on stories authored by `plan`. |
| `created` | No | `drydock refit` | ISO date the story was appended to the graph. |
| `type` | Yes | Model | `foundational` \| `service` \| `feature` |
| `kind` | Yes | Model | Delivery kind: `capability` \| `integration` \| `migration` \| `test harness` |
| `phase` | Yes | Model | Commander build sequencing; see below |
| `block` | Generated | Drydock | Context-optimization group; computed, never authored |
| `implements` | Yes | Model | The single governed specification this story builds |
| `covers` | No | Model | `ANALYSIS.md` Story IDs this story delivers. Every analyzed Story ID is named by exactly one story, whatever its `type`; a story with no analyzed counterpart omits the field |
| `accepts` | No | Model | `SEA_TRIALS.md` IDs this story implements |
| `context` | No | Model | Read-only support context files. Never a Compass file |
| `stack` | No | Model | Rigging stack files this story builds with |
| `stack_mode` | Generated | Drydock | `builder` \| `consumer`; computed from first use in build order |
| `provides` | No | Model | Routes, commands, symbols, datasets, queues, or events this story defines |
| `consumes` | No | Model | Interface points this story calls |
| `rules` | No | Model | Rigging rules files to inject |
| `copy` | No | Model | `source -> destination` file copies applied before build |
| `instructions` | Yes | Model | Freeform build instructions. A `feature` carries assembly and intent, not implementation |
| `acceptance` | Yes | Model | `yes` when the story has real acceptance to honor |
| `depends` | No | Model | Story ids that must be `closed/verified` first |
| `state` | Yes | Drydock | Current block state |
| `evidence` | No | Drydock | Path to the evidence file written after execution |
| `scope` | No | Model | `blueprint` \| `target` \| `both` — what this story changes |
Stories and governed specifications are one-to-one: every story implements exactly one
specification, and every specification is implemented by exactly one story. The story is the atomic
build primitive.
**Story sizing.** A story is a normal Agile story: 1 to 5 story points. Never a half point — that is
a task, folded into the story it serves. Never twelve — that is split. A story does one thing
completely, carries test criteria, and is releasable on its own; a task is not releasable and is
therefore not a story. A story has no token dimension. Token cost is measured against the block a
story is built in, never against the story. Story count is not capped: it is an output of correct
decomposition, not a target.
### Authorship versus verification
The model authors relationships, the actual topology (the story dependency graph), the high-level
topology (phases), and Programmatic Acceptance. Drydock verifies all of it, groups blocks, orders
the work, and serializes the Manifest.
The model never sorts, never checks its own consistency, and never reasons about a position in an
order it has not computed. It states what each story requires and provides; Drydock does the rest.
Contradictions become a deterministic error with a precise message instead of a shape failure.
`drydock plan create` therefore does not emit this file. It emits a flat `TOPOLOGY.md` declaration
carrying the Model-authored fields below — one `## story <id>` heading per governed specification,
no ordering, no `block:`, no `stack_mode:`, no `state:` — and Drydock serializes `MANIFEST.md` from
it. The field semantics in this contract govern both forms.
**Two-topology check.** The high-level and actual topologies must agree: a story in phase 2 cannot
depend on a story in phase 3.
### Phase
`Phase` is Commander instruction on how to build: *build Feature X, then Feature Y*. It is not a
layer chain. The layer stack repeats inside each phase rather than running once across the project —
foundational / database / service / ui, then service / ui, then foundational / service / service /
ui. Commander ordering direction is input the model weighs, not an override applied afterward.
`Phase` describes when a file is built, not the file, so it lives in the Manifest and never in a
Blueprint header.
### Blocks
A **block** is a set of stories optimized for context: sized to amortize fixed stack-file cost
across one build run, never crossing stacks. Blocks are an optimization output, not a taxonomy. UI
stories group together whether or not they belong to the same Agile feature. Context economy comes
from blocks, not from feature grouping.
Blocks are ephemeral, Manifest-only, regenerated every run, and computed by Drydock:
- **Hard:** one topology type per block; never cross a phase boundary; never violate the edges
- **Objective:** amortize stack-file cost across the most stories that still fit one build pass
The mechanism behind the no-cross-stack guardrail is stack creep from Rigging. Mixing topology types
in one block forces every stack file each type needs into the block, so it pays for context neither
half uses and the build agent reads instructions for work it is not doing. This is the reason story
types exist: they are the block-partition key.
### Builder and consumer mode
The model authors the foundational story that stands a stack up. Drydock assigns the
builder/consumer flag from first use in the computed order: by definition the first story using a
stack is the builder and later ones are consumers. Ordering is build-order-global, as compact
substitution already is — not per-block, not phase-based. A builder story receives the full stack
file; a consumer story receives the interface view.
If the model assigned the flag it would be asserting a position in an order it has not computed.
Disagreement is a defect signal, not a tie to break: if the first user of a stack is not a
`foundational` story, an edge or a foundational story is missing and Drydock reports it. Ambiguity
defaults to builder, because consumer-when-it-should-be-builder starves the build agent while
builder-when-it-should-be-consumer merely costs tokens.
---
## Acceptance
Acceptance lives in one place per audience:
- **Programmatic Acceptance** — executable assertions carrying pass/fail state. Lives in
`MANIFEST.md`. Not human-readable, not human-editable, regenerated wholly by every plan run.
- **User Acceptance** — human-readable intent. Lives in the Blueprint specification.
The discriminator for every other fact is the same question: **does the fact describe the artifact
or the schedule?**
| Fact | Home | Why |
|---|---|---|
| `Provides`, `Consumes`, `Depends On` | Blueprint header | Describe the file — what it offers and requires |
| Story `type` | Manifest | Computed, machine-focused |
| `Phase` | Manifest | Describes when the file is built, not the file |
| Programmatic Acceptance | Manifest | Machine-focused; nobody should hand-edit it |
| User Acceptance, `## Questions` | Blueprint | Human intent |
Durability is not a discriminator: the Blueprint does not survive a replan. Only the `## Questions`
section, harvested deterministically beforehand, survives.
---
## Block States
Every story uses the same four states:
| State | Meaning |
|-------|---------|
| `pending` | Not run yet |
| `implemented` | Work done, waiting to be accepted |
| `closed/verified` | Passed or accepted |
| `closed/failed` | Failed or rejected |
---
## Execution Rules
A story runs only when everything in `depends:` is `closed/verified`.
Programmatic Acceptance runs after the story build and is part of the story's own state
transition: a story that fails its acceptance becomes `closed/failed` and blocks dependent work.
There is no separate acceptance node with independent state.
A `feature` story runs after its member stories close. Its assembly and intent instructions are
made to pass like any other story's, which is what turns integration testing into a real build step
covering the seams between stories where multi-story builds actually break.
`closed/failed` is not terminal. The product owner reopens failed work from the QuarterDeck —
revising instructions, acceptance, or scope interactively — and the decision writer returns it to
`pending` with the revision recorded. Recovery never requires hand-editing the Manifest.
An open `Blocking` Blueprint question projects the story state as `blocked/questions`. That story
and its dependents are unavailable, while independent frontier stories remain buildable. Open `Low`
and `Material` decisions remain visible without gating.
`User Acceptance` entries are Commander review signals and do not block ordinary downstream build
unless modeled as explicit dependencies.
---
## Sea Trials Traceability
`accepts:` lists stable project-acceptance IDs from `SEA_TRIALS.md` that the story implements.
Every required technical or behavioral Sea Trial is referenced by at least one story or by a
Blueprint Programmatic Acceptance proof. Unknown IDs are invalid.
## Plan State Writer
The **decision writer** is the only mutator of Manifest block state. It is invoked by:
- the QuarterDeck review controls (approve, revise, reject, add defect on individual blocks)
- the `drydock build` engine (state transitions during execution)
Review decisions written in the QuarterDeck write back to `MANIFEST.md` through the same
decision writer used by the CLI.
---
## Relationship to Blueprint
The Manifest is generated from the Blueprint; it is not a second product definition. `drydock plan
create` reads all Blueprint inputs and writes `MANIFEST.md` — the single work graph carrying build
order, grouping, and per-step prompt-assembly fields. It regenerates after each planning cycle.
The Blueprint remains the source of truth for what the project is and must do. The Manifest is
the source of truth for build state. The QuarterDeck renders Manifest state and records decisions
through the plan writer — the console can be deleted and regenerated at any time.
</pblock>
<pblock filename="BLUEPRINTS_CONTRACT.md" role="contract" path="/mnt/c/Users/barlo/projects/drydock/prompts/BLUEPRINTS_CONTRACT.md" guidance="Blueprint output contract. Follow it exactly.">
---
name: Blueprints Contract
description: Contract governing the layout, file types, header format, and dependency conventions for Drydock Blueprint files.
version: 20260813 V12
---
## Overview
A **Blueprint** is the complete Typed Specification for one project. It lives at
`$DRYDOCK_WORKSPACE/targets/<Target>/blueprint/` and contains all human-authored and
process-created specification files. The Blueprint is the single source of truth for what the
project is, what it must do, and how it is built.
---
## Specification File Types
| File | Purpose | Required |
|------|---------|----------|
| `METADATA.md` | Project identity: name, display_name, short_description, status, stack, code_root | Yes |
| `COMPASS.md` | Project guidance: intent, constraints, and guardrails | Yes |
| `ARCHITECTURE.md` | Modules, routes, boundaries, interfaces, technical decisions | Yes |
| `README.md` | One-line description and `## Intent` section | Yes |
| `DATABASE.md` | Persistence contract: access patterns, typed interfaces, all stores, schemas, migrations | If has persistent state |
| `UI-GENERAL.md` | Shared UI patterns across screens | If has UI |
| `SCREEN-{Name}.md` | Per-screen: route, layout, interactions, programmatic and user acceptance | If has UI |
| `FEATURE-{Name}.md` | Per-feature: purpose, status, trigger, sequence, routes, reads, writes, acceptance, guardrails | As needed |
| `ARCHITECTURE_compact.md` | Compact architecture derivative for downstream build-step injection | Optional |
| `DATABASE_compact.md` | Compact persistence derivative for downstream build-step injection | Optional |
| `HOMEPAGE.md` | Portfolio homepage: branding, contact, bio | If publishes a portfolio |
| `HOMEPAGE-PUBLISHER.md` | Template-based homepage publishing configuration | If publishes a portfolio |
| `IDEAS.md` | Feature ideas and backlog — no typed header required | No |
| `*-AC.md` / `AC-*.md` / `*-AC-*.md` | Acceptance criteria — any file where `AC` is a whole word in the filename | As needed |
| `changes/TICKET-NNN-{Name}.md` | Post-baseline change, defect, or spike request | As needed |
Every authored Specification file ends with `## Programmatic Acceptance`, `## User Acceptance`,
and `## Guardrails`. Use `- None.` when no entries apply. Planning disclosures and Commander
responses are records in the target's `DECISIONS.json`.
`ARCHITECTURE_compact.md` is a compact derivative of `ARCHITECTURE.md` produced by
`drydock rigging compact`. Drydock uses filename-selected compaction algorithms rather than
phase-aware compact variants.
`DATABASE_compact.md` is a compact derivative of `DATABASE.md` produced by `drydock rigging compact`.
---
## Specification File Header Format
Every authored Specification file except `METADATA.md` and `README.md` must begin with a typed
header. Operational and generated files (`IDEAS.md`, build plans, analysis outputs, and AC files)
are not authored Specification files.
```markdown
# {FileType}: {ObjectName}
| Field | Value |
|-------------|-------|
| Version | YYYYMMDD V1 |
| Description | One sentence summary. |
| Depends On | FEATURE-SERVICE-CATALOG.md, UI-GENERAL.md |
| Provides | GET /welcome, GET /welcome/summary |
| Phase | 2 |
```
**FileType values:** `COMPASS`, `SCREEN`, `FEATURE`, `DATABASE`, `UI-GENERAL`, `ARCHITECTURE`,
`HOMEPAGE`, `CHANGE`
**ObjectName:** Human-readable name matching the file subject (e.g., `Welcome Summary`,
`Service Catalog`).
**Fields:**
| Field | Set By | Required | Description |
|-------|--------|----------|-------------|
| `Version` | Author | Yes | Date + increment: `YYYYMMDD V1`. Every agent write must set this to the current date with the next increment. If the existing version is already today's date, increment the number. Never carry forward a stale date. |
| `Description` | Author | Yes | One sentence |
| `Depends On` | `drydock plan create` | No | Filenames this file requires to exist before build |
| `Provides` | `drydock plan create` | No | HTTP routes or interfaces this file exposes |
| `Phase` | `drydock plan create` | No | Build phase hint (integer); tooling may override |
**Additional optional fields for SCREEN files:**
| Field | Required | Description |
|-------|----------|-------------|
| `Route` | No | The URL this screen is served at |
| `Parent` | No | Parent menu item or `—` |
| `Main Menu` | No | Menu label and position |
| `Sub Menu` | No | Submenu label and position |
| `Tab Order` | No | Tab index within parent, or `—` |
`Depends On` and `Provides` are written by `drydock plan create` — do not edit manually.
`Phase` is written by `drydock plan create` — do not edit manually unless overriding.
**Additional required fields for CHANGE files (`changes/TICKET-NNN-{Name}.md`):**
| Field | Set By | Required | Description |
|-------|--------|----------|-------------|
| `Amends` | Author / `drydock refit` | Yes | The parent Blueprint spec this ticket modifies (e.g. `FEATURE-Copy.md`). `drydock refit` reads this field to resolve dependency inheritance and inject parent context. |
| `Depends On` | `drydock refit` | Yes | Copied from the parent spec's `Depends On` set plus the parent spec filename itself. Do not edit manually. |
| `Scope` | Author / `drydock refit --sources` | Yes | `additive` or `amending`. Governs what the ticket supersedes. |
| `Created` | `drydock refit` | Yes | ISO date the ticket was authored. |
| `Origin` | `drydock refit --sources` | No | The source version this ticket came from, as `<source>@<commit>`. Absent on hand-authored tickets. |
| `Stories` | `drydock refit --sources` | No | The Manifest story ids this ticket owns. When present, `drydock refit` emits exactly these ids and never invents new ones. |
**Scope semantics.** A ticket declares its authority over its parent in one sentence directly
below the header table.
- `additive` — the ticket adds behavior. It supersedes nothing, and every assertion in the parent
Blueprint remains in force. Sentence: *"This ticket is additive. It supersedes nothing; every
assertion in `<parent>` remains in force."*
- `amending` — the ticket alters behavior already specified. It supersedes only the sections
listed under `## Amended Sections`, each of which must exist as a heading in the parent.
Sentence: *"This ticket amends `<parent>`. It supersedes only the sections named under
`## Amended Sections`; every other assertion in `<parent>` remains in force."*
An additive ticket must never claim authority over its whole parent: a single added requirement
would otherwise supersede assertions it does not mention and that have already been proven.
---
## Common Authored Specification Sections
Plan and Build disclosures use the existing `DECISIONS.json` schema. `severity: blocking` is the
only decision gate and blocks only the attached story while its Commander response is absent.
Analyze questionnaire answers are converted to `origin: analyze-questionnaire` records. Commander
responses remain in the same records across replans.
Every authored Specification file ends with these sections, using `- None.` when no entries apply:
```markdown
## Programmatic Acceptance
- None.
## User Acceptance
- None.
## Guardrails
- None.
```
`Programmatic Acceptance` contains executable Python assertion snippets. Each check is one
explicitly delimited block that can run from the build directory after the story implementing the
file completes:
```
=== AC {check-id} ===
Intent: One sentence stating what the check proves.
Suite: scoped
Requires: executable=python3; scope=test
<Python source, verbatim, to the end marker>
=== END AC {check-id} ===
```
The delimiters are the whole format. The id lives in the opening marker, so it is never inferred
from a nearby heading. Declarations are the `Key: value` lines at the top of the block, ending at
the first blank line; `Intent:` is required and the rest are optional. Everything after that blank
line is the proof body, taken character for character to the matching end marker.
Nothing inside the body can move a boundary. A Markdown fence, a `##` line, a `###` line, or a
`Requires:` line inside a string is ordinary content — which matters, because a target that
processes markup will legitimately embed all of them in its proof. Write the body as plain Python;
do not wrap it in a fence.
An unterminated block, an end marker naming a different id, a stray end marker, and a duplicate id
are all hard errors that stop planning. None of them degrade into a criterion that silently stops
gating.
### The oracle rule
> **Act on the system. Read the state back. Compare to expected.**
Arrange–Act–Assert, where the assertion reads *state*, never text a process printed.
| Oracle | Verdict |
|---|---|
| Return value, parsed JSON, status code, DB row, file contents read back, exit status | **Correct** |
| Substring of captured stdout/stderr, test-runner tally text, log lines | **Forbidden** |
A state oracle cannot pass against a stub and cannot fail because a runner printed the word
"warning". Almost every acceptance defect observed in practice has the same shape: the oracle was
a string in captured output.
### The expected value must be one you could not get wrong
Reading state back is half the rule. The other half is what you compare it *to*.
> **Never type an expected value twice. Bind it to a name and use the name on both sides.**
You are authoring this criterion before the code exists, so a hand-typed expectation is a
prediction about bytes you have not seen. When the prediction is wrong the criterion fails against
a correct implementation, and nothing downstream can tell that from a real defect. This is the
single largest source of wasted build budget on record.
| Expected value | Verdict |
|---|---|
| A name bound to the value the criterion supplied as input | **Correct** |
| A status code, exit status, or count | **Correct** |
| A contract token read off a declared interface — `"integer"`, `"application/json"`, `"POST"` | **Correct** |
| A staged suite's exit status | **Correct** |
| A string literal you typed out as the expected result | **Forbidden** |
The forbidden row is judged mechanically: a string expectation carrying anything escapable —
whitespace, a backslash, a quote, a newline, a non-ASCII character — that the criterion did not
also supply as input. A criterion that breaks the rule still runs and is still reported, but it
settles `DISPUTED` and gates nothing, so it buys the story no coverage at all.
The case this comes from. Wrong:
```
source = 'basic = "line\\nvalue"\nraw = \'C:\\\\Users\\\\nodejs\'\n'
result = subprocess.run(["./toml-decoder"], input=source, capture_output=True, text=True)
decoded = json.loads(result.stdout)
assert decoded["raw"]["value"] == r"C:\Users\nodejs" # re-typed, and wrong
```
A TOML literal string preserves its backslashes verbatim, so the decoder returned the doubled
form and the expectation was wrong. Right:
```
raw = "C:\\Users\\nodejs"
source = f"raw = '{raw}'\n"
result = subprocess.run(["./toml-decoder"], input=source, capture_output=True, text=True)
decoded = json.loads(result.stdout)
assert decoded["raw"]["value"] == raw # one spelling, cannot disagree
```
When a transform's output genuinely cannot be derived from its input — a renderer turning `# h`
into `<h1>h</h1>` — do not hand-write the expectation at all. Bind the criterion to the
authoritative suite that defines correctness for that transform. Where no such suite exists, put
the case in the project's own test suite, where the implementer writes it against real output,
rather than predicting it here.
### Two test destinations
A project carries tests in two places, and they are not the same artifact with different names.
| | **Story AC** — `=== AC <id> ===` | **The project's own test suite** |
|---|---|---|
| Job | gate the block | know the code works |
| Count | few | unbounded |
| Authored | here, by planning, **before the code exists** | by the build agent, **alongside the code** |
| Oracle discipline | the rules above, without exception | full latitude — expectations are observed, not predicted |
| Effect | binding: it decides whether the block closes | diagnostic: it guides repair, and its command is what a project criterion runs |
| Runs | at its block | continuously, cumulatively |
The split is not a matter of taste. Every expected value written here is a *prediction* about
bytes that do not exist yet, and a wrong prediction fails a correct implementation — which is why
the oracle rule and the no-re-typed-literal rule are absolute in this file. A test written beside
the finished code compares against output its author has actually seen, so the same assertion that
is hazardous here is safe there.
So this is *more* testing, not less. Exhaustive coverage belongs to the project's suite, which has
no ceiling. An AC block is permanently constrained by having to survive as a gate, so author few
and author them bulletproof. Coverage is never demonstrated by the number of AC blocks a story
carries; it is demonstrated by the suite, and it is graded at the project level through the Sea
Trial that runs that suite.
**Where an authoritative suite exists, it is the coverage.** A conformance corpus staged into
`sources/` defines correctness for the surface it covers. Bind one criterion to it and do not
restate its cases in either destination — a restated case adds no coverage and adds one more
expectation that can be wrong.
### What a criterion is worth
Every criterion you write lands in one of four tiers. The tier is decided by how the criterion is
written, not by how it is labelled, and it decides what the criterion can do:
| Tier | What it is | What it does |
|---|---|---|
| **BLOCKING** | a Commander-governed gate, or a criterion bound to a staged authoritative suite | fails the block |
| **CONSULTATIVE** | a criterion whose expected value could not have been invented — a status code, an exit status, a value the criterion itself supplied as input | drives repair; unattended, it marks the block implemented-but-unverified rather than stalling the run |
| **ADVISORY** | a criterion that re-types an expected literal | runs, is reported `DISPUTED`, **gates nothing** |
| **VOID** | malformed: does not compile, or an unclosed container | not a criterion; recorded as a decision and gates nothing |
Aim deliberately. A hand-typed expectation does not merely risk being wrong — it demotes the
criterion to ADVISORY, so the story it was written to protect ends up with no gate at all. Binding
the value to a name is what buys the criterion its authority back.
None of these tiers reaches the release verdict. Story AC decides whether an increment was built;
project acceptance is decided by Sea Trials alone.
### Authoring patterns
Patterns **1, 4, 6, 9, and 10** are the discipline of a gate and govern what you write here.
Patterns **2, 3, 5, 7, and 8** are the discipline of a test suite: state them as expectations on
the project's own suite, which the build agent grows beside the code, rather than enumerating them
into AC blocks.
**1 — Round trip (the default form).** For anything that stores, mutates, or removes state:
```
create → read back → assert present, with expected field values
update → read back → assert changed, and only the intended fields changed
delete → read back → assert absent
```
The read-back is a *separate call through the public interface*, not an inspection of the object
returned by the write. A write that returns a plausible object while persisting nothing must fail.
**2 — Exercise every callable workflow.** *Suite pattern.* One test per public entry point, per
verb. Coverage is enumerated from the interface, not sampled: every HTTP route × every method it
declares including declared error paths; every CLI subcommand and every flag that changes
behavior; every exported library function. This belongs to the project's suite. Here, name the
routes a SCREEN provides — that gate is real — and leave the enumeration to the suite. Where a
staged authoritative suite already covers the surface, it is the coverage.
**3 — Idempotence.** *Suite pattern.* Where a verb claims idempotence (PUT, DELETE), apply it twice and assert the
second is a no-op — same resulting state, and the declared status for a repeat. Where a verb is not
idempotent (POST), apply twice and assert the declared behavior: two resources, or the declared
conflict. Prefer idempotent verbs where the semantics allow; the assertion is stronger.
**4 — Negative paths assert the contract, not the message.** Invalid input asserts the declared
failure signal — status code, exception type, exit status — never the wording of an error message.
Message text is prose and belongs to no contract.
**5 — Boundaries.** *Suite pattern.* Empty collection, exactly one, many. Absent optional fields.
Declared maxima. This is where a plausible-looking implementation actually breaks — and where a
predicted expectation is most likely to be wrong, which is why the cases belong beside the code
rather than here. Where a staged authoritative suite covers the surface, it is the coverage.
**6 — RED before GREEN.** The assertion must fail against the pre-implementation tree and pass
after. A check that passes against a stub is not a check.
**7 — Isolation and determinism.** *Suite pattern, and it applies here too.* Each test arranges its own data and does not depend on another
test's residue or on ordering. No wall-clock dependence, no third-party network, no unseeded
randomness, no sleep-based timing. Fresh store per test, or explicit teardown.
**8 — One behavior per test, named for the behavior.** *Suite pattern.* A failure should be
diagnosable from the test's name alone.
**9 — Subprocess discipline.** Where a check must shell out, **exit status is the verdict**. A
substring check beside an exit-status assertion is redundant at best and a false-positive generator
at worst. Never assert that a literal is absent from captured output.
**10 — In-language tooling.** A check is written in the project's own language and uses that
language's libraries — Python check, Python libraries; Go check, Go libraries. An in-language HTTP
client yields a status code and a parsed body, which is state. `curl` yields stdout, which is text
to scrape. Pattern 10 and the oracle rule are the same rule seen twice.
### Declaring external tooling
Reaching for an external executable is the exception, not the norm, and `curl` in particular will
not work in every environment. When a check genuinely needs one, the tool belongs in the project's
Rigging or `TECHNOLOGY_STACK.md`, declared once by the Commander and true for every check in the
project. A per-check declaration is also accepted and is recorded as a report:
```markdown
Requires: python-package=httpx; scope=test
Requires: executable=node; scope=test
```
Kinds are `python-package` and `executable`; scopes are `runtime` and `test`. Framework test
clients include their transport dependencies. `Requires:` metadata is not acceptance intent, and
a missing declaration never fails planning — a tool that is present and undeclared works fine.
A declared tool that is *absent* when the check runs reports UNVERIFIED, not FAIL: the check never
reached the code under test, so it says nothing about the build.
### Satisfiability
Every assertion must be satisfiable by a correct implementation. An expectation no implementation
can meet is a defect, not a red baseline. Escaping is the usual source of one: inside a raw
literal, `\n` and `\r` are a backslash followed by a letter, not a control character, so
`r"text\n"` asserts against six characters ending in a literal backslash. Binding the value to a
name and using it on both sides removes the question entirely, which is why that is the rule.
### Runnability
**Subprocess mode.** Match the mode to `input=`. Text input declares `text=True` or `encoding=...`;
binary input uses a bytes-like value and does not declare `text`, `encoding`, `errors`, or
`universal_newlines`. A mismatch raises `TypeError` before the program under test starts, which
reports UNVERIFIED — the criterion buys the story nothing. Write:
```
payload = "one line\n"
result = subprocess.run(["./program"], input=payload, capture_output=True, text=True)
assert result.returncode == 0
```
For a binary or invalid-encoding criterion, write:
```
result = subprocess.run(["./program"], input=b"\xff", capture_output=True)
assert result.returncode != 0
```
**ASCII test data.** Acceptance data is ASCII. Do not invent an encoding requirement: characters
outside ASCII test a property the specification never stated, and a criterion that fails on them
fails the build for something nobody asked the product to do. When the imported specification does
state an encoding requirement, the criterion says so and may then use that encoding:
```
=== AC runtime-utf8 ===
Intent: The executable round-trips UTF-8 source, per INSTRUCTIONS.md.
Encoding: utf-8
source = "café\n"
result = subprocess.run(
["./program"], input=source, capture_output=True, text=True, encoding="utf-8"
)
assert result.returncode == 0
assert source.strip() in result.stdout
=== END AC runtime-utf8 ===
```
`Encoding:` is a declaration of deliberate intent, reviewable as such. Absent it, ASCII.
**Every check is standalone.** Drydock writes each fenced block to its own script and runs it in
its own process from the build directory. Checks in the same file share no imports, no variables,
and no execution order. A snippet that reads a name another snippet bound raises `NameError` on
every run — it reports UNVERIFIED rather than failing the build, which means it verifies nothing
and buys nothing. Each snippet imports what it uses and binds every name it reads.
**A check that shells out prints what it captured before it asserts.** `capture_output=True`
routes the runner's tally and its failing cases into a variable; asserting on the exit code alone
then discards them, and the failure reports the assertion with no evidence of what went wrong.
Print the captured `stdout` and `stderr` first, so the console, the evidence file, and the repair
pass all carry the runner's own account of the failure. Printing is for diagnosis; it is never the
oracle.
```markdown
## Programmatic Acceptance
=== AC health-check ===
Intent: The health endpoint returns an OK response.
from app import create_app
client = create_app().test_client()
response = client.get("/health")
assert response.status_code == 200
assert response.get_json()["status"] == "ok"
=== END AC health-check ===
=== AC suite-conformance ===
Intent: The implementation passes the conformance sections this story owns.
Suite: scoped
import subprocess
import sys
result = subprocess.run(
[sys.executable, "tests/run_suite.py", "--sections", "headings,lists"],
capture_output=True, text=True,
)
print(result.stdout)
print(result.stderr, file=sys.stderr)
assert result.returncode == 0
=== END AC suite-conformance ===
```
`User Acceptance` contains only Commander-observed checks that cannot be honestly automated,
such as look-and-feel or subjective workflow acceptance. Do not place deterministic behavior in
`User Acceptance`.
Do not tag an assertion with a project-acceptance ID. Sea Trials flow into planning as context for
authoring acceptance; nothing points back at them. Project acceptance is settled at `score release`
by observing the finished tree, never by looking up which assertion claimed which criterion.
**Programmatic acceptance is the story's definition of done, and a deterministic definition of
done is never sampled.** Drydock builds each block in a single pass with no iterate loop, so the
acceptance you author *is* the objective handed to the builder: sample the checks and the builder
builds to the sample. When an authoritative, externally-authored test suite already defines
"correct" for what a story builds — an imported conformance suite and its runner (for example a
specification's example suite plus a `*_tests.py` runner) — the acceptance runs that suite and
requires a full pass over the story's scope, never a hand-picked subset. A feature story binds to
the sections it owns and declares `Suite: scoped`; a terminal verification story gates on the whole
suite and declares `Suite: full`. The marker is one of the block's declaration lines and tells the
runner the check gates on the whole test suite rather than a story-scoped sample.
**A scoped selector must select something.** A check that runs a suite with a section filter
matching no cases exits zero and reports a pass while proving nothing. Select on a heading that
actually owns cases, never on a chapter title that merely contains such headings. Drydock fails a
criterion that is already green before the story's code exists.
**The runner's exit status is the verdict, and it is the whole verdict.** A conformance runner
already decides pass or fail and reports it the one way a caller can rely on. Asserting on its
printed summary as well adds no information and adds a failure mode: the case count belongs to the
installed suite rather than to the specification, and runners column-align their summaries
(`valid tests: 205 passed, 0 failed` carries two spaces), so a literal such as
`assert "valid tests: 210 passed, 0 failed" in result.stdout` is false on correct code and no
implementation can move it. The same holds for tallies of errors, skips, and warnings: a runner
with none of them commonly prints no such line at all, so requiring one is false on a clean run.
Print the captured output for diagnosis, assert `result.returncode == 0`, and stop there. This
holds for both `Suite: scoped` and `Suite: full`.
Place a whole-project deterministic suite on the story that **completes the runnable capability**
— never on a foundation step that cannot yet run it, where it would fail vacuously. Naming the suite file or asserting it is staged (`Path(...).is_file()`)
is staging, not testing: a stubbed or absent definition of done for an available suite is a defect,
not an acceptable check.
An assertion that invokes a staged asset obeys that asset's own documented interface. Read the
asset before writing the call. Every environment variable it declares required is supplied, and it
is supplied by extending the inherited environment — `env={**os.environ, "NAME": value}`. Never
write `env={"NAME": value}`: that replaces the environment, leaving the child with no `PATH`, so
nothing it invokes resolves and the assertion fails at every level of implementation quality. Never
repair a staged asset's interface by editing the asset; it is restored before grading, so the edit
is reported as tampering rather than honored.
An assertion that feeds input to a program passes it through `subprocess` `input=` rather than a
shell. When a shell is unavoidable, `printf '%s'` copies its argument verbatim: `\n` reaches the
program as a backslash and a letter, not a newline, so the program is graded on input the author
never wrote. Use `printf '%b'` or a real line break.
`COMPASS.md` uses `## Compass`, `## Constraints`, and `## Guardrails` as its body sections.
Success criteria belong in `SEA_TRIALS.md`; open questions in spike questionnaires. Do not add
those sections to `COMPASS.md`.
---
---
## Acceptance Criteria Files
**Naming rule:** any file where `AC` is a whole word in the filename is an acceptance criteria
file. `AC` must be delimited by `-`, `_`, or file boundaries — not embedded in another word.
Examples: `AC-001-login.md`, `FEATURE-LOGIN-AC.md`, `AC-NAVIGATION.md`.
`ACCEPTANCE_CRITERIA.md` does NOT follow this standard (AC is not a standalone word).
AC files enable test-driven design and a way to enforce specific behaviors without polluting the
parent specification.
**Two types of AC statements:**
| Type | Example | Rule |
|------|---------|------|
| Positive assertion | "The status badge color is red" | Reconcile into parent spec, then archive this entry |
| Negative/guardrail | "Field X must not appear on this screen" | Keep permanently in AC — these guard against model hallucination, not spec omission |
**Reconciliation:** When a positive AC fact has been implemented and verified, move it to the
parent spec body and delete the AC entry. Negative guardrails are permanent — never move them to
the spec.
**AC file format:**
```markdown
# AC: {ObjectName}
| Field | Value |
|-------------|-------|
| Version | YYYYMMDD V1 |
| Description | Acceptance criteria for {ObjectName}. |
| Parent | FEATURE-{Name}.md |
## Guardrails
- Field X must not appear on this screen.
- The delete button must not be shown to read-only users.
## Assertions
- The status badge is rendered in red when severity is HIGH.
```
**Standard AC filename forms:**
- `AC-NNN-{Name}.md` — numbered sequential acceptance-criteria ticket (authored)
- `{Parent}-AC.md` — paired directly with a spec file (e.g. `FEATURE-LOGIN-AC.md`)
- `AC-{Topic}.md` — topic-scoped AC file (e.g. `AC-NAVIGATION.md`)
**All fix and change tickets use AC naming** — `AC` as a whole word in the filename. A targeted
bug fix is expressed as a testable acceptance criterion.
---
## Dependency Declarations
`drydock plan create` scans spec file headers to populate `Depends On` and `Provides`. The
following conventions apply automatically without explicit header declaration:
| Convention | Rule |
|------------|------|
| `SCREEN-*.md` → `UI-GENERAL.md` | All screens depend on shared UI patterns |
| `DATABASE.md` → Phase 1 | Always first phase; always base context |
| `ARCHITECTURE.md` → base context | Included in every phase prompt |
| `FEATURE-*.md` providing routes → listed in `Provides` | Extracted from route tables in file |
| `SCREEN-*.md` using a route → depends on providing `FEATURE` | Matched from route references in body |
The `Depends On` and `Provides` fields form a simple directed dependency graph. `drydock plan
create` traverses this graph to assign phases, assign build order, and compute context sizes.
A file can only be built in a phase after all its `Depends On` files are built.
---
## Persistence Encapsulation (DATABASE.md scope)
`DATABASE.md` is the project's persistence contract — not SQL schema alone. It documents every
persistent store and the typed class that encapsulates it:
- **Relational tables** — schema plus the row dataclass / CRUD class / composing `Database` class.
- **Config / `.env`** — required keys and the typed `Config` class.
- **File stores** — directories and the `FileStore` class.
- **External services** — the service contract and its wrapper.
Application code reaches each store only through its class. A storage change that leaves the
interface unchanged does not invalidate downstream features.
Every `DATABASE.md` includes `## Access Patterns` and `## Persistence Interfaces` before schema
details. Access patterns name the caller, operation, store, and interface method. Persistence
interfaces name the store, public interface, module location, allowed callers, and notes.
`ARCHITECTURE.md` includes a module ownership table for persistence, configuration, file-store, and
external-service boundaries. It states which module owns each boundary and which low-level APIs that
module may access.
Any Manifest story that implements `DATABASE.md` includes `persistence.md` in `stack:` plus the
selected backend stack file such as `sqlite.md`, `postgres.md`, or `aws-dynamodb.md`.
---
## METADATA.md — Service Identity Fields
In addition to standard project fields, service repositories should declare:
```
service_name: Platform # top-level service grouping (e.g. Platform, Analytics, Tools)
service_component: GAME # component name within the service (matches directory name)
```
These fields are used by build-time service registration artifacts and by GAME's service registry
scanner to group related repositories under a named service.
---
## Authoring Conventions
**Authoring phase:** all unresolved product decisions go in `DECISIONS.json`. Do not create
`MANIFEST.md` or numbered ticket files while authoring.
**Build phase:** run `drydock plan create` once the specification is ready. Use `drydock status`
to check for spec errors and staleness before building. After a build, fold changes back by editing
the specification and re-applying with `drydock refit`.
**Spikes:** a spike is a runnable investigation. Results feed future iterations. When run, the
finding is written into the named file, resolving the matching `## Open Question` in place.
**Feature specifications:** all feature purpose, status, triggers, sequences, routes, reads,
writes, acceptance criteria, and guardrails belong in individual `FEATURE-*.md` files. README,
METADATA, and generated files do not contain feature specifications.
</pblock>
<pblock label="Imported source file header" kind="section">
Imported source files
</pblock>
<pblock filename="sources/reading-list.md" role="source file" path="/mnt/c/Users/barlo/projects/drydock/uat/ReadingList/runs/20260815.171255/workspace/targets/ReadingList/blueprint/sources/reading-list.md" guidance="Raw User Source">
# Reading List
Build a web application that keeps a list of books to read.
The reader can add a book with a title and author, view the books in the order added,
and remove a book. An empty title or author is rejected with a clear error message.
The application includes automated tests for each behavior.
The completed application provides a POSIX-compatible `bin/test.sh` that runs the complete
automated test suite from the application root. `sh bin/test.sh` exits zero only when every test
passes. The final build story runs this command after every implementation story and preserves its
command, exit code, standard output, and standard error as evidence.
</pblock>
<pblock label="Persistent Plan feedback" kind="feedback">
Commander decisions
Apply these decisions as constraints; do not recreate them as questions.
analyze-display_name
- Title: Display Name
- Decision: ReadingList
- Severity: material
- Blueprint: ARCHITECTURE.md
analyze-short_description
- Title: Short Description
- Decision: A web application for maintaining an ordered list of books to read.
- Severity: material
- Blueprint: ARCHITECTURE.md
</pblock>
Agent Task
Agent for: planning session synthesis
Map each required technical or behavioral ID in structured SEA_TRIALS.md into the implementing story's accepts: field. Never invent or rename Sea Trial IDs. Do not tag a Programmatic Acceptance assertion with a Sea Trial ID: Sea Trials flow into planning as context and nothing points back at them. Project acceptance is settled at score release, by observing the finished tree. Do not turn a final project measurement or release threshold into a story Programmatic Acceptance assertion. Those remain Sea Trials and run at final scoring after all stories close. The one terminal Suite: full assertion is the exception: it runs the supplied suite and requires success. It may additionally verify the total using either a count derived from authoritative suite data or an explicitly declared authoritative exact count.
accepts: is human-readable traceability, not a child acceptance command and not a gate. A story that stages or implements the capability exercised by a final Sea Trial still names that trial in accepts: even when the Sea Trial command itself must not run during the story. TOPOLOGY.md is emitted in Stage 1 before any Blueprint, so settle the complete story set and its acceptance before emitting anything.
When ACCEPTANCE.json is present, it is the Commander-owned governed stage topology. Each key in stages is an exact story id and each argv is the authoritative gate for that story. Preserve those ids verbatim in TOPOLOGY.md and shape each story around the scope its command exercises; merge related analyzed Story IDs into that story's covers: field when one governed stage owns their combined slice. Do not emit or amend ACCEPTANCE.json. The optional full command is the finished-project release gate, not an ordinary story id.
You represent an Agile Scrum Development Team and follow Agile best practices.
You have received the outputs of drydock analyze plus the imported source material and planning decisions. Your job is to turn that reviewed planning basis into a Blueprint: authored Typed Specification files under blueprint/ and the topology declaration (TOPOLOGY.md) that Drydock serializes into MANIFEST.md, the single work graph carrying build order, grouping, and per-step prompt-assembly fields.
The core elements are defined below.
Planning Objective
Your goal is to convert the analysis artifacts into a build-ready Drydock Blueprint.
The analyze step identified story candidates, blockers, questions, and strategic direction. This step converts that information into durable specification files with exact header formatting and clear relationships. You are not writing prose notes; you are writing structured product definition and build-planning artifacts.
The primary outputs are:
- Typed Specification files such as
ARCHITECTURE.md,FEATURE-*.md,SCREEN-*.md,
DATABASE.md, UI-GENERAL.md, and AC files where warranted.
TOPOLOGY.md— the declared work graph: one story declaration per governed specification, typed
foundational, service, or feature. Drydock verifies it, computes build order and block grouping, and serializes MANIFEST.md from it.
This planning step is a test-driven-development review, not only a decomposition. Weight the authoring of executable acceptance as heavily as the decomposition itself. Every buildable story carries several concrete Python assertions in the ## Programmatic Acceptance sections of the specs it implements, so that drydock build has a failing test to satisfy for each behavior before the code exists. A plan that decomposes cleanly but ships specs with empty acceptance has failed this step. Assertion authoring is mandatory-or-justified: a spec's acceptance is - None. only when the item genuinely has no programmatic surface, and then the reason is stated inline.
This step must produce decomposed specifications with solid header relationships:
- every authored spec file uses the Drydock typed header format
Depends On,Provides, andConsumesare declared consistently across the emitted Blueprint- story declarations in
TOPOLOGY.mdpoint at real emitted spec files - the runnable frontier implied by the Manifest is coherent
Treat the Story List and Story Realization Map in ANALYSIS.md as the completed planning decomposition and the default work breakdown. Preserve their proposed story boundaries and mapped source filenames unless the complete planning context shows that a story is non-atomic, inaccurate, contradictory, incomplete, or assigns content to the wrong owner. When correction is necessary, split, merge, move, replace, or reorder the affected scope. Rewrite every resulting story as a governed specification using all planning inputs; source structure is strong evidence for the story boundary, but source content is not authoritative.
When the analysis is too coarse, refine it into smaller spec scopes. When it is too fine, merge it into the smallest durable spec structure that preserves correctness and clear ownership. The Analyze story list is the Team Lead's expert proposal, not an immutable work breakdown. Preserve a source Markdown file and filename when it already represents one atomic story, but split it when it combines independent actions. A screen and its provider route are separate stories and separate specifications even when they participate in one workflow.
Inputs
The job block injects the following. SYSTEM_SHAPE and ANALYSIS_QUALITY are stated directly in the job block; the rest are fenced sections.
- Plan feedback (standing directive) —
PLAN_COMPASS.md, persistent human direction
injected near the top of this prompt when present. Treat it as authoritative steering for this run; it overrides default decomposition and ordering choices where it speaks.
ANALYSIS.md— the Team Lead's reviewed proposal: quality signal, candidate story/file map,
open questions, tuning options, expectations, and notes. Review its mapping as an agile expert; preserve, merge, split, replace, or reorder it when the complete planning context requires that.
## Surfaced Acceptance CriteriainANALYSIS.md— additional criteria analyze derived per
story; fold each row into the ## Programmatic Acceptance or ## User Acceptance section of the spec file implementing its Story ID.
## Relationship Modeland## Planning InstructionsinANALYSIS.md— primary
Analyze-to-Plan handoff. Honor the Story Realization Map when selecting durable Blueprint scopes; carry the stated sequencing/dependency model into Manifest ordering and depends:; embed cited interfaces, workflows, test-kit behavior, and acceptance in the matching specs. Every readable imported source is available below. Analyze guides interpretation and proposes a realization map; it never limits which source evidence the Planning Crew may consult.
SYSTEM_SHAPE— the determined project type (web|api|cli|library|pipeline|event-driven),
parsed from the analysis. Drives the default decomposition table below.
SEA_TRIALS.mdandSOUNDINGS.md— product objectives and acceptance milestones from
analyze. Use these as planning context; do not overwrite their intent.
- Answered questionnaires (
discovery-*.json) — settled human-owned decisions on intent and
guardrails. Do not re-raise a question that a questionnaire has already answered. Drydock preflight guarantees that every Analyze question marked required_before_plan is answered before this prompt runs. Questionnaires never carry technology-stack decisions.
TECHNOLOGY_STACK.md— the Commander-owned technology decisions of record: one row per
technology, with the Rigging file that governs building it or — when none exists. This is the sole authority on the stack. It may be absent or incomplete; that means undecided, and you resolve the gap from the sources rather than stopping.
COMPASS.md— existing product intent if already present; otherwise derive emitted content
from the analysis and sources. It does not carry technology choices.
Precedence
When authoritative inputs disagree, apply this order and proceed. Do not stop on a disagreement that this order resolves:
PLAN_COMPASS.mdCommander Direction- Answered questionnaires and Commander-directed
DECISIONS.jsonitems (commander_directionor
override_text set)
TECHNOLOGY_STACK.md(technology questions only)COMPASS.md- Imported source files and
ANALYSIS.md
Absence is never prohibition. An item missing from TECHNOLOGY_STACK.md, unselected in a questionnaire, or unmentioned in COMPASS.md is undecided, not forbidden. Never treat an omission as a negative requirement, and never raise a conflict because one input lists something another does not.
Conflict Scope
- SQS, S3, databases, logs, and Marina/application-managed files are distinct from repository
checkout content.
- “Project file” and “project-associated file” do not imply a file inside a Git checkout.
- A repository-write guardrail applies only to destinations explicitly located in the repository.
- A guardrail scoped to discovery or registration does not govern runtime processing unless an
authoritative source explicitly extends it to runtime.
- Missing detail is not a conflict. Use a conservative reasonable interpretation unless
authoritative inputs contain mutually exclusive requirements.
- Error Mode must cite the exact files, clauses, and scopes that conflict and explain why the
Precedence order cannot resolve them.
MANIFEST_CONTRACT.mdandBLUEPRINTS_CONTRACT.md— authoritative format and field
contracts for the outputs.
- Imported source files — all readable material under
blueprint/sources/, injected below.
It is unconstrained Commander input, not governed Blueprint syntax. Never reject a source because of its filename, headings, tables, question labels, or formatting. Authored Markdown specs are a structured interpretation. Non-Markdown assets are projected byte-for-byte by Drydock; never emit or rewrite them.
If ANALYSIS_QUALITY is Blocked, planning must not proceed. Emit only a refusal message inside the required output block contract described below.
Story and Task Criteria
Decomposition is Agile feature and story decomposition. Apply that discipline at expert level: INVEST stories, vertical slices, test-driven acceptance per story. The rules below are the criteria, not a substitute for that judgement.
- A story delivers one observable behavior or capability slice. It is independently buildable,
independently verifiable, and carries its own acceptance gate. The story is the unit Drydock gates, builds, and attributes failure to.
- A task is a technical sub-step of a story — add a helper, refactor a module, wire a parameter.
A task is never a story block and never becomes a Blueprint file. Instructions inside a story may describe its tasks.
- Prefer more, smaller stories over fewer large ones. Distinctness is the limit: each story owns
its behavior alone, and no two stories own the same behavior.
- Story size in Drydock is the token and context size of the build step. A story whose build step
would not fit comfortably in one build prompt is too large. Split it into smaller stories that each still meet the story criteria above; never split it into tasks, and never leave a single story owning several independent construct families.
- When the source material is short or names few features, keep the story set lined up with the
source's own shape. Preserving author intent outranks splitting for its own sake, and the criteria above still bound the result.
Decomposition Method
Execute in order. Do not skip a step.
1. Review the planning basis.
- Consumes: imported sources,
ANALYSIS.md,PLAN_COMPASS.mddirection, answered questionnaires. - Emits: working understanding of the project shape, stack, constraints, and unanswered items.
2. Confirm the decomposition shape.
- Consumes: the analysis story list, project type signals, and source structure.
- Emits: one authored Blueprint file per story-sized capability, per the story criteria above.
Fewest file kinds, not fewest stories: use only the spec kinds the project needs, then decompose within them.
Default decomposition rules:
| System shape | Durable authored files |
|---|---|
web | ARCHITECTURE.md, UI-GENERAL.md if shared UI exists, one FEATURE-*.md per route/service workflow, one SCREEN-*.md per user-facing screen, DATABASE.md if persistence exists |
api | ARCHITECTURE.md, one FEATURE-*.md per endpoint/capability cluster, DATABASE.md if persistence exists |
cli | ARCHITECTURE.md, one FEATURE-*.md per command/capability cluster |
library | ARCHITECTURE.md, one FEATURE-*.md per public module or service area, DATABASE.md only if stateful |
pipeline | ARCHITECTURE.md, one FEATURE-*.md per pipeline stage or major dataset transformation, DATABASE.md only if persistent stores exist |
event-driven | ARCHITECTURE.md, one FEATURE-*.md per handler or event workflow cluster |
Use SCREEN-*.md only for actual user-facing screens. Use DATABASE.md only when persistent state or external stored state exists. Use AC files only when separate permanent guardrails are needed and they should not bloat the parent spec.
3. Map analysis stories to authored spec scopes.
- Consumes:
ANALYSIS.md ## Story List. - Emits: a mapping from analyzed stories to emitted files.
Rules:
- Each emitted authored spec file must represent one durable capability boundary.
- The
## Story Realization MapinANALYSIS.mdis a proposed partition. Keep a row that names a
distinct, atomic capability scope unless complete planning context supports a better partition.
- Two analysis stories collapse into one authored file only when both describe the same
behavior and the merged unit still satisfies the story criteria above. Distinct scopes — for example a block parser, an inline parser, reference resolution, a renderer, and an executable interface — are separate stories even when they ship in one program.
- One analysis story may expand into several authored spec files when the boundary naturally
separates into screen, feature, architecture, or persistence contracts, or when the single story is too large to build in one step.
- Record the mapping in the Manifest: each story's
covers:field names theANALYSIS.mdStory IDs
it delivers. Every Story ID in the analysis is covered by exactly one story. A story that covers several IDs is the declared collapse case and must satisfy the collapse rule above.
- When one analysis story expands into several stories, exactly one of them carries its ID in
covers: — the story that delivers the analyzed behavior, whatever its type:. A foundational persistence or architecture story that realizes an analyzed story still covers it; type: never decides ownership.
- A plan-introduced story with no analyzed counterpart — an architecture boundary, a scaffold, a
test-harness story — omits covers: entirely. Never duplicate an ID that another story owns, and never fill the field to make it look complete: two stories claiming one analyzed story destroys failure attribution.
- Every important user-facing screen named in analysis must land in a
SCREEN-*.md. - Every important route, capability, interface, dataset, topic, or command named in analysis must
be represented in one or more FEATURE-*.md files, with ARCHITECTURE.md and DATABASE.md carrying shared technical structure where needed.
- Drydock deterministically injects
ARCHITECTURE_compact.mdandDATABASE_compact.mdinto
FEATURE-* build steps when those source files exist. Do not model that policy manually with screen stories or ad hoc context duplication.
4. Write authored specification content.
- Consumes: the file mapping and all planning inputs.
- Emits: complete authored spec markdown with exact header format and required terminal sections.
Each authored file must be build-usable. Write concrete sections, not placeholders, unless the source material genuinely leaves an item open; then put it under ## Questions.
5. Author programmatic acceptance (test-driven).
- Consumes: each authored spec's routes, interfaces, reads, writes, guardrails, any tests
carried in the imported source material, and any ANALYSIS.md ## Surfaced Acceptance Criteria rows tied to this spec's Story ID.
- Emits: the
## Programmatic Acceptancesection of every authored spec, as concrete Python
assertions.
Rules:
- Every
=== AC <id> ===block is a standalone Python script. It repeats every import it uses;
imports, variables, and execution order from another AC block are never in scope. Before closing each block, inspect every name it reads and either import or bind that name inside the same block. In particular, every block that calls subprocess.run contains its own import subprocess.
- Treat this as writing the failing tests first. For every story, the specs it implements together
carry several executable assertions — generally one per distinct observable behavior, route, invariant, or error mode described in that spec. A single assertion for a multi-behavior spec is insufficient.
- Every split story owns its own assertions in the spec it implements. Splitting must never leave a
story gated by another story's acceptance, and never leave two stories asserting one behavior.
- Assertions are concrete and executable from the build directory: assert a route responds, a
record is written with the expected keys, an invariant holds, a guardrail rejects, an error type is raised. Cover the ordinary "the thing exists and responds" checks explicitly (for a route, that it is reachable and returns the expected status) — do not assume they are obvious.
- Route coverage is enforced: a SCREEN spec's assertions must literally call every route in its
Provides and Consumes (the plan is rejected otherwise); a FEATURE spec's assertions must exercise every route and interface it provides, naming each literal route path in at least one assertion.
- Imported test material is input, not output — with one exception. Ad hoc tests, test
scripts, or a prose ## Test section: review them and re-express the intended checks as Drydock Programmatic Acceptance assertions in the spec; do not trust their format, copy them verbatim, or point at that script. The exception is an authoritative conformance suite — an externally-authored, executable suite whose runner defines "correct" for the capability (for example a specification's example set plus its *_tests.py runner). A conformance suite is never paraphrased into hand assertions: paraphrase samples it and drops coverage. Its acceptance invokes the imported runner over the scope the spec owns and asserts a full pass of that scope, per the suite-binding rule below.
- Act on the system. Read the state back. Compare to expected. The assertion reads state —
a return value, parsed JSON, a status code, a stored row, file contents read back, an exit status. It never reads a substring of captured stdout or stderr, a test-runner tally, or a log line. A state oracle cannot pass against a stub and cannot fail because a runner printed the word "warning"; a text oracle can do both. Print captured output for diagnosis, never assert on it.
- Write the check in the project's own language, using that language's libraries. An in-language
HTTP client yields a status code and a parsed body, which is state; curl yields stdout, which is text to scrape. Reaching for an external executable is the exception and belongs in Rigging.
- Prefer the round trip for anything that stores, mutates, or removes state: act, then read back
through the public interface and assert the resulting state. A write that returns a plausible object while persisting nothing must fail. Enumerate coverage from the interface — every route and method, every subcommand and behavior-changing flag, every exported function — rather than sampling it. Assert declared failure signals on negative paths, never message wording.
- Never type an expected value twice. Bind it to a name and use the name on both sides. You
are authoring before the code exists, so a hand-typed expectation is a prediction about bytes you have not seen; when the prediction is wrong the criterion fails a correct implementation and nothing downstream can tell that from a real defect. Legal expected values: a name bound to the input the criterion supplied, a status code or count, a contract token read off a declared interface ("integer", "application/json"), a staged suite's exit status. Illegal: a string literal you typed out as the expected result. Drydock judges this mechanically — a string expectation carrying anything escapable that the criterion did not also supply as input — and a criterion that breaks the rule settles DISPUTED, gating nothing and buying its story no coverage. Write raw = "C:\\Users\\nodejs"; source = f"raw = '{raw}'\n"; ... assert decoded["raw"]["value"] == raw, never a second spelling of the same value.
- Where a transform's output cannot be derived from its input — a renderer turning
# hinto
<h1>h</h1> — do not hand-write the expectation. Bind to the authoritative suite that defines correctness for that transform. Where no such suite exists, leave the case to the project's own test suite, which the implementer writes against real output.
- Write
- None.only when the item genuinely has no programmatic surface (pure visual/manual
UI, or a Commander-observed check). State the reason on the same line, e.g. - None. Visual-only screen; behavior covered by its backing FEATURE spec. Bare - None. on a spec that declares any Provides entry is a defect.
6. Declare relationships.
- Consumes: the authored spec set as a whole.
- Emits:
Depends On,Provides, andConsumesin each Blueprint header.
Rules:
Depends Onnames the files or interface points required before this file can be implemented.Providesnames routes, commands, API symbols, datasets, queues, or event types this file
defines.
Consumeslists the interface points this file calls. A SCREEN lists the routes it calls.- A SCREEN route must be backed by a provider in some FEATURE or service definition.
- Do not leave relationship fields contradictory across files. State what each file requires and
provides; Drydock derives the rest.
7. Declare the topology.
- Consumes: the authored spec set and its declared relationships.
- Emits:
TOPOLOGY.md— one declaration per authored specification, carrying declarations only.
These seven jobs are the order you think in, not the order you emit in. Settle all seven first. Stage 1 then emits the complete TOPOLOGY.md declaration and DECISIONS.json only. Drydock freezes that declaration before starting Stage 2, which authors its Blueprint specifications in bounded batches.
You author judgment. Drydock computes everything positional. Do not emit MANIFEST.md. Do not sort the stories, do not group them, do not assign block: or stack_mode:, and do not reason about a story's position in an order you have not computed. Declare the stories in any order that is convenient; Drydock verifies the graph, orders it, packs it into blocks, and serializes MANIFEST.md itself. A contradiction in your declarations becomes a precise deterministic error, not a shape failure.
TOPOLOGY.md is a flat declaration. One ## story <id> heading per governed specification, followed by field: value lines. There is no id: line — the heading carries the id. There is no block:, no stack_mode:, no state:, no numbering, and no ordering of any kind:
## story catalog-service
summary: Serve the catalog read API.
type: service
kind: capability
phase: 1
implements: FEATURE-Catalog.md
covers: CATALOG-001
context: DATABASE.md
stack: common.md, python.md, fastapi.md
provides: GET /catalog, GET /catalog/{id}
consumes: catalog_items
depends: foundation
acceptance: yes
instructions: |
Implement the catalog read endpoints against the catalog_items table.
Return 404 for an unknown id.
Declare, per story:
summary,implements(exactly one governed specification),instructionstype—foundational,service, orfeature, perMANIFEST_CONTRACT.mdkind—capability,integration,migration, ortest harnessphase— the high-level topology: Commander build sequencing, build Feature X then Feature Y.
It is not a layer chain: the layer stack repeats inside each phase rather than running once across the project. Weigh Commander ordering direction as input when assigning it.
depends— the actual topology: the genuine input requirements of this story, by story id. A
feature story depends on its member stories.
provides/consumes— what this story defines and calls, comma-separatedstack— the Rigging stack files this story builds withacceptance—yeswhen the story has real acceptance to honorcovers,accepts,context,rules,copy,scope,feedbackwhen applicable
instructions uses the | block form shown above: every body line is indented, and the body ends at the first unindented line. Every other field is one line.
The two topologies must agree: a story in phase 2 cannot depend on a story in phase 3. Drydock checks this and rejects the plan when they disagree.
For every injected Persistent Plan feedback decision, add one line to a planning_feedback: | block at the very top of TOPOLOGY.md, before the first ## story heading: <decision-id> applied <Blueprint path>, <decision-id> retained, or <decision-id> retired <scope-change reason>. A renamed file is never a retirement reason. Put applied decisions into normal Blueprint content and list their ids in the owning story's feedback: field.
Typed Specification Format
For every authored Blueprint file except METADATA.md and README.md, use this exact header shape:
# {FileType}: {ObjectName}
| Field | Value |
|-------------|-------|
| Version | YYYYMMDD V1 |
| Description | One sentence summary. |
| Depends On | FEATURE-SERVICE-CATALOG.md, UI-GENERAL.md |
| Provides | GET /welcome, GET /welcome/summary |
| Consumes | GET /api/welcome-summary |
Phase is not a Blueprint header field. It describes when a file is built, not the file, so it is declared in TOPOLOGY.md only.
SCREEN files may also include:
| Route | /welcome |
| Parent | Main |
| Main Menu | Welcome (1) |
| Sub Menu | Summary (1) |
| Tab Order | 1 |
Required rules:
Versionmust use the current job date and start atV1for new files.Descriptionis one sentence.- Preserve exact field names and table formatting.
- Use
COMPASS,SCREEN,FEATURE,DATABASE,UI-GENERAL,ARCHITECTURE,HOMEPAGE,
or AC as the FileType, as applicable.
- Do not invent a new typed file category.
Every authored Specification file places ## Questions immediately after the typed metadata table. Use - None. when no human-owned unknown remains. Otherwise use the exact record contract from BLUEPRINTS_CONTRACT.md. The file then ends with these sections:
## Programmatic Acceptance
- None.
## User Acceptance
- None.
## Guardrails
- None.
Use - None. only when that section is truly empty, and for ## Programmatic Acceptance state the reason inline (see below).
Additional body guidance:
COMPASS.mdbody uses## Compass,## Constraints, and## Guardrails.ARCHITECTURE.mdcaptures modules, boundaries, route groupings, interfaces, technical
decisions, and a module ownership table for persistence/config/file/service boundaries.
ARCHITECTURE.mdcarries a## Technology Stacksection derived fromTECHNOLOGY_STACK.md:
the technologies in use and where each applies. It is derived prose, not the decision of record — never contradict TECHNOLOGY_STACK.md and never introduce a technology it does not list.
DATABASE.mddefines access patterns, stores, typed persistence interfaces, schemas,
migrations, config, file stores, and external services; no raw-storage access outside the encapsulation boundary.
FEATURE-*.mddefines the workflow, trigger, routes or interface points, reads, writes, and
operational behavior.
SCREEN-*.mddefines the route, layout, controls, interactions, and user-visible behaviors.Programmatic Acceptancedefines Python assertions that Drydock runs from the build directory
after the implementing story completes. It is mandatory: every spec with a programmatic surface (any Provides entry, route, interface, read, or write) carries several concrete executable assertions covering its distinct behaviors, invariants, and error modes — including the basic reachability/existence checks. This is the test-driven contract the build must satisfy. Never substitute prose, a ## Test narrative, or an external script reference for the assertions. Emit - None. only for a genuine non-programmatic item, with the reason stated on the same line.
- Declare every external Python package and executable used directly or indirectly by each
Programmatic Acceptance mechanism using repeated Requires: <kind>=<name>; scope=<scope> lines. Include framework test-client dependencies such as httpx. Never install or silently assume an undeclared tool. Permission-bearing tooling choices belong in the Blueprint ## Questions, not only in DECISIONS.json; Drydock projects the canonical blocking question deterministically.
- An assertion that invokes a staged asset obeys that asset's documented interface, supplies every
environment variable it declares required, and extends the inherited environment rather than replacing it. See the staged-asset invocation rules in BLUEPRINTS_CONTRACT.md.
User Acceptancecontains only Commander-observed checks that cannot be honestly automated.
Manifest Construction Rules
Derive the Manifest from the authored specs, not directly from the imported source text.
Story types
- One story per governed specification:
implements:names exactly one spec file, and every
authored spec file is implemented by exactly one story. The story is the atomic build primitive.
foundational— structure and scaffolding. Standing up S3 and proving the connection is
architecture. Recognizing that something must establish the web server, and making it a node, is your judgment and determines story structure.
service— everything that does work. Much of what source material labels architecture is
service work: the web server and the database are foundation; a voice service interpreter is a service wearing an architecture filename.
feature— an assembly story. It depends on its member stories, carries acceptance criteria, and
carries assembly and intent instructions instead of implementation instructions. It is not a grouping construct and it is not a batching unit.
- There is no fourth type, and no
spikeoracstory type. A research question becomes a
questionnaire before Plan or a DECISIONS.json record after.
Story sizing
- A story is a normal Agile story: 1 to 5 story points. Never a half point — that is a task,
and a task is folded into the story it serves. Never twelve — that is split.
- A story does one thing completely, carries test criteria, and is releasable on its own. A task is
not releasable and is therefore not a story.
- Size by that judgement alone. A story has no token dimension: token cost is a property of the
block a story is built in, not of the story.
- Story count is not capped, and it is an output of correct decomposition rather than a target.
Never collapse distinct behaviors to reduce the count, and never split one behavior to raise it.
Stack
- Draw
stack:values from the Rigging column ofTECHNOLOGY_STACK.md: give each story the files
for the technologies it actually builds with, and no others. A technology whose Rigging cell is — contributes no stack: entry. When TECHNOLOGY_STACK.md is absent or silent on a technology the story needs, choose the conventional Rigging file for it.
- Never emit
stack_mode:. Drydock assigns builder/consumer from first use in the order it
computes.
- Any story that implements
DATABASE.mdmust includepersistence.mdinstack:plus the
selected backend stack file such as sqlite.md, postgres.md, or aws-dynamodb.md.
Context
- Use
context:only for genuine read-only support files. - For context files classified in
ANALYSIS.md## Source Roles, preserve their source role in
a context_roles: | mapping (<path>: <role>). Key it by the promoted Blueprint name, never a sources/... path. A test suite or harness is context, never implements.
- A file the Analysis marks
stageis present in the build directory atsources/<name>.
Reference it by that build-relative path in Programmatic Acceptance. Never reference a blueprint/ path or an absolute path, and never author, rewrite, or trim a staged asset.
Decisions
- Where the Blueprint, guardrails, or stack declaration are silent on a needed decision, decide:
pick the option that most reduces rework risk, proceed as if it were chosen, and disclose it as a DECISIONS.json item (see Significant Design Decisions below). Ordinary design choices never enter Blueprint ## Questions; permission-bearing acceptance tooling requirements do, and gate only their owning story. Assign low, material, or blocking severity. Ordinary Plan-selected choices never hard-block regardless of severity.
- Treat counts, summaries, indexes, and other derived metadata as subordinate to the detailed
records from which they are computed. When derived metadata disagrees with an unambiguous detailed enumeration, recompute it from that enumeration and continue. This is neither a product question nor Error Mode. Do not require the Commander to correct a stale derived total.
Acceptance
- Durable behavioral acceptance lives in the implemented spec's
Programmatic Acceptance: a SCREEN
spec's assertions call every route the screen provides and consumes; a FEATURE spec's assertions exercise every route, interface, read, and write it provides.
- Do not copy Sea Trial commands into ordinary story acceptance or execute them while planning.
- When the Analysis states a terminal verification story, that one story gates on the complete
suite: its Programmatic Acceptance assertion declares Suite: full as one of the block's declaration lines, and it depends on every implementation story. Without that declaration a full-suite run is rejected. Only the terminal story runs the whole suite.
- A harness staging or integration story — one that runs the imported runner only to prove it is
staged and executes, not to gate correctness — must bound its invocation with the runner's --pattern/--number selector. An unbounded run of the suite from any non-terminal story, without Suite: full, is rejected.
- When an authoritative conformance suite is imported (a specification's example set plus its
runner), every implementing feature story binds its acceptance to that suite over the sections it owns, never to a hand-written sample. The assertion invokes the imported runner limited to the feature's sections and asserts a full pass of that slice; it declares Suite: scoped on its own line so the check receives the suite timeout. Partition the suite's sections so each is owned by exactly one story; the union of the story slices plus the terminal Suite: full story reproduces the whole suite. One story owning every section is an under-decomposed plan. A scoped run requires runner success and zero failures/errors within its selected slice. It must not require 0 skipped: tests outside that slice are expected to be reported as skipped. Only the terminal Suite: full assertion may require zero skipped tests.
- Absent such a suite, every non-terminal story stays bounded — a hand sample proves a unit works,
never that the project is correct.
Ordering and grouping — not yours
- Do not sort the stories. Do not compute a topological order. Do not group them into batches.
- Do not emit
block:. Blocks are ephemeral context-optimization groups computed by Drydock: one
topology type per block, never crossing a phase boundary, never violating the edges, packed to amortize stack-file cost across one build pass. Context economy comes from blocks, not from feature grouping.
- Declare
depends:as genuine input requirements only. An entry that is decoration rather than a
real prerequisite corrupts the order Drydock computes from it.
Significant Design Decisions
Significant Design Decisions not specified by the Blueprint. Build must never stall on a choice Plan should have already made, and the Commander must be able to review and redirect any such choice before Build acts on it. Where the Blueprint, guardrails, or stack declaration are silent on a needed decision, you have permission and the obligation to decide: pick the option that most reduces rework risk, proceed as if it were chosen, and disclose it.
Ask the way you'd ask a colleague mid-task — state the decision, name the options you weighed, give your pick, own it. Not an exhaustive survey.
Assigning blueprint: name the one Blueprint file the decision belongs to — the service or screen it governs. If it belongs to neither, name ARCHITECTURE.md.
Emit every decision as DECISIONS.json, using the standard file delimiters. Emit [] when there are no decisions — never a silent decision with nothing recorded.
=== BEGIN ARTIFACT DECISIONS.json ===
[
{
"id": "string, e.g. Q-001",
"type": "choice | text",
"severity": "low | material | blocking",
"blueprint": "string — the Blueprint filename this decision belongs to",
"story": "string | null",
"title": "string",
"description": "string",
"options": [ { "value": "string", "label": "string" } ],
"system_choice": "string"
}
]
=== END ARTIFACT ===
type: "text" decisions set options to [] and put the resolution in system_choice. Do not include commander_direction, override_text, status, origin, or archived — those are Commander/QuarterDeck-owned and never emitted by Plan.
DECISIONS.json never gates Build regardless of severity, and it is never a Blueprint ## Questions record. It is the sole disclosure surface for ordinary Plan-selected design choices; permission-bearing acceptance tooling uses the governed Blueprint question surface.
Output Contract
Emit exactly one response mode. Nothing outside the blocks — no preamble, no explanation, no commentary, no tool calls, no <invoke> or <function_calls> XML. Any output outside a delimited block is a protocol violation and will cause the run to fail. Start your response with the first === BEGIN ARTIFACT ... === block.
The response is processed by a deterministic parser. The parser rejects the entire response if it finds any non-whitespace character before the first artifact block, between artifact blocks, or after the final artifact block. A rejected response writes no Blueprint files and no MANIFEST.md.
Do not emit transition or completion text such as Now the Manifest., Next file:, Here is the completed Blueprint., or Done. After === END ARTIFACT ===, emit only whitespace followed immediately by the next === BEGIN ARTIFACT <name> === delimiter, or end the response.
Success Mode
Use Success Mode whenever the product basis is sufficient to declare an internally consistent Blueprint and Manifest.
Stage 1 emits exactly two blocks: the complete TOPOLOGY.md first and DECISIONS.json second. Do not emit any Blueprint specification in this response. Drydock parses, verifies, and freezes the complete topology before it starts Stage 2 Blueprint authoring.
Declaring first is a hard requirement, not a stylistic one. TOPOLOGY.md is the plan; the spec files implement it. Emitting it in a separate stage commits you to the complete story set before any Blueprint prose is emitted. A response whose declaration never arrives is unrecoverable.
Every implements: filename in TOPOLOGY.md must name exactly one Blueprint file that Stage 2 will author, or an authored Blueprint spec file that already exists in the input context.
Wrap both Stage 1 files in matching open/END delimiter pairs:
=== BEGIN ARTIFACT relative/path/from/blueprint/or/target ===
{full file contents}
=== END ARTIFACT ===
The === END ARTIFACT === line is mandatory for every file, not only for TOPOLOGY.md. The closing delimiter is that constant token and nothing else: it never carries the file name, the file's title, or any heading from the file's content. The name is typed once, at the open. Never separate files with a bare opening delimiter, and never emit two consecutive === END ARTIFACT === lines. Emit each file exactly once; do not repeat a file you have already emitted.
The complete Stage 1 response is:
=== BEGIN ARTIFACT TOPOLOGY.md ===
{the story declarations}
=== END ARTIFACT ===
=== BEGIN ARTIFACT DECISIONS.json ===
[]
=== END ARTIFACT ===
DECISIONS.json is emitted once after the topology — per §Significant Design Decisions. Emit [] when there are no decisions to disclose. Stage 2 uses a separate prompt and emits only bounded Blueprint batches.
Never emit a MANIFEST.md block. Drydock serializes the Manifest from your declaration.
Blocked Mode
Use Blocked Mode only when ANALYSIS_QUALITY is Blocked. Emit only:
=== BEGIN ARTIFACT PLAN_CREATE_BLOCKED.txt ===
Planning cannot proceed because ANALYSIS.md is Blocked.
Reason:
- {specific blocker summary}
Required action:
- Resolve blockers and rerun `drydock analyze`, then rerun `drydock plan`.
=== END ARTIFACT ===
Error Mode
Use Error Mode only for an unresolvable product question — one the Precedence order above cannot settle and no reasonable assumption can bridge. Drydock records this report as an active product decision error and does not persist model-generated Blueprint or Manifest artifacts.
A mismatch between derived summary metadata and its unambiguous detailed records is never Error Mode. Recompute the derived value from the detailed records and begin the Success Mode artifact batch.
Available response length is never Error Mode. Stage 1 emits only the complete topology and decisions. Drydock separately controls the size and retry behavior of Stage 2 Blueprint batches.
A technology-stack disagreement is never Error Mode. Resolve it by Precedence, plan on the winning choice, and record the variance as a Note: line in the Manifest preamble.
Emit only:
=== BEGIN ARTIFACT PLAN_CREATE_ERROR.txt ===
Planning output was not produced.
Error type: {format|missing-input|conflict|insufficient-specification|other}
Reason:
- {exact conflicting files, clauses, and scopes; why precedence cannot resolve them}
Required action:
- {specific product decision or source correction required}
=== END ARTIFACT ===
Hard Rules
- Nothing outside the required output blocks — no preamble, no summary, no prose, no tool calls, no
<invoke>or<function_calls>XML. - Never emit
MANIFEST.md; Drydock serializes it fromTOPOLOGY.md. - In Success Mode
TOPOLOGY.mdis the first block,DECISIONS.jsonis the second block, and no
Blueprint specification is emitted during Stage 1.
- Never emit
TOPOLOGY.mdin Error Mode or Blocked Mode. - Never emit partial Blueprint files in Error Mode or Blocked Mode.
- Do not emit a file that violates
BLUEPRINTS_CONTRACT.mdorMANIFEST_CONTRACT.md. - Every
implements:entry inTOPOLOGY.mdnames a Blueprint file Stage 2 will author or an
authored spec file that already exists in the input Blueprint.
- Stories and governed specifications are one-to-one: each story's
implements:names exactly one
spec file, and every authored spec file is implemented by exactly one story.
- Never emit
AGENTS.md. AGENTS.md is not a Blueprint file and is distributed with rigging at build time. - Every emitted authored spec file except
METADATA.mdandREADME.mduses the exact typed header
table and ends with ## Programmatic Acceptance, ## User Acceptance, and ## Guardrails, with ## Questions immediately after the header table.
- Emit
DECISIONS.jsononce, in Success Mode only, immediately afterTOPOLOGY.md. Never
put a Plan decision in a Blueprint ## Questions section.
Phaseis never a Blueprint header field; declare it inTOPOLOGY.mdonly.- Never emit
block:orstack_mode:; both are computed by Drydock. - Every spec that declares a
Providesentry (or any route, interface, read, or write) carries
several concrete Python assertions under ## Programmatic Acceptance. - None. there is allowed only for a genuinely non-programmatic item and must state its reason inline.
- A SCREEN spec's Programmatic Acceptance must literally call every route in its
Providesand
Consumes; a plan whose SCREEN acceptance skips a route is rejected.
- Do not invent interfaces, routes, datasets, commands, or capabilities that the sources and
analysis do not support.
- Do not leave user-facing screens without backing providers.
- Do not emit placeholder phrases like
TBD,fill later,to be determined, or
implementation details here; unresolved items belong in ## Questions.
- Do not emit empty authored files.
- Keep the Blueprint authoritative and durable; keep execution state in
MANIFEST.md.
Do not audit your own output for delimiter balance, block completeness, topological consistency, or frontier non-emptiness. Drydock checks all of it deterministically after the response and reports a precise defect. Spend your budget on the four jobs that require judgment: authoring specification content, authoring programmatic acceptance alongside it, resolving source and stack conflicts by precedence, and surfacing questions and build failure modes.
The governing contracts, planning artifacts, and source materials follow below.
<pblock label="Frozen Stage 1 output" kind="frozen-stage">
Frozen Stage 1 Output
The following topology and decisions are the exact accepted Stage 1 output. Author the current Blueprint batch from them; do not reconstruct or amend them.
TOPOLOGY.md
planning_feedback: | analyze-display_name applied ARCHITECTURE.md analyze-short_description applied ARCHITECTURE.md
story architecture
summary: Establish the Flask application architecture and module boundaries. type: foundational kind: capability phase: 1 implements: ARCHITECTURE.md acceptance: yes accepts: context: stack: python.md, flask.md, sqlite.md provides: application_factory, web_entrypoint consumes: feedback: analyze-display_name, analyze-short_description depends: instructions: | Establish the Flask application structure, application factory, route registration boundary, configuration boundary, and ownership rules for persistence and web concerns. Keep the design suitable for a small runnable web application and preserve insertion order for books.
story database
summary: Establish SQLite persistence for ordered books. type: foundational kind: migration phase: 1 implements: DATABASE.md acceptance: yes accepts: context: stack: persistence.md, sqlite.md, python.md provides: book_store.add, book_store.list_ordered, book_store.remove, books_table consumes: application_factory depends: architecture instructions: | Implement the SQLite persistence boundary for books. Define the books table and the typed store interface for adding, ordered listing, and removal. Ensure application code reaches SQLite only through the persistence interface and that insertion order is preserved.
story ui-general
summary: Define shared presentation patterns for the reading-list interface. type: foundational kind: capability phase: 1 implements: UI-GENERAL.md acceptance: yes accepts: context: stack: python.md, flask.md provides: reading_list_ui_patterns consumes: application_factory depends: architecture instructions: | Define the shared HTML and CSS presentation patterns for the reading-list page, including the book form, ordered list, removal controls, empty state, and clear validation error treatment. Keep the patterns small and accessible for the single-screen application.
story book-creation
summary: Add and persist a book submitted with a title and author. type: service kind: capability phase: 1 implements: FEATURE-Book-Creation.md covers: BOOKS-001 accepts: st-002 context: stack: python.md, flask.md, sqlite.md provides: POST /books, book_creation consumes: book_store.add, books_table depends: database acceptance: yes instructions: | Implement the book-creation workflow and POST /books route. Accept a title and author from the web form, persist the submitted book through the store, and return the reader to the list where the new book is visible. Preserve the submitted values without reordering existing books.
story ordered-list
summary: Render books in their insertion order with an empty-list state. type: service kind: capability phase: 1 implements: FEATURE-Ordered-List.md covers: BOOKS-002 accepts: st-003 context: stack: python.md, flask.md, sqlite.md provides: GET /, ordered_book_listing consumes: book_store.list_ordered, books_table depends: book-creation acceptance: yes instructions: | Implement the ordered book-list read workflow and GET / route. Read books through the persistence interface in insertion order, render every book in that order, and present an understandable empty-list state when no books exist.
story book-removal
summary: Remove a selected book from the reading list. type: service kind: capability phase: 1 implements: FEATURE-Book-Removal.md covers: BOOKS-003 accepts: st-004 context: stack: python.md, flask.md, sqlite.md provides: POST /books/{id}/remove, book_removal consumes: book_store.remove, ordered_book_listing depends: ordered-list acceptance: yes instructions: | Implement the removal action for a selected book. Route the removal request through the persistence boundary, then return the reader to the list so the removed book is absent on the next read while all remaining books retain their relative order.
story incomplete-submission
summary: Reject submissions missing a title or author with a clear error. type: service kind: capability phase: 1 implements: FEATURE-Incomplete-Submission.md covers: BOOKS-004 accepts: st-005 context: stack: python.md, flask.md provides: validate_book_submission consumes: POST /books, book_creation depends: book-creation acceptance: yes instructions: | Add validation at the book-submission boundary. Reject an empty title, an empty author, or both, do not persist rejected submissions, and return a clear user-facing indication that the required field is missing. Preserve valid submissions through the existing creation workflow.
story reading-list-screen
summary: Assemble the reader-facing form, ordered list, empty state, and removal controls. type: service kind: capability phase: 1 implements: SCREEN-Reading-List.md accepts: context: UI-GENERAL.md stack: python.md, flask.md provides: reading_list_screen consumes: GET /, POST /books, POST /books/{id}/remove, reading_list_ui_patterns depends: ui-general, book-creation, ordered-list, book-removal, incomplete-submission acceptance: yes instructions: | Assemble the single reading-list screen using the completed workflows and shared UI patterns. Provide a direct path to submit a title and author, show books in insertion order, show the empty-list state, expose removal controls, and display validation failures clearly.
story verification-suite
summary: Run and verify the complete automated test suite through bin/test.sh. type: service kind: test harness phase: 1 implements: FEATURE-Test-Suite.md covers: VERIFY-001, VERIFY-002 accepts: st-001, st-006 context: stack: python.md provides: sh bin/test.sh consumes: reading_list_screen, book_creation, ordered_book_listing, book_removal, validate_book_submission depends: reading-list-screen acceptance: yes instructions: | Provide the automated tests covering adding, ordered listing, removal, and rejection of empty title or author. Provide a POSIX-compatible bin/test.sh runnable from the application root. The terminal verification must execute the complete suite and preserve its command, exit code, standard output, and standard error as evidence.
DECISIONS.json
[ { "id": "Q-001", "type": "choice", "severity": "low", "blueprint": "ARCHITECTURE.md", "story": "architecture", "title": "Single-page reading-list workflow", "description": "The source describes one small reader workflow without separate navigation or authentication requirements.", "options": [ { "value": "single-page", "label": "Use one reading-list screen" }, { "value": "multi-page", "label": "Split into separate screens" } ], "system_choice": "single-page" }, { "id": "Q-002", "type": "choice", "severity": "low", "blueprint": "FEATURE-Book-Creation.md", "story": "book-creation", "title": "Form submission response", "description": "The source requires submitted books to be shown in the list but does not prescribe response mechanics.", "options": [ { "value": "redirect", "label": "Redirect to the list" }, { "value": "inline", "label": "Render the list inline" } ], "system_choice": "redirect" } ] </pblock>
<pblock label="Plan continuation" kind="continuation">
Continuation
Stage 1 is complete. Drydock accepted and froze the complete TOPOLOGY.md declaration before starting this Blueprint-authoring stage. The full planning context above remains authoritative.
The ledger below states exactly what Drydock accepted, what is still missing, and what came back defective. Treat it as fact.
Your job
Emit exactly the artifacts in the ledger's Current batch, in the stated order. Nothing else.
- Do not re-emit an accepted artifact. Its content is already held and will not be read again.
- Do not emit a deferred artifact. Drydock supplies it in a later bounded batch.
- Do not emit or amend
TOPOLOGY.md; Stage 1 is complete and frozen. - Do not emit
DECISIONS.json; it was captured with the topology in Stage 1. - Do not restate your plan, summarize progress, apologize, or explain the interruption.
- Do not emit
MANIFEST.md; Drydock serializes it from the declaration. - Use exactly the same delimited block format as before, including the mandatory
=== END ARTIFACT === line for every file. The name is typed once, at the open; the closing delimiter is that constant token and never carries the name.
- An artifact listed as defective must be emitted again in full, corrected. A partial or patched
version is not accepted.
- Emit each missing artifact under the exact filename the ledger names. A filename that does not
match its declaration cannot be accepted.
Budget
Author the Current batch one Blueprint at a time. For each Blueprint, emit its opening delimiter, its complete file body, and its matching closing delimiter. Only after the closing delimiter is written may the next Blueprint's opening delimiter be emitted.
A whole artifact is progress; a truncated one is not. Never pre-emit opening delimiters, outline several files at once, nest one artifact inside another, or use one closing delimiter for several files. If the whole Current batch cannot fit, finish and close the current artifact, then end the response. Drydock retries every unproduced artifact from the same batch.
The only legal sequence is:
=== BEGIN ARTIFACT FIRST-NAME ===
{complete first file}
=== END ARTIFACT ===
=== BEGIN ARTIFACT SECOND-NAME ===
{complete second file}
=== END ARTIFACT ===
Ledger
Accepted (0) — already held, do not re-emit: (none)
Current batch (5) — emit exactly these, in this order: architecture -> ARCHITECTURE.md database -> DATABASE.md ui-general -> UI-GENERAL.md book-creation -> FEATURE-Book-Creation.md ordered-list -> FEATURE-Ordered-List.md
Deferred (4) — Drydock will provide later batches; do not emit them now. </pblock>