fdeops 4.1.0 → 4.1.1

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.
@@ -2,6 +2,7 @@
2
2
  // Generated packages are independent installations, not independently authored methods.
3
3
  const fs = require('node:fs')
4
4
  const path = require('node:path')
5
+ const { createHash } = require('node:crypto')
5
6
  const catalog = require('./skill-catalog')
6
7
  const root = path.resolve(__dirname, '..')
7
8
  const source = path.join(root, 'skills/fde/references')
@@ -38,31 +39,103 @@ function expectedFiles(item, referenceRoot = source) {
38
39
  for (const ref of referencesFor(item.method, referenceRoot)) files.set(`references/${ref}`, fs.readFileSync(path.join(referenceRoot, ref), 'utf8'))
39
40
  return files
40
41
  }
42
+ const marker = '<!-- Generated by bin/generate-skills.js; edit the canonical references and catalog. -->'
43
+ const manifestName = '.fde-generated.json'
44
+ const digest = body => createHash('sha256').update(body).digest('hex')
45
+ const stat = file => {
46
+ try { return fs.lstatSync(file) } catch (error) { if (error.code === 'ENOENT') return null; throw error }
47
+ }
41
48
  function walk(dir, prefix = '') {
42
- if (!fs.existsSync(dir)) return []
43
- return fs.readdirSync(dir, { withFileTypes: true }).flatMap(e => {
44
- if (e.isSymbolicLink()) throw new Error(`Unexpected symlink: ${path.join(dir, e.name)}`)
49
+ const entries = []
50
+ for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
45
51
  const rel = prefix + e.name
46
- return e.isDirectory() ? walk(path.join(dir, e.name), rel + '/') : [rel]
47
- })
52
+ if (e.isSymbolicLink() || (!e.isDirectory() && !e.isFile()) || (e.isFile() && fs.lstatSync(path.join(dir, e.name)).nlink > 1)) throw new Error(`Unsafe generated path: ${path.join(dir, e.name)}`)
53
+ if (e.isDirectory()) {
54
+ if (rel !== 'references') throw new Error(`Unowned generated directory: ${path.join(dir, e.name)}`)
55
+ entries.push(...walk(path.join(dir, e.name), rel + '/'))
56
+ } else entries.push(rel)
57
+ }
58
+ return entries
48
59
  }
