fdeops 3.23.0 → 3.26.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/bin/lib/trust.js CHANGED
@@ -56,6 +56,22 @@ function createTrustApi(deps) {
56
56
  'blocker', 'outage', 'fire', 'issue', 'sev', 'sev1', 'sev2', 'p1', 'p2', 'p3',
57
57
  'resolved', 'risk', 'decision', 'delivery', 'contact',
58
58
  ])
59
+ // Articles and weekdays are not people. "the finance controller…" and
60
+ // "Friday's readout" must key on the role/name, not the filler word.
61
+ const SIGNAL_NAME_NOISE = new Set([
62
+ 'the', 'a', 'an', 'and', 'or', 'for', 'from', 'with', 'without', 'this', 'that',
63
+ 'these', 'those', 'their', 'our',
64
+ 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday',
65
+ 'today', 'tomorrow', 'yesterday', 'tonight',
66
+ ])
67
+
68
+ function isSignalNameNoise(word) {
69
+ const n = String(word || '').replace(/[^a-z0-9]/gi, '').toLowerCase()
70
+ if (SIGNAL_NAME_NOISE.has(n)) return true
71
+ // "Friday's" → fridays after stripping punctuation
72
+ if (n.endsWith('s') && SIGNAL_NAME_NOISE.has(n.slice(0, -1))) return true
73
+ return false
74
+ }
59
75
 
60
76
  function personFromSignalText(text) {
61
77
  let cleaned = String(text || '')
@@ -63,14 +79,19 @@ function createTrustApi(deps) {
63
79
  .replace(/\([^)]*\)/g, '')
64
80
  .replace(/\[signal:[^\]]+\]/gi, '')
65
81
  .replace(/\[\d{4}-\d{2}-\d{2}\]/g, '')
66
- .replace(/^([A-Z]{2,}[A-Z0-9_-]*):?\s+/, '')
82
+ .replace(/^([A-Z]{2,}[A-Z0-9_-]*):\s+/, '')
67
83
  .trim()
68
84
  const names = cleaned.match(/\b[A-Z][a-z]{1,20}(?:\s+[A-Z][a-z]{1,20})?\b/g) || []
69
85
  for (const name of names) {
70
86
  const first = name.split(/\s+/)[0].toLowerCase()
71
- if (SIGNAL_EVENT_KEYS.has(first)) continue
87
+ if (SIGNAL_EVENT_KEYS.has(first) || isSignalNameNoise(first) || isSignalNameNoise(name)) continue
72
88
  return name
73
89
  }
90
+ const acronyms = cleaned.match(/\b[A-Z]{3,6}\b/g) || []
91
+ for (const acronym of acronyms) {
92
+ if (SIGNAL_EVENT_KEYS.has(acronym.toLowerCase()) || isSignalNameNoise(acronym)) continue
93
+ return acronym
94
+ }
74
95
  return ''
75
96
  }
76
97
 
@@ -84,10 +105,11 @@ function createTrustApi(deps) {
84
105
  if (frag.length >= 3) return frag
85
106
  }
86
107
  const cleaned = String(text).replace(/\[@[^\]]+\]/g, '').replace(/\([^)]*\)/g, '')
87
- .replace(/^([A-Z]{2,}[A-Z0-9_-]*):?\s+/, '')
108
+ .replace(/^([A-Z]{2,}[A-Z0-9_-]*):\s+/, '')
88
109
  const words = cleaned.split(/\s+/).filter(w => {
89
110
  const n = w.replace(/[^a-z0-9]/gi, '').toLowerCase()
90
- return n.length >= 3 && !SIGNAL_EVENT_KEYS.has(n) && !/^(dr|mr|mrs|ms)$/i.test(w)
111
+ return n.length >= 3 && !SIGNAL_EVENT_KEYS.has(n) && !isSignalNameNoise(n)
112
+ && !/^(dr|mr|mrs|ms)$/i.test(w)
91
113
  })
92
114
  const frag = (words[0] || '').replace(/[^a-z0-9]/gi, '').toLowerCase()
93
115
  return frag.length >= 3 ? frag : ('anon:' + cleaned.slice(0, 48).toLowerCase())
