@agentsfleet/orly 0.10.5 → 0.10.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,91 +1,65 @@
1
- # write_spec.md — spec-authoring dispatch (LATENT façade)
1
+ # Spec authoring
2
2
 
3
- This is the prose the AGENT reads **before writing or editing a spec** under
4
- `docs/v*/{pending,active,done}/`. It pairs with the deterministic half
5
- `audits/spec-template.sh`, which runs in `make lint`. (This is the former Spec Template gate absorbed into
6
- the dispatch model — `docs/TEMPLATE.md` remains the canonical section source.)
3
+ Read this before editing a spec under `docs/v*/{pending,active,done}/`, or
4
+ `docs/TEMPLATE.md`. The template defines the document shape. The authoring skill
5
+ fills it; the audit checks structural consistency. None proves design quality.
7
6
 
8
- **Signal legend:**
7
+ ## What must be ready, and when
9
8
 
10
- - 🟢 / 🔴 — `audits/spec-template.sh` mechanically passes/fails the prohibited-pattern and
11
- required-section checks.
12
- - 🤔 DECIDE — whether a required section is *meaningfully filled* (not just
13
- present) is the agent's judgment at author time.
9
+ | Stage | Required content |
10
+ |---|---|
11
+ | Authoring | Goal, scope, existing references, decisions and prerequisites, Dimensions with test mappings, failures, interfaces, and acceptance checks |
12
+ | CHORE(open) | Active status, branch, full comparison revision, baseline measurement pending |
13
+ | PLAN | Implementer's comprehension handshake; resolved scope and decisions needed by the next Section |
14
+ | Before Pull Request | Declared unit/integration baseline counts, comparison revision, and evidence reference |
15
+ | Completion | Passing behavior proofs, final repository checks, and any required human evidence |
16
+
17
+ The sequence and hydration timing live in `dispatch/lifecycle.md`. A preparation
18
+ Section may establish inputs for later Sections when the spec states its output
19
+ and who may decide it. A required human sign-off remains a human dependency.
20
+
21
+ ## Mechanical checks
22
+
23
+ `audits/spec-template.sh` is the entry point; its Bun helper
24
+ `audits/spec-template.ts` reads headings, lists, and tables from the runtime's
25
+ parsed Markdown tree. Code examples and quoted headings cannot supply sections.
26
+
27
+ - Prohibited authoring estimates, ownership labels, and completion percentages.
28
+ - Required sections with content, known placeholder residue, and the spec length cap.
29
+ - Existing repository files or URLs in the read-first list. Planned CREATE files
30
+ belong in Files Changed, not in the existing-reference list.
31
+ - Each Dimension names a proof and has a matching tiered Test Specification row
32
+ with an assertion. Duplicate identifiers and orphan test rows fail.
33
+ - The rubric's Verify cells contain the exact declared `conform` and `verify.*`
34
+ commands, with Expected values. Include conditional suites; the final gate
35
+ decides their applicability from the actual branch diff. Additional
36
+ spec-specific commands and explicitly named manual checks remain valid.
37
+
38
+ `--staged` reads spec contents, configuration, and local references from the Git
39
+ index. `--file <path>` checks the working copy. Missing runtime or configuration
40
+ fails these readiness checks. Bulk `--all` and `--include-done` scans retain
41
+ prohibited-pattern checks only; they do not retrofit historical documents.
42
+
43
+ ## Author review
44
+
45
+ Check that required content is meaningful, prerequisites are attainable, failures
46
+ are tested, and the acceptance checks prove the goal. A structural pass does not
47
+ mean the feature is implemented. Use `manual` for a human proof; record its
48
+ procedure, required person, and durable evidence without inventing sign-off.
49
+
50
+ Use `{{fill:description}}` for authoring slots. Delete them and all `tpl:`
51
+ guidance before staging. Runtime parameters such as `/items/{id}` are allowed
52
+ when the spec defines them. Lifecycle-owned values use explicit pending text,
53
+ not unfilled authoring slots. Existing specs follow current rules; examples do
54
+ not override them.
14
55
 
15
- ## Trigger — every Edit/Write to
56
+ **Override:** `SPEC TEMPLATE GATE: SKIPPED per user override (reason: ...)`.
57
+ User-invokable only; an external constraint must explain the exception.
16
58
 
17
- - Any spec under `docs/v*/{pending,active,done}/**/*.md`.
18
- - `docs/TEMPLATE.md` itself.
19
- - Any `*.md` whose body carries the spec frontmatter pattern (`^**Milestone:** M\d+`).
59
+ ## Required output
20
60
 
