fdeops 3.20.0 → 3.22.0

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.
package/AGENTS.md CHANGED
@@ -4,7 +4,7 @@ This repository **is** fdeops - the engagement record for Forward Deployed Engin
4
4
 
5
5
  ## If you are helping use fdeops in an engagement
6
6
 
7
- Route via **`@fde`** - read `skills/fde/SKILL.md` (the single source of truth), pick the phase, do the work, and write `.fde/` memory. Never ask the human to pick a skill. Other tools get the same behavior through thin pointer files in [`adapters/`](adapters/README.md).
7
+ Route via **`@fde`** - read `skills/fde/SKILL.md` (the single source of truth), route to one `references/*.md`, do the work, and write `.fde/` memory. Never ask the human to pick a skill. Other tools get the same behavior through thin pointer files in [`adapters/`](adapters/README.md).
8
8
 
9
9
  ## If you are contributing to this repository
10
10
 
package/README.md CHANGED
@@ -2,91 +2,78 @@
2
2
 
3
3
  **Forward deployed engineering skills for AI coding agents.**
4
4
 
5
- Skills encode the workflows, quality gates, and judgment Forward Deployed Engineers use on someone else's site. Packaged so an AI coding agent can run the embed end-to-end: discovery, POC, their codebase (greenfield or brownfield), go-live, eval, signed outcome. The workspace still compiles and commits. `@fde` does not leave.
5
+ You're on a customer site. The AI coding agent writes code in their repo. This kit is the work around that code: the brief, who can say yes, proof on their staging then live, whether they signed off, whether they can run it after you leave.
6
6
 
7
- <img width="1774" height="887" alt="FDEops-githubposter" src="https://github.com/user-attachments/assets/9eb842d2-a356-4995-9057-841f1b2d15d6" />
7
+ Notes stay on your laptop. Their repo stays theirs. You confirm before anything is written down.
8
8
 
9
- ---
10
-
11
- ## Commands
9
+ Keep the coding pack you already use. Install this next to it. FDEOps is the client work. The other pack writes the code.
12
10
 
13
- One command per stage. Skills load automatically.
11
+ <img width="1536" height="1024" alt="fdeops" src="https://github.com/user-attachments/assets/2bcb8739-55ee-445d-8a1a-8b38433b7b58" />
14
12
 
15
- Six commands map to the embed. Each one loads `@fde`, which opens the skill for that moment: a thin brief pulls land, a wrong brief pulls discover, a Friday number pulls readout. Sprint or programme. Greenfield or brownfield. Any industry. You never pick from 30 names.
16
-
17
- | Work | Command | Stage | Principle |
18
- |------|---------|-------|-----------|
19
- | Engage | `/brief` | Land | Name who signs done |
20
- | Diagnose | `/discover` | Discover | Treat the brief as a hypothesis |
21
- | Align | `/plan` | Plan | Work backwards from done |
22
- | Deliver | `/ship` | Ship | One visible change, then go live |
23
- | Realize | `/outcome` | Outcome | Promised, measured, accepted |
24
- | Transfer | `/close` | Close | They operate it without you |
13
+ ---
25
14
 
26
- Also:
15
+ ## Quick Start
27
16
 
28
- | Work | Command | Principle |
29
- |------|---------|-----------|
30
- | Diagnose trust | `/trust` | Process gap, or they stopped trusting you |
31
- | Find the receipt | `/receipts` | A dated line, or it did not happen |
32
- | Capture the meeting | `/debrief` | Notes into the record |
33
- | Prepare the meeting | `/prep` | One page from the record |
34
- | Report the outcome | `/readout` | Promised, measured, accepted |
17
+ **Try it first, nothing installed.** In any repo:
35
18
 
36
- Skills also activate on English: naming a client, running a POC, changing their checkout, going live, asking what was agreed. A throwaway one-liner in an unbound repo can skip `@fde`. Bound client work cannot.
19
+ ```bash
20
+ npx fdeops scan
21
+ ```
37
22
 
38
- ---
23
+ Two minutes. It prints what to look at on day one and the questions to ask. Local only, nothing written.
39
24
 
40
- ## Quick Start
25
+ **Then install the skill:**
41
26
 
42
27
  ```bash
43
28
  npx skills add suboss87/fdeops --skill fde
44
29
  ```
45
30
 
46
- Then one chat. Name the client. The AI coding agent binds.
31
+ One chat. Name the client:
47
32
 
48
33
  ```text
49
- @fde this is Acme
34
+ @fde this is client01
50
35
  ```
51
36
 
52
- Paste kickoff notes in the same thread. `@fde` routes; you confirm judgment. Same folder every time: `~/fde-engagements/<client>/.fde/`. Workflow: [docs/USAGE.md](docs/USAGE.md).
37
+ That creates `~/fde-engagements/client01/.fde/` on your laptop. Paste kickoff notes in the same thread. `@fde` picks what to check. You still decide.
38
+
39
+ Day to day: [docs/USAGE.md](docs/USAGE.md).
53
40
 
54
41
  <details>
55
- <summary><b>Claude Code (recommended)</b></summary>
42
+ <summary><b>Claude Code</b></summary>
56
43
 
57
44
  ```text
58
45
  /plugin marketplace add suboss87/fdeops
59
46
  /plugin install fdeops@fdeops
60
47
  ```
61
48
 
62
- Hooks load where you left off. Slash commands match the map above.
49
+ Hooks resume where you left off. Slash commands match the table below.
63
50
 
64
51
  </details>
65
52
 
66
53
  <details>
67
54
  <summary><b>Cursor</b></summary>
68
55
 
56
+ After the skill install, in the **client repo** you have open (pointer, not a second pack):
57
+
69
58
  ```bash
70
- npx skills add suboss87/fdeops --skill fde
59
+ npx fdeops adapters .
71
60
  ```
72
61
 
73
- Or `npx fdeops adapters .`. See [adapters/](adapters/README.md).
62
+ See [adapters/](adapters/README.md).
74
63
 
75
64
  </details>
76
65
 
77
66
  <details>
78
- <summary><b>Other agents</b></summary>
67
+ <summary><b>Air-gap, PATH, override</b></summary>
79
68
 
80
69
  ```bash
81
- npx skills add suboss87/fdeops --skill fde
70
+ git clone https://github.com/suboss87/fdeops.git && node bin/install.js
82
71
  ```
83
72
 
84
- Gemini, Copilot, Codex, local LLMs: [adapters/](adapters/README.md). Air-gapped: `git clone https://github.com/suboss87/fdeops.git && node bin/install.js`.
85
-
86
- Fallback if the agent cannot bind:
73
+ If the agent cannot create the folder:
87
74
 
88
75
  ```bash
89
- npx fdeops resume --init acme # ~/fde-engagements/acme + bind this checkout
76
+ npx fdeops resume --init client01 # ~/fde-engagements/client01
90
77
  ```
91
78
 
92
79
  Requires Node.js >= 18. Override: `FDEOPS_ENGAGEMENT`. See [docs/install.md](docs/install.md). Try the loop: `npx fdeops demo`.