@@ -243,6 +265,7 @@ function createTrustApi(deps) {
243
265
  stakeholdersMemoryHealth,
244
266
  personFromSignalText,
245
267
  signalSubjectKey,
268
+ isSignalNameNoise,
246
269
  parsePhase,
247
270
  countOpenRisks,
248
271
  nextActionLine,
@@ -0,0 +1,34 @@
1
+ 'use strict'
2
+
3
+ // Empty measurements and unsigned outcomes are different facts. Keep their
4
+ // interpretation shared by status, reports, and exported vaults.
5
+ const PENDING_CELL_RE = /^(?:pending|tbd|to ?be ?(?:measured|confirmed|determined)|n\s*\/\s*a|na|none|unknown|not(?:\s+yet)?\s+measured|unmeasured|awaiting|\?+|\.{2,}|…|-+)(?:[^\w].*)?$/i
6
+ const UNCERTAIN_ACCEPTANCE_RE = /\b(?:not|no|never|pending|awaiting|unapproved|unsigned|unconfirmed|unaccepted|unverified|rejected|declined|denied|revoked|withdrawn|superseded|proposed|requested|unknown|tbd|tentative|conditional|required|needed|blocked|draft)\b|\?|\b(?:wait(?:ing)?|request(?:ing)?|seek(?:ing)?)\s+(?:for\s+)?(?:approval|sign.?off|acceptance)\b/i
7
+ const APPROVAL_PROSE_RE = /^(?:yes|true|ok(?:ay)?|approved|accepted|confirmed|signed(?:\s+off)?|done|complete(?:d)?)\b/i
8
+
9
+ function acceptanceName(value) {
10
+ const name = String(value || '').trim()
11
+ if (!name || PENDING_CELL_RE.test(name) || UNCERTAIN_ACCEPTANCE_RE.test(name) || APPROVAL_PROSE_RE.test(name.replace(/[*_`]/g, ''))) return ''
12
+ // A date, number, or punctuation cannot identify a customer-side signer.
13
+ if (!/\p{L}/u.test(name)) return ''
14
+ // Legacy cells must name a signer, not just a role plus a date. Keep names
15
+ // first: "Priya Shah, approved 2026-09-10" remains a recorded assertion.
16
+ const withoutDates = name.replace(/\b(?:jan(?:uary)?|feb(?:ruary)?|mar(?:ch)?|apr(?:il)?|may|jun(?:e)?|jul(?:y)?|aug(?:ust)?|sep(?:t(?:ember)?)?|oct(?:ober)?|nov(?:ember)?|dec(?:ember)?)\.?\s+\d{1,4}\b/gi, '')
17
+ const identity = withoutDates.replace(/\b(?:yes|true|okay|ok|approved|accepted|confirmed|signed|off|done|complete|completed|approval|acceptance)\b/gi, '').replace(/[\d\p{P}\p{S}]/gu, ' ').trim()
18
+ if (!identity || /^(?:(?:the|by|on|customer|client|sponsor|approver|owner|team|lead|manager|stakeholder|signer|signatory|ceo|cto|cfo)\s*)+$/i.test(identity)) return ''
19
+ return name
20
+ }
21
+
22
+ function valueState({ measured, accepted, acceptanceStatus, evidence }) {
23
+ if (!measured || PENDING_CELL_RE.test(measured)) return 'unmeasured'
24
+ if (!acceptanceName(accepted)) return 'claimed'
25
+ // Explicit status is authoritative when the column exists. Unknown values
26
+ // fail closed. Existing name-only ledgers remain readable during migration.
27
+ if (acceptanceStatus !== undefined) {
28
+ if (acceptanceStatus.trim().toLowerCase() !== 'accepted') return 'claimed'
29
+ if (!evidence || PENDING_CELL_RE.test(evidence)) return 'claimed'
30
+ }
31
+ return 'accepted'
32
+ }
33
+
34
+ module.exports = { PENDING_CELL_RE, acceptanceName, valueState }
@@ -91,7 +91,7 @@ fi
91
91
 
92
92
  # 5) Optional in-repo .fde (customer-approved only)
93
93
  if [ -z "$CONTEXT_FILE" ] && [ -f ".fde/context.md" ]; then
94
- ENG_DIR=".fde"
94
+ ENG_DIR="$(pwd -P)/.fde"
95
95
  CONTEXT_FILE=".fde/context.md"
96
96
  fi
97
97
 
@@ -105,72 +105,8 @@ if [ "$IS_FDE_PROJECT" -eq 0 ]; then
105
105
  exit 0
106
106
  fi
107
107
 
108
- # Mirrors stripPrivate() in bin/fde.js: this is what an agent loads as
109
- # context, so <private>...</private> blocks (sacred data, never-AI content)
110
- # must never reach here unredacted, same guarantee as the dashboard renderer.
111
- # <private> blocks are written one per line in the templates (own line, own
112
- # closing tag), so a line-based state machine matches the real usage; an
113
- # unclosed <private> redacts to end-of-file, same as the JS regex fallback.
114
- strip_private() {
115
- # Detection is case-insensitive (matches the JS /gi redactor) - <PRIVATE>,
116
- # <Private>, <private> all redact. Detect on a lowercased copy of the line;
117
- # never print the original when a tag is present.
118
- awk '
119
- BEGIN { inblock = 0 }
120
- {
121
- line = $0
122
- lc = tolower(line)
123
- if (inblock) {
124
- if (index(lc, "</private>") > 0) { inblock = 0 }
125
- next
126
- }
127
- if (index(lc, "<private>") > 0) {
128
- print "(private - redacted)"
129
- if (index(lc, "</private>") == 0) { inblock = 1 }
130
- next
131
- }
132
- print line
133
- }
134
- ' "$1"
135
- }
136
-
137
- # Token discipline: context.md grows every session (session-stop appends a
138
- # snapshot). Inject a bounded view - curated head + most recent activity -
139
- # instead of the whole log. Mirrors resumeView() in bin/fde.js; keep in sync.
140
- bounded_context() {
141
- local f="$1" total head_end tail_start hidden
142
- total=$(wc -l < "$f" 2>/dev/null | tr -d ' ')
143
- [ -z "$total" ] && { cat "$f"; return; }
144
- if [ "$total" -le 160 ]; then cat "$f"; return; fi
145
- # Anchor on the "## Session end" heading, matching resumeView() in bin/fde.js.
146
- # The JS path reads via readClean (strips HTML comments), so both sides must
147
- # anchor on a marker that survives redaction - the heading, not the comment.
148
- head_end=$(grep -n -m1 '^## Session end' "$f" 2>/dev/null | cut -d: -f1)
149
- if [ -n "$head_end" ]; then head_end=$((head_end - 1)); else head_end=120; fi
150
- [ "$head_end" -gt 120 ] && head_end=120
151
- [ "$head_end" -lt 0 ] && head_end=0
152
- tail_start=$((total - 40 + 1))
153
- if [ "$tail_start" -le "$((head_end + 1))" ]; then cat "$f"; return; fi
154
- hidden=$((tail_start - head_end - 1))
155
- [ "$head_end" -ge 1 ] && sed -n "1,${head_end}p" "$f"
156
- printf '\n_(… %s lines of earlier session log hidden - `fde resume --full` or open context.md for the full history)_\n\n' "$hidden"
157
- sed -n "${tail_start},\$p" "$f"
158
- }
159
-
160
- CONTENT=""
161
-
162
- # Lean pointer only - never cat SKILL.md. Methods load on @fde / skill trigger.
163
- CONTENT="${CONTENT}fdeops: engagement fieldbook active. Human speaks plain language with @fde - you (the agent) run the local fde CLI for memory plumbing; never ask the human to type fde commands. Load skills/fde/SKILL.md when @fde triggers.\n\n"
164
-
165
- # Same TRIAGE block as `fde resume` / `fde triage` (includes proactive hygiene
166
- # when the fieldbook has doctor issues; silent when clean). Monday morning must
167
- # not depend on the model remembering to run a CLI command. Prefer the installed
168
- # fde binary; fall back to the plugin/repo copy of bin/fde.js.
108
+ # Prefer this installation so its hook and CLI share the same safety contract.
169
109
  resolve_fde() {
170
- if command -v fde >/dev/null 2>&1; then
171
- printf '%s\n' "fde"
172
- return 0
173
- fi
174
110
  for candidate in \
175
111
  "${CLAUDE_PLUGIN_ROOT:+$CLAUDE_PLUGIN_ROOT/bin/fde.js}" \
176
112
  "$(dirname "$0")/../bin/fde.js" \
@@ -181,25 +117,23 @@ resolve_fde() {
181
117
  return 0
182
118
  fi
183
119
  done
120
+ if command -v fde >/dev/null 2>&1; then
121
+ printf '%s\n' "fde"
122
+ return 0
123
+ fi
184
124
  return 1
185
125
  }
186
126
 
187
- if [ -n "$CONTEXT_FILE" ] && [ -f "$CONTEXT_FILE" ]; then
188
- FDE_CMD=$(resolve_fde || true)
189
- if [ -n "$FDE_CMD" ]; then
190
- if [ "$FDE_CMD" = "fde" ]; then
191
- TRIAGE=$(FDEOPS_ENGAGEMENT="$ENG_DIR" fde triage 2>/dev/null || true)
192
- else
193
- TRIAGE=$(FDEOPS_ENGAGEMENT="$ENG_DIR" node "$FDE_CMD" triage 2>/dev/null || true)
194
- fi
195
- if [ -n "$TRIAGE" ]; then
196
- CONTENT="$CONTENT---\n$TRIAGE\n\n"
197
- fi
198
- fi
199
- REDACTED_CONTEXT=$(mktemp)
200
- strip_private "$CONTEXT_FILE" > "$REDACTED_CONTEXT"
201
- CONTENT="$CONTENT---\nEngagement context ($CONTEXT_FILE):\n$(bounded_context "$REDACTED_CONTEXT")\n"
202
- rm -f "$REDACTED_CONTEXT"
127
+ # The matching CLI owns triage, private redaction, and context bounds.
128
+ # Never fall back to reading raw notes when Node or the CLI is unavailable.
129
+ FDE_CMD=$(resolve_fde || true)
130
+ [ -n "$FDE_CMD" ] || exit 0
131
+ [ -n "$CONTEXT_FILE" ] && [ -f "$CONTEXT_FILE" ] || exit 0
132
+ if [ "$FDE_CMD" = "fde" ]; then
133
+ CONTEXT=$(FDEOPS_ENGAGEMENT="$ENG_DIR" fde resume 2>/dev/null) || exit 0
134
+ else
135
+ CONTEXT=$(FDEOPS_ENGAGEMENT="$ENG_DIR" node "$FDE_CMD" resume 2>/dev/null) || exit 0
203
136
  fi
204
-
205
- printf '%b' "$CONTENT"
137
+ [ -n "$CONTEXT" ] || exit 0
138
+ printf '%s\n\n' 'fdeops: engagement fieldbook active. Human speaks plain language with @fde - you (the agent) run the local fde CLI for memory plumbing; never ask the human to type fde commands. Load skills/fde/SKILL.md when @fde triggers.'
139
+ printf '%s\n' 'Engagement context:' "$CONTEXT"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fdeops-ingest-mcp",
3
- "version": "3.23.0",
3
+ "version": "3.26.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.23.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.",
3
+ "version": "3.26.0",
4
+ "description": "Client delivery tools for Forward Deployed Engineers. One @fde skill, local Markdown engagement records, and an offline dashboard for decisions, evidence, approvals, and next actions.",
5
5
  "bin": {
6
6
  "fdeops": "bin/install.js",
7
7
  "fde": "bin/fde.js"
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
3
  "name": "fdeops",
4
- "version": "3.23.0",
4
+ "version": "3.26.0",
5
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",
@@ -28,7 +28,7 @@ A one-line typo or compile error in a file that will not ship. On a bound client
28
28
  | **When did we agree?** | Don't argue from memory. Search the record. | `fde receipts <term>` | - |
29
29
  | **What's the outcome?** | A number nobody signed is claimed, not delivered. | `fde status` | `references/readout.md` |
30
30
 
31
- After a meeting: `fde debrief --smart` → one REVIEW screen (decided / asked / open / next / signer) → confirm once → `--apply`. Walk-in: `fde prep`. Friday: `fde status`.
31
+ After a meeting: `fde debrief --smart` → one REVIEW screen (decided / asked / open / next / signer) → in chat, a four-row card (omit empty; Previously / Not yet agreed) → **Save this update?** (engineer accepted the record, not customer approval of every ask) → `--apply`. Walk-in: `fde prep`. Friday: `fde status`.
32
32
 
33
33
  ## Ground loop
34
34
 
@@ -44,6 +44,10 @@ A throwaway file can skip the loop. Bound client work cannot.
44
44
 
45
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
46
 
47
+ ## Working with an engineering pack
48
+
49
+ Use the customer's existing coding, testing, review, and repository instructions for implementation. Carry the confirmed outcome, scope boundary, acceptance criteria, and evidence requirements into that workflow. Reference its existing plan from `decisions.md`; do not create a competing backlog or repeat questions already answered. FDEOps owns the engagement record and acceptance status. A coding pack's green tests do not establish customer acceptance. Never claim compatibility was tested with a host or pack you have not run.
50
+
47
51
  ## Human surface vs agent plumbing
48
52
 
49
53
  **FDE (human):** `@fde` + English, or `/brief` `/discover` `/plan` `/ship` `/outcome` `/close` `/debrief` `/prep` `/trust` `/receipts` `/readout`. Never a skill catalog.
@@ -54,7 +58,7 @@ Fallbacks: `node ~/.claude/fdeops/fde.js …`, then `npx --yes fdeops …`. Skil
54
58
 
55
59
  ## Entry (every session)
56
60
 
57
- 1. `fde resume` (bounded `context.md`). `--full` only if you need the whole log.
61
+ 1. `fde resume` (16 KiB output ceiling, not a model token count). Read the goals, risks and current context. If truncated or a decision needs evidence, run `fde recall <specific topic>`; narrow the query rather than loading the whole history. `--max-bytes 4096` reduces the allowance for smaller models. `--full` only when the complete log is explicitly needed.
58
62
  2. **NO ENGAGEMENT:** ask "What should we call this client?" then **you** init. Pasted notes → debrief after bind.
59
63
  3. Playback 2-3 lines. `hygiene:` → offer `fde doctor`; **never auto-rewrite**.
60
64
  4. Route. Read **one** `references/*.md`. Confirm, then write.
@@ -65,12 +69,12 @@ Writes need a bind (`FDEOPS_ENGAGEMENT` or registry). Never install fdeops on in
65
69
  |----------|---------|
66
70
  | where are we | `fde resume` |
67
71
  | day-1 look at the repo | `fde scan` |
68
- | debrief / pasted notes | `fde debrief --smart` → REVIEW → confirm once → `--apply`. `--smart` is a gate, not a brain. `references/debrief.md` |
72
+ | debrief / pasted notes | `fde debrief --smart` → REVIEW → four-row chat card → Save this update? → `--apply`. `--smart` is a gate, not a brain. `references/debrief.md` |
69
73
  | prep me for … | `fde prep "<label>"` |
70
74
  | when did we agree | `fde receipts <term>` |
71
75
  | sponsor update / the outcome | `fde status` |
72
76
  | they went quiet | `fde log contact "…" --signal amber\|green\|red` |
73
- | fieldbook page | `fde dashboard` |
77
+ | fieldbook page | `fde dashboard` (`--all` portfolio, `--open` to open the file) |
74
78
  | clean up the fieldbook | `fde doctor` - never auto-rewrite |
75
79
  | scrub a secret | `fde redact <term>` then `--apply` after confirm |
76
80
  | pull Granola/Slack/transcript | capability check → `fde ingest stage` → confirm → apply. Never auto-apply. `references/ingest.md` |
@@ -140,7 +144,7 @@ Work names (engage, diagnose, align, deliver, realize, transfer) are the same ma
140
144
 
141
145
  | You hear | Skill | Reference |
142
146
  |----------|-------|-----------|
143
- | Align, break this down, what order, sequence the build, plan the roadmap, create user stories, write the tasks | plan | `references/plan.md` |
147
+ | Align, break this down, what order, sequence the delivery, align the plan | plan | `references/plan.md` |
144
148
  | Sponsor needs justification, need to defend budget or timeline, build the business case | business-case | `references/business-case.md` |
145
149
  | 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` |
146
150
  | 20 things are "urgent," need to pick the 3 that matter, prioritize three | pick-three | `references/pick-three.md` |
@@ -154,7 +158,7 @@ Work names (engage, diagnose, align, deliver, realize, transfer) are the same ma
154
158
  | Deliver, start building, update their checkout, first module, visible progress, their tests, POC follow-through, ready to deploy, going live, pre-flight, deliver the increment, build the increment, create the launch plan, design their UI | ship | `references/ship.md` |
155
159
  | Review this change, review the pull request, is it safe, does it match what we agreed | review | `references/review.md` |
156
160
  | Diff grew / scope creep in the PR / "did we only build what we said" / KEEP JUSTIFY SPLIT DROP | review (+ ship if going live) | `references/review.md` Stage 1 · `references/ship.md` Intent vs diff |
157
- | Wrap the session / share the thinking / catch teammates up / before I open the PR | (memory contract - session digest) | SKILL.md **On exit** - write TL;DR + decisions/why into `.fde/`; no transcript sync |
161
+ | Wrap the session / share the thinking / catch teammates up / before I open the PR | (memory contract - session digest) | SKILL.md **Session digest** - write TL;DR + decisions/why into `.fde/`; no transcript sync |
158
162
  | "We can always revert" - need to actually test the escape route, rehearse rollback | rollback | `references/rollback.md` |
159
163
 
160
164
  ### Outcome
@@ -4,11 +4,11 @@
4
4
 
5
5
  **Read per engagement:** `reality.md`, `brief.md`, `success.md`, `risks.md`, `decisions.md`, `delivery.md`, `stakeholders.md`. Never `terrain.md` (too large) or `trust-profile.md` (sensitive - stakeholder signals live in `stakeholders.md`).
6
6
 
7
- The visual artifact is rendered by code, not by you. `fde dashboard` reads every `.fde/` folder and writes a self-contained `fieldbook.html` - deterministically, offline, **at zero token cost**. Your job is the judgment the render can't do: which engagement gets tomorrow morning, and why.
7
+ The visual artifact is rendered by code, not by you. Bare `fde dashboard` renders the **bound** engagement into `fieldbook-current.html`. Pass `--all` for every engagement (default file `~/fde-engagements/fieldbook.html`). Deterministic, offline, **at zero token cost**. Your job is the judgment the render can't do: which engagement gets tomorrow morning, and why.
8
8
 
9
9
  ## Method (you do this work)
10
10
 
11
- 0. **First move: `fde status`** - instant heuristic triage (trust-first ordering) across every engagement. Use it as the index; then deep-read only the folders that are red/amber or that the FDE asks about, and apply the full card below.
11
+ 0. **First move: `fde status`** - value ledger, then trust, for the bound engagement. Pass `--all` for the portfolio. Use it as the index; then deep-read only the folders that are red/amber/`new` or that the FDE asks about, and apply the full card below.
12
12
  1. **Find the engagements:** `~/fde-engagements/*/.fde/` (primary) · workspace `./.fde/` if present · paths the FDE names. Read each folder **separately** - never merge two customers.
13
13
  2. **Per engagement, read the card the way a human would:**
14
14
  - Name, phase, week
@@ -17,15 +17,15 @@ The visual artifact is rendered by code, not by you. `fde dashboard` reads every
17
17
  - Top active risk
18
18
  - Last significant action + next step
19
19
  - Value delivered so far
20
- - **Trust signal** - the most important row: **green** (no adverse signals) / **amber** (a stakeholder gone quiet or routing around the FDE) / **red** (escalation or explicit concern). Technical progress on a red-trust engagement is wasted until trust is addressed.
20
+ - **Trust signal** - the most important row: **new** (no dated `[signal:]` token - empty is not green) / **green** (someone was asked, and the latest token for that person is green) / **amber** (a stakeholder gone quiet or routing around the FDE) / **red** (escalation or explicit concern). Technical progress on a red-trust engagement is wasted until trust is addressed.
21
21
  3. **Triage order:** red trust first, then overdue risks, then stalled delivery. Say which engagement gets tomorrow morning and why.
22
- 4. **Refresh the visual:** run `fde dashboard` to (re)generate `fieldbook.html` (defaults to `~/fde-engagements/fieldbook.html`). It is a deterministic render of the `.fde/` markdown - never hand-write HTML, never paste a model-built page. The session-end hook also refreshes it automatically when an engagement moved, so it is current next time the FDE opens it.
22
+ 4. **Refresh the visual:** run `fde dashboard` (add `--all` for the portfolio, `--open` to open the file). Default output is `fieldbook-current.html` for the bound client. It is a deterministic render of the `.fde/` markdown - never hand-write HTML, never paste a model-built page. The session-end hook also refreshes the bound fieldbook when an engagement moved.
23
23
 
24
24
  Sparse data: the render shows what exists and pads nothing. An empty field honestly shows what hasn't been captured.
25
25
 
26
26
  ## Artifact
27
27
 
28
- **`fieldbook.html`** - generated by `fde dashboard`, never hand-maintained. One file, opens in a browser, works offline, `<private>` notes redacted. Portfolio grid on top (a card per client: trust, phase, next action, top risk); click a card to drill into that engagement's full memory below.
28
+ **`fieldbook-current.html`** (bound) or **`fieldbook.html`** (`--all`) - generated by `fde dashboard`, never hand-maintained. Opens in a browser, works offline, `<private>` notes redacted. Today plus a left rail of engagements; not a card grid.
29
29
 
30
30
  ## Checkpoint
31
31
 
@@ -31,8 +31,14 @@
31
31
  - `next: send one-pager before Thursday 9am`
32
32
  - unprefixed lines stay context color only
33
33
  4. Show the **REVIEW** block first (decided / asked / open / next / signer). That is the one screen to confirm. File routing stays underneath.
34
- 5. On FDE confirm → run `fde debrief --apply`.
35
- 6. On reject → stop; ask what to change; do not apply.
34
+ 5. In **chat**, after that REVIEW, present a four-row card and omit empty rows:
35
+ - Decided
36
+ - Asked / open
37
+ - Next
38
+ - Signer
39
+ Then a **Previously:** line from the record, and **Not yet agreed** for anything still proposed. Ask **Save this update?** Saving means the engineer accepted this as the engagement record, not that the customer approved every ask. Uncertainty stays visible.
40
+ 6. On FDE confirm → run `fde debrief --apply`.
41
+ 7. On reject → stop; ask what to change; do not apply. Do not rebuild or replace the CLI REVIEW engine.
36
42
 
37
43
  No invented names or quotes. If the propose looks wrong, fix prefixes with judgment then re-apply or use the fallback path.
38
44
 
@@ -47,8 +53,8 @@ If `--smart` is unavailable or you already have clean prefixes:
47
53
  - **Risks** - new / confirmed / retired
48
54
  - **Open questions** - what to chase next
49
55
  2. Format lines as `decision:` / `risk:` / `delivery:` / `contact:` / `next:` / `signer:` (contacts may end with `[signal:green|amber|red]`).
50
- 3. Show that structured version to the FDE for confirmation.
51
- 4. Pipe to `fde debrief` (or write a file and run it).
56
+ 3. Show the same **chat card** as the smart path (omit empty rows; Previously; Not yet agreed; **Save this update?**). Do not invent a second confirm surface.
57
+ 4. On confirm, pipe to `fde debrief` (or write a file and run it).
52
58
 
53
59
  One clarifying question max if the dump is ambiguous - then write. Never stall capture on completeness.
54
60
 
@@ -18,6 +18,8 @@ Then check - probe ONLY if it prevents wasted discovery:
18
18
 
19
19
  State your read, let the FDE correct, then discover.
20
20
 
21
+ Before asking for facts, inspect the supplied brief and existing redacted records for the answer. Once the decision frame is confirmed and code access is authorized, use the scan below and targeted file reads to resolve technical unknowns. Phrase remaining questions around the discrepancy found: “The queue already exists, but alerts are disabled; who currently checks it?”
22
+
21
23
  ## Brief interrogation (when the hypothesis is still mush)
22
24
 
23
25
  Use when the "problem" is unfalsifiable, success is undefined, or you cannot name the decision discovery informs. Skip when `reality.md` / `terrain.md` already pin a testable claim and the FDE is ready to dig.
@@ -66,7 +68,7 @@ Do not mark pieces as facts or assumptions here. That is `test-assumptions`. Do
66
68
 
67
69
  ## Method - part 1: the codebase (you do this work)
68
70
 
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.
71
+ **First code move: `fde scan`** - after the Question is locked. 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.
70
72
 
71
73
  If the CLI is unavailable, run the manual commands below. Either way: do not load the full codebase into context - scan wide, read deep only on hotspots.
72
74
 
@@ -106,6 +108,8 @@ Flag every one. AI components don't fail like regular code - they degrade as the
106
108
 
107
109
  **6. Data flow.** Where data enters, how it moves, where it stops. Entry points first: routes, queues, cron, file drops.
108
110
 
111
+ **7. Existing capability.** Trace the requested user action through existing code, configuration, tests, and operating workarounds. In `terrain.md`, record what can already be reused and the evidence that it works or fails. Check whether a configuration, ownership, or process change could resolve the observed break. A disabled feature is a lead, not a proven root cause. Keep observations and hypotheses distinct; option selection still belongs to plan / three-options.
112
+
109
113
  ## Method - part 2: the humans (you coach, the FDE asks)
110
114
 
111
115
  The real spec is what people **do** when the system fails - not what the slide deck says. Arm the FDE with these, in their own words:
@@ -25,7 +25,7 @@ Level 5: Trusted → they call you before making decisions
25
25
 
26
26
  | Day | Move | Why it works |
27
27
  |-----|------|-------------|
28
- | 1 | Fix a small, visible, annoying bug - something the team has been stepping over | Proves you can ship in their environment without breaking things |
28
+ | 1 | Fix a small, visible, annoying bug - something the team has been stepping over (only after `success.md` has a signer, or the FDE overrides with the unknown still visible) | Proves you can ship in their environment without breaking things |
29
29
  | 1 | Ask the passed-over team what naming conventions they use - then use them | Shows respect before competence |
30
30
  | 2 | Send a one-paragraph status to the sponsor without being asked | Sets the pattern: they hear from you before they have to ask |
31
31
  | 3 | Find a genuine risk and flag it without drama | Demonstrates you're protecting them, not performing |
@@ -32,7 +32,7 @@ List what you can actually call **this session**:
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
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
- 7. **Show** the proposed routing in plain language. Wait for confirm.
35
+ 7. **Show** the same chat card as debrief (decided / asked / open / next / signer; omit empty; Previously; Not yet agreed; **Save this update?**). Wait for confirm. The CLI REVIEW printout is unchanged.
36
36
  8. **Apply** - on FDE confirm only → `fde ingest apply` (= `fde debrief --apply`). On reject → stop; ask what to change.
37
37
 
38
38
  No invented names, meetings, or quotes. If the propose looks wrong, fix prefixes with judgment, then re-show before apply.
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Enter when:** new customer, first meeting, just got the brief, nothing started yet.
4
4
 
5
- **Read first:** `context.md` if it exists. Nothing else until you know what kind of engagement this is.
5
+ **Read first:** `context.md` if it exists, then the supplied brief. Once the engagement type and AI/access policy are known, inspect the supplied repo/docs relevant to the ask before asking questions they can answer. This is a bounded evidence check, not a full discovery scan.
6
6
 
7
7
  ## Validation gate (confirm understanding, clarify where it elevates)
8
8
 
@@ -35,7 +35,7 @@ Wait for the reaction before the next question. Stop when confidence is high eno
35
35
 
36
36
  ## Method - part 1: interrogate the brief (you do this work)
37
37
 
38
- Read the brief the FDE gives you. What is **not** in it matters as much as what is. Produce the gap list yourself:
38
+ Read the brief the FDE gives you. Separate **observed** (source/path and date), **reported** (who said it), and **hypothesis** (how to test it). A requested solution such as “build an agent” is not evidence of the cause. Ask only about gaps that change scope, access, acceptance, or the next investigation. What is **not** in the brief matters as much as what is. Produce the gap list yourself:
39
39
 
40
40
  - **No named decision-maker** → the FDE will spend two weeks building for someone who can't say yes. Flag it.
41
41
  - **"Straightforward cleanup" on an 8-year-old system** → the previous attempt is still visible in git history as a revert. Flag it.
@@ -52,7 +52,7 @@ Pre-arrival checks to run through with the FDE:
52
52
 
53
53
  ## Method - part 2: the first conversation (you coach, the FDE asks)
54
54
 
55
- Intent: before any tech, learn what keeps the sponsor up at night - personally, not the project charter. Failure talk surfaces truth faster than "requirements." Angles in the FDE's own words:
55
+ Intent: coach the FDE's first *customer* conversation - what keeps the sponsor up at night, personally, not the project charter. You already inspected the supplied brief and any authorized repo/docs. This is before *their* laptop in the room / before a deep build, not before you read evidence. Failure talk surfaces truth faster than "requirements." Angles in the FDE's own words:
56
56
 
57
57
  - "Before you open the laptop - what would make this a bad engagement for *them*, not just a delayed project?"
58
58
  - "What are they afraid you'll miss?"
@@ -71,13 +71,13 @@ Let silence sit. If their fear doesn't match the written brief, the brief is wro
71
71
 
72
72
  ## The day 1 deliverable
73
73
 
74
- Before the end of day 1, ship one visible thing: a small bug fix, a cleanup the team has stepped over, a dashboard tweak, a config improvement. Not because it matters technically - because it proves you can ship in their environment without breaking things. The first deploy sets the trust trajectory for the entire engagement. A day-1 deliverable earns more credibility than a week-3 architecture deck.
74
+ After `success.md` names a signer (or the FDE explicitly overrides with `unknown - ask:` still visible), ship one visible thing before the end of day 1: a small bug fix, a cleanup the team has stepped over, a dashboard tweak, a config improvement. Not because it matters technically - because it proves you can ship in their environment without breaking things. The first deploy sets the trust trajectory for the entire engagement. A day-1 deliverable earns more credibility than a week-3 architecture deck. Skip it until the land gate is met.
75
75
 
76
76
  ## Artifact (write as the conversation is debriefed)
77
77
 
78
78
  **`brief.md`** - what they said, who sent the FDE, the timeline, **and the gap list**.
79
79
 
80
- **`success.md`** - what done looks like, **primary value bucket** (`cost-save` | `risk-mitigation` | `revenue-uplift`), baseline → target, who actually signs off, what is explicitly out of scope. Agreed with the customer, not assumed.
80
+ **`success.md`** - what done looks like, **primary value bucket** (`cost-save` | `risk-mitigation` | `revenue-uplift`), baseline → target, who actually signs off, what is explicitly out of scope. Record agreement only with its source and scope; otherwise label the target proposed. For each baseline, record source, date/window, environment, and sample size when relevant. An operator recollection is reported, not measured. If no baseline exists, name the measurement owner and cheapest way to obtain it; do not manufacture a number.
81
81
 
82
82
  For every target number, run the **gaming check** before it is written down: *how could this metric hit its target without the customer being any better off?* There is always an answer, and the answer is what the org will drift toward under pressure. Write the guard next to the metric:
83
83
 
@@ -113,7 +113,7 @@ One falsifiable hypothesis about the real problem also goes at the bottom of `br
113
113
 
114
114
  One page back to the FDE: success + value bucket + sign-off owner, out-of-scope boundary, sacred data, stakeholder map with veto power, AI posture, the hypothesis, the top CRITICAL assumptions still OPEN, and any exception-path seeds heard (break → workaround → owner) for discover to map into `terrain.md`. If it doesn't fit one page, the engagement isn't understood yet.
115
115
 
116
- If remote: trust-building takes ~40% longer - push for a short video call before anything asynchronous.
116
+ If remote: agree how progress and blockers will be shared; use a short call when asynchronous context is insufficient.
117
117
 
118
118
  ## Worked example
119
119
 
@@ -61,7 +61,7 @@ Notice: every stakeholder's initiative is P0 or P1. That's the problem this skil
61
61
 
62
62
  ## Artifact
63
63
 
64
- **`decisions.md`** - the triage table with scores, lanes, **and an explicit Kill / Later commitment**. Dated. Referenced by plan and status.
64
+ **`decisions.md`** - the triage table with scores, lanes, **and an explicit Kill / Later commitment**. Dated. Updates the same Now/Next/Later plan already uses; do not open a second plan section. Referenced by plan and status.
65
65
 
66
66
  Required closing block (plan will not treat triage as done without it):
67
67
 
@@ -24,6 +24,8 @@ An FDE plan is not a sprint backlog. The technical sequence is the easy part. Th
24
24
 
25
25
  **0. Lock scope first.** Read `success.md`, `assumptions.md`, and the **Question** on `reality.md`. If out-of-scope is undefined, define it now with the FDE - a plan on undefined scope accumulates silent commitments. If any CRITICAL assumption is still `OPEN`, stop and run test-assumptions / discover before sequencing work. If `reality.md` has no Question, stop and finish discover - you are sequencing trivia.
26
26
 
27
+ **Reuse check.** Before sequencing a build, compare the requested solution with the smallest existing capability or operating change that could satisfy the same acceptance test. Cite the relevant repo/config/workaround evidence. Record why reuse is sufficient or insufficient in `decisions.md`; include “no new code” when supported. A request for AI does not establish that a model is needed. If a host engineering pack already has an approved implementation plan, reference it from `decisions.md`; do not generate a parallel user-story backlog.
28
+
27
29
  **1. Work backwards from success.** What's the last thing that must be true before done? And before that? That's the dependency chain - not a wish list.
28
30
 
29
31
  **2. Front-load the fragile.** Check `terrain.md` hotspots. Risky modules go early - fail fast, not in week three.
@@ -57,6 +59,10 @@ Risk: <what could go wrong + fallback>
57
59
  Kill if: <the observation that voids this slice - copy from assumptions.md How we test, or the check that means stop>
58
60
  Verify: <specific check>
59
61
  Value promised: <business unit change this slice claims>
62
+ Baseline: <value + source/date/window/environment, or pending + measurement owner>
63
+ Acceptance owner: <name + authority source, or unknown - ask: who can accept?>
64
+ Evidence to collect: <before/after check, sample/window, environment, and receipt location>
65
+ Reuse: <existing capability used, or evidence it cannot satisfy the criteria>
60
66
 
61
67
  ### Next
62
68
  - ...
@@ -70,6 +76,8 @@ Value promised: <business unit change this slice claims>
70
76
  | <rewrite / nice-to-have / political ask> | <evidence> | <name, date> |
71
77
  ```
72
78
 
79
+ In `Who accepted`, distinguish a proposed deferral from an agreement: use `pending` until a named person accepted this scope with a dated source. Sponsorship alone is not approval of every plan detail.
80
+
73
81
  No kill list → not a finished plan. Reopen with the FDE until the deferrals are written.
74
82
  ## Checkpoint
75
83
 
@@ -12,7 +12,7 @@ A green check on synthetic data is not a validated solution. The person who can
12
12
 
13
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.
14
14
 
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.
15
+ **1. Pick by score when several use cases compete.** Use the scoring model from `discover.md` - (Value × Data readiness) / Complexity. If discover or score-use-cases already produced a ranking, reuse it; never invent a third ranking.
16
16
 
17
17
  **2. Build the minimum that tests the assumption.** No error handling, no polish. Same-day demo if possible. Rough is honest. The POC is done when the person who can say no has seen it and reacted, not when the code looks finished.
18
18
 
@@ -6,7 +6,9 @@
6
6
 
7
7
  ## Method (you do this work)
8
8
 
9
- **First:** run `fde status`. It prints the value ledger before trust - promised → measured → accepted by, or `claimed, not yet accepted`. Those lines are the Situation. Do not invent a number the CLI did not print.
9
+ **First:** run `fde status`. It prints the value ledger before trust - promised → measured → accepted by, or `claimed, not yet accepted`. Those lines locate the Situation; check their cited records before making the claim. CLI output summarizes recorded text, not independently verified acceptance. Do not invent a number the CLI did not print. If the CLI is unavailable, use the redacted source records and say so.
10
+
11
+ **Qualify the evidence before drafting.** For each result, identify baseline source, measurement environment, observation window/sample, and the scope of acceptance. Report an informal baseline as reported and a staging sample as staging; neither establishes realized savings. “Looks good” without what was accepted is not outcome acceptance. Attribute an engineer's note as such; do not turn it into a direct customer receipt. If evidence conflicts, include the conflict and the next verification action rather than choosing the flattering version.
10
12
 
11
13
  **Always draft in SCQA.** One page maximum. No other shape.
12
14
 
@@ -23,7 +25,7 @@ Then add, still on the same page:
23
25
  3. **Kill / defer reminder** - one line from the plan kill list so scope fights stay visible.
24
26
  4. **Hostile Q prep** - three questions a skeptical sponsor will ask, with one-line answers from memory.
25
27
 
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.
28
+ Exec voice: no jargon, explicit uncertainty where evidence is incomplete, every claim traceable (`(shipped Tue, delivery.md)`). Draft in the **FDE's voice, for the FDE to send** - never send anything yourself.
27
29
 
28
30
  For board / renewal / sponsor's boss (longer pyramid): use `board-memo.md`. Do not invent a second weekly format.
29
31
 
@@ -59,7 +59,7 @@ Five dimensions, line-specific ("line 47 fails under concurrent writes - no lock
59
59
 
60
60
  ## Before the PR - thinking for the next reader
61
61
 
62
- Code alone loses the "why." Before you call the change reviewable, run the **session digest** from the memory contract (SKILL.md On exit): TL;DR, key decisions & rationale, scope + how you verified, gotchas. Confirm with the FDE, then write into `.fde/` - `decisions.md` / `delivery.md` / `context.md`. Reviewers (or Monday-you) should answer "why this approach?" from the fieldbook, not from a chat transcript. Do **not** dump agent logs into the product repo.
62
+ Code alone loses the "why." Before you call the change reviewable, run the **session digest** from the memory contract (SKILL.md Session digest): TL;DR, key decisions & rationale, scope + how you verified, gotchas. Confirm with the FDE, then write into `.fde/` - `decisions.md` / `delivery.md` / `context.md`. Reviewers (or Monday-you) should answer "why this approach?" from the fieldbook, not from a chat transcript. Do **not** dump agent logs into the product repo.
63
63
 
64
64
  ## Artifact
65
65
 
@@ -10,7 +10,7 @@ The most dangerous moment in a multi-use-case engagement is when the technically
10
10
 
11
11
  **1. List every candidate.** From the brief, from discovery conversations, from the FDE's own observations. Include the ones the customer hasn't said aloud but the codebase implies - a high-churn module with no tests is a candidate even if nobody named it.
12
12
 
13
- **2. Score on five dimensions.** Each 1-5, with the scoring rubric below:
13
+ **2. Score on five dimensions.** Each 1-5, with the scoring rubric below. If discover already ranked candidates with (Value × Data readiness) / Complexity, reuse that order; this table extends the conversation. Do not invent dimension scores from a thin brief - write `unknown` and ask.
14
14
 
15
15
  | Dimension | 1 | 3 | 5 |
16
16
  |-----------|---|---|---|