21
- **Override:** `SPEC TEMPLATE GATE: SKIPPED per user override (reason: ...)`.
22
- **User-invokable only.** Auto-mode does NOT cover it; reasons must cite a concrete
23
- external constraint (vendor doc requirement, regulatory format), never internal
24
- preference.
25
-
26
- ## What this covers
27
-
28
- **Family 1 — prohibited patterns (negative space).** `docs/TEMPLATE.md`
29
- "Prohibited" forbids: time/effort estimates, effort columns, complexity ratings,
30
- percentage-complete fields, assigned owners, implementation dates. Specs created
31
- from the template don't carry the Prohibited section forward — only the body
32
- below the divider gets copied — so without enforcement these drift back in.
33
-
34
- **Family 2 — required-present + no-placeholder (positive space).** The
35
- agent-facing template mandates the determinism sections the executing agent reads
36
- to emit invariant output: PR Intent & comprehension handshake, Applicable Rules,
37
- Applicable Gates, Overview, Prior-Art / Reference Implementations, Files Changed,
38
- Decomposition & alternatives, Sections, Metrics & Observability, Interfaces,
39
- Failure Modes, Invariants, Test Specification, Acceptance Rubric (legacy heading `Acceptance Criteria` accepted), Product Clarity (authoring record), Discovery. A spec missing one — or
40
- leaving template residue (`path/to/file.ext`, `test_<short_name>`,
41
- `{one-line reason}`, any surviving `tpl:` guidance comment — the template's fill
42
- grammar deletes them all at authoring) — forces the agent to guess intent.
43
-
44
- **Family 2b — declared-command parity.** A staged `pending/` or `active/`
45
- spec's Acceptance Rubric must quote the repository's declared `conform` and
46
- `verify.unit` commands (`.oracle/orly.json`) **verbatim** — the same set
47
- `orly gate` runs, so the rubric and the mechanical PR gate grade one boundary.
48
- Missing → BLOCK. No config, no bun, or no declared commands → NOTE + skip.
49
- Done specs are historical records and are never retrofitted.
50
-
51
- **Scope (no legacy carve-out).** Family 2 fires in `--staged` only — the spec
52
- being authored now (the agent's own output): BLOCK. Bulk scans (`--all` /
53
- `--include-done`, which `make harness-verify` runs) execute Family 1 only, so they
54
- behave identically over the corpus and never break an existing spec.
55
-
56
- ## Pre-edit check
57
-
58
- | Pattern | Rule |
59
- |---|---|
60
- | `## Estimated effort` (any heading variant) | Forbidden. Delete the section. |
61
- | `## Effort` / `## Complexity` / `## Sizing` | Forbidden. Use Priority. |
62
- | `\b\d+\s*[-–]\s*\d+\s*h\b` (hour ranges like "10-14h") | Forbidden. |
63
- | `\b\d+\s*hours?\b` / `\b\d+\s*days?\b` / `\b\d+\s*min(utes?)?\b` | Forbidden. |
64
- | `\b(low|medium|high|small|large)\s*[:|-]\s*(effort|complexity)\b` | Forbidden. |
65
- | `\d+%\s*complete` / `\b\d+/\d+\b\s*tasks` | Forbidden — binary PENDING/IN_PROGRESS/DONE. |
66
- | `**Owner:**` / `**Assigned to:**` | Forbidden — use git history. |
67
- | `**Due:**` / `**Deadline:**` (with date) | Forbidden — use Priority. |
68
- | Missing a required determinism section in a **staged** spec | BLOCK — add it. |
69
- | Rubric missing a declared `conform`/`verify.unit` command (**staged** pending/active) | BLOCK — copy it verbatim from `.oracle/orly.json`. |
70
- | Unfilled template residue in a **staged** spec | BLOCK — fill the section. |
71
- | Surviving `tpl:` guidance comment in a **staged** spec | BLOCK — delete it; the executor reads instance content only. |
72
- | Spec without the SPEC AUTHORING RULES banner | Informational — reminds future edits. |
73
-
74
- ## Required output (default — one line)
75
-
76
- ```
77
- SPEC TEMPLATE GATE: <file> | prohibited:<0|list> required-sections:<all-present|missing-list — staged only> placeholders:<0|list> banner:<yes|no>
78
- ```
79
-
80
- Full multi-line block fires on violation (prohibited sections / time estimates /
81
- effort fields / %-complete / owner-date fields, each with line numbers, plus the
82
- `audits/spec-template.sh` staged-diff finding count).
83
-
84
- ## Scope
85
-
86
- `audits/spec-template.sh` walks the **full pending+active spec set** via `git ls-files`;
87
- the index includes staged-but-uncommitted content, so a fix staged in pre-commit
88
- satisfies the check on the same hook run. `--staged` is the opt-in narrowing mode.
61
+ Report structural findings with file paths. Report an implementation verdict
62
+ only after the spec's behavior and repository checks have run.
89
63
 
90
64
  ## Authoring discipline (judgment layer)
91
65
 
@@ -71,9 +71,14 @@ determinism proof is unchanged by any of this.
71
71
 
72
72
  | Gate | Proves |
73
73
  |---|---|
74
- | `work` | branch is not the default; tree is clean; the repository declares its commands in `.oracle/orly.json` |
75
- | `verify` | Dimensions marked DONE (when a spec exists); `conform`; the fast `verify.*` commands |
76
- | `pr` | tree clean; branch pushed; spec gate + closed-spec follow-through (`spec.moved` / `spec.baseline` / `spec.ordering` / `spec.deferrals`); docs updated for user-surface changes; the slow suites |
74
+ | `work` | repository configuration and the declared `conform` command over the staged change |
75
+ | `verify` | documentation checks and non-test `verify.*` commands; unfinished Sections may be pushed |
76
+ | `pr` | exact pushed revision, branch/spec criteria, docs surface, and every declared `verify.*` command |
77
+
78
+ The authoritative sequence is `dispatch/lifecycle.md`. Full unit, integration,
79
+ and memory suites run at the PR boundary. No stored verification cache or
80
+ assumption about a custom pre-push hook can remove them. Baselines name an
81
+ immutable comparison revision and are measured before the Pull Request.
77
82
 
78
83
  Every criterion is mechanical — it reads an exit code or a file. Claims that
79
84
  cannot be proven that way stay prose and are graded by the spec's rubric; they
