@antoneeo/mkt-agentic-sdlc-skill 0.2.1 → 0.3.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.
@@ -0,0 +1,287 @@
1
+ # Operative Guides — pipeline
2
+
3
+ Support file for `ai_docs/reference/GUIDE_[topic].md`. Read this only when the
4
+ trigger below fires; the template lives in `templates.md`.
5
+
6
+ **The training model (what a guide IS).** A guide TRAINS the agent on a topic
7
+ the user cares about, the way training works for a person: you study the
8
+ material once, you carry a SYNTHESIS in your head, and you go back to the book
9
+ when a task needs detail. Two levels, both produced by this pipeline:
10
+ - **The guide = the synthesis** — compact and dense: core principles, decision
11
+ rules, the map of what exists, where people go wrong. Small enough that a
12
+ reader takes it in WHOLE before acting (that is the "preparation").
13
+ - **The snapshot = the book** (`.sources/`, verbatim) — the details live here,
14
+ reachable on demand.
15
+ - **The fidelity markers are the bridge**: `[source: <snapshot>#anchor]` both
16
+ proves provenance AND tells the reader where in the book the full detail is.
17
+ A guide that restates the source at length is as wrong as a fragmented one:
18
+ completeness is guaranteed by the book level, economy by the synthesis level.
19
+
20
+ **Two source kinds.** A guide's `source_kind` is either `document` (the default —
21
+ distilled from USER-PROVIDED indications; operative, "how to act") or `code`
22
+ (distilled from the project's own code; a comprehension map of a complex component,
23
+ "how it works"). Both are **source-faithful and snapshot-anchored** — the machinery
24
+ below (snapshot, `source_hash`, fidelity markers, router, `stale`) is identical; only
25
+ what is gathered into `.sources/` differs (a handed document vs verbatim code
26
+ excerpts). Where a rule applies to only one kind, it says so.
27
+
28
+ ## 0. Consuming a guide (consult before acting)
29
+
30
+ Guides only pay off if they reach the work they govern. **Before operative work,
31
+ proportional to triage** — L1 is exempt; engaged for L2/L3 — ask: *does a guide
32
+ already cover how to do this well?*
33
+
34
+ - **Scan the router, not the guides.** Read the when-to-consult descriptions in
35
+ the guide router `ai_docs/reference/INDEX.md` **and** the agent-KB router
36
+ `~/.agentic-sdlc/ai_docs/reference/INDEX.md` (if present). Match by topic.
37
+ - **On a match, read that guide's synthesis whole** before acting (the snapshot
38
+ stays on demand via the section markers). No match → proceed normally.
39
+ - **Targeted match, never blanket.** Open only the guide whose description fits
40
+ the task — never load every guide, which would reintroduce the exact token
41
+ cost the "point to them" model exists to avoid. The two-level model (compact
42
+ synthesis / verbatim snapshot) already bounds a single guide's cost.
43
+ - **Declare the router verdict.** The lookup result travels with the triage
44
+ level (`SKILL.md` Rule Zero) as one line — `router: no match`, or
45
+ `router: GUIDE_x.md → read`. This is what makes the consult reliable: an
46
+ undeclared lookup is indistinguishable from a skipped one, to the user, to a
47
+ later reviewer, and to you in the next session. Declaring `no match` on a repo
48
+ with no matching guide is the correct, expected output — not noise.
49
+ - **Three legal verdicts, not two.** `GUIDE_x.md → read`, `no match` (the router
50
+ was read; nothing fitted — including a project whose router is an empty stub,
51
+ which is the normal state before the first guide exists), and
52
+ `router: absent (no router file)` for the case where `ai_docs/reference/INDEX.md`
53
+ does not exist at all. That third value exists so the honest answer is always
54
+ available: a required declaration with no truthful value gets faked or dropped,
55
+ and it takes the rest of Rule Zero with it. Regenerate the router
56
+ (`sdlc_check.py index`) when you report `absent`.
57
+ - **Never fake the verdict.** `no match` means the router was read and nothing
58
+ fitted. A verdict that is always `no match` certifies a lookup that did not
59
+ happen and is worse than silence; a verdict listing the catalogue means the
60
+ match was not targeted (T7). Two guides are legitimate only when they cover
61
+ distinct concerns — typically an operative guide plus the comprehension map of
62
+ the component being touched; three is a smell, not a thorough lookup.
63
+ - **Under subagent dispatch** the consult happens at plan-authoring time (the
64
+ orchestrator populates each task's `guides` field); a context-free subagent
65
+ reads the pointers it was handed and does not run its own router lookup. See
66
+ `dispatch.md`.
67
+
68
+ ## 1. When to trigger
69
+
70
+ Trigger test is origin + purpose, not content taxonomy (no "is this technical
71
+ enough" judgement call):
72
+ - **Origin**: the user hands you indications to follow — a document to adhere
73
+ to, a pasted policy, "do it this way", a style guide, a runbook.
74
+ - **Purpose**: the material is meant to GOVERN how the agent operates, not
75
+ just inform a one-off answer.
76
+
77
+ Both hold → this is guide material. Either is missing (e.g. the user pastes
78
+ background context with no operative intent, or asks a one-off question) →
79
+ this is not a guide; answer normally, do not create a file.
80
+
81
+ Never manufacture a guide from model knowledge. If the user asks for "a guide
82
+ on X" without handing over source material, ask for the source first — a
83
+ guide with no `distilled_from` is not this pipeline's output.
84
+
85
+ ### Proactive trigger (after reusable success)
86
+
87
+ The trigger above is reactive (the user hands material over). It has a proactive
88
+ twin: **after completing work that was governed by user-provided indications and
89
+ is plausibly reusable** — it would prepare a future task — **PROPOSE** distilling
90
+ a guide.
91
+
92
+ - It is a **proposal to the user**, routed into this same pipeline (§2 onward):
93
+ the user confirms topic/scope before any file is written.
94
+ - **Never a silent write, never from model knowledge.** If the work was not
95
+ governed by user-provided material there is nothing to distill — do not invent
96
+ a guide from general knowledge (the `distilled_from` fidelity constraint, §3,
97
+ is absolute). This adds a moment to PROPOSE, not a new writer.
98
+
99
+ ### Comprehension trigger (code source, autonomous — a duty, not a proposal)
100
+
101
+ The two triggers above are for `source_kind: document` (the user hands material
102
+ over). There is a third, for `source_kind: code`: while doing L2/L3 work, when you
103
+ recognize that a component / feature / abstraction layer is **high-complexity** and
104
+ no CURRENT guide already covers it, it is your **duty to WRITE a comprehension
105
+ guide** — autonomously, no proposal, no human gate. The next session (or another
106
+ agent) must not have to re-derive the model you just paid to build, and then break
107
+ the component from partial understanding.
108
+
109
+ - **Why autonomous is allowed here** (it is NOT for `document` guides): a
110
+ comprehension guide is **additive, code-anchored and reversible** (git). It changes
111
+ no code, plan or governed artifact — so the skill-wide "propose, never a silent
112
+ write" rule is relaxed for THIS kind only. The anti-hallucination floor still holds:
113
+ §3 fidelity is absolute — every claim traces to a verbatim code excerpt in the
114
+ snapshot, never to your assumption about what the code does.
115
+ - **Recognize "high-complexity" by concrete signals** (any strong combination, not a
116
+ vibe): you had to trace one behavior across several files/modules (summaries were
117
+ not enough); high fan-in / large blast radius (many consumers); non-obvious control
118
+ or data flow (state machine, async/eventing, DI/plugin indirection, metaprogramming,
119
+ cross-cutting invariants); the area was already broken once — or **repeatedly
120
+ across sessions** — from partial understanding (handoff / diary / git shows it);
121
+ the "why" is not reconstructable from a single file.
122
+ - **Guard-rails (autonomous is not unconstrained).** Search first (§2.0 — one CURRENT
123
+ guide per topic, both routers). Honor the fidelity floor (§3). RECOMMEND the
124
+ independent guide-vs-source review (§5) — it matters more here, since no human gated
125
+ creation. Announce the autonomous write in the closure / handoff so it is visible.
126
+ - **When it fires.** As soon as you recognize the signal, during the work. The
127
+ Phase-5 **Comprehension checkpoint** (`SKILL.md` §5) is the backstop that asks the
128
+ question out loud before closure — a safety net for a signal you noticed and did not
129
+ act on, never a licence to defer. Writing it at closure is still far better than not
130
+ writing it: the model you built is complete now and gone next session.
131
+
132
+ ## 2. Pipeline
133
+
134
+ 0. **Search before creating (DRY — one CURRENT guide per topic).** Before
135
+ proposing anything, read `ai_docs/reference/INDEX.md` and grep
136
+ `reference/GUIDE_*.md` for topic overlap with the new material. Never end
137
+ up with two CURRENT guides on the same topic. Search BOTH routers: project
138
+ `ai_docs/reference/INDEX.md` AND the agent KB router
139
+ `~/.agentic-sdlc/ai_docs/reference/INDEX.md` (if present) — one CURRENT
140
+ guide per topic PER SCOPE; a project guide on a KB topic requires the
141
+ explicit `overrides:` declaration. On overlap, pick by provenance:
142
+ - **Same source, evolved** → UPDATE the existing guide in place: new
143
+ snapshot, new `source_hash`, same file (history lives in git).
144
+ - **Different source replacing the old one** → NEW guide + mark the old
145
+ one `status: SUPERSEDED` (its provenance chain must stay honest — do not
146
+ graft a new source onto a guide distilled from another).
147
+ - **Different source, partial overlap** → flag it to the user explicitly:
148
+ the current frontmatter binds ONE source per guide (`distilled_from`/
149
+ `source_hash` are singular), so a clean multi-source merge is not yet
150
+ supported — regenerate from the prevailing source and mark what the
151
+ merge drops, or keep the topics separate if they truly are.
152
+ Semantic overlap is NOT mechanically detectable: this step is agent
153
+ discipline plus the human reviewing the router — say what you found.
154
+ **Also verify the handed SOURCE itself is current**: check its lifecycle
155
+ (status/supersedes headers) and search the project for a newer version of
156
+ the same document before snapshotting. A user may hand you a path that a
157
+ migrated copy has since superseded — distilling from it produces a guide
158
+ that is born stale. If you find a newer version, surface it and distill
159
+ from that one. (Learned the hard way on first field use, 2026-07-02.)
160
+ 1. **Decompose into PREPARATION units — and weigh the fragmentation risk.**
161
+ A guide's goal is to PREPARE an agent for a situation: everything that
162
+ situation needs must arrive in ONE guide. The risk is asymmetric — extra
163
+ context injected costs tokens (cheap, recoverable); missing context makes
164
+ the agent invent or fail (the exact failure this pipeline exists to
165
+ prevent). Every split is a bet that no future task will cross the cut.
166
+ Therefore:
167
+ - **Default = one guide per source/domain.** Split ONLY when the resulting
168
+ guides would be consulted in DISJOINT situations — no plausible task
169
+ needs two of them at once.
170
+ - **Run the split test per proposed fragment and DECLARE it** in the
171
+ proposal: "which tasks consult this fragment, and would any of those
172
+ tasks also need another fragment?" Any overlap → merge, do not split.
173
+ - Heterogeneous sources (unrelated policies handed over together) are the
174
+ legitimate split case; a single coherent document about one subsystem
175
+ almost never is.
176
+ - **Also decide SCOPE per proposed guide**: project-scope
177
+ (`ai_docs/reference/`) or agent-scope (`~/.agentic-sdlc/ai_docs/reference/`,
178
+ governs the agent across ALL projects; origin+purpose test unchanged,
179
+ scope is a LOCATION decision by the user, never a content taxonomy; KB
180
+ created lazily with `.sources/` on the first agent-scope guide).
181
+ 2. **User confirms** the topic decomposition — including the fragmentation-risk
182
+ assessment and scope decision — before any file is written. **`source_kind: code`
183
+ skips this gate**: the comprehension guide is written autonomously (§1
184
+ comprehension trigger). Still run the fragmentation/scope judgement yourself — just
185
+ do not block on confirmation.
186
+ 3. **Snapshot each source verbatim** into
187
+ `ai_docs/reference/.sources/<slug>-<hash8>.md`:
188
+ - `slug` derives from the topic (lowercase, hyphenated).
189
+ - `hash8` = first 8 hex chars of the snapshot file's own SHA-256 (compute
190
+ the snapshot first, hash it, then name it — the hash is of the file you
191
+ just wrote, not of the original source).
192
+ - The hash is computed over LF-normalized content (CRLF → LF), exactly as
193
+ `sdlc_check.py` does in `sha256_file` — so recorded hashes survive
194
+ checkouts that rewrite line endings (e.g. Windows `core.autocrlf=true`).
195
+ - Recommended for consumer projects: add
196
+ `ai_docs/reference/.sources/** -text` to `.gitattributes` so git never
197
+ rewrites snapshot bytes at all (keeps snapshots byte-verbatim; the
198
+ normalized hash stays stable either way).
199
+ - The snapshot is verbatim: no paraphrasing, no reformatting beyond what is
200
+ needed to save it as markdown.
201
+ - **For `source_kind: code`** the snapshot is the verbatim CODE EXCERPTS the guide
202
+ explains — the specific functions / classes / regions of the real files, each
203
+ labelled with its `path:symbol` (or `path:startLine-endLine`) — assembled into
204
+ the one `.sources/<slug>-<hash8>.md` and hashed identically. Copy the code
205
+ verbatim (no paraphrase); include ONLY the regions the guide covers, not whole
206
+ files, so `stale` tracks the code that matters. `distilled_from` records those
207
+ code paths.
208
+ 4. **Source-anchored SYNTHESIS (not restatement).** Select and compress what
209
+ the source says into the operative essence — decision rules, invariants,
210
+ the "where people go wrong" list — and POINT INTO the snapshot for the
211
+ detail (`[source: <snapshot>#anchor]` doubles as the detail-lookup
212
+ pointer: "full checklist → snapshot §7"). Every claim must still trace to
213
+ a specific point in the snapshot; do not extract from memory of the
214
+ conversation — re-read the snapshot while writing each section. Selection
215
+ and compression are allowed and expected; ADDITION is not (that stays
216
+ summarize-and-expand, forbidden). A guide approaching the source's own
217
+ length is a paraphrase, not a synthesis — wrong output.
218
+ 5. **Render per template** (`templates.md` → `## ai_docs/reference/GUIDE_[topic].md`):
219
+ frontmatter with `source_kind` (`document` | `code`), `source`, `distilled_from`,
220
+ `source_hash` (the snapshot's SHA-256, matching what you just computed), optional
221
+ `source_version`; body sections chosen from the repertoire (a `code` guide uses the
222
+ comprehension repertoire — how it works / control & data flow / invariants / where
223
+ it breaks), each with a fidelity marker.
224
+ **Write for the two-level read**: the guide (synthesis) is small enough to
225
+ be read WHOLE before acting; the snapshot (book) is where size lives and
226
+ where readers grep/partial-read on demand, following the section markers.
227
+ Use the repertoire's stable, self-describing headings, keep one concern per
228
+ `##` section, and make the frontmatter `description` the "should I open
229
+ this file at all" answer. This is why one synthesis + one book beats
230
+ several fragments: the synthesis guarantees the whole picture, the book
231
+ guarantees the details, the markers connect them.
232
+ 6. **Run `sdlc_check.py index`** so both `ai_docs/INDEX.md` and
233
+ `ai_docs/reference/INDEX.md` (the guide router) regenerate.
234
+
235
+ ## 3. Fidelity rules (mandatory, the D5 constraint)
236
+
237
+ "The source" below means the SNAPSHOT — a handed document for `source_kind: document`,
238
+ verbatim code excerpts for `source_kind: code`. The constraint is identical for both:
239
+ never from UNVERIFIED knowledge. A code guide's every claim traces to the actual code
240
+ in the snapshot, never to your assumption about what the code does.
241
+
242
+ - Only what the source supports goes in the guide. If the source is silent on
243
+ something a reader might expect, mark the section `[not covered by source]`
244
+ — never fill the gap from general knowledge.
245
+ - Every `##` section body carries exactly one kind of marker: `[source:
246
+ <snapshot>#<anchor-or-line>]` for content traceable to the snapshot, or the
247
+ literal `[not covered by source]` for an acknowledged gap. A section with
248
+ neither is a validator warning.
249
+ - `summarize-and-expand` is forbidden: do not take a short source note and
250
+ "helpfully" expand it into a longer procedure using inferred steps. If the
251
+ source says one sentence, the guide section says that one sentence
252
+ (source-anchored), not an elaborated version of it.
253
+ - When in doubt about whether something is "supported" by the source, treat it
254
+ as not covered rather than stretching the marker to fit.
255
+
256
+ ## 4. Ingestion bound (T9)
257
+
258
+ If a source document exceeds roughly 2000 lines, do not silently truncate or
259
+ skim it. Stop and ask the user to either split it into smaller documents or
260
+ select the specific sections relevant to the guide being built. Silent
261
+ truncation produces a guide that looks complete but is missing unreviewed
262
+ material — worse than asking.
263
+
264
+ ## 5. Review
265
+
266
+ Before the guide is used operatively for the first time, recommend an
267
+ independent guide-vs-source review (a fresh pass comparing the rendered guide
268
+ against the snapshot, checking every marker) — process control per the
269
+ threat model (P-TM). This is a recommendation to the user, not a hard gate:
270
+ state it explicitly when handing off a newly created guide.
271
+
272
+ ## 6. Maintenance
273
+
274
+ - **Source changed**: create a new snapshot (new hash), regenerate the guide
275
+ from it (new `source_hash`), and if the guide is replacing a prior guide
276
+ rather than updating in place, mark the old one `status: SUPERSEDED`.
277
+ - **`stale` flags hash drift**: `sdlc_check.py stale` (also under `--hybrid`)
278
+ compares each guide's recorded `source_hash` against the live snapshot file
279
+ and reports `[stale]` when they diverge — that is the signal to regenerate,
280
+ not a manual freshness check.
281
+ - **`source_kind: code` freshness**: `stale` works unchanged (the code-excerpt
282
+ snapshot drifts when the code changes → regenerate). ADDITIONALLY, when you modify
283
+ the code a comprehension guide describes, refresh that guide in the SAME closure
284
+ (docs travel with the code) — do not wait for `stale` to catch it. A stale
285
+ comprehension guide is a confident-wrong map, worse than none.
286
+ - **Agent-global KB guides** use the same pipeline and validator via
287
+ `--root ~/.agentic-sdlc`; freshness via the same `stale` engine.
@@ -1,104 +1,104 @@
1
- # Research Playbook + Evidence Ledger Discipline
2
-
3
- Research turns the user's facts into a defendable picture of the outside
4
- world. Its output is never prose alone: every number lands in the ledger,
5
- every claim carries its reference.
6
-
7
- ## The Evidence Ledger
8
-
9
- Single file: `mkt_docs/research/evidence_ledger.md`. One table, one row per
10
- piece of evidence:
11
-
12
- | ID | Claim | Class | Value / Range | Source | Date | Confidence |
13
- |---|---|---|---|---|---|---|
14
-
15
- - **ID**: `EV-01`, `EV-02`, ... sequential, never reused. Artifacts cite
16
- numbers as `[EV-nn]`.
17
- - **Class** (exactly one):
18
- - `FACT` — user input or primary data (their analytics, their CRM export).
19
- Source = "user, Wave 1" or the data file.
20
- - `BENCHMARK` — external number. Source URL **and** publication date
21
- mandatory. The Source cell must carry the actual external URL, NOT a
22
- pointer to one of your own research documents that aggregates it ("see
23
- VOC.md" is not a source — the validator rejects a BENCHMARK whose Source
24
- has no `http`). A benchmark older than 24 months is flagged in review.
25
- - `ASSUMPTION` — a number we need but could not source. Range mandatory
26
- (not a point estimate), Confidence mandatory (HIGH/MED/LOW), and the
27
- rationale in the Claim cell. Assumptions that drive budget decisions are
28
- listed in the plan's page-one Assumptions section.
29
- - **Laundering is the cardinal sin:** an ASSUMPTION never migrates to
30
- BENCHMARK without a real source; a stale benchmark is not refreshed by
31
- editing its date. `mkt_check.py ledger` enforces the mechanical part
32
- (references resolve, benchmarks have URLs, assumptions have confidence);
33
- honesty enforces the rest.
34
-
35
- **Two-source rule:** any number that will drive a budget allocation or an
36
- objective target needs two independent sources (two ledger rows or one row
37
- citing both). One vendor's blog post does not size a market.
38
-
39
- **Source hierarchy** (prefer higher): primary data > official statistics /
40
- regulator data > industry analyst reports > trade press > vendor benchmarks >
41
- individual blog posts (last resort, flag as weak in Confidence).
42
-
43
- ## The engine
44
-
45
- **Preferred:** when the `deep-research` skill (or an equivalent multi-agent
46
- research harness) is available, use it as the engine — one refined question
47
- per sweep, findings adversarially verified, sources cited. Feed its cited
48
- findings into the ledger; do not bypass the ledger because the engine already
49
- cites.
50
-
51
- **Fallback:** manual web search per the sweep playbooks below. Slower;
52
- the ledger discipline is identical.
53
-
54
- ## Mandatory sweeps (E3)
55
-
56
- ### 1. Market sizing
57
- - Bottom-up first: reachable potential customers (from official statistics,
58
- association registries, platform audience tools) × realistic price
59
- `[EV: price FACT]`. Top-down (report % slicing) only as cross-check.
60
- - Output: TAM/SAM/SOM with every input as a ledger row.
61
-
62
- ### 2. Competitor scan
63
- - Start from the user's seeds (Wave 1) + search-discovered players.
64
- - Per competitor: positioning claim (their own words, from their site),
65
- visible pricing, observed channels (where do they show up: ads
66
- transparency libraries, social presence, SEO footprint), review sentiment.
67
- - Output: `mkt_docs/research/COMPETITORS.md` + ledger rows for anything
68
- numeric. Observed facts, not speculation about their strategy.
69
-
70
- ### 3. Voice of customer (VoC)
71
- - Mine reviews (their category on G2/Capterra/Trustpilot/Amazon/app stores as
72
- applicable), forums, Reddit, comment sections — where the target segment
73
- already speaks.
74
- - Harvest verbatim quotes with URLs: pains, desired outcomes, objections,
75
- vocabulary (the actual words become messaging raw material).
76
- - Output: `mkt_docs/research/VOC.md`. Persona traits in `ICP_PERSONAS.md`
77
- must trace here.
78
-
79
- ### 4. Channel benchmarks
80
- - For candidate channels: typical CPC/CPM, CTR, conversion rates, CAC ranges
81
- for the industry — each a BENCHMARK row with URL + date.
82
- - These feed the funnel model; without them the funnel is fiction.
83
-
84
- ### Optional sweeps
85
- - Trends/seasonality (search-volume tools, industry calendars) when timing
86
- matters; regulatory scan when PESTEL is in play.
87
-
88
- ## Research spikes
89
-
90
- A standalone market question outside a full engagement:
91
- `mkt_docs/spikes/RESEARCH_[topic].md` — question, time-box, method, answer,
92
- ledger rows created, consequences. Max 1 page + ledger entries.
93
-
94
- ## Anti-patterns
95
-
96
- - **Numbers from memory:** model knowledge is not a source. If it matters,
97
- search it; if unsearchable, it is an ASSUMPTION with a range.
98
- - **Single-source budget decisions** (violates the two-source rule).
99
- - **Prose-only research:** findings that never become ledger rows are lost
100
- and unverifiable.
101
- - **Competitor mind-reading:** report what is observable; label inference as
102
- inference.
103
- - **Benchmark hoarding:** 50 ledger rows nobody cites. Research serves the
104
- plan; unreferenced rows get pruned at closure (validator warns).
1
+ # Research Playbook + Evidence Ledger Discipline
2
+
3
+ Research turns the user's facts into a defendable picture of the outside
4
+ world. Its output is never prose alone: every number lands in the ledger,
5
+ every claim carries its reference.
6
+
7
+ ## The Evidence Ledger
8
+
9
+ Single file: `mkt_docs/research/evidence_ledger.md`. One table, one row per
10
+ piece of evidence:
11
+
12
+ | ID | Claim | Class | Value / Range | Source | Date | Confidence |
13
+ |---|---|---|---|---|---|---|
14
+
15
+ - **ID**: `EV-01`, `EV-02`, ... sequential, never reused. Artifacts cite
16
+ numbers as `[EV-nn]`.
17
+ - **Class** (exactly one):
18
+ - `FACT` — user input or primary data (their analytics, their CRM export).
19
+ Source = "user, Wave 1" or the data file.
20
+ - `BENCHMARK` — external number. Source URL **and** publication date
21
+ mandatory. The Source cell must carry the actual external URL, NOT a
22
+ pointer to one of your own research documents that aggregates it ("see
23
+ VOC.md" is not a source — the validator rejects a BENCHMARK whose Source
24
+ has no `http`). A benchmark older than 24 months is flagged in review.
25
+ - `ASSUMPTION` — a number we need but could not source. Range mandatory
26
+ (not a point estimate), Confidence mandatory (HIGH/MED/LOW), and the
27
+ rationale in the Claim cell. Assumptions that drive budget decisions are
28
+ listed in the plan's page-one Assumptions section.
29
+ - **Laundering is the cardinal sin:** an ASSUMPTION never migrates to
30
+ BENCHMARK without a real source; a stale benchmark is not refreshed by
31
+ editing its date. `mkt_check.py ledger` enforces the mechanical part
32
+ (references resolve, benchmarks have URLs, assumptions have confidence);
33
+ honesty enforces the rest.
34
+
35
+ **Two-source rule:** any number that will drive a budget allocation or an
36
+ objective target needs two independent sources (two ledger rows or one row
37
+ citing both). One vendor's blog post does not size a market.
38
+
39
+ **Source hierarchy** (prefer higher): primary data > official statistics /
40
+ regulator data > industry analyst reports > trade press > vendor benchmarks >
41
+ individual blog posts (last resort, flag as weak in Confidence).
42
+
43
+ ## The engine
44
+
45
+ **Preferred:** when the `deep-research` skill (or an equivalent multi-agent
46
+ research harness) is available, use it as the engine — one refined question
47
+ per sweep, findings adversarially verified, sources cited. Feed its cited
48
+ findings into the ledger; do not bypass the ledger because the engine already
49
+ cites.
50
+
51
+ **Fallback:** manual web search per the sweep playbooks below. Slower;
52
+ the ledger discipline is identical.
53
+
54
+ ## Mandatory sweeps (E3)
55
+
56
+ ### 1. Market sizing
57
+ - Bottom-up first: reachable potential customers (from official statistics,
58
+ association registries, platform audience tools) × realistic price
59
+ `[EV: price FACT]`. Top-down (report % slicing) only as cross-check.
60
+ - Output: TAM/SAM/SOM with every input as a ledger row.
61
+
62
+ ### 2. Competitor scan
63
+ - Start from the user's seeds (Wave 1) + search-discovered players.
64
+ - Per competitor: positioning claim (their own words, from their site),
65
+ visible pricing, observed channels (where do they show up: ads
66
+ transparency libraries, social presence, SEO footprint), review sentiment.
67
+ - Output: `mkt_docs/research/COMPETITORS.md` + ledger rows for anything
68
+ numeric. Observed facts, not speculation about their strategy.
69
+
70
+ ### 3. Voice of customer (VoC)
71
+ - Mine reviews (their category on G2/Capterra/Trustpilot/Amazon/app stores as
72
+ applicable), forums, Reddit, comment sections — where the target segment
73
+ already speaks.
74
+ - Harvest verbatim quotes with URLs: pains, desired outcomes, objections,
75
+ vocabulary (the actual words become messaging raw material).
76
+ - Output: `mkt_docs/research/VOC.md`. Persona traits in `ICP_PERSONAS.md`
77
+ must trace here.
78
+
79
+ ### 4. Channel benchmarks
80
+ - For candidate channels: typical CPC/CPM, CTR, conversion rates, CAC ranges
81
+ for the industry — each a BENCHMARK row with URL + date.
82
+ - These feed the funnel model; without them the funnel is fiction.
83
+
84
+ ### Optional sweeps
85
+ - Trends/seasonality (search-volume tools, industry calendars) when timing
86
+ matters; regulatory scan when PESTEL is in play.
87
+
88
+ ## Research spikes
89
+
90
+ A standalone market question outside a full engagement:
91
+ `mkt_docs/spikes/RESEARCH_[topic].md` — question, time-box, method, answer,
92
+ ledger rows created, consequences. Max 1 page + ledger entries.
93
+
94
+ ## Anti-patterns
95
+
96
+ - **Numbers from memory:** model knowledge is not a source. If it matters,
97
+ search it; if unsearchable, it is an ASSUMPTION with a range.
98
+ - **Single-source budget decisions** (violates the two-source rule).
99
+ - **Prose-only research:** findings that never become ledger rows are lost
100
+ and unverifiable.
101
+ - **Competitor mind-reading:** report what is observable; label inference as
102
+ inference.
103
+ - **Benchmark hoarding:** 50 ledger rows nobody cites. Research serves the
104
+ plan; unreferenced rows get pruned at closure (validator warns).