49
- function generate(check = false) {
60
+ function generate(check = false, options = {}) {
61
+ const skillRoot = path.join(options.root || root, 'skills')
62
+ const referenceRoot = options.referenceRoot || source
63
+ const items = options.catalog || catalog
64
+ const wanted = new Map()
65
+ for (const item of items) {
66
+ if (!/^fde-[a-z-]+$/.test(item.name) || wanted.has(item.name)) throw new Error(`Invalid generated skill name: ${item.name}`)
67
+ wanted.set(item.name, expectedFiles(item, referenceRoot))
68
+ }
69
+ const rootStat = stat(skillRoot)
70
+ if (rootStat && (!rootStat.isDirectory() || rootStat.isSymbolicLink())) throw new Error(`Unsafe skills root: ${skillRoot}`)
71
+ const names = new Set([...wanted.keys(), ...(rootStat ? fs.readdirSync(skillRoot).filter(n => /^fde-[a-z-]+$/.test(n)) : [])])
50
72
  const errors = []
51
- for (const item of catalog) {
52
- const dest = path.join(root, 'skills', item.name)
53
- const expected = expectedFiles(item)
54
- for (const rel of walk(dest)) if (!expected.has(rel)) errors.push(`Unexpected generated file: ${item.name}/${rel}`)
55
- for (const [rel, body] of expected) {
56
- const target = path.join(dest, rel)
57
- if (check) {
58
- if (!fs.existsSync(target) || fs.readFileSync(target, 'utf8') !== body) errors.push(`Stale generated skill: ${item.name}/${rel}`)
73
+ const plans = []
74
+ for (const name of names) {
75
+ const dest = path.join(skillRoot, name)
76
+ const expected = wanted.get(name) || new Map()
77
+ const destStat = stat(dest)
78
+ let owned = {}
79
+ let actual = []
80
+ if (destStat) {
81
+ if (!destStat.isDirectory() || destStat.isSymbolicLink()) {
82
+ if (wanted.has(name)) throw new Error(`Unsafe generated path: ${dest}`)
83
+ continue
84
+ }
85
+ const entry = path.join(dest, 'SKILL.md')
86
+ const entryStat = stat(entry)
87
+ const isGenerated = entryStat && entryStat.isFile() && fs.readFileSync(entry, 'utf8').includes(marker)
88
+ if (!isGenerated) {
89
+ if (wanted.has(name) || stat(path.join(dest, manifestName))) throw new Error(`Unowned skill: ${name}`)
90
+ continue
91
+ }
92
+ actual = walk(dest)
93
+ if (actual.includes(manifestName)) {
94
+ const manifest = JSON.parse(fs.readFileSync(path.join(dest, manifestName), 'utf8'))
95
+ if (manifest.generator !== 'bin/generate-skills.js' || manifest.version !== 1 || !manifest.files || Array.isArray(manifest.files) || typeof manifest.files !== 'object') throw new Error(`Invalid ownership manifest: ${name}`)
96
+ owned = manifest.files
97
+ for (const [rel, hash] of Object.entries(owned)) {
98
+ if (!/^(?:SKILL\.md|references\/[a-z][a-z-]*\.md)$/.test(rel) || !/^[a-f0-9]{64}$/.test(hash)) throw new Error(`Invalid ownership entry: ${name}/${rel}`)
99
+ }
59
100
  } else {
60
- fs.mkdirSync(path.dirname(target), { recursive: true })
61
- fs.writeFileSync(target, body)
101
+ // Migrate 4.1.0 packages conservatively: only the marked entry and exact
102
+ // canonical copies are known to belong to the generator.
103
+ for (const rel of actual) {
104
+ const body = fs.readFileSync(path.join(dest, rel))
105
+ const canonical = path.join(referenceRoot, path.basename(rel))
106
+ if (rel === 'SKILL.md' || (/^references\/[a-z][a-z-]*\.md$/.test(rel) && stat(canonical)?.isFile() && body.equals(fs.readFileSync(canonical)))) owned[rel] = digest(body)
107
+ }
108
+ }
109
+ for (const rel of actual.filter(rel => rel !== manifestName)) {
110
+ if (!Object.hasOwn(owned, rel)) throw new Error(`Unowned generated file: ${name}/${rel}`)
111
+ if (!expected.has(rel) && digest(fs.readFileSync(path.join(dest, rel))) !== owned[rel]) throw new Error(`Modified obsolete generated file: ${name}/${rel}`)
62
112
  }
63
113
  }
114
+ const output = new Map(expected)
115
+ if (wanted.has(name)) output.set(manifestName, JSON.stringify({ generator: 'bin/generate-skills.js', version: 1, files: Object.fromEntries([...expected].map(([rel, body]) => [rel, digest(body)])) }, null, 2) + '\n')
116
+ for (const rel of actual) if (!output.has(rel)) errors.push(`Obsolete generated file: ${name}/${rel}`)
117
+ for (const [rel, body] of output) {
118
+ if (!actual.includes(rel) || fs.readFileSync(path.join(dest, rel), 'utf8') !== body) errors.push(`Stale generated skill: ${name}/${rel}`)
119
+ }
120
+ plans.push({ dest, actual, output })
121
+ }
122
+ if (check) {
123
+ if (errors.length) throw new Error(errors.join('\n'))
124
+ return
125
+ }
126
+ // All ownership and path checks finish before any package is changed.
127
+ for (const { dest, actual, output } of plans) {
128
+ for (const rel of actual) if (!output.has(rel)) fs.unlinkSync(path.join(dest, rel))
129
+ for (const [rel, body] of output) {
130
+ fs.mkdirSync(path.dirname(path.join(dest, rel)), { recursive: true })
131
+ fs.writeFileSync(path.join(dest, rel), body)
132
+ }
133
+ if (!output.size) {
134
+ const refs = path.join(dest, 'references')
135
+ if (stat(refs)) fs.rmdirSync(refs)
136
+ fs.rmdirSync(dest)
137
+ }
64
138
  }
65
- if (errors.length) throw new Error(errors.join('\n'))
66
139
  }
67
140
  module.exports = { referencesFor, expectedFiles, generate }
68
141
  if (require.main === module) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fdeops-ingest-mcp",
3
- "version": "4.1.0",
3
+ "version": "4.1.1",
4
4
  "private": true,
5
5
  "description": "Thin stdio MCP sink for FDEOps ingest (stage \u2192 propose \u2192 apply). Zero runtime dependencies.",
6
6
  "bin": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fdeops",
3
- "version": "4.1.0",
3
+ "version": "4.1.1",
4
4
  "description": "Forward deployed engineering skills for AI coding agents. Use focused task skills or @fde for discovery, implementation, verification and handoff, with local engagement records.",
5
5
  "bin": {
6
6
  "fdeops": "bin/install.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": "4.1.0",
4
+ "version": "4.1.1",
5
5
  "description": "Forward deployed engineering skills for AI coding agents. Use focused task skills or @fde for discovery, implementation, verification and handoff, with local engagement records.",
6
6
  "author": {
7
7
  "name": "Subash Natarajan",
@@ -4,7 +4,7 @@
4
4
 
5
5
  **Enter when:** the engagement is ending - the customer team must run this without the FDE.
6
6
 
7
- **Read first:** bounded `fde handoff` or `fde resume`, then targeted `fde recall` for missing evidence. Build the full picture through relevant excerpts, not a full-directory load. Consult `terrain.md` only for the code paths needed by the successor.
7
+ **Read first:** for standalone work, use the supplied permitted operating notes, evidence and ownership; no engagement binding or CLI command is required. For a bound engagement, use bounded `fde handoff` or `fde resume`, then targeted `fde recall` for missing evidence. Never initialize records merely to draft a handoff. Build the picture through relevant excerpts, not a full-directory load. Consult `terrain.md` only for code paths needed by the successor.
8
8
 
9
9
  The engagement doesn't end at ship. It ends when the customer can maintain what was built without calling.
10
10
 
@@ -1,12 +1,14 @@
1
1
  # readout - Report the outcome
2
2
 
3
+ **Context:** apply [task context and evidence](task-context.md). Standalone readouts use supplied permitted notes and evidence; no engagement binding or CLI command is required.
4
+
3
5
  **Enter when:** the weekly update is due, an exec asks "where are we," or the FDE says "I need to send Dana something." This artifact decides renewals; engineers underinvest in it.
4
6
 
5
- **Read first:** `success.md` (the yardstick), `delivery.md` (value ledger), `decisions.md` (plan + kill list), `assumptions.md` (OPEN criticals), `risks.md`, `context.md`. Gather the week's facts: `fde receipts` for agreements, `git log --since='7 days ago' --oneline` for shipped work.
7
+ **Read first:** `success.md` (the yardstick), `delivery.md` (value ledger), `decisions.md` (plan + kill list), `assumptions.md` (OPEN criticals), `risks.md`, `context.md`. For bound work, gather agreements through `fde receipts`; use permitted repository history only when relevant. A commit shows a code change, not proof of deployment. For standalone work, use the supplied facts and mark missing evidence explicitly.
6
8
 
7
9
  ## Method (you do this work)
8
10
 
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.
11
+ **First:** for a bound engagement, run `fde status`. It prints the value ledger before trust - promised → measured → accepted by, or `claimed, not yet accepted`. Check cited records through sanitized CLI views before making the claim. CLI output summarizes recorded text, not independently verified acceptance. For standalone work, build the same distinction from supplied permitted context without running engagement-only commands or initializing records. If a bound CLI is unavailable, use only permitted supplied excerpts and report the limitation. Never infer acceptance or fabricate missing measurements.
10
12
 
11
13
  **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.
12
14
 
@@ -20,8 +22,8 @@
20
22
  | **A - Answer** | What you recommend / what happens next week (≤3 bullets) | plan Now lane, delivery promised→measured |
21
23
 
22
24
  Then add, still on the same page:
23
- 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?".
24
- 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."
25
+ 1. **Value this week** - from the value ledger: promised → measured (or "pending") → **accepted by whom**, with evidence citation. An unaccepted measurement stays labeled as measured but unaccepted; do not present it as realized or accepted value. Preserve the actual decision needed: it may be funding a bounded test to resolve uncertainty, rather than asking for sign-off on evidence that does not yet exist.
26
+ 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. If the old path remains live, report its role and remaining effort. Parallel operation may be a deliberate control; do not demand its removal without evidence and authority. Frame the next ask around the actual blocker or uncertainty.
25
27
  3. **Kill / defer reminder** - one line from the plan kill list so scope fights stay visible.
26
28
  4. **Hostile Q prep** - three questions a skeptical sponsor will ask, with one-line answers from memory.
27
29
 
@@ -0,0 +1,16 @@
1
+ {
2
+ "generator": "bin/generate-skills.js",
3
+ "version": 1,
4
+ "files": {
5
+ "SKILL.md": "958f58e8ee13d187fe92a0c9d17e0499d8918a7f19b7f321378977038c103556",
6
+ "references/build.md": "3dfeed619eeb1c8401f5cdf65e6f803fb209c70cb464dac4e60a1c890fd3a6f7",
7
+ "references/debug.md": "c3bb344d38cc3552cb4e230c601a9be3fe173af2b2efb89aab6b7b04339f24f4",
8
+ "references/eval-pack.md": "0590b85d3cae0903c6b1274540c92eaa2a4373047e8a0548d6942516ef0bb9e1",
9
+ "references/integrate.md": "107a50bddf6cb0ba7f2bc006dfe9851800c6868e43f785a33ae4b737aeb74c95",
10
+ "references/qa.md": "d8f58e6d36436469a58aeb1107037f3e27fa81ff5b82d0e4df3c23eeadaf683c",
11
+ "references/review.md": "63a007f78288089cc84cccc72647e8ce6721b7efa0f4f8d6774c0f0af594749d",
12
+ "references/ship.md": "8cdcb2d4d6eb57e0adf3f1996bc02ae66920852ca304d2afd778fa483b7e969a",
13
+ "references/task-context.md": "8ec90708522e512a50a57ab2a377a7472e93bae169c6f075a93fa603ce2ad780",
14
+ "references/verification.md": "d453c075b849437375338fd23782ca7fe6d427b05137a2b10fc2f724aaf7f8a9"
15
+ }
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "generator": "bin/generate-skills.js",
3
+ "version": 1,
4
+ "files": {
5
+ "SKILL.md": "1b73c7e4b81b007a79d84e33931d9e2292f13165fac6298e00ff0c4e80f74283",
6
+ "references/build.md": "3dfeed619eeb1c8401f5cdf65e6f803fb209c70cb464dac4e60a1c890fd3a6f7",
7
+ "references/debug.md": "c3bb344d38cc3552cb4e230c601a9be3fe173af2b2efb89aab6b7b04339f24f4",
8
+ "references/eval-pack.md": "0590b85d3cae0903c6b1274540c92eaa2a4373047e8a0548d6942516ef0bb9e1",
9
+ "references/integrate.md": "107a50bddf6cb0ba7f2bc006dfe9851800c6868e43f785a33ae4b737aeb74c95",
10
+ "references/qa.md": "d8f58e6d36436469a58aeb1107037f3e27fa81ff5b82d0e4df3c23eeadaf683c",
11
+ "references/review.md": "63a007f78288089cc84cccc72647e8ce6721b7efa0f4f8d6774c0f0af594749d",
12
+ "references/ship.md": "8cdcb2d4d6eb57e0adf3f1996bc02ae66920852ca304d2afd778fa483b7e969a",
13
+ "references/task-context.md": "8ec90708522e512a50a57ab2a377a7472e93bae169c6f075a93fa603ce2ad780",
14
+ "references/verification.md": "d453c075b849437375338fd23782ca7fe6d427b05137a2b10fc2f724aaf7f8a9"
15
+ }
16
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "generator": "bin/generate-skills.js",
3
+ "version": 1,
4
+ "files": {
5
+ "SKILL.md": "ca2ab4e5d01f8715b344e0726a692aa6bc66a599a45ebea37b7f8e05f71b1e65",
6
+ "references/audit.md": "ed32ea78cbccb100742dd838e8cf4cd4b6f33ad44b3de7424fc624670d571dbc",
7
+ "references/discover.md": "6fc143a4224248c496b209bf36509c2f1aac7872aa0c0ba82656a94d0dee0f66",
8
+ "references/task-context.md": "8ec90708522e512a50a57ab2a377a7472e93bae169c6f075a93fa603ce2ad780"
9
+ }
10
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "generator": "bin/generate-skills.js",
3
+ "version": 1,
4
+ "files": {
5
+ "SKILL.md": "c26b4dade2397ce447b10eb24e24bd8fff9e42ead4602f3e175f4aa71b1437e1",
6
+ "references/build.md": "3dfeed619eeb1c8401f5cdf65e6f803fb209c70cb464dac4e60a1c890fd3a6f7",
7
+ "references/debug.md": "c3bb344d38cc3552cb4e230c601a9be3fe173af2b2efb89aab6b7b04339f24f4",
8
+ "references/eval-pack.md": "0590b85d3cae0903c6b1274540c92eaa2a4373047e8a0548d6942516ef0bb9e1",
9
+ "references/integrate.md": "107a50bddf6cb0ba7f2bc006dfe9851800c6868e43f785a33ae4b737aeb74c95",
10
+ "references/qa.md": "d8f58e6d36436469a58aeb1107037f3e27fa81ff5b82d0e4df3c23eeadaf683c",
11
+ "references/review.md": "63a007f78288089cc84cccc72647e8ce6721b7efa0f4f8d6774c0f0af594749d",
12
+ "references/ship.md": "8cdcb2d4d6eb57e0adf3f1996bc02ae66920852ca304d2afd778fa483b7e969a",
13
+ "references/task-context.md": "8ec90708522e512a50a57ab2a377a7472e93bae169c6f075a93fa603ce2ad780",
14
+ "references/verification.md": "d453c075b849437375338fd23782ca7fe6d427b05137a2b10fc2f724aaf7f8a9"
15
+ }
16
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "generator": "bin/generate-skills.js",
3
+ "version": 1,
4
+ "files": {
5
+ "SKILL.md": "c70af27393a64319c7113cf100328b05bc317b0b95aba73ac5f3c77976ba24d9",
6
+ "references/encode-pattern.md": "3be7bf9d0f69af31659423c54d6023a4af1556e2ce200fb025bf64d0757de4d8",
7
+ "references/task-context.md": "8ec90708522e512a50a57ab2a377a7472e93bae169c6f075a93fa603ce2ad780"
8
+ }
9
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "generator": "bin/generate-skills.js",
3
+ "version": 1,
4
+ "files": {
5
+ "SKILL.md": "81250bf05e9edab5128a9ae72d2c33aac7e3a0d3dbdfbaaaa8352e21f81d0323",
6
+ "references/close.md": "095266722624e4bc647628243c8be0e69b02017ef6b4e3a7e7790ec1f53ab7c0",
7
+ "references/encode-pattern.md": "3be7bf9d0f69af31659423c54d6023a4af1556e2ce200fb025bf64d0757de4d8",
8
+ "references/task-context.md": "8ec90708522e512a50a57ab2a377a7472e93bae169c6f075a93fa603ce2ad780"
9
+ }
10
+ }
@@ -4,7 +4,7 @@
4
4
 
5
5
  **Enter when:** the engagement is ending - the customer team must run this without the FDE.
6
6
 
7
- **Read first:** bounded `fde handoff` or `fde resume`, then targeted `fde recall` for missing evidence. Build the full picture through relevant excerpts, not a full-directory load. Consult `terrain.md` only for the code paths needed by the successor.
7
+ **Read first:** for standalone work, use the supplied permitted operating notes, evidence and ownership; no engagement binding or CLI command is required. For a bound engagement, use bounded `fde handoff` or `fde resume`, then targeted `fde recall` for missing evidence. Never initialize records merely to draft a handoff. Build the picture through relevant excerpts, not a full-directory load. Consult `terrain.md` only for code paths needed by the successor.
8
8
 
9
9
  The engagement doesn't end at ship. It ends when the customer can maintain what was built without calling.
10
10
 
@@ -0,0 +1,16 @@
1
+ {
2
+ "generator": "bin/generate-skills.js",
3
+ "version": 1,
4
+ "files": {
5
+ "SKILL.md": "e7d4fd3e324fe60e1794dc79f532e8f72fb7524fe9cecb215d4c3f82e7b58688",
6
+ "references/build.md": "3dfeed619eeb1c8401f5cdf65e6f803fb209c70cb464dac4e60a1c890fd3a6f7",
7
+ "references/debug.md": "c3bb344d38cc3552cb4e230c601a9be3fe173af2b2efb89aab6b7b04339f24f4",
8
+ "references/eval-pack.md": "0590b85d3cae0903c6b1274540c92eaa2a4373047e8a0548d6942516ef0bb9e1",
9
+ "references/integrate.md": "107a50bddf6cb0ba7f2bc006dfe9851800c6868e43f785a33ae4b737aeb74c95",
10
+ "references/qa.md": "d8f58e6d36436469a58aeb1107037f3e27fa81ff5b82d0e4df3c23eeadaf683c",
11
+ "references/review.md": "63a007f78288089cc84cccc72647e8ce6721b7efa0f4f8d6774c0f0af594749d",
12
+ "references/ship.md": "8cdcb2d4d6eb57e0adf3f1996bc02ae66920852ca304d2afd778fa483b7e969a",
13
+ "references/task-context.md": "8ec90708522e512a50a57ab2a377a7472e93bae169c6f075a93fa603ce2ad780",
14
+ "references/verification.md": "d453c075b849437375338fd23782ca7fe6d427b05137a2b10fc2f724aaf7f8a9"
15
+ }
16
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "generator": "bin/generate-skills.js",
3
+ "version": 1,
4
+ "files": {
5
+ "SKILL.md": "0b8ab7ce06b63ae36baa062bf852cd0fe5f03bcaaf0126cb5c616951dd6ff977",
6
+ "references/business-case.md": "32e000e8351cd59f9eaad8be40babb276df69948ea4f81e01a4672e47f48cb25",
7
+ "references/task-context.md": "8ec90708522e512a50a57ab2a377a7472e93bae169c6f075a93fa603ce2ad780",
8
+ "references/test-assumptions.md": "bf60d8bb4c0701fcffb196d78f7f6c8b1c472fc877fb2caf41058fbf8e2415a1",
9
+ "references/three-options.md": "168fab9fb8ac8de85b0d1fa58e1db17deaa244cdef8c99623a04a0a6c70fe52c"
10
+ }
11
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "generator": "bin/generate-skills.js",
3
+ "version": 1,
4
+ "files": {
5
+ "SKILL.md": "0185c12f6f7411b2fa36923cb6d7658681caf00577be5e54c20fb6bf8ec21539",
6
+ "references/audit.md": "ed32ea78cbccb100742dd838e8cf4cd4b6f33ad44b3de7424fc624670d571dbc",
7
+ "references/build.md": "3dfeed619eeb1c8401f5cdf65e6f803fb209c70cb464dac4e60a1c890fd3a6f7",
8
+ "references/business-case.md": "32e000e8351cd59f9eaad8be40babb276df69948ea4f81e01a4672e47f48cb25",
9
+ "references/debug.md": "c3bb344d38cc3552cb4e230c601a9be3fe173af2b2efb89aab6b7b04339f24f4",
10
+ "references/discover.md": "6fc143a4224248c496b209bf36509c2f1aac7872aa0c0ba82656a94d0dee0f66",
11
+ "references/eval-pack.md": "0590b85d3cae0903c6b1274540c92eaa2a4373047e8a0548d6942516ef0bb9e1",
12
+ "references/integrate.md": "107a50bddf6cb0ba7f2bc006dfe9851800c6868e43f785a33ae4b737aeb74c95",
13
+ "references/plan.md": "a096831ea7afdde1fe954541ad854a99d2d118c1abbf8826f2332e695a802ae1",
14
+ "references/poc.md": "818dc90c2d401819735233ab9d69df171675d75abf8644c403dab7dd1dcf9199",
15
+ "references/qa.md": "d8f58e6d36436469a58aeb1107037f3e27fa81ff5b82d0e4df3c23eeadaf683c",
16
+ "references/review.md": "63a007f78288089cc84cccc72647e8ce6721b7efa0f4f8d6774c0f0af594749d",
17
+ "references/ship.md": "8cdcb2d4d6eb57e0adf3f1996bc02ae66920852ca304d2afd778fa483b7e969a",
18
+ "references/task-context.md": "8ec90708522e512a50a57ab2a377a7472e93bae169c6f075a93fa603ce2ad780",
19
+ "references/test-assumptions.md": "bf60d8bb4c0701fcffb196d78f7f6c8b1c472fc877fb2caf41058fbf8e2415a1",
20
+ "references/three-options.md": "168fab9fb8ac8de85b0d1fa58e1db17deaa244cdef8c99623a04a0a6c70fe52c",
21
+ "references/verification.md": "d453c075b849437375338fd23782ca7fe6d427b05137a2b10fc2f724aaf7f8a9"
22
+ }
23
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "generator": "bin/generate-skills.js",
3
+ "version": 1,
4
+ "files": {
5
+ "SKILL.md": "bcd42a3f9485e49467c180b51e280f577a7d525329ab1c1e550a84b1233d0575",
6
+ "references/build.md": "3dfeed619eeb1c8401f5cdf65e6f803fb209c70cb464dac4e60a1c890fd3a6f7",
7
+ "references/debug.md": "c3bb344d38cc3552cb4e230c601a9be3fe173af2b2efb89aab6b7b04339f24f4",
8
+ "references/eval-pack.md": "0590b85d3cae0903c6b1274540c92eaa2a4373047e8a0548d6942516ef0bb9e1",
9
+ "references/integrate.md": "107a50bddf6cb0ba7f2bc006dfe9851800c6868e43f785a33ae4b737aeb74c95",
10
+ "references/qa.md": "d8f58e6d36436469a58aeb1107037f3e27fa81ff5b82d0e4df3c23eeadaf683c",
11
+ "references/review.md": "63a007f78288089cc84cccc72647e8ce6721b7efa0f4f8d6774c0f0af594749d",
12
+ "references/ship.md": "8cdcb2d4d6eb57e0adf3f1996bc02ae66920852ca304d2afd778fa483b7e969a",
13
+ "references/task-context.md": "8ec90708522e512a50a57ab2a377a7472e93bae169c6f075a93fa603ce2ad780",
14
+ "references/verification.md": "d453c075b849437375338fd23782ca7fe6d427b05137a2b10fc2f724aaf7f8a9"
15
+ }
16
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "generator": "bin/generate-skills.js",
3
+ "version": 1,
4
+ "files": {
5
+ "SKILL.md": "c19925672ca687fe5f9bc82d612134b5b54504e409484bddddd78439ccb154a1",
6
+ "references/board-memo.md": "44eb3c27f164da63af694591025b3fc96bb23d149c29de400997c1653e3322f8",
7
+ "references/business-case.md": "32e000e8351cd59f9eaad8be40babb276df69948ea4f81e01a4672e47f48cb25",
8
+ "references/readout.md": "46856e9452ef3928a394fc89425bf4b9ba912f5586584537345a10f6c3a20903",
9
+ "references/task-context.md": "8ec90708522e512a50a57ab2a377a7472e93bae169c6f075a93fa603ce2ad780"
10
+ }
11
+ }
@@ -1,12 +1,14 @@
1
1
  # readout - Report the outcome
2
2
 
3
+ **Context:** apply [task context and evidence](task-context.md). Standalone readouts use supplied permitted notes and evidence; no engagement binding or CLI command is required.
4
+
3
5
  **Enter when:** the weekly update is due, an exec asks "where are we," or the FDE says "I need to send Dana something." This artifact decides renewals; engineers underinvest in it.
4
6
 
5
- **Read first:** `success.md` (the yardstick), `delivery.md` (value ledger), `decisions.md` (plan + kill list), `assumptions.md` (OPEN criticals), `risks.md`, `context.md`. Gather the week's facts: `fde receipts` for agreements, `git log --since='7 days ago' --oneline` for shipped work.
7
+ **Read first:** `success.md` (the yardstick), `delivery.md` (value ledger), `decisions.md` (plan + kill list), `assumptions.md` (OPEN criticals), `risks.md`, `context.md`. For bound work, gather agreements through `fde receipts`; use permitted repository history only when relevant. A commit shows a code change, not proof of deployment. For standalone work, use the supplied facts and mark missing evidence explicitly.
6
8
 
7
9
  ## Method (you do this work)
8
10
 
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.
11
+ **First:** for a bound engagement, run `fde status`. It prints the value ledger before trust - promised → measured → accepted by, or `claimed, not yet accepted`. Check cited records through sanitized CLI views before making the claim. CLI output summarizes recorded text, not independently verified acceptance. For standalone work, build the same distinction from supplied permitted context without running engagement-only commands or initializing records. If a bound CLI is unavailable, use only permitted supplied excerpts and report the limitation. Never infer acceptance or fabricate missing measurements.
10
12
 
11
13
  **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.
12
14
 
@@ -20,8 +22,8 @@
20
22
  | **A - Answer** | What you recommend / what happens next week (≤3 bullets) | plan Now lane, delivery promised→measured |
21
23
 
22
24
  Then add, still on the same page:
23
- 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?".
24
- 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."
25
+ 1. **Value this week** - from the value ledger: promised → measured (or "pending") → **accepted by whom**, with evidence citation. An unaccepted measurement stays labeled as measured but unaccepted; do not present it as realized or accepted value. Preserve the actual decision needed: it may be funding a bounded test to resolve uncertainty, rather than asking for sign-off on evidence that does not yet exist.
26
+ 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. If the old path remains live, report its role and remaining effort. Parallel operation may be a deliberate control; do not demand its removal without evidence and authority. Frame the next ask around the actual blocker or uncertainty.
25
27
  3. **Kill / defer reminder** - one line from the plan kill list so scope fights stay visible.
26
28
  4. **Hostile Q prep** - three questions a skeptical sponsor will ask, with one-line answers from memory.
27
29
 
@@ -0,0 +1,16 @@
1
+ {
2
+ "generator": "bin/generate-skills.js",
3
+ "version": 1,
4
+ "files": {
5
+ "SKILL.md": "c36da35dffc22f820e91e52556c0a598bcac67647ffcdbd29811bf11eb638da2",
6
+ "references/build.md": "3dfeed619eeb1c8401f5cdf65e6f803fb209c70cb464dac4e60a1c890fd3a6f7",
7
+ "references/debug.md": "c3bb344d38cc3552cb4e230c601a9be3fe173af2b2efb89aab6b7b04339f24f4",
8
+ "references/eval-pack.md": "0590b85d3cae0903c6b1274540c92eaa2a4373047e8a0548d6942516ef0bb9e1",
9
+ "references/integrate.md": "107a50bddf6cb0ba7f2bc006dfe9851800c6868e43f785a33ae4b737aeb74c95",
10
+ "references/qa.md": "d8f58e6d36436469a58aeb1107037f3e27fa81ff5b82d0e4df3c23eeadaf683c",
11
+ "references/review.md": "63a007f78288089cc84cccc72647e8ce6721b7efa0f4f8d6774c0f0af594749d",
12
+ "references/ship.md": "8cdcb2d4d6eb57e0adf3f1996bc02ae66920852ca304d2afd778fa483b7e969a",
13
+ "references/task-context.md": "8ec90708522e512a50a57ab2a377a7472e93bae169c6f075a93fa603ce2ad780",
14
+ "references/verification.md": "d453c075b849437375338fd23782ca7fe6d427b05137a2b10fc2f724aaf7f8a9"
15
+ }
16
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "generator": "bin/generate-skills.js",
3
+ "version": 1,
4
+ "files": {
5
+ "SKILL.md": "50f085f1199bdd7325f1628f61bf34d74018bde6f6bc0e629d1d3df1ddb36132",
6
+ "references/hold-scope.md": "42b3823f6b49b87b432f81208b0a61115f22340f6a922a4e858012e908c6643d",
7
+ "references/task-context.md": "8ec90708522e512a50a57ab2a377a7472e93bae169c6f075a93fa603ce2ad780"
8
+ }
9
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "generator": "bin/generate-skills.js",
3
+ "version": 1,
4
+ "files": {
5
+ "SKILL.md": "b286e9f2a3f80ae0707bfbae7c90f9c9f0f6c7b03ab22c81d61d3474f1aa03a2",
6
+ "references/build.md": "3dfeed619eeb1c8401f5cdf65e6f803fb209c70cb464dac4e60a1c890fd3a6f7",
7
+ "references/debug.md": "c3bb344d38cc3552cb4e230c601a9be3fe173af2b2efb89aab6b7b04339f24f4",
8
+ "references/eval-pack.md": "0590b85d3cae0903c6b1274540c92eaa2a4373047e8a0548d6942516ef0bb9e1",
9
+ "references/integrate.md": "107a50bddf6cb0ba7f2bc006dfe9851800c6868e43f785a33ae4b737aeb74c95",
10
+ "references/qa.md": "d8f58e6d36436469a58aeb1107037f3e27fa81ff5b82d0e4df3c23eeadaf683c",
11
+ "references/review.md": "63a007f78288089cc84cccc72647e8ce6721b7efa0f4f8d6774c0f0af594749d",
12
+ "references/ship.md": "8cdcb2d4d6eb57e0adf3f1996bc02ae66920852ca304d2afd778fa483b7e969a",
13
+ "references/task-context.md": "8ec90708522e512a50a57ab2a377a7472e93bae169c6f075a93fa603ce2ad780",
14
+ "references/verification.md": "d453c075b849437375338fd23782ca7fe6d427b05137a2b10fc2f724aaf7f8a9"
15
+ }
16
+ }