@@ -121,6 +126,11 @@ surfaces:
121
126
  ```
122
127
 
123
128
  Orly owns policy and invokes these commands. The repository owns what they do.
129
+ Setup requires `conform` and at least one named `verify.*` command.
130
+ Documentation repositories can use `verify.docs` for site validation and link
131
+ checks without declaring application test suites. `init` reports missing
132
+ commands; `doctor` rejects incomplete setup without running those commands.
133
+ The final tree check includes the spec, so its evidence must be committed.
124
134
 
125
135
  ## Usage telemetry
126
136
 
@@ -12,9 +12,9 @@ regenerates this file and fails on any difference. To update it, run
12
12
  | `docs/DOCUMENTATION_RULES.md` | — | 0 | 0 | 0/22 | latent |
13
13
  | `docs/LIFECYCLE_PATTERNS.md` | — | 0 | 0 | 0/22 | mechanical |
14
14
  | `docs/CHANGELOG_VOICE.md` | — | 0 | 0 | 0/3 | latent |
15
- | `docs/VERIFY_TIERS.md` | — | 0 | 0 | 0/7 | uncited |
15
+ | `docs/VERIFY_TIERS.md` | — | 0 | 0 | 0/6 | uncited |
16
16
  | `docs/greptile-learnings/RULES.md` | — | 0 | 0 | 0/114 | mechanical |
17
- | **corpus** | | | | **30/279** | |
17
+ | **corpus** | | | | **30/278** | |
18
18
 
19
19
  ## How to read this
20
20
 
package/docs/TEMPLATE.md CHANGED
@@ -3,7 +3,7 @@
3
3
  > **CANONICAL TEMPLATE — two agents consume this file, in different ways.**
4
4
  > The **authoring agent** (via the `orly-spec-new` skill) copies the body below the divider into `docs/v{N}/pending/M{N}_{NNN}_….md` and fills it — authoring order lives in the skill, not in this file. The **executing agent** reads the filled spec **top-to-bottom**: the body is physically ordered by execution need (understand → prepare → build → prove → record).
5
5
  > Enforced by `audits/spec-template.sh` (SPEC TEMPLATE GATE, façade `dispatch/write_spec.md`): required sections present, zero template residue, prohibited patterns absent. Lifecycle: `AGENTS.md → Specification Standards`.
6
- > A shipped instance outranks guidance: when `docs/v{N}/done/` holds specs, read the newest first and pattern-match.
6
+ > Read a recent completed instance for examples; current rules and this template govern any conflict.
7
7
 
8
8
  ---
9
9
 
@@ -13,7 +13,7 @@ Three markup classes appear below the divider. The gate tells them apart mechani
13
13
 
14
14
  | Marker | Meaning | Fate in the filled spec |
15
15
  |---|---|---|
16
- | `{…}` | Fill slot — replace with instance content | Gone. Surviving slots are residue; the gate BLOCKs the known sentinels. |
16
+ | `{{fill:description}}` | Authoring slot — replace with instance content | Gone before staging. Runtime parameters such as `/items/{id}` remain when defined. |
17
17
  | `tpl:` guidance comment | How to fill the section — written for the authoring agent only | **Deleted after filling.** The gate BLOCKs any survivor. |
18
18
  | SPEC AUTHORING RULES banner comment | Standing constraints on the instance | The one comment that survives, verbatim. |
19
19
 
@@ -89,22 +89,24 @@ SPEC AUTHORING RULES (load-bearing — the one comment that survives):
89
89
  sequencing signal. A section that contradicts these rules loses — delete it.
90
90
  -->
91
91
 
92
- # M{Milestone}_{Workstream}: {Title — testable, not vague}
92
+ # M{{fill:Milestone}}_{{fill:Workstream}}: {{fill:Title — testable, not vague}}
93
93
 
94
- **Prototype:** v{major}.{minor}.{patch}
95
- **Milestone:** M{Number}
96
- **Workstream:** {001-009}
97
- **Date:** {MMM DD, YYYY}
94
+ **Prototype:** v{{fill:major}}.{{fill:minor}}.{{fill:patch}}
95
+ **Milestone:** M{{fill:Number}}
96
+ **Workstream:** {{fill:001-009}}
97
+ **Date:** {{fill:MMM DD, YYYY}}
98
98
  **Status:** PENDING | IN_PROGRESS | DONE
99
- **Priority:** P0 | P1 | P2 | P3 — {one-line reason}
100
- **Categories:** {API | CLI | UI | SKILL | DOCS | OBS | INFRA — alphabetised, one or more}
101
- **Batch:** B{1-4} — {parallel execution context}
102
- **Branch:** {feat/mNN-name — added at CHORE(open)}
99
+ **Priority:** P0 | P1 | P2 | P3 — {{fill:one-line reason}}
100
+ **Categories:** {{fill:API | CLI | UI | SKILL | DOCS | OBS | INFRA — alphabetised, one or more}}
101
+ **Batch:** B{{fill:1-4}} — {{fill:parallel execution context}}
102
+ **Branch:** pending — set at CHORE(open)
103
103
  <!-- A deliberately folded workstream adds Folded-into metadata per dispatch/lifecycle.md. -->
104
- **Test Baseline:** set at CHORE(open) — `unit=<N> integration=<M>` from the repository's declared `verify.*` commands (`.oracle/orly.json`)
105
- **Depends on:** {M{N}_{NNN} (one-line reason), …}
106
- **Provenance:** human-written | LLM-drafted ({model}, {date}) | agent-generated (pre-spec, {source doc})
107
- **Canonical architecture:** `docs/architecture/{relevant-doc}.md` §{N}
104
+ **Baseline revision:** pending — record the full comparison commit at CHORE(open)
105
+ **Test Baseline:** pending — measure declared unit and integration lanes before the Pull Request
106
+ **Baseline evidence:** pending — report path or run URL with revision, commands, passed/failed/skipped counts, and environment
107
+ **Depends on:** {{fill:spec identifiers with one-line reasons, or none}}
108
+ **Provenance:** human-written | LLM-drafted ({{fill:model}}, {{fill:date}}) | agent-generated (pre-spec, {{fill:source doc}})
109
+ **Canonical architecture:** `docs/architecture/{{fill:relevant-doc}}.md` §{{fill:N}}
108
110
 
109
111
  <!-- tpl: Provenance is load-bearing — the implementing agent calibrates trust by
110
112
  who wrote the spec: LLM-drafted gets extra cross-checking against the codebase;
@@ -116,9 +118,9 @@ Update Gate); greenfield → point at the doc that defines the shape. -->
116
118
 
117
119
  ## Overview
118
120
 
119
- **Goal (testable):** {one sentence that could be a test name}
120
- **Problem:** {observable symptoms, in user-facing terms}
121
- **Solution summary:** {one paragraph — what changes, at what layer, what the user-visible outcome is}
121
+ **Goal (testable):** {{fill:one sentence that could be a test name}}
122
+ **Problem:** {{fill:observable symptoms, in user-facing terms}}
123
+ **Solution summary:** {{fill:one paragraph — what changes, at what layer, what the user-visible outcome is}}
122
124
 
123
125
  <!-- tpl: Goal — bad: "Implement streaming." Good: "Server-Sent Events (SSE)
124
126
  handler streams Redis pubsub messages as text/event-stream with stable ordering
@@ -128,18 +130,18 @@ don't have a foo handler"). Implementation steps belong in Sections, not here. -
128
130
 
129
131
  ## PR Intent & comprehension handshake
130
132
 
131
- - **PR title (eventual):** {imperative, ≤72 chars — what the merged Pull Request (PR) is called}
132
- - **Intent (one sentence):** {why this PR exists, in user-facing-outcome terms}
133
- - **Handshake** — the implementing agent fills this at PLAN, before EXECUTE: restate the Intent in its own words and list `ASSUMPTIONS I'M MAKING: …`. A mismatch between the restatement and the Intent above → STOP and reconcile before any edit.
133
+ - **PR title (eventual):** {{fill:imperative, ≤72 chars — what the merged Pull Request (PR) is called}}
134
+ - **Intent (one sentence):** {{fill:why this PR exists, in user-facing-outcome terms}}
135
+ - **Handshake** — pending until the implementing agent performs PLAN, before EXECUTE: restate the Intent in its own words and list `ASSUMPTIONS I'M MAKING: …`. A mismatch between the restatement and the Intent above → STOP and reconcile before any edit.
134
136
 