@@ -95,13 +82,34 @@ Requires Node.js >= 18. Override: `FDEOPS_ENGAGEMENT`. See [docs/install.md](doc
95
82
 
96
83
  ---
97
84
 
85
+ ## Commands
86
+
87
+ One command per stage. Skills load automatically.
88
+
89
+ Six stages, same order every job: Land, Discover, Plan, Ship, Outcome, Close.
90
+
91
+ | What you're doing | Command | Stage |
92
+ |-------------------|---------|-------|
93
+ | First days. Get the brief. Name who signs. | `/brief` | Land |
94
+ | Check the brief is the real job. | `/discover` | Discover |
95
+ | Sequence from done, not from the ticket. | `/plan` | Plan |
96
+ | Prove it on their staging, then go live. | `/ship` | Ship |
97
+ | What you promised, measured, and who accepted. | `/outcome` | Outcome |
98
+ | Hand it over. They run it without you. | `/close` | Close |
99
+
100
+ Same `@fde`, when you need them: `/debrief` (notes into the record), `/prep` (one page before you walk in), `/trust` (process gap, or they stopped trusting you), `/receipts` (a dated line, or it did not happen), `/readout` (Friday page for the sponsor; not a seventh stage).
101
+
102
+ You can also just say it: naming a client, a POC, changing their checkout, going live, asking what was agreed. A typo in a repo that is not a client job can skip this. A named client, a POC, or go-live cannot.
103
+
104
+ ---
105
+
98
106
  ## All 30 Skills
99
107
 
100
- The catalog. 30 skills spanning the embed. Not prompts - structured workflows with steps, an artifact, and a checkpoint. Type English or a slash command. `@fde` activates the right skill. You never pick one by name.
108
+ Thirty situations, grouped by stage. Not prompts - each one has steps, a file it writes, and a checkpoint with you. Type English or a slash command. `@fde` opens the matching skill. You never pick one by name.
101
109
 
102
110
  Full detail: [docs/skills-reference.md](docs/skills-reference.md).
103
111
 
104
- ### Land - Engage
112
+ ### Land
105
113
 
106
114
  | Skill | What it does | Use when |
107
115
  |--------|--------------|----------|
@@ -111,7 +119,7 @@ Full detail: [docs/skills-reference.md](docs/skills-reference.md).
111
119
  | [earn-trust](skills/fde/references/earn-trust.md) | Earn access | Need access or credibility |
112
120
  | [hold-scope](skills/fde/references/hold-scope.md) | Hold scope | "Also can you…", timeline unchanged |
113
121
 
114
- ### Discover - Diagnose
122
+ ### Discover
115
123
 
116
124
  | Skill | What it does | Use when |
117
125
  |--------|--------------|----------|
@@ -120,7 +128,7 @@ Full detail: [docs/skills-reference.md](docs/skills-reference.md).
120
128
  | [score-use-cases](skills/fde/references/score-use-cases.md) | Score use cases | Everything is P0 |
121
129
  | [poc](skills/fde/references/poc.md) | Validate the solution | POC, spike, need to de-risk |
122
130
 
123
- ### Plan - Align
131
+ ### Plan
124
132
 
125
133
  | Skill | What it does | Use when |
126
134
  |--------|--------------|----------|
@@ -129,7 +137,7 @@ Full detail: [docs/skills-reference.md](docs/skills-reference.md).
129
137
  | [three-options](skills/fde/references/three-options.md) | Generate options | "What should we do?" |
130
138
  | [pick-three](skills/fde/references/pick-three.md) | Prioritize three | Everything is urgent |
131
139
 
132
- ### Ship - Deliver
140
+ ### Ship
133
141
 
134
142
  | Skill | What it does | Use when |
135
143
  |--------|--------------|----------|
@@ -139,7 +147,7 @@ Full detail: [docs/skills-reference.md](docs/skills-reference.md).
139
147
  | [review](skills/fde/references/review.md) | Review the change | Before merge, scope creep |
140
148
  | [rollback](skills/fde/references/rollback.md) | Rehearse rollback | "We can always revert" |
141
149
 
142
- ### Outcome - Realize
150
+ ### Outcome
143
151
 
144
152
  | Skill | What it does | Use when |
145
153
  |--------|--------------|----------|
@@ -151,7 +159,7 @@ Full detail: [docs/skills-reference.md](docs/skills-reference.md).
151
159
  | [ingest](skills/fde/references/ingest.md) | Ingest sources | Transcript, Notion, Slack |
152
160
  | [connect](skills/fde/references/connect.md) | Connect a source | Connect Granola |
153
161
 
154
- ### Close - Transfer
162
+ ### Close
155
163
 
156
164
  | Skill | What it does | Use when |
157
165
  |--------|--------------|----------|
@@ -161,7 +169,7 @@ Full detail: [docs/skills-reference.md](docs/skills-reference.md).
161
169
  | [encode-pattern](skills/fde/references/encode-pattern.md) | Encode the pattern | It will apply again |
162
170
  | [red-team](skills/fde/references/red-team.md) | Challenge the plan | "Poke holes in this" |
163
171
 
164
- Overlays (on signal, not on request): [ai](skills/fde/references/ai.md) · [artifacts](skills/fde/references/artifacts.md) · [fintech](skills/fde/references/fintech.md) · [healthcare](skills/fde/references/healthcare.md) · [gov](skills/fde/references/gov.md) · [eval-pack](skills/fde/references/eval-pack.md)
172
+ Overlays (on signal, not on request): [ai](skills/fde/references/ai.md) · [artifacts](skills/fde/references/artifacts.md) · [fintech](skills/fde/references/fintech.md) · [healthcare](skills/fde/references/healthcare.md) · [gov](skills/fde/references/gov.md). AI companion (not a sixth overlay): [eval-pack](skills/fde/references/eval-pack.md).
165
173
 
166
174
  Optional pull: you add the source MCP; we **pull** on request. [mcp/recipes/](mcp/recipes/)
167
175
 
@@ -169,33 +177,84 @@ Optional pull: you add the source MCP; we **pull** on request. [mcp/recipes/](mc
169
177
 
170
178
  ## How Skills Work
171
179
 
172
- One skill. One reference file per situation. One folder per client.
180
+ One `@fde`. One file per situation. One folder per client.
173
181
 
174
182
  ```
175
- /brief or "@fde this is Acme"
176
-
177
-
178
- skills/fde/SKILL.md hosts load this one file
183
+ "@fde this is client01" creates ~/fde-engagements/client01/.fde/
184
+ /brief or English the AI coding agent loads skills/fde/SKILL.md
179
185
  │ routes. you never pick a skill by name
180
186
 
181
- references/land.md one skill, then stop
187
+ references/<one>.md one skill, then stop
182
188
 
183
189
 
184
190
  fde CLI (local) dates, gates, redacts. no network
185
191
  │ after you confirm
186
192
 
187
- ~/fde-engagements/<client>/.fde/
193
+ ~/fde-engagements/client01/.fde/
188
194
  ```
189
195
 
190
- **One skill routes.** Hosts load `@fde`. It reads the situation and opens one `references/*.md`. Slash commands and English both land here. You never pick a skill by name.
196
+ **A dated line, or it did not happen.** Promised measured accepted. If it is not in `.fde/`, it is not on the record.
191
197
 
192
- **Evidence, not memory.** Promised measured accepted. A dated line in `.fde/`, or it did not happen. Nothing is done on vibes.
198
+ **Confirm, then it is written.** The CLI stays on your laptop: git and files, no network. The AI coding agent runs the command. You say yes. Then it is in the folder.
193
199
 
194
- **Confirm before write.** Local CLI: git and files, no network. `.fde/` on your laptop. The AI coding agent runs the command. You confirm. Then it is on the record.
200
+ **The record is on your laptop.** Change hosts, install `@fde` on the new one, keep talking. The notes are not inside any vendor.
195
201
 
196
- **Progressive disclosure.** `SKILL.md` is the entry. One skill file loads when routed. Writes and status cost zero model tokens.
202
+ One skill hosts load: `skills/fde/SKILL.md`. It opens one file in `skills/fde/references/` and stops. Slash commands live in `.claude/commands/`. The local CLI is `bin/fde.js` (git + files, no network). Layout: [docs/REPO_LAYOUT.md](docs/REPO_LAYOUT.md).
197
203
 
198
- Change hosts, install `@fde` on the new one, bind if needed, keep talking. The record is not inside any vendor.
204
+ ---
205
+
206
+ ## Engagement memory (`.fde/`)
207
+
208
+ One folder per client. Plain markdown. Grep it, copy it, take it into a meeting.
209
+
210
+ | File | Holds |
211
+ |------|-------|
212
+ | `context.md` | Where you are |
213
+ | `brief.md` / `success.md` | What they asked; what “done” is and who signs |
214
+ | `reality.md` / `terrain.md` | The real problem; the map |
215
+ | `stakeholders.md` | `[signal:green\|amber\|red]` |
216
+ | `trust-profile.md` | Sacred data, AI policy, approval chain |
217
+ | `decisions.md` / `risks.md` / `delivery.md` | Dated choices; live risks; what shipped and how it rolls back |
218
+
219
+ Schema: [docs/schema.md](docs/schema.md). Local HTML: `npx fdeops dashboard`.
220
+
221
+ ---
222
+
223
+ ## Who this is for
224
+
225
+ You sit with a customer's team. An AI coding agent writes in their repo. You need a record of the brief, who can say yes, what went live, and whether they signed off.
226
+
227
+ If you ship your own company's product from HQ, with no customer team that has to run it after you leave, you do not need this kit.
228
+
229
+ ---
230
+
231
+ ## Your data stays yours
232
+
233
+ The **CLI** is local: git + files, no network, no telemetry. The **host model** sees `.fde/` the agent loads (usually a bounded `context.md`) and any client code you open. It must not see `<private>` blocks - redacted from CLI, dashboard, and hooks; do not paste them or open them with file tools. Nothing is written until you confirm. `~/fde-engagements` is in `$HOME`; iCloud/Dropbox is an NDA incident waiting.
234
+
235
+ [PRIVACY.md](PRIVACY.md) · [SECURITY.md](SECURITY.md)
236
+
237
+ ---
238
+
239
+ ## Why FDEOps?
240
+
241
+ AI coding agents are built for a repo, not for a client. Left alone they skip who signs, whether the brief is true, and whether anyone accepted the number. Monday they start from the ticket again.
242
+
243
+ This is the kit you take on site. `@fde` runs the client work around the code. A local command dates every decision. The notes are markdown on your laptop. You confirm; then it is on the record.
244
+
245
+ ---
246
+
247
+ ## Principles
248
+
249
+ - **Who signs** - name them in the first days
250
+ - **Brief vs real job** - check the floor, not only the slide
251
+ - **Back from done** - sequence from signed-off, not from the ticket
252
+ - **Their staging then live** - prove it where they operate, then go live
253
+ - **Promised, measured, accepted** - a number nobody signed is claimed, not delivered
254
+ - **They run it** - if they cannot operate it without you, you are not done
255
+ - **A dated line, or it did not happen** - these files get defended in the room
256
+ - **One customer, one folder** - context never bleeds
257
+ - **The kit says what to check. You still decide.**
199
258
 
200
259
  ---
201
260
 
@@ -258,7 +317,7 @@ fdeops/
258
317
  ├── bin/ # local CLI: git + files, no network
259
318
  ├── hooks/ # session-start / session-stop / pre-compact
260
319
  ├── adapters/ # Cursor, Gemini, Copilot, Codex pointers
261
- ├── templates/.fde/ # memory files created on bind
320
+ ├── templates/.fde/ # memory files created on first client
262
321
  ├── examples/ # fictional walkthroughs
263
322
  ├── mcp/ # optional ingest + source recipes
264
323
  ├── evals/ # routing checks
@@ -267,59 +326,6 @@ fdeops/
267
326
 
268
327
  ---
269
328
 
270
- ## Why FDEOps?
271
-
272
- AI coding agents are built for a repo, not for a client. Left alone they skip who signs done, whether the brief is true, and whether anyone accepted the number. Monday morning they start from the ticket again.
273
-
274
- FDEOps is the catalog you take on site. One `@fde` skill runs the embed from discovery to signed outcome: POC, their codebase, go-live, eval when a model judges, promised → measured → accepted. A local CLI dates every decision. `.fde/` is markdown on your laptop. You confirm; then it is on the record.
275
-
276
- ---
277
-
278
- ## Engagement memory (`.fde/`)
279
-
280
- One folder per client. Plain markdown. Grep it, copy it, defend it.
281
-
282
- | File | Holds |
283
- |------|-------|
284
- | `context.md` | Where you are |
285
- | `brief.md` / `success.md` | What they asked; what “done” is and who signs |
286
- | `reality.md` / `terrain.md` | The real problem; the map |
287
- | `stakeholders.md` | `[signal:green\|amber\|red]` |
288
- | `trust-profile.md` | Sacred data, AI policy, approval chain |
289
- | `decisions.md` / `risks.md` / `delivery.md` | Dated choices; live risks; what shipped and how it rolls back |
290
-
291
- Schema: [docs/schema.md](docs/schema.md). Local HTML: `npx fdeops dashboard`.
292
-
293
- ---
294
-
295
- ## Who this is for
296
-
297
- You embed with a customer and an AI coding agent. Take this on the ground. Discovery through signed outcome lives in `@fde`. One `.fde/` per client so they do not blur.
298
-
299
- If you only write code in your own repo with no client record to defend, you do not need this kit.
300
-
301
- ---
302
-
303
- ## Your data stays yours
304
-
305
- Local only - `git` + files, no network, no telemetry. Plain markdown. The model sees client code only when you point the AI coding agent at it. `<private>` is redacted from CLI, dashboard, and hooks. Nothing is written until you confirm. `~/fde-engagements` is in `$HOME`; iCloud/Dropbox is an NDA incident waiting.
306
-
307
- [PRIVACY.md](PRIVACY.md) · [SECURITY.md](SECURITY.md)
308
-
309
- ---
310
-
311
- ## Principles
312
-
313
- - **One map** - any scale, greenfield or brownfield, any industry. Overlays carry the vertical
314
- - **The artifact is the memory** - producing the work and recording it are one action
315
- - **Ground loop** - name the change, characterise their code, prove it on their staging, go live, log the outcome
316
- - **Skills, not autonomy** - the kit says what to check; judgment stays yours
317
- - **Brief is a hypothesis** - discover before building the wrong thing
318
- - **Evidence on every claim** - these files get defended in the room
319
- - **One customer, one folder** - context never bleeds
320
-
321
- ---
322
-
323
329
  ## Contributing
324
330
 
325
331
  **[Subash Natarajan](https://www.linkedin.com/in/subashn/)**. [Issues](https://github.com/suboss87/fdeops/issues) · [Discussions](https://github.com/suboss87/fdeops/discussions) · [CONTRIBUTING.md](CONTRIBUTING.md) · [Code of Conduct](CODE_OF_CONDUCT.md)
package/bin/check.js CHANGED
@@ -153,8 +153,8 @@ ok(`router dispatch (${mentioned.length} reference targets verified) + memory co
153
153
  }
154
154
  if (!routed.size) fail('check.js could not parse the SKILL.md routing table')
155
155
 
156
- // docs/skills-reference.md is the canonical per-method list: one row per
157
- // method inside the six domain tables, ending at the Overlays section.
156
+ // docs/skills-reference.md is the canonical per-skill list: one row per
157
+ // skill inside the six stage tables, ending at the Overlays section.
158
158
  const reference = read('docs/skills-reference.md')
159
159
  const documented = new Set()
160
160
  let documentedRows = 0
@@ -409,6 +409,28 @@ for (const f of exampleFiles) {
409
409
  }
410
410
  ok('examples walkthrough files')
411
411
 
412
+ // The examples are the first .fde/ a newcomer reads. They must pass the kit's
413
+ // own doctor, or the kit is telling people to do what its showcase does not.
414
+ // Tolerated: things a frozen reference copy cannot have (an owner, a memory
415
+ // git, a fresh trust signal).
416
+ {
417
+ const { spawnSync } = require('child_process')
418
+ const tolerated = /no \.owner|not git-versioned|trust signal is STALE/
419
+ for (const ex of fs.readdirSync(path.join(root, 'examples'))) {
420
+ const eng = path.join(root, 'examples', ex, '.fde')
421
+ if (!fs.existsSync(eng)) continue
422
+ const r = spawnSync(process.execPath, [path.join(root, 'bin', 'fde.js'), 'doctor'], {
423
+ encoding: 'utf8',
424
+ env: { ...process.env, FDEOPS_ENGAGEMENT: eng, HOME: fs.mkdtempSync(path.join(require('os').tmpdir(), 'fdeops-check-')) },
425
+ })
426
+ const issues = (r.stdout || '').split('\n')
427
+ .map(l => l.match(/^\s+\d+\.\s+(.*)$/)).filter(Boolean).map(m => m[1])
428
+ .filter(i => !tolerated.test(i))
429
+ if (issues.length) fail(`examples/${ex} fails its own doctor:\n - ${issues.join('\n - ')}`)
430
+ else ok(`examples/${ex} passes fde doctor`)
431
+ }
432
+ }
433
+
412
434
  if (fs.existsSync(path.join(root, 'tasks', 'plan.md'))) {
413
435
  fail('tasks/plan.md should not be in public tree (move to docs/internal)')
414
436
  }
package/bin/fde.js CHANGED
@@ -1515,8 +1515,8 @@ function smartProposeText(input) {
1515
1515
  out.push(`decision: ${bare.replace(/^decided:\s+/i, '')}`)
1516
1516
  continue
1517
1517
  }
1518
- if (/^(decision|risk|delivery|contact|next):\s*/i.test(bare)) {
1519
- let routed = bare.replace(/^(decision|risk|delivery|contact|next):\s*/i, (m, t) => `${t.toLowerCase()}: `)
1518
+ if (/^(decision|risk|delivery|contact|next|signer):\s*/i.test(bare)) {
1519
+ let routed = bare.replace(/^(decision|risk|delivery|contact|next|signer):\s*/i, (m, t) => `${t.toLowerCase()}: `)
1520
1520
  if (/^contact:/i.test(routed) && !/\[signal:(red|amber|green)\]/i.test(routed)) {
1521
1521
  const sig = inferContactSignal(routed)
1522
1522
  if (sig) routed = routed.replace(/\s*$/, ` [signal:${sig}]`)
@@ -1524,6 +1524,12 @@ function smartProposeText(input) {
1524
1524
  out.push(routed)
1525
1525
  continue
1526
1526
  }
1527
+ // Sentence-level: a signer named mid-paragraph gets its own routed line and
1528
+ // the original stays as context, so nothing is invented or lost.
1529
+ for (const sentence of bare.split(/(?<=[.!?])\s+/)) {
1530
+ const who = signerFromLine(sentence)
1531
+ if (who) { out.push(`signer: ${who}`); break }
1532
+ }
1527
1533
  if (/^(next action|follow-?ups?|action items?|todo):\s*/i.test(bare) ||
1528
1534
  /\b(next action|walk in with|follow up with)\b/i.test(bare)) {
1529
1535
  const next = bare.replace(/^(next action|follow-?ups?|action items?|todo):\s*/i, '').trim()
@@ -1549,6 +1555,56 @@ function smartProposeText(input) {
1549
1555
  return out.join('\n') + (out.length ? '\n' : '')
1550
1556
  }
1551
1557
 
1558
+ // "Priya signs off" is the most expensive sentence in a kickoff and used to land
1559
+ // in context.md as a note. signer: fills the success.md line the whole kit
1560
+ // keys on, and logs the person as a contact so prep/status can see them.
1561
+ const SIGNER_RX = /^(?<who>[A-Z][\w.'-]+(?:\s+[A-Z][\w.'-]+){0,3}(?:\s*\([^)]{1,40}\))?)\s+(?:signs?(?:\s+off)?|approves|has (?:the )?final say|can say yes|owns the decision|is the (?:sponsor|signer|decision[- ]maker))\b/
1562
+
1563
+ function signerFromLine(text) {
1564
+ const t = String(text || '').trim()
1565
+ const m = t.match(SIGNER_RX)
1566
+ if (!m) return ''
1567
+ const who = m.groups.who.trim()
1568
+ // "Staging exists" / "The API is slow" also match "Capital Word + verb"; a
1569
+ // sentence-initial common noun is not a person.
1570
+ if (/^(The|This|That|It|We|They|Staging|Budget|Prod|Production|Nobody|Someone|Everyone)\b/.test(who)) return ''
1571
+ return who
1572
+ }
1573
+
1574
+ function setSigner(eng, who) {
1575
+ ensureMemoryGit(eng)
1576
+ const p = path.join(eng, 'success.md')
1577
+ let md = readEng(eng, 'success.md')
1578
+ if (!md) md = '# Success definition\n\n'
1579
+ const norm = (s) => String(s).replace(/\s+/g, ' ').trim().toLowerCase()
1580
+ const line = /^\*\*Stakeholder who signs off:\*\*\s*(.*)$/m
1581
+ const m = md.match(line)
1582
+ if (m && !m[1].trim()) {
1583
+ md = md.replace(line, `**Stakeholder who signs off:** ${who}`)
1584
+ } else if (m) {
1585
+ // Whole-name compare against the primary and every "also named" line under
1586
+ // it: "Sam" must not vanish inside "Samantha", and re-applying must not
1587
+ // stack duplicates.
1588
+ const start = md.indexOf(m[0]) + m[0].length
1589
+ const alsoNamed = []
1590
+ for (const l of md.slice(start).split('\n').slice(1)) {
1591
+ const a = l.match(/^- also named:\s*(.+)$/)
1592
+ if (!a) break
1593
+ alsoNamed.push(a[1])
1594
+ }
1595
+ const known = [m[1], ...alsoNamed].map(norm)
1596
+ if (known.includes(norm(who))) return false
1597
+ // A second, different name is a fact worth keeping next to the first, not
1598
+ // a silent overwrite - who signs is exactly the thing people argue about.
1599
+ const block = [m[0], ...alsoNamed.map(a => `- also named: ${a}`)].join('\n')
1600
+ md = md.replace(block, `${block}\n- also named: ${who}`)
1601
+ } else {
1602
+ md = md.replace(/\n*$/, `\n\n**Stakeholder who signs off:** ${who}\n`)
1603
+ }
1604
+ withFileLock(p, () => { atomicWriteFile(p, md.endsWith('\n') ? md : md + '\n') })
1605
+ return true
1606
+ }
1607
+
1552
1608
  function setNextAction(eng, text) {
1553
1609
  ensureMemoryGit(eng)
1554
1610
  const bullet = `- ${stripControlChars(String(text).replace(/^[-*]\s+/, '').trim())}`
@@ -1665,7 +1721,7 @@ function readSealedProposal(eng) {
1665
1721
  function routeDebriefInput(eng, input, { dry, force, sealed = [] }) {
1666
1722
  const d = new Date()
1667
1723
  const date = d.toISOString().slice(0, 10)
1668
- const counts = { decision: 0, risk: 0, delivery: 0, contact: 0, next: 0 }
1724
+ const counts = { decision: 0, risk: 0, delivery: 0, contact: 0, next: 0, signer: 0 }
1669
1725
  const ctxLines = []
1670
1726
  let nextAction = ''
1671
1727
  ensureMemoryGit(eng)
@@ -1678,8 +1734,8 @@ function routeDebriefInput(eng, input, { dry, force, sealed = [] }) {
1678
1734
  for (const raw of routable.split('\n')) {
1679
1735
  let line = raw.trim()
1680
1736
  if (!line) continue
1681
- const bare = line.replace(/^[-*+]\s+/, '').replace(/^\*\*(decision|risk|delivery|contact|next):?\*\*:?\s*/i, '$1: ')
1682
- const m = bare.match(/^(decision|risk|delivery|contact|next):\s*(.+)$/i)
1737
+ const bare = line.replace(/^[-*+]\s+/, '').replace(/^\*\*(decision|risk|delivery|contact|next|signer):?\*\*:?\s*/i, '$1: ')
1738
+ const m = bare.match(/^(decision|risk|delivery|contact|next|signer):\s*(.+)$/i)
1683
1739
  if (m) {
1684
1740
  const type = m[1].toLowerCase()
1685
1741
  let body = m[2]
@@ -1688,6 +1744,18 @@ function routeDebriefInput(eng, input, { dry, force, sealed = [] }) {
1688
1744
  console.error(`skipped ${type} line - looks like a ${hit}. Redact it, or re-run with --force.`)
1689
1745
  continue
1690
1746
  }
1747
+ if (type === 'signer') {
1748
+ const who = body.replace(/\s+signs?(?:\s+off)?\b.*$/i, '').trim() || body.trim()
1749
+ if (dry) {
1750
+ console.log(`→ success.md **Stakeholder who signs off:** ${previewLine(who)}`)
1751
+ console.log(`→ stakeholders.md ${previewLine(datedEntry(eng, date, `${who} signs off`))}`)
1752
+ } else {
1753
+ setSigner(eng, who)
1754
+ appendLogEntry(eng, 'contact', datedEntry(eng, date, `${who} signs off`), { skipCommit: true })
1755
+ }
1756
+ counts.signer++
1757
+ continue
1758
+ }
1691
1759
  if (type === 'next') {
1692
1760
  if (dry) console.log(`→ context.md ## Next action - ${previewLine(body)}`)
1693
1761
  else nextAction = body
@@ -1760,7 +1828,7 @@ function cmdDebrief(args) {
1760
1828
  if (smart) {
1761
1829
  const { proposePath, clean, blocks } = writeProposal(eng, smartProposeText(input))
1762
1830
  console.log('SMART PROPOSE (heuristic - review before apply; no new facts invented beyond line rewrites)\n')
1763
- console.log('Prefix vocabulary (lines that route): decision: risk: delivery: contact: next:')
1831
+ console.log('Prefix vocabulary (lines that route): decision: risk: delivery: contact: next: signer:')
1764
1832
  console.log('Everything else → context.md. Keep the prefixes; the preview gate stays.\n')
1765
1833
  routeDebriefInput(eng, clean, { dry: true, force, sealed: blocks })
1766
1834
  if (!apply) {
@@ -1776,7 +1844,7 @@ function cmdDebrief(args) {
1776
1844
  const { counts, ctxLines, privateBlocks } = routeDebriefInput(eng, input, { dry, force, sealed })
1777
1845
  if (!dry) {
1778
1846
  const hash = commitMemory(eng, 'debrief', {
1779
- files: ['decisions.md', 'risks.md', 'delivery.md', 'stakeholders.md', 'context.md', SIGNAL_LEDGER],
1847
+ files: ['decisions.md', 'risks.md', 'delivery.md', 'stakeholders.md', 'success.md', 'context.md', SIGNAL_LEDGER],
1780
1848
  })
1781
1849
  try { fs.unlinkSync(path.join(eng, DEBRIEF_PROPOSE)) } catch (_) {}
1782
1850
  try { fs.unlinkSync(path.join(eng, DEBRIEF_PRIVATE)) } catch (_) {}
@@ -1784,7 +1852,7 @@ function cmdDebrief(args) {
1784
1852
  if (hash) console.log(`memory @${hash}`)
1785
1853
  }
1786
1854
  const plural = {
1787
- decision: 'decisions', risk: 'risks', delivery: 'deliveries', contact: 'contacts', next: 'next actions',
1855
+ decision: 'decisions', risk: 'risks', delivery: 'deliveries', contact: 'contacts', next: 'next actions', signer: 'signers',
1788
1856
  }
1789
1857
  const parts = Object.keys(counts).filter(t => counts[t])
1790
1858
  .map(t => `${counts[t]} ${counts[t] === 1 ? (t === 'next' ? 'next action' : t) : plural[t]}`)
@@ -2176,6 +2244,66 @@ function findDuplicateOpenRisks(eng) {
2176
2244
  return [...byKey.values()].filter(g => g.length >= 2)
2177
2245
  }
2178
2246
 
2247
+ // The bound client repo moved and delivery.md did not. This is the one place
2248
+ // the CLI can catch "we shipped code and told the record nothing" without AI:
2249
+ // registry gives the workspace(s) bound to this engagement, git gives commits
2250
+ // newer than the last dated delivery line. Local reads only.
2251
+ // Only dates that stamp an entry count: a ledger row's Date cell, a dated
2252
+ // bullet, a dated heading. "trial night 2026-06-02" inside a Measured cell is a
2253
+ // promise, not a receipt - and a future promise must not hide today's commits.
2254
+ function latestDeliveryEntry(md) {
2255
+ const today = new Date().toISOString().slice(0, 10)
2256
+ let latest = { date: '', line: '' }
2257
+ for (const raw of stripTemplateNoise(md).split('\n')) {
2258
+ const t = raw.trim()
2259
+ const m = t.match(/^[-*]\s*\[(\d{4}-\d{2}-\d{2})\]/) ||
2260
+ t.match(/^#{1,6}\s+\[?(\d{4}-\d{2}-\d{2})(?:\]|\b)/) ||
2261
+ t.match(/^\|\s*(\d{4}-\d{2}-\d{2})\s*\|/)
2262
+ if (!m || m[1] > today) continue
2263
+ if (m[1] >= latest.date) latest = { date: m[1], line: t }
2264
+ }
2265
+ return latest
2266
+ }
2267
+
2268
+ function silentCommitIssues(eng) {
2269
+ const slug = path.basename(path.dirname(eng))
2270
+ const workspaces = readRegistry().filter(r => r.slug === slug).map(r => r.workspace)
2271
+ if (!workspaces.length) return []
2272
+ const entry = latestDeliveryEntry(readClean(eng, 'delivery.md'))
2273
+ const lastDelivery = entry.date
2274
+ const out = []
2275
+ for (const ws of workspaces) {
2276
+ let st
2277
+ try { st = fs.statSync(ws) } catch (_) { continue }
2278
+ if (!st.isDirectory()) continue
2279
+ // The memory folder is itself a git repo; never lint it as the client repo.
2280
+ if (path.resolve(ws) === path.resolve(eng) || path.resolve(ws) === path.dirname(path.resolve(eng))) continue
2281
+ if (sh('git rev-parse --is-inside-work-tree', ws) !== 'true') continue
2282
+ // Memory git knows the exact moment that entry was written; dates in the
2283
+ // file are day-grained and would miss a commit made later the same day.
2284
+ // Pickaxe on the entry text, not the file: a later status edit to
2285
+ // delivery.md must not become the cutoff and hide commits before it.
2286
+ const raw = entry.line
2287
+ ? sh(`git log -1 --format=%cI -S${JSON.stringify(entry.line)} -- delivery.md`, eng)
2288
+ : ''
2289
+ // git --since is inclusive at second grain; a commit in the same second as
2290
+ // the receipt is the receipt's own work, not a silent one.
2291
+ const stamp = raw && !Number.isNaN(Date.parse(raw)) ? new Date(Date.parse(raw) + 1000).toISOString() : ''
2292
+ const since = stamp ? `--since="${stamp}"`
2293
+ : lastDelivery ? `--since="${lastDelivery} 23:59:59"`
2294
+ : "--since='30 days ago'"
2295
+ const commits = sh(`git log ${since} --format=%h -- .`, ws).split('\n').filter(Boolean).length
2296
+ if (!commits) continue
2297
+ const where = path.basename(ws)
2298
+ out.push(
2299
+ lastDelivery
2300
+ ? `${commits} commit(s) in ${where} since the last delivery line (${lastDelivery}) - code moved, ledger did not; log the receipt or say why nothing shipped`
2301
+ : `${commits} commit(s) in ${where} in 30d and delivery.md has no dated line - code moved, ledger did not; fde log delivery "slice | bucket | promised | measured | accepted | evidence | rollback"`
2302
+ )
2303
+ }
2304
+ return out
2305
+ }
2306
+
2179
2307
  // Deterministic fieldbook hygiene - shared by doctor + session TRIAGE.
2180
2308
  // Silent when clean OR brand-new (no dated work yet). Never auto-rewrites.
2181
2309
  // High-value moments: week-start (via triage), ship/close, after real work accrues.
@@ -2246,9 +2374,11 @@ function collectDoctorIssues(eng) {
2246
2374
  'duplicate ## Next action headings in context.md - fill the first (template) section and remove extras; triage reads the last non-empty'
2247
2375
  )
2248
2376
  }
2249
- if ((s.phase === 'close' || s.phase === 'ship') && s.openRisks > 0) {
2377
+ // Open, owned risks are normal mid-ship (triage already shows the count every
2378
+ // session). The gate is close: nothing still live when you call the embed done.
2379
+ if (s.phase === 'close' && s.openRisks > 0) {
2250
2380
  issues.push(
2251
- `phase is ${s.phase} with ${s.openRisks} open risk(s) - retire, hand off, or move still-live ones before calling the embed done`
2381
+ `phase is close with ${s.openRisks} open risk(s) - retire, hand off, or move still-live ones before calling the embed done`
2252
2382
  )
2253
2383
  }
2254
2384
  if (s.phase === 'close' || s.phase === 'ship') {
@@ -2268,6 +2398,7 @@ function collectDoctorIssues(eng) {
2268
2398
  `phase is ${s.phase} with AI in scope but no eval receipt (evals.md Verdict or delivery Eval / Ship receipts) - required before green ship/close`
2269
2399
  )
2270
2400
  }
2401
+ issues.push(...silentCommitIssues(eng))
2271
2402
  }
2272
2403
  const dupes = findDuplicateOpenRisks(eng)
2273
2404
  if (dupes.length) {
package/bin/lib/trust.js CHANGED
@@ -194,6 +194,9 @@ function createTrustApi(deps) {
194
194
  }) || '').replace(/\|/g, ' ').replace(/\s+/g, ' ').trim().slice(0, 80)
195
195
  // Prefer trust trigger / memory warn over a random risk line; always keep mem.warn available
196
196
  const reason = (trustReason || mem.warn) ? (trustReason || mem.warn) : topRisk
197
+ // What the triage line is actually quoting. A risk bullet printed under
198
+ // "trust:" read as a stakeholder problem that did not exist.
199
+ const reasonKind = mem.warn && trustReason === mem.warn ? 'memory' : trustReason ? 'trust' : mem.warn ? 'memory' : topRisk ? 'risk' : ''
197
200
  const openRisks = countOpenRisks(eng)
198
201
  const nextAction = nextActionLine(ctx)
199
202
  let updated = 'never', ageDays = Infinity
@@ -203,7 +206,7 @@ function createTrustApi(deps) {
203
206
  } catch (_) {}
204
207
  const dirty = memoryDirtyManual(eng)
205
208
  return {
206
- phase, trust, signalAge, stale, topRisk, reason, memoryWarn: mem.warn,
209
+ phase, trust, signalAge, stale, topRisk, reason, reasonKind, memoryWarn: mem.warn,
207
210
  dirtyFiles: dirty, openRisks, nextAction, updated, ageDays,
208
211
  }
209
212
  }
@@ -215,9 +218,9 @@ function createTrustApi(deps) {
215
218
  const lines = [
216
219
  `TRIAGE [${label.padEnd(6)}] phase:${phase} updated:${s.updated} open risks:${s.openRisks}`,
217
220
  ]
218
- if (s.reason) {
219
- const age = s.signalAge != null ? ` (${s.signalAge}d old${s.stale ? ', STALE - reconfirm' : ''})` : ''
220
- lines.push(` trust: ${s.reason}${age}`)
221
+ if (s.reason && s.reasonKind !== 'memory') {
222
+ const age = s.reasonKind === 'trust' && s.signalAge != null ? ` (${s.signalAge}d old${s.stale ? ', STALE - reconfirm' : ''})` : ''
223
+ lines.push(` ${s.reasonKind === 'risk' ? 'top risk' : 'trust'}: ${s.reason}${age}`)
221
224
  }
222
225
  // Always surface corruption / unreadable memory - even when trust still reads green
223
226
  if (s.memoryWarn) lines.push(` memory: ${s.memoryWarn}`)
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fdeops-ingest-mcp",
3
- "version": "3.20.0",
3
+ "version": "3.22.0",
4
4
  "private": true,
5
5
  "description": "Thin stdio MCP sink for FDEOps ingest (stage → propose → apply). Zero runtime dependencies.",
6
6
  "bin": {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fdeops",
3
- "version": "3.20.0",
4
- "description": "Forward deployed engineering skills for AI coding agents. Your agent forgets the client every morning - the sponsor, the promise, who signed off. FDEOps keeps that as dated markdown on your laptop: one @fde skill, a deterministic local CLI, and hooks that make it automatic. Claude Code plugin and any agent that loads skills.",
3
+ "version": "3.22.0",
4
+ "description": "Forward deployed engineering skills for AI coding agents. One @fde skill for the client work around the code: who can say yes, what went live, whether they signed off. Dated markdown on your laptop. You confirm each write.",
5
5
  "bin": {
6
6
  "fdeops": "bin/install.js",
7
7
  "fde": "bin/fde.js"
package/plugin.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
3
  "name": "fdeops",
4
- "version": "3.20.0",
5
- "description": "Forward deployed engineering skills for AI coding agents: per-client memory in local .fde/ files, one @fde skill. Local-only, no network.",
4
+ "version": "3.22.0",
5
+ "description": "Forward deployed engineering skills for AI coding agents. One @fde skill for the client work around the code. You confirm; then it lands in .fde/ on your laptop.",
6
6
  "author": {
7
7
  "name": "Subash Natarajan",
8
8
  "url": "https://github.com/suboss87"
@@ -42,6 +42,8 @@ On someone else's site the work is not "write code, remember later." Every chang
42
42
 
43
43
  A throwaway file can skip the loop. Bound client work cannot.
44
44
 
45
+ **Skip is loud.** Bound + a change that will ship + no this-turn line in `delivery.md` = not done. Say that. Do not call it shipped. A coding pack may write the function; `@fde` still owns done.
46
+
45
47
  ## Human surface vs agent plumbing
46
48
 
47
49
  **FDE (human):** `@fde` + English, or `/brief` `/discover` `/plan` `/ship` `/outcome` `/close` `/debrief` `/prep` `/trust` `/receipts` `/readout`. Never a skill catalog.
@@ -129,8 +131,8 @@ Work names (engage, diagnose, align, deliver, realize, transfer) are the same ma
129
131
 
130
132
  | You hear | Skill | Reference |
131
133
  |----------|-------|-----------|
132
- | Diagnose, don't know the real problem, brief feels wrong, shadow processes, frame discovery, understand the problem space, data not ready, data estate, catalog the data | discover | `references/discover.md` |
133
- | The brief feels too neat, assumptions untested, "we just need…", test assumptions | test-assumptions | `references/test-assumptions.md` |
134
+ | Diagnose, don't know the real problem, brief feels wrong, shadow processes, frame discovery, understand the problem space, data not ready, data estate, catalog the data, parts of the problem, decompose | discover | `references/discover.md` |
135
+ | The brief feels too neat, assumptions untested, "we just need…", test assumptions, inherited convention, why do we always | test-assumptions | `references/test-assumptions.md` |
134
136
  | Multiple use cases competing, "we want to do everything", score use cases | score-use-cases | `references/score-use-cases.md` |
135
137
  | Need to validate a direction, prototype, demo to de-risk, **POC**, spike, killer assumption, validate the solution, build prototype | poc | `references/poc.md` |
136
138
 
@@ -140,7 +142,7 @@ Work names (engage, diagnose, align, deliver, realize, transfer) are the same ma
140
142
  |----------|-------|-----------|
141
143
  | Align, break this down, what order, sequence the build, plan the roadmap, create user stories, write the tasks | plan | `references/plan.md` |
142
144
  | Sponsor needs justification, need to defend budget or timeline, build the business case | business-case | `references/business-case.md` |
143
- | Significant decision, multiple approaches, "what should we do?", generate solutions, generate options | three-options | `references/three-options.md` |
145
+ | Significant decision, multiple approaches, "what should we do?", generate solutions, generate options, not the playbook, from the surviving facts | three-options | `references/three-options.md` |
144
146
  | 20 things are "urgent," need to pick the 3 that matter, prioritize three | pick-three | `references/pick-three.md` |
145
147
 
146
148
  ### Ship
@@ -196,8 +198,8 @@ Ready to build with no `terrain.md` / plan: discover or plan first. Takeover wit
196
198
 
197
199
  - Never ask the FDE to pick a phase. That's your job.
198
200
  - Same six stages at any scale. Overlays carry the industry. Greenfield and brownfield change the first move inside ship, not the map.
199
- - Ground loop on a bound client: name → characterise → prove on their staging → go live → log. Do not hand their repo to a generic coding pack.
200
- - Do not call a change done until the signer in `success.md` can reject it on staging they operate.
201
+ - Ground loop on a bound client: name → characterise → prove on their staging → go live → log. A coding pack may write the function. `@fde` still owns done. When they disagree, their repo and the signer win.
202
+ - Do not call a change done until the signer in `success.md` can reject it on staging they operate. No this-turn receipt in `delivery.md` is a failed test, not a note to write later.
201
203
  - Read `context.md` before speaking. One sharp question - never a barrage.
202
204
  - Never invent people, meetings, or numbers - `unknown - ask:` beats a polished lie.
203
205
  - Every phase ends with its artifact written. No artifact, no "done."
@@ -11,7 +11,8 @@
11
11
  ## Honest contract (read once)
12
12
 
13
13
  - The `fde` CLI is **local, deterministic, no AI**. `--smart` is a **gate + writer**, not a brain.
14
- - It keeps lines that already have `decision:` / `risk:` / `delivery:` / `contact:` / `next:` prefixes, plus a thin keyword pass (e.g. "we agreed", person+verb lines, "open question").
14
+ - It keeps lines that already have `decision:` / `risk:` / `delivery:` / `contact:` / `next:` / `signer:` prefixes, plus a thin keyword pass (e.g. "we agreed", person+verb lines, "open question", "X signs off").
15
+ - `signer: Priya` fills **Stakeholder who signs off** in `success.md` and logs Priya as a contact. The CLI proposes it when a sentence says someone signs off / approves / has final say. If the notes name who can say yes and the proposal does not carry a `signer:` line, add one - that is the most expensive sentence in the meeting.
15
16
  - Real messy notes without prefixes often route **0 useful lines** - everything else lands as a context dump. That is expected. **You are the router:** rewrite `.debrief-propose` with type prefixes, then `--apply`.
16
17
  - `.debrief-propose` is raw lines only (no routing annotations). "Edit if mis-routed" means **rewrite the line with the right prefix**, not leave a comment in the file.
17
18
 
@@ -25,6 +26,7 @@
25
26
  - `decision: agreed chargebacks stay phase 2 - Priya`
26
27
  - `risk: legal may reopen scope if we slip the SOW date`
27
28
  - `contact: Priya pushed hard on Friday deck [signal:amber]`
29
+ - `signer: Priya` (she can say yes; lands in `success.md`)
28
30
  - `next: send one-pager before Thursday 9am`
29
31
  - unprefixed lines stay context color only
30
32
  4. Show the **proposed** routing in plain language (what would become decisions, risks, contacts, next).
@@ -43,7 +45,7 @@ If `--smart` is unavailable or you already have clean prefixes:
43
45
  - **Stakeholder signals** - tone shifts with evidence → green/amber/red
44
46
  - **Risks** - new / confirmed / retired
45
47
  - **Open questions** - what to chase next
46
- 2. Format lines as `decision:` / `risk:` / `delivery:` / `contact:` / `next:` (contacts may end with `[signal:green|amber|red]`).
48
+ 2. Format lines as `decision:` / `risk:` / `delivery:` / `contact:` / `next:` / `signer:` (contacts may end with `[signal:green|amber|red]`).
47
49
  3. Show that structured version to the FDE for confirmation.
48
50
  4. Pipe to `fde debrief` (or write a file and run it).
49
51
 
@@ -54,6 +54,16 @@ Tests on **Question** - rewrite until all five hold:
54
54
 
55
55
  Cannot write the Question → keep interrogating. Do not `fde scan`. Every later output of this phase aims at that Question. Sub-questions go to the operating map or `assumptions.md`, not into the Question.
56
56
 
57
+ ## Parts of the problem (decompose only)
58
+
59
+ After the Question is locked, and **before** `fde scan` or any option: write what the problem is made of. No advice, no playbook, no solution.
60
+
61
+ If the stated brief hides a deeper job, name that deeper job in one sentence and **wait**. Do not silently replace their problem with yours.
62
+
63
+ In `terrain.md` under `## Parts`, list the smallest useful pieces that still change what you examine next. Typical cuts: people, process step, system, data, time, cost. For each piece: what it contains, and how it connects to the Question. Stop when a further split would not change where you dig.
64
+
65
+ Do not mark pieces as facts or assumptions here. That is `test-assumptions`. Do not assemble options here. That is `three-options`.
66
+
57
67
  ## Method - part 1: the codebase (you do this work)
58
68
 
59
69
  **First move: `fde scan`** - it runs everything below deterministically in seconds (churn×tests, "temporary" archaeology, AI components, secrets redacted, previous attempts). Your job is then **interpretation**: read its output against the brief, follow the hotspots into the code, and connect the technical findings to the human signals in part 2.
@@ -127,9 +137,11 @@ When discovery requires a structured session with multiple stakeholders (alignme
127
137
 
128
138
  **After the room:** Summary in `decisions.md` within 2 hours. Decisions decay - what felt clear at 3pm is debatable by 5pm if unwritten.
129
139
 
130
- ## Method - part 4: data estate assessment
140
+ ## Method - part 4: data estate and the pipe
141
+
142
+ Always map the estate before you score a use case - not only when someone said "AI." A path they cannot feed is a discover miss, not a ship surprise.
131
143
 
132
- When the engagement involves AI, analytics, or data-heavy automation, assess the data estate before scoring use cases:
144
+ **Their words first.** In `terrain.md`, write the names the floor uses for the workaround, the sheet, the exception path, and the person who left. Later plan/ship/review sentences use those names. Do not translate their floor into generic product language.
133
145
 
134
146
  **The 5 questions (ask the data owner, not the sponsor):**
135
147
  1. **Where does data live?** - List every source: databases, warehouses, SaaS exports, spreadsheets, S3 buckets, vendor APIs. Map it.
@@ -138,13 +150,15 @@ When the engagement involves AI, analytics, or data-heavy automation, assess the
138
150
  4. **What's the quality?** - Sample 100 rows from each critical source. Check: nulls, duplicates, format consistency, semantic correctness. A 60% null rate in a key field = that source is fiction.
139
151
  5. **What are the governance constraints?** - PII classification, retention policies, cross-border rules, consent basis. One missed constraint = a compliance stop later.
140
152
 
153
+ **The pipe (what talks to what).** For each source that a use case depends on, write: the system it flows from and to, the contract (object, table, file, API), whose credentials, what happens when the vendor 500s or the Monday file does not land, and whether the join the sponsor described actually exists. Their IdP, CRM, and warehouse are delivery work when the path needs them - policy questions in `trust-profile.md` are not a substitute.
154
+
141
155
  **The data readiness matrix:**
142
156
 
143
- | Source | Location | Freshness | Owner | Quality (sample) | Governance | Verdict |
144
- |--------|----------|-----------|-------|-----------------|------------|---------|
145
- | _fill per source_ | | | | | | Ready / Needs work / Blocker |
157
+ | Source | Location | Freshness | Owner | Quality (sample) | Governance | Pipe | Verdict |
158
+ |--------|----------|-----------|-------|-----------------|------------|------|---------|
159
+ | _fill per source_ | | | | | | | Ready / Needs work / Blocker |
146
160
 
147
- A use case that depends on a "Blocker" source doesn't get scored - it gets a data remediation conversation first. Write this to `terrain.md` under a `## Data estate` section.
161
+ A use case that depends on a "Blocker" source **or a Blocker pipe** doesn't get scored - it gets a remediation conversation first. `what-breaks` finding an invisible integration at ship is already too late. Write this to `terrain.md` under a `## Data estate` section.
148
162
 
149
163
  ## When scope is a transformation, not a single problem
150
164
 
@@ -47,6 +47,7 @@ The difference between a 5-year FDE and a 15-year FDE is not talent - it's encod
47
47
  | **Specific enough?** | Contains concrete steps, not just principles | "Build trust" / "Communicate well" - too vague to act on |
48
48
  | **Repeatable?** | Applies to a class of situations, not just this one | Only worked because of a unique circumstance |
49
49
  | **Falsifiable?** | You can tell when the pattern is working or not | No way to measure whether applying it helped |
50
+ | **Monday bag?** | You would refuse the next similar embed without this in your bag - a named move plus an artifact you can drop on day one (pipe questions, CAB dance, eval golden shape, floor-drill script) | "We learned to communicate." Patterns that only live in this client's `.fde/` do not compound |
50
51
 
51
52
  **4. Classify by stage.** Patterns sort into the same stages as the skills:
52
53
 
@@ -22,9 +22,9 @@ Intelligence without evidence is token-maxing with a nicer name. An FDE earns tr
22
22
 
23
23
  **3. Score pass/fail, not vibes.** Run the suite. Record count pass / fail. Failures get a failure-mode tag (missing data, wrong record, format drift, hallucination, retrieval miss, unsafe action, other).
24
24
 
25
- **4. Human-in-the-loop gate.** Name which outcomes require human approve before side effects. If none, write why that is allowed under `trust-profile.md` AI policy - do not invent permission.
25
+ **4. Human-in-the-loop gate.** Name which outcomes require human approve before side effects. Judgement that has a side effect (write, send, transfer, ticket, deploy, pay, page) is **NO-SHIP** without a named human on their side in the loop. Do not write "none - allowed under policy" to bless lights-out write-access. Staging may run a supervised loop with a kill switch, a cost cap, and a golden set from **their** failures. Production stays gated until they have a written policy, a named owner, and dated eval receipts on real traffic.
26
26
 
27
- **5. Ship rule.** Until `evals.md` shows Verdict **SHIP** with a dated run (critical fails = 0) and HITL filled when policy requires it, AI-touching ship stays **fix-first**. Log a one-line eval receipt in `delivery.md` → `## Ship receipts`.
27
+ **5. Ship rule.** Until `evals.md` shows Verdict **SHIP** with a dated run (critical fails = 0) and HITL filled, AI-touching ship stays **fix-first**. Eval fails do not sit in a backlog - they reopen plan (descope, move the judgement, or kill the path). Log a one-line eval receipt in `delivery.md` → `## Ship receipts`. No "probably fine."
28
28
 
29
29
  ## Artifact - `evals.md`
30
30
 
@@ -39,5 +39,5 @@ Present to the FDE: suite size, pass rate, top failure mode, HITL gate, Verdict
39
39
  - No golden set, no AI ship.
40
40
  - Pass/fail beats “looks good.”
41
41
  - Failure modes are the product - the happy path is table stakes.
42
- - HITL is a gate, not a slide.
42
+ - HITL is a gate, not a slide. Side effects without a named human on their side are NO-SHIP.
43
43
  - Non-AI work does not need this file.
@@ -31,7 +31,7 @@ List what you can actually call **this session**:
31
31
  3. **Stage** - `fde ingest stage [--source NAME] [--title TEXT] [file|-]` writes raw text into `<engagement>/.inbox/` (outside the memory git ledger).
32
32
  4. **List** (optional) - `fde ingest list` shows staged items when you need an id or filename.
33
33
  5. **Propose** - `fde ingest propose <id-or-filename>` runs the debrief `--smart` path on the staged body (+ provenance line). Opens `.debrief-propose`.
34
- 6. **Rewrite prefixes** - same as debrief: lines without `decision:` / `risk:` / `delivery:` / `contact:` / `next:` need **you** to rewrite before showing the FDE. `--smart` is a gate, not a brain.
34
+ 6. **Rewrite prefixes** - same as debrief: lines without `decision:` / `risk:` / `delivery:` / `contact:` / `next:` / `signer:` need **you** to rewrite before showing the FDE. `--smart` is a gate, not a brain.
35
35
  7. **Show** the proposed routing in plain language. Wait for confirm.
36
36
  8. **Apply** - on FDE confirm only → `fde ingest apply` (= `fde debrief --apply`). On reject → stop; ask what to change.
37
37
 
@@ -99,12 +99,12 @@ If `stakeholders.md` already has a `## Signal history` section (it does from the
99
99
 
100
100
  **`trust-profile.md`** - sacred data (`<private>` tagged), fears heard, AI policy, approval chain. Sensitive: skip for status reads; use CLI/redacted surfaces; never paste raw `<private>` into prompts or subagents.
101
101
 
102
- **`assumptions.md`** - seed every unverified claim from the brief (and the day-1 hypothesis) as rows with blast radius CRITICAL / LOAD-BEARING / CONVENIENCE and status `OPEN`. Do not wait for test-assumptions - land makes the register exist. Example:
102
+ **`assumptions.md`** - seed every unverified claim from the brief (and the day-1 hypothesis) as rows with Kind `UNKNOWN` (or `CONVENTION` if they said "we always"), blast radius CRITICAL / LOAD-BEARING / CONVENIENCE, and status `OPEN`. Do not wait for test-assumptions - land makes the register exist. Example:
103
103
 
104
104
  ```markdown
105
- | # | Assumption | Blast radius | How we test | Status | Evidence |
106
- |---|------------|--------------|-------------|--------|----------|
107
- | 1 | <claim from brief> | CRITICAL | <cheapest falsifying test> | OPEN | (stated, unverified) |
105
+ | # | Assumption | Kind | Blast radius | How we test | Status | Evidence |
106
+ |---|------------|------|--------------|-------------|--------|----------|
107
+ | 1 | <claim from brief> | UNKNOWN | CRITICAL | <cheapest falsifying test> | OPEN | (stated, unverified) |
108
108
  ```
109
109
 
110
110
  One falsifiable hypothesis about the real problem also goes at the bottom of `brief.md` - discover / test-assumptions will test it.
@@ -8,7 +8,9 @@ A green check on synthetic data is not a validated solution. The person who can
8
8
 
9
9
  ## Method (you do this work)
10
10
 
11
- **0. Name the killer assumption.** With the FDE: "What's the belief that kills the project if it's wrong?" Prototype **that** - not the pretty demo.
11
+ **0. Name the killer assumption.** With the FDE: "What's the belief that kills the project if it's wrong?" Prototype **that** - not the pretty demo. If `three-options` just ran: the cheapest test is for the recommended option first, unless they pick another.
12
+
13
+ **0b. Pass / fail before you build.** For the test you will run, write three lines in `prototype-log.md` first: what you will actually do (who you talk to, what you show, on whose screen); the result that **kills** this option; the result that keeps it alive. What you would learn either way. If every option's test would fail, name which `assumptions.md` block to reopen - do not invent a fourth playbook.
12
14
 
13
15
  **1. Pick by score when several use cases compete.** Use the scoring model from `discover.md` - (Value × Data readiness) / Complexity. If discover already scored, reuse; never re-score independently.
14
16
 
@@ -37,6 +39,7 @@ Tell the FDE: did the riskiest assumption hold · what the customer's reaction a
37
39
  ## Principles
38
40
 
39
41
  - Speed of learning beats code quality. Never more than a day.
42
+ - Write pass/fail before you build. A demo with no kill line is a show.
40
43
  - Show it rough. Polish misleads.
41
44
  - Prototype the killer assumption, not the demo.
42
45
  - Kill fast; log the learning.
@@ -12,15 +12,16 @@
12
12
 
13
13
  | Block | What to write | Source |
14
14
  |-------|---------------|--------|
15
- | **S - Situation** | Where we are against `success.md`, in their words | success.md, delivery value ledger |
15
+ | **S - Situation** | Where we are against `success.md`, in their words - including whether the floor still uses the old path | success.md, delivery value ledger, reality.md workaround |
16
16
  | **C - Complication** | What changed, what is at risk, or what we learned (bad news first) | risks.md, assumptions DISPROVED/OPEN, stakeholders signal |
17
17
  | **Q - Question / Ask** | The one decision or help you need from them | decisions.md, access/sign-off needs |
18
18
  | **A - Answer** | What you recommend / what happens next week (≤3 bullets) | plan Now lane, delivery promised→measured |
19
19
 
20
20
  Then add, still on the same page:
21
21
  1. **Value this week** - from the value ledger: promised → measured (or "pending") → **accepted by whom**, with evidence citation. A measured number nobody on the customer side has agreed to is written as `claimed`, and the Ask never rests on it - if the whole case for the next phase is a claimed number, the real ask this week is "who signs off that this is real?".
22
- 2. **Kill / defer reminder** - one line from the plan kill list so scope fights stay visible.
23
- 3. **Hostile Q prep** - three questions a skeptical sponsor will ask, with one-line answers from memory.
22
+ 2. **Are they using it?** - Situation must say whether the workaround is still open: spreadsheet still running, shadow paste still happening, named operator completed Tuesday's job on the new path without you at the keyboard. A measured metric with the old path still live is `claimed`. That week's Ask is not "fund phase 2." It is "who on their side stops the old way, by when."
23
+ 3. **Kill / defer reminder** - one line from the plan kill list so scope fights stay visible.
24
+ 4. **Hostile Q prep** - three questions a skeptical sponsor will ask, with one-line answers from memory.
24
25
 
25
26
  Exec voice: no jargon, no hedging, every claim traceable (`(shipped Tue, delivery.md)`). Draft in the **FDE's voice, for the FDE to send** - never send anything yourself.
26
27
 
@@ -1,6 +1,6 @@
1
1
  # review - Review the change
2
2
 
3
- **Enter when:** a change needs review before merge - "is this safe," "does it match what we agreed."
3
+ **Enter when:** a change needs review before merge - "is this safe," "does it match what we agreed." Their team commented on the PR: same skill. Comments are to check, not to obey.
4
4
 
5
5
  **Read first:** `context.md`, `decisions.md`, `trust-profile.md`, `terrain.md`. Not `reality.md`/`stakeholders.md` - irrelevant to reviewing code against agreed scope.
6
6
 
@@ -52,7 +52,7 @@ Five dimensions, line-specific ("line 47 fails under concurrent writes - no lock
52
52
 
53
53
  1. Read the full diff before commenting.
54
54
  2. Verdicts: **Stage 1: Pass / Blocked (reason)** · **Stage 2: Pass / Concerns (line-specific)**.
55
- 3. Fix only **real** findings tied to this change - no drive-by refactors. Reject false positives with one sentence why.
55
+ 3. Fix only **real** findings tied to this change - no drive-by refactors. Reject false positives with one sentence why. Their comments are to check, not to obey. Restate each against the one-line intent and `trust-profile.md`. One item unclear → ask before changing any of them. If it breaks a signed constraint, a sacred system, or nothing calls it: one-sentence pushback, then wait.
56
56
  4. Add or update a test per bug found where possible.
57
57
  5. Re-run tests/typechecks - state what ran.
58
58
  6. Re-review. Repeat until Pass/Pass or a human must decide scope/product.
@@ -60,6 +60,7 @@ Rollback: <exact command and expected time>
60
60
  |---------|-------|-----------|----------|--------|
61
61
  | **Architecture walkthrough** | Why, not what. The decisions, the trade-offs, the things that almost went wrong. | Full team | 60-90 min | Recording + Q&A log |
62
62
  | **Operational drill** | Deploy, rollback, incident response. They do it, you watch. | On-call team | 60 min | Drill report with confidence level |
63
+ | **Floor drill** | They run the real job (the exception on the operating map) while you watch, hands off. Then they teach the next person. If they cannot, the runbook is a PDF. | Named operator on the floor | 45-60 min | They used the 2am doc during the drill, or the embed is not closed |
63
64
  | **Edge-case handover** | The things that aren't in any document. The workarounds, the fragile spots, the "ask Sarah because she's the only one who knows." | Team lead + 1 | 30 min | Additions to `handoff.md` |
64
65
 
65
66
  **4. The confidence check.** After the knowledge transfer, score the team's readiness:
@@ -68,11 +69,12 @@ Rollback: <exact command and expected time>
68
69
  |------|------------------|----------|
69
70
  | Daily operations | | Can they deploy and rollback without help? |
70
71
  | Incident response | | Did they complete the drill within acceptable time? |
72
+ | Floor job | | Did the named operator complete Tuesday's real exception without you at the keyboard? |
71
73
  | Architecture decisions | | Can they explain why the system is built this way? |
72
74
  | AI components (if any) | | Do they know how to monitor, retrain, and disable? |
73
75
  | Stakeholder management | | Do they know who to update and how? |
74
76
 
75
- **Average below 3.5 → the handoff is not complete.** Extend if possible; if not, document the gaps and name the risk.
77
+ **Average below 3.5 → the handoff is not complete.** Extend, or tell the sponsor the embed is not closed. Do not document the gap and leave.
76
78
 
77
79
  **5. The successor brief.** If a new FDE is taking over, write a brief that gets them operational in one hour:
78
80
 
@@ -132,7 +134,7 @@ If you see 2+: accelerate the handoff immediately. The longer you stay past usef
132
134
 
133
135
  - The goal of every engagement is to make yourself replaceable.
134
136
  - The 2am document is the real handoff - everything else supports it.
135
- - Knowledge transfer is three sessions, not a doc dump.
137
+ - Knowledge transfer is four sessions, not a doc dump. The floor drill is the named operator completing Tuesday's real job from the 2am doc, hands off. If they cannot, do not close.
136
138
  - A confidence score below 3.5 means the handoff isn't done.
137
139
  - The successor brief gets the next FDE operational in one hour or it's too long.
138
140
  - Clean exit: no personal credentials left behind, ever.
@@ -27,7 +27,7 @@ Skip POC only when the killer assumption already lives in the repo (typical brow
27
27
 
28
28
  **Done means:** the signer in `success.md` can reject this on staging they operate. A green check on your laptop is not delivery. Do not start the next change until this one is rejectable.
29
29
 
30
- If `terrain.md` **Data estate** lists a **Blocker** this change depends on: stop. That is discover, not ship. Do not build a path they cannot feed.
30
+ If `terrain.md` **Data estate** lists a **Blocker** this change depends on (source or pipe): stop. That is discover, not ship. Do not build a path they cannot feed.
31
31
 
32
32
  ## Method - one change they can see
33
33
 
@@ -56,6 +56,10 @@ Each change is independently revertible.
56
56
  - [ ] Rollback named: revert this change, or something more specific
57
57
  - [ ] No dependency on an unmerged change (if dependent, state it and land in order)
58
58
  - [ ] `Kill if` is written - the observation that stops this change
59
+ - [ ] Before-receipt captured: the failing output, number, or screen as it is today, dated in `delivery.md`, before you change anything
60
+ - [ ] Open PRs and uncommitted work in the area checked (`gh pr list`, `gh pr diff <n> --name-only`); overlap goes to `decisions.md` before you start
61
+
62
+ Your coding pack writes the function. This skill owns done. When they disagree with this repo, the repo wins.
59
63
 
60
64
  **The loop.** In this order:
61
65
 
@@ -72,10 +76,12 @@ Read existing code in the area (search before creating)
72
76
 
73
77
  **Prove it on their staging.** A green check on your laptop is not delivery.
74
78
 
75
- - Run **their** test command, typecheck, or smallest proving path. Write the command and the result in `delivery.md`.
79
+ - Run **their** test command, on **their** CI, with **their** fixtures. Write the command and the result in `delivery.md` in this turn. You do not add a runner they will not keep. If you have not run their command in this turn, you cannot write that it passed. Last session's green, "should pass," and "looks correct" are not a receipt. Missing this-turn line = not proven. Same as a failing test.
76
80
  - If the signer in `success.md` cannot reject this on a screen they already use, it is not proven.
77
81
  - Staging they operate beats a local demo. If you have no staging: `unknown - ask:` who owns an environment, then stop pretending it shipped.
82
+ - **Monday-shaped data.** Staging that is empty, synthetic, or last quarter is not next Tuesday. Before go-live, write what staging is missing (volume, PII, the batch that only runs in prod, the account that only exists in the warehouse) and what that means for the kill test. If the signer cannot reject it on a screen they already operate, with data that looks like next Tuesday, it is not proven.
78
83
  - Model in the path: `eval-pack` until `evals.md` says SHIP. Do not skip because "it looked right in chat."
84
+ - A model drafts. A named human on their side ships. No unsupervised loop on their production. If the brief demands lights-out write-access, that is `who-decides` / `hold-scope`, not ship.
79
85
 
80
86
  The proof is whatever this client already believes, plus one new receipt they can replay.
81
87
 
@@ -214,6 +220,8 @@ grep -rnE "(api[_-]?key|secret|password|token)\s*[:=]\s*['\"][^'\"]{8,}" \
214
220
 
215
221
  **Canary:** 1-5% of traffic, ≥10 minutes. Watch error rate, latency, and **the business metric this change affects**. Anything looks wrong → roll back immediately; investigate safely; redeploy when confident. Never investigate during the canary. Then stage up: 5% → 25% → 100%, each confirmed stable.
216
222
 
223
+ **Canary receipt** (write it, or the canary did not happen): what was watched, on whose dashboard, for how long, and that the next change did not start in the window. If prod is a CAB console, vendor button, or their pipeline, write the owner and the click path - the host agent does not get to pretend it shipped.
224
+
217
225
  **Programme-scale rollout (transformations)** - different problem from one service:
218
226
  1. **Pilot** - one team, one use case; success metrics defined *before* it starts (after = fitting metrics to results).
219
227
  2. **Limited release** - 3-5 teams, real load; this is where the failure modes the pilot hid show up.
@@ -8,7 +8,7 @@ Every engagement is built on assumptions. Most are invisible until they're wrong
8
8
 
9
9
  ## Method (you do this work)
10
10
 
11
- **1. Extract the assumptions.** Read `brief.md` and `reality.md` line by line. Every statement that isn't backed by evidence is an assumption. Common hiding places:
11
+ **1. Extract the assumptions.** Read `brief.md`, `reality.md`, and `terrain.md` `## Parts` line by line. Every statement that isn't backed by evidence is an assumption. Treat every "obvious" block as a convention until a receipt proves it. Common hiding places:
12
12
 
13
13
  | Where assumptions hide | Example | The real question |
14
14
  |----------------------|---------|-------------------|
@@ -19,7 +19,17 @@ Every engagement is built on assumptions. Most are invisible until they're wrong
19
19
  | **The data claim** | "We have good data for this" | Defined how? Validated when? By whom? Sample checked? |
20
20
  | **The "just"** | "We just need to add a feature" | On what system? With what dependencies? What breaks? |
21
21
 
22
- **2. Classify each assumption by blast radius:**
22
+ **2. Kind first, then blast radius.** For each row, classify:
23
+
24
+ | Kind | Meaning |
25
+ |------|---------|
26
+ | **FACT** | A dated receipt, a measurement, or the repo. You can point at it. |
27
+ | **CONVENTION** | How they have always done it. The playbook. "We just…" |
28
+ | **UNKNOWN** | No evidence either way. |
29
+
30
+ Order the list load-bearing first. For each CONVENTION or UNKNOWN, one line: what breaks if it is wrong, and what opens if you **invert** it (stop obeying it). A FACT with no receipt is UNKNOWN - do not promote it to protect the brief.
31
+
32
+ Then classify blast radius:
23
33
 
24
34
  ```
25
35
  CRITICAL - if wrong, the engagement fails or the approach changes fundamentally
@@ -55,11 +65,11 @@ Evidence first, then the question. Let them reach the conclusion.
55
65
  **`assumptions.md`** - this IS the register (create if land did not). Keep one live table; do not only bury results in `reality.md`:
56
66
 
57
67
  ```markdown
58
- | # | Assumption | Blast radius | How we test | Status | Evidence |
59
- |---|------------|--------------|-------------|--------|----------|
60
- | 1 | API is the bottleneck | CRITICAL | p95 instrumentation 24h | DISPROVED | 80% wait in DB layer (Day N) |
61
- | 2 | Team will adopt new tool | LOAD-BEARING | 3 individual interviews | CONFIRMED | 2/3 describe a use case unprompted |
62
- | 3 | Data clean enough for ML | CRITICAL | 200-record sample | PARTIAL → OPEN follow-up | 12% nulls on key field; cleaning task added |
68
+ | # | Assumption | Kind | Blast radius | How we test | Status | Evidence |
69
+ |---|------------|------|--------------|-------------|--------|----------|
70
+ | 1 | API is the bottleneck | CONVENTION | CRITICAL | p95 instrumentation 24h | DISPROVED | 80% wait in DB layer (Day N) |
71
+ | 2 | Team will adopt new tool | UNKNOWN | LOAD-BEARING | 3 individual interviews | CONFIRMED | 2/3 describe a use case unprompted |
72
+ | 3 | Data clean enough for ML | UNKNOWN | CRITICAL | 200-record sample | PARTIAL → OPEN follow-up | 12% nulls on key field; cleaning task added |
63
73
  ```
64
74
 
65
75
  Status values: `OPEN` · `TESTING` · `CONFIRMED` · `DISPROVED` · `PARKED`. A CRITICAL row still `OPEN` blocks plan.
@@ -85,6 +95,7 @@ Result: acked in 40 minutes, by Marco, not finance. Assumption DISPROVED, and th
85
95
  ## Principles
86
96
 
87
97
  - Every "just" is an assumption. Every "should" is an assumption.
98
+ - Kind before blast radius. A FACT with no receipt is UNKNOWN.
88
99
  - Kill the riskiest, cheapest-to-test assumption first.
89
100
  - Evidence first, then the question. Let the customer reach the conclusion.
90
101
  - A brief with zero disproved assumptions wasn't audited - it was accepted.
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Enter when:** a significant technical or strategic decision needs to be made, the FDE is asked "what should we do?", the team is stuck between approaches, or a fork in the engagement requires the sponsor's input.
4
4
 
5
- **Read first:** `reality.md`, `terrain.md`, `success.md`, `context.md`. Load `business-case.md` if the decision has cost implications.
5
+ **Read first:** `reality.md`, `terrain.md`, `assumptions.md`, `success.md`, `context.md`. Load `business-case.md` if the decision has cost implications.
6
6
 
7
7
  One option is a request for trust. Two options is a false choice. Three options is a conversation between professionals. The FDE who presents three genuine options earns the decision-maker's respect - and their protection when things get hard.
8
8
 
@@ -12,24 +12,30 @@ One option is a request for trust. Two options is a false choice. Three options
12
12
 
13
13
  > "Decision: approach for the payment migration. Decided by: CTO. Needed by: Friday. Deferral cost: blocks the next sprint and delays the pilot by two weeks."
14
14
 
15
- **2. Generate three genuine options.** Not "good / medium / bad" - three approaches with real trade-offs:
15
+ **2. Generate three genuine options from what survived.** Read `assumptions.md` (CONFIRMED / DISPROVED) and `terrain.md` `## Parts`. The playbook is unavailable. Assemble from those blocks only.
16
16
 
17
- | Option archetype | Description | When it fits |
18
- |-----------------|-------------|-------------|
19
- | **Conservative** | Lowest risk, smallest change, longest timeline | When trust is thin or the system is fragile |
20
- | **Pragmatic** | Balanced risk/reward, proven patterns, moderate timeline | When the team is competent and the deadline is real |
21
- | **Ambitious** | Highest reward, most change, highest risk | When the sponsor has appetite and the team has capacity |
17
+ Not "good / medium / bad." Not three speeds of the same plan (Conservative / Pragmatic / Ambitious of one architecture). Three approaches that differ in **structure** - rearrange the same surviving parts.
22
18
 
23
- Each option must be one the FDE would genuinely recommend under different circumstances. If you can't defend an option, replace it - padding is visible.
19
+ Each option must be one the FDE would genuinely recommend under different circumstances. If you cannot defend an option, replace it - padding is visible.
20
+
21
+ For each option, name:
22
+ - which surviving blocks it is built from
23
+ - which CONVENTION it refuses to obey
24
+ - its single biggest point of failure
25
+ - any new building block, labelled as a new assumption (`UNKNOWN` in `assumptions.md`) - do not smuggle one in as a fact
26
+
27
+ If all three are the same system at different risk levels, you wrote the playbook. Start over.
24
28
 
25
29
  **3. Structure each option identically.** Same dimensions, same format - so comparison is instant:
26
30
 
27
31
  ```markdown
28
- ### Option A: <name> (Conservative)
32
+ ### Option A: <name>
33
+ - **Blocks:** <which surviving assumptions / parts it is built from>
34
+ - **Convention refused:** <the "we just…" it will not obey>
29
35
  - **What:** <the approach in one paragraph>
30
36
  - **Timeline:** <estimate with basis>
31
37
  - **Cost:** <effort, infrastructure, external>
32
- - **Risk:** <what could go wrong and the mitigation>
38
+ - **Biggest failure:** <the single point that kills this option>
33
39
  - **Trade-off:** <what you give up by choosing this>
34
40
  - **Best when:** <the condition that makes this the right choice>
35
41
  ```
@@ -85,6 +91,7 @@ Recommendation: pragmatic, conditional - *if* Raj is on the design, otherwise sa
85
91
  ## Principles
86
92
 
87
93
  - Three options, never one. One option is a request for trust; three is a real decision.
94
+ - Assemble from surviving blocks. Three speeds of the same plan is the playbook - start over.
88
95
  - Each option must be genuinely defensible - no straw men.
89
96
  - Same structure for each option. Comparison should take 30 seconds.
90
97
  - Recommend one. State why. Accept the override gracefully.
@@ -5,7 +5,7 @@
5
5
  Create with:
6
6
 
7
7
  ```bash
8
- node bin/install.js init <engagement-name> # from fdeops repo; or npx fdeops@latest init when npm ≥ 3.0.0
8
+ fde resume --init <engagement-name> # or: npx fdeops resume --init <engagement-name>
9
9
  ```
10
10
 
11
11
  Stays on **your machine** - not in shared git by default.
@@ -2,9 +2,10 @@
2
2
 
3
3
  <!-- Brief claims that are not yet evidence. Land seeds; test-assumptions / discover update. -->
4
4
 
5
- | # | Assumption | Blast radius | How we test | Status | Evidence |
6
- |---|------------|--------------|-------------|--------|----------|
5
+ | # | Assumption | Kind | Blast radius | How we test | Status | Evidence |
6
+ |---|------------|------|--------------|-------------|--------|----------|
7
7
 
8
+ **Kind:** `FACT` · `CONVENTION` · `UNKNOWN`
8
9
  **Blast radius:** `CRITICAL` · `LOAD-BEARING` · `CONVENIENCE`
9
10
  **Status:** `OPEN` · `TESTING` · `CONFIRMED` · `DISPROVED` · `PARKED`
10
11