135
137
  ## Implementing agent — read these first
136
138
 
137
- 1. `{path/to/file.ext}` — {why this is the right pattern to mirror}
138
- 2. `{path/to/spec_or_doc.md}` — {what canonical knowledge lives there}
139
- 3. {external doc URL, if relevant} — {what convention to follow}
139
+ 1. `{{fill:path/to/file.ext}}` — {{fill:why this is the right pattern to mirror}}
140
+ 2. `{{fill:path/to/spec_or_doc.md}}` — {{fill:what canonical knowledge lives there}}
141
+ 3. {{fill:external doc URL, if relevant}} — {{fill:what convention to follow}}
140
142
 
141
- <!-- tpl: 3–5 pointers. Fewer than 3 = authoring homework not done (the executing
142
- agent repeats it); more than 5 = a tutorial (trim). This is where judgment is
143
+ <!-- tpl: Prefer 3–5 useful pointers; include enough to resolve the existing
144
+ implementation and governing requirements. This is where judgment is
143
145
  preserved without pseudocode: point at code/docs to read BEFORE touching any
144
146
  file. Greenfield (no existing pattern)? Say so explicitly and point at the
145
147
  docs/architecture/ doc that defines the shape. Every pointer must resolve
@@ -150,7 +152,7 @@ never selected materialised nothing here. -->
150
152
 
151
153
  | File | Action | Why |
152
154
  |------|--------|-----|
153
- | `path/to/file.ext` | CREATE / EDIT / DELETE | {one line — what changes about this file's role} |
155
+ | `path/to/file.ext` | CREATE / EDIT / DELETE | {{fill:one line — what changes about this file's role}} |
154
156
 
155
157
  <!-- tpl: Every file created, modified, or deleted. Scopes the length gates,
156
158
  orphan sweeps, and review effort; per AGENTS.md the executing agent may only
@@ -161,8 +163,8 @@ no path filter (dispatch/write_spec.md, Authoring discipline). -->
161
163
 
162
164
  ## Applicable Rules
163
165
 
164
- - **`docs/greptile-learnings/RULES.md`** — {specific rule IDs this diff trips: e.g. UFS, NDC, NLR, ORP, FLL}
165
- - {per-surface rule file} — {why it applies to this diff}
166
+ - **`docs/greptile-learnings/RULES.md`** — {{fill:specific rule IDs this diff trips: e.g. UFS, NDC, NLR, ORP, FLL}}
167
+ - {{fill:per-surface rule file}} — {{fill:why it applies to this diff}}
166
168
 
167
169
  <!-- tpl: The rule files the executing agent re-reads BEFORE EXECUTE and
168
170
  re-checks during VERIFY. Name the exact rule IDs the diff will trip — generic
@@ -177,8 +179,8 @@ set only — docs/greptile-learnings/RULES.md; no other rule files apply." -->
177
179
 
178
180
  | Gate | Fires? | Satisfaction strategy |
179
181
  |------|--------|-----------------------|
180
- | {gate from this repository's AGENTS.md dispatch index} | {yes/no — why} | {how the diff stays clean} |
181
- | File & Function Length (≤350/≤50/≤70) | {yes/no} | {split plan if a file approaches the cap} |
182
+ | {{fill:gate from this repository's AGENTS.md dispatch index}} | {{fill:yes/no — why}} | {{fill:how the diff stays clean}} |
183
+ | File & Function Length (≤350/≤50/≤70) | {{fill:yes/no}} | {{fill:split plan if a file approaches the cap}} |
182
184
 
183
185
  <!-- tpl: Which Action-Triggered Guards this Pull Request (PR) WILL trip, and
184
186
  how each stays clean — pre-declared so the agent plans for them instead of
@@ -190,7 +192,7 @@ replace the table with "N/A — docs/markdown only." -->
190
192
 
191
193
  ## Prior-Art / Reference Implementations
192
194
 
193
- - **Reference:** {path / codebase} — {one line on alignment, or the justified divergence}
195
+ - **Reference:** {{fill:path / codebase}} — {{fill:one line on alignment, or the justified divergence}}
194
196
 
195
197
  <!-- tpl: SOUL.md rule — before proposing architecture, find the reference
196
198
  codebase; there almost always is one. Name it so the agent mirrors a known-good
@@ -205,22 +207,25 @@ divergence. API → docs/REST_API_DESIGN_GUIDELINES.md + the closest existing
205
207
  handler. Schema → the nearest migration + docs/SCHEMA_CONVENTIONS.md. UI →
206
208
  design-system primitives + theme.css tokens. Cite each doc only where this
207
209
  repository materialises it. Greenfield → "no prior art; shape
208
- defined in docs/architecture/{doc}.md." -->
210
+ defined in docs/architecture/{{fill:doc}}.md." -->
209
211
 
210
212
  ## Sections (implementation slices)
211
213
 
212
- ### §1 — {Slice title}
214
+ ### §1 — {{fill:Slice title}}
213
215
 
214
- {What this slice delivers in goal terms; why it must exist; what it unblocks. Non-obvious choice → **Implementation default:** `{choice}` because `{reason}`.}
216
+ {{fill:what this slice delivers, why it exists, and what it unblocks}}. Non-obvious choice → **Implementation default:** `{{fill:choice}}` because `{{fill:reason}}`.
215
217
 
216
- - **Dimension 1.1** — {smallest verifiable behaviour} → Test `test_…`
217
- - **Dimension 1.2** — {…} → Test `test_…`
218
+ - **Dimension 1.1** — {{fill:smallest verifiable behaviour}} → Test `test_…`
219
+ - **Dimension 1.2** — {{fill:…}} → Test `test_…`
218
220
 
219
- ### §2 — {Slice title}
221
+ ### §2 — {{fill:Slice title}}
220
222
 
221
- {Same shape.}
223
+ {{fill:Same shape.}}
222
224
 
223
- <!-- tpl: Each Section: WHAT one slice delivers and WHY (not how); numbered
225
+ <!-- tpl: State prerequisites and who resolves each decision: agent choice,
226
+ measured preparation output, or required human decision. A preparation Section
227
+ may establish budgets or fixtures needed by later Sections; name its completion
228
+ condition. Each Section: WHAT one slice delivers and WHY (not how); numbered
224
229
  Dimensions map 1:1 to Tests and get marked DONE in the same commit as their
225
230
  code. The agent picks each Implementation default unless it has evidence to
226
231
  deviate. Good: "§3 — Replay idempotency. Receiver dedupes on the delivery id.
@@ -234,7 +239,7 @@ the existing dedupe pattern and writes the call. -->
234
239
  ## Interfaces
235
240
 
236
241
  ```
237
- {HTTP endpoints, request/response shapes, internal signatures other code depends on}
242
+ {{fill:HTTP endpoints, request/response shapes, internal signatures other code depends on}}
238
243
  ```
239
244
 
240
245
  <!-- tpl: Lock the interface — the surface the agent must NOT change without
@@ -246,7 +251,7 @@ implementation. -->
246
251
 
247
252
  | Mode | Cause | Handling (system response + what the caller observes) |
248
253
  |------|-------|--------------------------------------------------------|
249
- | {short name} | {trigger} | {response + observable} |
254
+ | {{fill:short name}} | {{fill:trigger}} | {{fill:response + observable}} |
250
255
 
251
256
  <!-- tpl: Every failure path the agent must handle; each row → a negative/
252
257
  integration test in the Test Specification. Cover at minimum: timeout,
@@ -255,7 +260,7 @@ dependency unavailable. -->
255
260
 
256
261
  ## Invariants
257
262
 
258
- 1. {Invariant} — {how it's enforced}
263
+ 1. {{fill:Invariant}} — {{fill:how it's enforced}}
259
264
 
260
265
  <!-- tpl: Each MUST be enforceable by code (compiler, lint, comptime assertion,
261
266
  runtime check) — NOT by review discipline. If a human can violate it silently,
@@ -265,7 +270,7 @@ it's not an invariant. None → "N/A — no invariants." -->
265
270
 
266
271
  | Metric / event | Owner | Fires when | Properties allowed | Privacy guard | Test proof |
267
272
  |----------------|-------|------------|--------------------|---------------|------------|
268
- | `{event_name}` | {product / ops / not applicable} | {exact user or system action} | {coarse product context, resource id, duration, outcome} | {no raw email/password/token/One-Time Password (OTP)/Secure Shell (SSH) key material} | `{test_name}` |
273
+ | `{{fill:event_name}}` | {{fill:product / ops / not applicable}} | {{fill:exact user or system action}} | {{fill:coarse product context, resource id, duration, outcome}} | {{fill:no raw email/password/token/One-Time Password (OTP)/Secure Shell (SSH) key material}} | `{{fill:test_name}}` |
269
274
 
270
275
  <!-- tpl: Every realized spec declares what product or operational signal it
271
276
  adds, or explicitly why none: internal-only cleanup → the single row "not
@@ -284,7 +289,7 @@ are implementation gaps, not notes for later. -->
284
289
 
285
290
  | Dimension | Tier | Test | Asserts (concrete inputs → expected output) |
286
291
  |-----------|------|------|---------------------------------------------|
287
- | 1.1 | {unit / integration / e2e} | `test_<short_name>` | {one-line behavioural claim} |
292
+ | 1.1 | {{fill:unit / integration / e2e / manual}} | `test_<short_name>` | {{fill:one-line behavioural claim}} |
288
293
 
289
294
  <!-- tpl: Prose-and-assertions only — no test code. One row per Dimension;
290
295
  bound to the /orly-write-unit-test skill; ≥50% negative paths; every Failure Mode
@@ -296,8 +301,10 @@ user-centric scenario via test-e2e* walking the real path (subprocess CLI /
296
301
  real HTTP request / rendered UI); a unit test is not a substitute. Also
297
302
  include regression rows (pre-existing behaviour that must not change — "N/A —
298
303
  greenfield" if none) and idempotency/replay rows (any retry semantics).
304
+ Human acceptance uses tier manual, with its procedure, required person, and
305
+ durable evidence. An agent cannot manufacture human sign-off.
299
306
  Non-self-evident input shape → point at a fixture
300
- (samples/fixtures/m{N}-fixtures/{name}.json); don't inline JSON. Hard-to-
307
+ (samples/fixtures/m{{fill:N}}-fixtures/{{fill:name}}.json); don't inline JSON. Hard-to-
301
308
  describe behaviour in prose ⇒ the Goal is fuzzy — fix the Goal, not this
302
309
  table. -->
303
310
 
@@ -305,24 +312,24 @@ table. -->
305
312
 
306
313
  | # | Criterion (observable outcome) | Verify (copy-paste) | Expected | Priority | Graded (VERIFY) |
307
314
  |---|--------------------------------|---------------------|----------|----------|-----------------|
308
- | R1 | {outcome the user can observe} (§1) | `{command}` | {exit 0 / substring / 0 matches} | P0 | |
315
+ | R1 | {{fill:outcome the user can observe}} (§1) | `{{fill:command}}` | {{fill:exit 0 / substring / 0 matches}} | P0 | |
309
316
  | R2 | Diff stays inside Files Changed | `git diff --name-only origin/main...HEAD` | 0 paths missing from the Files Changed table | P0 | |
310
- | S1 | Conform gates green | `{conform command from .oracle/orly.json, verbatim}` | exit 0 | P0 | |
311
- | S2 | Unit tests pass | `{verify.unit command from .oracle/orly.json, verbatim}` | exit 0 | P0 | |
312
- | S3 | Slow tier green (code-carrying branch) | `{one row per declared slow verify.* the diff's surface needs — integration / e2e / memory / cross-compile — verbatim}` | exit 0 | P0 | |
317
+ | S1 | Conform gates green | `{{fill:conform command from .oracle/orly.json, verbatim}}` | exit 0 | P0 | |
318
+ | S2 | Unit tests pass | `{{fill:verify.unit command from .oracle/orly.json, verbatim}}` | exit 0 | P0 | |
319
+ | S3 | Slow tier green (code-carrying branch) | `{{fill:one row per remaining declared verify.* command, verbatim}}` | exit 0 | P0 | |
313
320
  | S4 | No secrets | `gitleaks detect` | exit 0 | P0 | |
314
321
  | S5 | No oversize source file | `git diff --name-only origin/main...HEAD \| grep -v '\.md$' \| xargs wc -l 2>/dev/null \| awk '$1>350 && $2!="total"'` | no output | P0 | |
315
322
  | S6 | Orphan sweep | Dead Code Sweep greps | 0 matches | P0 | |
316
323
 
317
- **Command source rule:** every S-row Verify command is copied **verbatim from `.oracle/orly.json`** (`conform`, `verify.*`) — the same set `orly gate` runs, so the rubric and the mechanical PR gate grade one boundary. The gate BLOCKs a staged pending/active spec whose rubric omits the declared `conform` or `verify.unit` command; a rubric naming a runner the repository does not declare is wrong by construction. `.oracle/orly.json` still a seed → complete it first (`dispatch/lifecycle.md` §Bootstrap); authoring against an unseeded config is the nondeterminism this rule exists to kill.
324
+ **Command source rule:** copy every declared `conform` and `verify.*` invocation from `.oracle/orly.json` into a Verify cell, verbatim, with an Expected value. Include conditional suites; the final gate decides applicability from the actual branch diff. Additional spec-specific commands, secret scans, and named manual checks are allowed. Missing configuration must be completed before authoring. See `dispatch/lifecycle.md` for command timing; baseline metadata is pending at opening and measured before the Pull Request.
318
325
 
319
- **Grading protocol (VERIFY):** run the Verify command verbatim; grade ONLY from its output. Graded = ✅/❌ + the one decisive output line (`342 passed`); long evidence goes to PR Session Notes with a pointer here. **Ship gate:** every row graded, every P0 ✅ → eligible for CHORE(close); any ❌ or empty cell → return to EXECUTE; a P1 ❌ ships only with an Indy-acked deferral quote in Discovery. A P0 may also be **MOVED** — see below.
326
+ **Grading protocol (VERIFY):** run each spec-specific Verify command verbatim; Graded = ✅/❌ + one decisive output line. Repository-command rows point to the final `orly gate pr` results in Pull Request Session Notes, so recording those results does not require another code commit and suite run. **Ship gate:** every required check must pass before the Pull Request is ready; missing evidence or any ❌ returns to EXECUTE. A P1 ❌ requires an Indy-acked deferral quote in Discovery. A P0 may also be **MOVED** — see below.
320
327
 
321
328
  **A P0 whose SCOPE moves is not a P0 shipped red.** Met and unmet are not the only two states a criterion has, and a gate that pretends otherwise forces an agent to invent a third. One did, twice in a day, before this clause existed.
322
329
 
323
330
  A deferral and a transfer are different claims. A **deferral** leaves work unowned inside a closed spec, which is what the P0 gate exists to prevent — the P1 quote is as far as that goes. A **transfer** moves the criterion whole: its Dimensions, its verification and its rubric row land in a named successor spec that carries them as its own P0. Nothing is less owned afterwards; it is owned somewhere else.
324
331
 
325
- Mark such a row `MOVED to M{N}_{NNN} R{n}` and it is not ❌, on three conditions, all of which must hold:
332
+ Mark such a row `MOVED to M{{fill:N}}_{{fill:NNN}} R{{fill:n}}` and it is not ❌, on three conditions, all of which must hold:
326
333
 
327
334
  1. The successor spec **exists** and carries the criterion as a rubric row of its own. A successor that does not carry the row is a deferral wearing a new word, and fails the gate as before.
328
335
  2. Both specs record the mapping — the closing spec names where each Dimension went, the successor names what it inherited. One-sided assertion is not a transfer.
@@ -332,20 +339,18 @@ A MOVED row is never rendered ✅. The criterion has not been met; it has change
332
339
 
333
340
  <!-- tpl: The single scoring surface — no other scoreboard. 5–12 rows after
334
341
  pruning: one per Section outcome, failure class, or hygiene gate — never one
335
- per Dimension (that ledger is the Test Specification). S-row commands come verbatim from
336
- `.oracle/orly.json`; expand S3 to one row per declared slow `verify.*` the
337
- diff's surface needs; delete rows whose command this repository does not
338
- declare. Expected litmus: every Expected is
342
+ per Dimension (that ledger is the Test Specification). Repository suite commands come verbatim from `.oracle/orly.json`; expand S3
343
+ for every remaining declared lane. Additional spec-specific checks stay explicit. Expected litmus: every Expected is
339
344
  mechanically checkable — an exit code, a literal substring, or a match count;
340
345
  can't write it that way → the criterion is fuzzy — fix the criterion, not the
341
346
  grading. Authoring fills every column except Graded; VERIFY fills Graded. -->
342
347
 
343
348
  ### Behaviour evals
344
349
 
345
- - **Grounding rule:** {one sentence the output must never violate}
346
- - **Golden set:** `samples/fixtures/{path}` — {N} cases across {3–5 coverage axes, incl. the nightmare case}. A failure found in the wild becomes a new case; the set only grows.
347
- - **Ship threshold:** grounding 100% · task pass ≥{N}% · 0 critical failures on {nightmare case}. Each threshold is one rubric row with the command that computes it.
348
- - **Fallback:** below threshold or low confidence → {named recoverable behaviour}; fabricated output is a P0 ❌.
350
+ - **Grounding rule:** {{fill:one sentence the output must never violate}}
351
+ - **Golden set:** `samples/fixtures/{{fill:path}}` — {{fill:N}} cases across {{fill:3–5 coverage axes, incl. the nightmare case}}. A failure found in the wild becomes a new case; the set only grows.
352
+ - **Ship threshold:** grounding 100% · task pass ≥{{fill:N}}% · 0 critical failures on {{fill:nightmare case}}. Each threshold is one rubric row with the command that computes it.
353
+ - **Fallback:** below threshold or low confidence → {{fill:named recoverable behaviour}}; fabricated output is a P0 ❌.
349
354
 
350
355
  <!-- tpl: Delete this whole sub-section unless the diff changes prompt/model/
351
356
  agent behaviour. Grounding-rule example: "responses cite only retrieved rows,
@@ -357,13 +362,13 @@ never invented identifiers." -->
357
362
 
358
363
  | File to delete | Verify |
359
364
  |----------------|--------|
360
- | `{path/to/old_file.ext}` | `test ! -f {path/to/old_file.ext}` |
365
+ | `{{fill:path/to/old_file.ext}}` | `test ! -f {{fill:path/to/old_file.ext}}` |
361
366
 
362
367
  **2. Orphaned references — zero remaining imports/uses.**
363
368
 
364
369
  | Deleted symbol/import | Grep | Expected |
365
370
  |-----------------------|------|----------|
366
- | `{old_symbol}` | `grep -rn "{old_symbol}" src/ \| head` | 0 matches |
371
+ | `{{fill:old_symbol}}` | `grep -rn "{{fill:old_symbol}}" src/ \| head` | 0 matches |
367
372
 
368
373
  <!-- tpl: Mandatory when the spec deletes or replaces files: for every deleted
369
374
  file and removed/renamed public symbol, grep the repo; non-zero = stale. Use
@@ -372,7 +377,7 @@ both tables with "N/A — no files deleted." -->
372
377
 
373
378
  ## Out of Scope
374
379
 
375
- - {Item explicitly not in this spec — points at a follow-up spec or "future work"}
380
+ - {{fill:Item explicitly not in this spec — points at a follow-up spec or "future work"}}
376
381
 
377
382
  ---
378
383
 
@@ -383,16 +388,16 @@ working sections stay front-loaded. -->
383
388
 
384
389
  ## Product Clarity (authoring record)
385
390
 
386
- 1. **Successful user moment** — {the single observable moment that proves this worked — a scene, not a metric}
387
- 2. **Preserved user behaviour** — {what users do today that keeps working unchanged; breaking any of it is a redesign}
388
- 3. **Optimal-way check** — {is this the most direct way to deliver moment #1? name the gap to the unconstrained-optimal shape and why it's acceptable now}
389
- 4. **Rebuild-vs-iterate** — {would a larger refactor serve better? verdict here; rationale in Decomposition below. A refactor that trades run-to-run determinism away is wrong by default}
390
- 5. **What we build** — {the shortest artifact list that delivers moment #1}
391
- 6. **What we do NOT build** — {adjacent scope rejected, one-line reason each — seeds Out of Scope}
392
- 7. **Fit with existing features** — {what this compounds with; the one feature it must not destabilize}
393
- 8. **Surface order** — {CLI-first (repo default), UI-first, or both; justify divergence}
394
- 9. **Dashboard restraint** — {what the UI must hide until the signal behind it is real: no controls before evidence, no quality claims before counters}
395
- 10. **Confused-user next step** — {the self-serve move (a command, an error message, a doc); "file a ticket" means a surface is missing from item 5}
391
+ 1. **Successful user moment** — {{fill:the single observable moment that proves this worked — a scene, not a metric}}
392
+ 2. **Preserved user behaviour** — {{fill:what users do today that keeps working unchanged; breaking any of it is a redesign}}
393
+ 3. **Optimal-way check** — {{fill:is this the most direct way to deliver moment #1? name the gap to the unconstrained-optimal shape and why it's acceptable now}}
394
+ 4. **Rebuild-vs-iterate** — {{fill:would a larger refactor serve better? verdict here; rationale in Decomposition below. A refactor that trades run-to-run determinism away is wrong by default}}
395
+ 5. **What we build** — {{fill:the shortest artifact list that delivers moment #1}}
396
+ 6. **What we do NOT build** — {{fill:adjacent scope rejected, one-line reason each — seeds Out of Scope}}
397
+ 7. **Fit with existing features** — {{fill:what this compounds with; the one feature it must not destabilize}}
398
+ 8. **Surface order** — {{fill:CLI-first (repo default), UI-first, or both; justify divergence}}
399
+ 9. **Dashboard restraint** — {{fill:what the UI must hide until the signal behind it is real: no controls before evidence, no quality claims before counters}}
400
+ 10. **Confused-user next step** — {{fill:the self-serve move (a command, an error message, a doc); "file a ticket" means a surface is missing from item 5}}
396
401
 
397
402
  <!-- tpl: Indy's product questions, answered in order at authoring BEFORE the
398
403
  implementation sections are written — so the authoring agent holds the product
@@ -403,9 +408,9 @@ no user surface" with the reason. -->
403
408
 
404
409
  ## Decomposition & alternatives (patch vs refactor)
405
410
 
406
- - **Chosen shape:** {why this Section/Workstream split — the decomposition rationale}
407
- - **Alternatives considered:** {≥1 — the larger refactor or the smaller patch — and why rejected for now}
408
- - **Patch-vs-refactor verdict:** this is a **{patch | refactor}** because {reason}. {If a larger refactor is the right long game but out of scope, name the follow-up spec rather than silently mud-patching.}
411
+ - **Chosen shape:** {{fill:why this Section/Workstream split — the decomposition rationale}}
412
+ - **Alternatives considered:** {{fill:≥1 — the larger refactor or the smaller patch — and why rejected for now}}
413
+ - **Patch-vs-refactor verdict:** this is a **{{fill:patch | refactor}}** because {{fill:reason}}. {{fill:If a larger refactor is the right long game but out of scope, name the follow-up spec rather than silently mud-patching.}}
409
414
 
410
415
  <!-- tpl: Indy's rule — don't ship a mud-patch when the problem wants a
411
416
  refactor, and don't refactor when a patch is right. Match solution-size to
@@ -14,35 +14,29 @@ page carries only what is specific to this repository.
14
14
  | version | `make check-version` | Boundary. `VERSION` against `build.zig.zon`, `cli/package.json` and both `rustd/Cargo.toml` sites. |
15
15
  | integration | `make test-integration-rustd` | Boundary. Live Postgres and Redis via docker compose, schemas reset per run. `orly gate pr` skips it on a branch carrying no code. |
16
16
 
17
- These five are exactly what `.oracle/orly.json` declares and exactly what
18
- `orly gate pr` runs, so the rubric and the mechanical gate grade one boundary.
19
-
20
- **Two cadences.** A Section closing is not a milestone closing. Inside a
21
- Section, run `make harness-verify` plus the lane covering the surface the
22
- Section touched (`make test-unit-rustd`, `make test-unit-app`, …) — enough to
23
- prove the Section, never a repository claim. The full table above runs ONCE, at
24
- CHORE(close).
25
-
26
- **Which gate runs which row.** `orly gate work` runs the `conform` row alone and
27
- is what the pre-commit hook fires, so it costs seconds. `orly gate verify` runs
28
- the lint, unit, and version rows and is what pre-push fires. `orly gate pr` runs
29
- the integration row plus the whole-branch and spec criteria, and is what
30
- CHORE(close) fires — it skips the fast rows because `git.pushed` proves HEAD is
31
- the commit pre-push already graded.
32
-
33
- One lane needs live datastores, and only one. `make/test-infra.mk` brings up
34
- docker compose Postgres and Redis for `test-integration-rustd`; `make
35
- test-unit-all` stays datastore-free, because every Rust test needing one is
36
- `#[ignore]`d and runs only in that lane. `KEEP_TEST_STATE=1` skips the reset for
37
- the inner loop; Continuous Integration (CI) never sets it.
17
+ These are the commands `.oracle/orly.json` declares. The commit hook runs
18
+ conformance; `orly gate pr` runs every verification row.
19
+
20
+ The authoritative timing and gate ownership live in
21
+ `dispatch/lifecycle.md` §What runs at each stage. At Section completion, run
22
+ `cargo fmt` from `rustd/`, `make lint-rustd`, conformance over staged changes,
23
+ and the relevant behavior tests. The existing `make test-unit-rustd` runs the
24
+ whole Rust workspace; it is not a single-package check.
38
25
 
39
26
  ## Test Baseline
40
27
 
41
- `make test-unit-all` reports its own counts per target. Record the cargo
42
- workspace total in the spec header at CHORE(open) as
43
- `**Test Baseline:** unit=<N>`, and compare against it in VERIFY's Test Delta row.
44
- Zero or negative growth on a code-adding diff needs justification or a return to
45
- EXECUTE.
28
+ Before the Pull Request, obtain `make test-unit-all` and
29
+ `make test-integration-rustd` results for the spec's full `Baseline revision`.
30
+ Record per-package unit counts and the integration lane's own summary in the
31
+ baseline report; put comparable totals in `Test Baseline` and its path or run
32
+ URL in `Baseline evidence`. The report includes passed, failed, and skipped
33
+ counts, commands, and environment. Never substitute the default checkout's
34
+ current revision for the recorded one. Keep integration datastores isolated.
35
+
36
+ The final PR gate runs all declared commands against the implementation.
37
+ Capture its output in Pull Request Session Notes, including the Test Delta.
38
+ Unit growth alone does not prove coverage; explain removals and changes in test
39
+ selection. Zero or negative growth on code-adding work requires justification.
46
40
 
47
41
  ## Wire fixtures
48
42