@cyber-dash-tech/revela 0.16.4 → 0.17.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.
Files changed (57) hide show
  1. package/README.md +7 -5
  2. package/README.zh-CN.md +7 -5
  3. package/lib/commands/brief.ts +9 -0
  4. package/lib/commands/help.ts +5 -2
  5. package/lib/commands/init.ts +42 -27
  6. package/lib/commands/narrative.ts +39 -6
  7. package/lib/commands/research.ts +36 -20
  8. package/lib/commands/review.ts +35 -28
  9. package/lib/ctx.ts +1 -1
  10. package/lib/decks-state.ts +38 -4
  11. package/lib/edit/prompt.ts +1 -1
  12. package/lib/hook-notifications.ts +53 -0
  13. package/lib/media/download.ts +23 -3
  14. package/lib/media/save.ts +1 -0
  15. package/lib/media/types.ts +1 -0
  16. package/lib/narrative-state/display.ts +74 -4
  17. package/lib/narrative-state/map-html.ts +242 -107
  18. package/lib/narrative-state/render-plan.ts +238 -35
  19. package/lib/narrative-state/research-binding-eval.ts +260 -0
  20. package/lib/narrative-state/research-gaps.ts +2 -88
  21. package/lib/narrative-vault/authoring-contract.ts +127 -0
  22. package/lib/narrative-vault/authoring-guard.ts +122 -0
  23. package/lib/narrative-vault/auto-compile.ts +134 -0
  24. package/lib/narrative-vault/bootstrap.ts +63 -0
  25. package/lib/narrative-vault/cache.ts +14 -0
  26. package/lib/narrative-vault/compile-mirror.ts +45 -0
  27. package/lib/narrative-vault/compile.ts +350 -0
  28. package/lib/narrative-vault/constants.ts +6 -0
  29. package/lib/narrative-vault/diagnostic-report.ts +117 -0
  30. package/lib/narrative-vault/export.ts +71 -0
  31. package/lib/narrative-vault/frontmatter.ts +41 -0
  32. package/lib/narrative-vault/hook-targets.ts +40 -0
  33. package/lib/narrative-vault/index.ts +18 -0
  34. package/lib/narrative-vault/inventory.ts +392 -0
  35. package/lib/narrative-vault/markdown-qa.ts +237 -0
  36. package/lib/narrative-vault/markdown.ts +34 -0
  37. package/lib/narrative-vault/migration.ts +52 -0
  38. package/lib/narrative-vault/mutate.ts +361 -0
  39. package/lib/narrative-vault/paths.ts +19 -0
  40. package/lib/narrative-vault/read.ts +52 -0
  41. package/lib/narrative-vault/relations.ts +32 -0
  42. package/lib/narrative-vault/source-loader.ts +19 -0
  43. package/lib/narrative-vault/timestamp.ts +32 -0
  44. package/lib/narrative-vault/types.ts +44 -0
  45. package/lib/qa/checks.ts +206 -5
  46. package/lib/qa/measure.ts +63 -1
  47. package/lib/refine/server.ts +157 -20
  48. package/lib/source-materials.ts +98 -0
  49. package/lib/tool-result.ts +34 -0
  50. package/package.json +2 -2
  51. package/plugin.ts +60 -22
  52. package/skill/NARRATIVE_SKILL.md +25 -10
  53. package/skill/SKILL.md +6 -1
  54. package/tools/decks.ts +363 -67
  55. package/tools/narrative-view.ts +16 -0
  56. package/tools/research-save.ts +3 -0
  57. package/tools/workspace-scan.ts +1 -0
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **English** | [中文](README.zh-CN.md)
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/@cyber-dash-tech/revela)](https://www.npmjs.com/package/@cyber-dash-tech/revela) [![license](https://img.shields.io/npm/l/@cyber-dash-tech/revela)](LICENSE) [![tests](https://img.shields.io/badge/tests-380%20passing-brightgreen)](tests/) [![OpenCode plugin](https://img.shields.io/badge/OpenCode-plugin-blue)](https://opencode.ai) [![Bun](https://img.shields.io/badge/Bun-%E2%89%A51.0-orange)](https://bun.sh)
5
+ [![npm version](https://img.shields.io/npm/v/@cyber-dash-tech/revela)](https://www.npmjs.com/package/@cyber-dash-tech/revela) [![license](https://img.shields.io/npm/l/@cyber-dash-tech/revela)](LICENSE) [![tests](https://img.shields.io/badge/tests-470%20passing-brightgreen)](tests/) [![OpenCode plugin](https://img.shields.io/badge/OpenCode-plugin-blue)](https://opencode.ai) [![Bun](https://img.shields.io/badge/Bun-%E2%89%A51.0-orange)](https://bun.sh)
6
6
 
7
7
  <p align="center">
8
8
  <img src="assets/img/logo.png" alt="Revela" width="800" />
@@ -20,7 +20,7 @@ Its first render target is still the HTML slide deck: start a Revela workflow co
20
20
  - injects one-shot workflow instructions for explicit commands such as `/revela init`, `/revela story`, and `/revela make --deck`
21
21
  - switches into deck-render prompt mode only when you explicitly start `/revela make --deck`
22
22
  - supports workspace document discovery, transparent text extraction for `.pdf`, `.docx`, `.pptx`, and `.xlsx`, and cached embedded-material extraction for those formats
23
- - keeps `DECKS.json` as the current workspace state engine for sources, research actions, findings, claims, evidence, narrative intent, render targets, and readiness
23
+ - uses `revela-narrative/` as the editable Markdown narrative vault when present, with `DECKS.json` as the compatibility/render-state mirror
24
24
  - reviews narrative readiness before artifact rendering, then separately gates deck HTML writes through deck/artifact readiness
25
25
  - records review snapshots so stale readiness cannot silently authorize new deck HTML after important state changes
26
26
  - treats HTML decks, PDF, and PPTX as render targets from shared workspace state rather than isolated output files
@@ -168,17 +168,19 @@ The ambient enabled or disabled state is session-level only.
168
168
 
169
169
  ### Workspace State
170
170
 
171
- `DECKS.json` is Revela's workspace state engine and compatibility file. It is still stored at the workspace root and remains readable as the current deck project state, but internally Revela now treats it as a lightweight persistence layer for more than a deck checklist.
171
+ `revela-narrative/` is Revela's editable Markdown narrative vault when present. It stores the human/LLM-editable source for audience, decision, thesis, claims, evidence nodes, objections, risks, research gaps, and typed narrative relations.
172
+
173
+ `DECKS.json` remains Revela's compatibility and render-state file. It is still stored at the workspace root and remains readable as the current deck project state, but when a vault exists its top-level `narrative` is a compiled mirror from Markdown rather than the primary editing surface.
172
174
 
173
175
  The state records:
174
176
 
175
177
  - workspace source materials and reusable extraction cache paths
176
178
  - research plans, saved findings, and compact action provenance
177
- - canonical narrative state, approvals, objections, risks, slide specs, claim candidates, and evidence trace
179
+ - compiled canonical narrative mirror, approvals, objections, risks, slide specs, claim candidates, and evidence trace
178
180
  - render targets such as the active HTML deck plus derived PDF and PPTX artifacts
179
181
  - review snapshots with input hashes so old readiness results become stale after meaningful state changes
180
182
 
181
- Existing root `DECKS.json` workspaces remain compatible. Running `/revela init` or `/revela story` on an older project can normalize canonical narrative state and refresh projection fields without requiring a manual migration, moving files, or replacing `DECKS.json` with a database. `writeReadiness.status: "ready"` is deck/artifact readiness only; it is never narrative approval.
183
+ New workspaces bootstrap `revela-narrative/` directly with `initNarrativeVault`; stable findings can be recorded as partial Markdown nodes without waiting for a complete story. `/revela init` is repeatable ingest: first runs consider all supported source files, later runs prioritize files added or modified after the latest vault Markdown timestamp plus same-path files whose fingerprint changed, then distill stable findings into vault nodes. Developer workspaces that still have a JSON narrative but no Markdown vault receive a migration hint from `revela-decks read` with `summary: true`; `exportNarrativeVault` can export that narrative into `revela-narrative/` without moving approvals, render targets, review snapshots, artifact coverage, actions, deck specs, or source material records into Markdown. Generated cache files live under `.opencode/revela/narrative-cache/` and should not be edited by hand. `writeReadiness.status: "ready"` is deck/artifact readiness only; it is never narrative approval.
182
184
 
183
185
  Decks remain the primary authored artifact, but they are now treated as render targets from the same workspace state that can later support briefs, appendix material, Evidence Inspector views, Q&A, and interactive reading layers without duplicating source/evidence logic.
184
186
 
package/README.zh-CN.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [English](README.md) | **中文**
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/@cyber-dash-tech/revela)](https://www.npmjs.com/package/@cyber-dash-tech/revela) [![license](https://img.shields.io/npm/l/@cyber-dash-tech/revela)](LICENSE) [![tests](https://img.shields.io/badge/tests-380%20passing-brightgreen)](tests/) [![OpenCode plugin](https://img.shields.io/badge/OpenCode-plugin-blue)](https://opencode.ai) [![Bun](https://img.shields.io/badge/Bun-%E2%89%A51.0-orange)](https://bun.sh)
5
+ [![npm version](https://img.shields.io/npm/v/@cyber-dash-tech/revela)](https://www.npmjs.com/package/@cyber-dash-tech/revela) [![license](https://img.shields.io/npm/l/@cyber-dash-tech/revela)](LICENSE) [![tests](https://img.shields.io/badge/tests-470%20passing-brightgreen)](tests/) [![OpenCode plugin](https://img.shields.io/badge/OpenCode-plugin-blue)](https://opencode.ai) [![Bun](https://img.shields.io/badge/Bun-%E2%89%A51.0-orange)](https://bun.sh)
6
6
 
7
7
  <p align="center">
8
8
  <img src="assets/img/logo.png" alt="Revela" width="800" />
@@ -20,7 +20,7 @@ Revela 是一个 [OpenCode](https://opencode.ai) 插件,用来把工作区来
20
20
  - 为 `/revela init`、`/revela story`、`/revela make --deck` 等显式命令注入一次性 workflow instructions
21
21
  - 只有在显式运行 `/revela make --deck` 时,才切换到 deck-render prompt mode
22
22
  - 支持工作区文档扫描,以及 `.pdf`、`.docx`、`.pptx`、`.xlsx` 的透明文本提取和嵌入素材缓存提取
23
- - `DECKS.json` 作为当前 workspace state engine,持续记录来源材料、调研动作、findings、claims、证据、叙事意图、render targets 和 readiness
23
+ - 存在 `revela-narrative/` 时,将它作为可编辑 Markdown narrative vault,并让 `DECKS.json` 作为兼容/render-state mirror
24
24
  - 先检查 narrative readiness,再用独立 deck/artifact gate 保护 deck HTML 写入
25
25
  - 记录 review snapshots,避免重要状态变化后旧的 ready 结果继续默默授权写入 deck HTML
26
26
  - 把 HTML deck、PDF 和 PPTX 视为来自同一 workspace state 的 render targets,而不是互相孤立的输出文件
@@ -166,17 +166,19 @@ Active domain 只进入 narrative pipeline。它帮助 `init`、`research`、`st
166
166
 
167
167
  ### Workspace State
168
168
 
169
- `DECKS.json` Revela 当前的 workspace state engine,也是兼容旧工作流的状态文件。它仍然保存在工作区根目录,也仍然可以理解为当前 deck 项目的状态入口,但 Revela 内部已经不再把它当成单纯的 deck checklist
169
+ 存在 `revela-narrative/` 时,它就是 Revela 可编辑的 Markdown narrative vault,用来保存 audience、decision、thesis、claims、evidence nodes、objections、risks、research gaps typed narrative relations
170
+
171
+ `DECKS.json` 仍然是 Revela 的兼容状态和 render-state 文件。它仍然保存在工作区根目录,也仍然可以理解为当前 deck 项目的状态入口;但当 vault 存在时,顶层 `narrative` 是从 Markdown 编译得到的 mirror,不再是主要编辑面。
170
172
 
171
173
  状态中会记录:
172
174
 
173
175
  - 工作区来源材料和可复用的 extraction cache 路径
174
176
  - 调研计划、已保存 findings,以及精简的 action provenance
175
- - canonical narrative state、approvals、objections、risks、slide specs、claim candidates 和 evidence trace
177
+ - 编译得到的 canonical narrative mirror、approvals、objections、risks、slide specs、claim candidates 和 evidence trace
176
178
  - active HTML deck 以及派生 PDF、PPTX 等 render targets
177
179
  - 带 input hash 的 review snapshots,使重要状态变化后旧的 readiness 自动变 stale
178
180
 
179
- 已有的根目录 `DECKS.json` 工作区继续兼容。对旧项目运行 `/revela init` `/revela story` 时,可以安全 normalize canonical narrative state 并刷新 projection 字段;用户不需要手动迁移、不需要移动文件,也不需要把 `DECKS.json` 换成数据库。`writeReadiness.status: "ready"` 只代表 deck/artifact readiness,永远不等于 narrative approval。
181
+ 新工作区会直接用 `initNarrativeVault` bootstrap `revela-narrative/`;LLM 扫描到稳定 finding 后,可以先写入 partial Markdown nodes,不需要等待完整故事成型。`/revela init` 是可重复 ingest:首次运行会考虑所有支持的 source files,后续运行优先处理晚于最新 vault Markdown timestamp 的新增/修改文件,以及同一路径 fingerprint 变化的文件,并把稳定 finding 提炼进 vault nodes。仍只有 JSON narrative、还没有 Markdown vault 的开发期工作区,会在 `revela-decks read``summary: true` 时收到 migration hint;`exportNarrativeVault` 可以把该 narrative 导出到 `revela-narrative/`,同时不会把 approvals、render targets、review snapshots、artifact coverage、actions、deck specs 或 source material records 搬进 Markdown。生成缓存位于 `.opencode/revela/narrative-cache/`,不应手工编辑。`writeReadiness.status: "ready"` 只代表 deck/artifact readiness,永远不等于 narrative approval。
180
182
 
181
183
  Deck 仍然是主要 authored artifact,但现在它是从同一份 workspace state 渲染出来的目标之一。后续 briefs、appendix material、Evidence Inspector views、Q&A 和 interactive reading layers 都可以复用同一套来源/证据逻辑,而不是各自生成孤立内容。
182
184
 
@@ -2,6 +2,7 @@ import { existsSync, mkdirSync, writeFileSync } from "fs"
2
2
  import { dirname, isAbsolute, join, normalize, resolve } from "path"
3
3
  import { readDecksState, writeDecksState } from "../decks-state"
4
4
  import { compileExecutiveBrief, DEFAULT_EXECUTIVE_BRIEF_PATH } from "../narrative-state/executive-brief"
5
+ import { compileNarrativeVault, formatVaultDiagnosticMarkdown, formatVaultDiagnosticReport, hasNarrativeVault } from "../narrative-vault"
5
6
 
6
7
  export interface BriefArgs {
7
8
  outputPath?: string
@@ -29,6 +30,14 @@ export async function handleBrief(
29
30
  }
30
31
 
31
32
  const state = readDecksState(input.workspaceRoot)
33
+ if (hasNarrativeVault(input.workspaceRoot)) {
34
+ const vault = compileNarrativeVault(input.workspaceRoot, { fallbackApprovals: state.narrative?.approvals ?? [] })
35
+ const report = formatVaultDiagnosticReport(vault.diagnostics)
36
+ if (!report.ok) {
37
+ await send(`**Executive brief not rendered**\n\n${formatVaultDiagnosticMarkdown(report)}\n\nFix the narrative vault blockers before rendering.`)
38
+ return
39
+ }
40
+ }
32
41
  const result = compileExecutiveBrief(state, { outputPath: input.outputPath })
33
42
  if (!result.ok) {
34
43
  await send(
@@ -14,7 +14,7 @@ export async function handleHelp(
14
14
  ): Promise<void> {
15
15
  const design = activeDesign()
16
16
  const domain = activeDomain()
17
- const status = ctx.enabled ? "enabled " : "disabled"
17
+ const status = ctx.enabled ? "enabled - Revela prompt is loaded" : "disabled - run `/revela enable` or any workflow command"
18
18
  await send(
19
19
  `\`\`\`\n` +
20
20
  ` R E V E L A H e l p v${pkg.version}\n` +
@@ -23,7 +23,8 @@ export async function handleHelp(
23
23
  `**Current**\n\n` +
24
24
  `Status: ${status}\n` +
25
25
  `Design: \`${design}\`\n` +
26
- `Domain: \`${domain}\`\n\n` +
26
+ `Domain: \`${domain}\`\n` +
27
+ `Run \`/revela enable\` to load Revela context without starting a workflow, or run \`/revela disable\` to pause it. Workflow commands still auto-enable Revela.\n\n` +
27
28
  `---\n\n` +
28
29
  `**Workflow**\n\n` +
29
30
  `1. \`init\` — discover workspace sources and capture intent\n` +
@@ -35,6 +36,8 @@ export async function handleHelp(
35
36
  `---\n\n` +
36
37
  `**Commands**\n\n` +
37
38
  `\`/revela\` — show REVELA help\n` +
39
+ `\`/revela enable\` — enable Revela prompt/context without starting a workflow\n` +
40
+ `\`/revela disable\` — disable Revela prompt/context for this session\n` +
38
41
  `\`/revela init\` — initialize or refresh workspace story state\n` +
39
42
  `\`/revela research\` — research, bind evidence, and reduce story gaps\n` +
40
43
  `\`/revela story [-l language]\` — open the read-only story workspace UI\n` +
@@ -9,17 +9,15 @@ export function buildInitPrompt({
9
9
  }): string {
10
10
  const mode = exists
11
11
  ? `A ${DECKS_STATE_FILE} file already exists. Read it first through the revela-decks tool and update it conservatively.`
12
- : `No ${DECKS_STATE_FILE} file exists yet. Create it through the revela-decks tool only when there is enough stable workspace or narrative context.`
12
+ : `No ${DECKS_STATE_FILE} file exists yet. Initialize the Markdown narrative vault through the revela-decks tool before writing narrative meaning.`
13
13
 
14
14
  return `Initialize Revela narrative workspace state.
15
15
 
16
16
  Goal:
17
- - Build or update ${DECKS_STATE_FILE}, the workspace-level machine-readable state file for Revela narrative and artifact work.
18
- - Use the \`revela-decks\` tool for state updates. Do not write or patch ${DECKS_STATE_FILE} directly.
19
- - Capture stable narrative context first: primary audience, belief before, belief after, decision/action, thesis, central claims, evidence availability, objections, risks, available source materials, existing artifact history, and open questions.
20
- - Do not treat initialization as permission to write a deck. Narrative readiness is reviewed later by \`/revela story\`; deck/artifact readiness is handled by \`/revela make --deck\` after story approval and deck-plan confirmation.
21
- - Do not require slide count, visual style, design selection, output path, layout choices, or component choices during narrative initialization unless the user explicitly asks to render a deck now.
22
- - ${DECKS_STATE_FILE} is the compatibility workspace-state file. Deck specs are render-target projections, not the center of initialization.
17
+ - Build or refresh ${DECKS_STATE_FILE} and the Markdown narrative vault from local workspace evidence.
18
+ - Treat init as repeatable ingest: discover files, register source materials, follow returned ingest task hints, and distill stable narrative meaning.
19
+ - Capture primary audience, belief before/after, decision/action, thesis, central claims, evidence availability, objections, risks, source materials, artifact history, and open questions.
20
+ - Do not treat initialization as permission to write a deck. Do not require slide count, visual style, design selection, output path, layout choices, or component choices unless the user explicitly asks to render.
23
21
 
24
22
  Current state:
25
23
  - ${mode}
@@ -33,26 +31,43 @@ Workspace boundary rules:
33
31
  - Do not use \`~\`, \`..\`, or parent-directory traversal to discover files.
34
32
  - If the current workspace appears too broad, stop and ask the user which workspace subdirectory to initialize instead of scanning outside or deeply across everything.
35
33
 
36
- Workflow:
37
- 1. Use the \`revela-workspace-scan\` tool to inspect document and data files in the workspace. Start with no \`path\` and \`max_depth: 2\`.
38
- 2. Separately search for existing artifact history, especially:
39
- - \`decks/**/*.html\`
40
- - \`slides/**/*.html\`
41
- - \`presentations/**/*.html\`
42
- - \`decks/**/*.pdf\`
43
- - \`slides/**/*.pdf\`
44
- Run these searches only inside the current workspace root. These are generated/output artifacts, not necessarily source materials. If \`decks/\` contains exactly one HTML file, record it as existing artifact history and possible current deck artifact. If \`decks/\` contains multiple HTML files, do not guess which one is canonical; ask the user which artifact belongs to this workspace or whether extra decks should move to separate workspaces.
45
- 3. Register or refresh source material records by passing the scan result's \`sourceMaterial\` objects to \`revela-decks\` action \`init\`. Preserve unchanged existing records; the tool will upsert by path and fingerprint.
46
- 4. Select the files that look most relevant for understanding the narrative problem. Prioritize source decks, PDFs, Word docs, spreadsheets, CSVs, Markdown, text notes, and relevant existing generated artifacts.
47
- 5. Do not automatically extract every PDF/PPTX/DOCX/XLSX during init. Call \`revela-extract-document-materials\` only for selected files that are clearly needed to form conservative narrative memory, or when the user explicitly asked to analyze the material now.
48
- 6. Before extracting or deeply reading a selected document, check \`DECKS.json.workspace.sourceMaterials\`. If the same path has the same fingerprint and valid extraction paths, reuse those paths instead of repeating extraction.
49
- 7. Read only the materials needed to form conservative narrative memory. Do not exhaustively read every file if the workspace is large.
50
- 8. If enough information is available, preserve canonical narrative intent through \`revela-decks\` action \`upsertNarrative\`: audience intent, decision intent, thesis, central claims, explicit evidence bindings where known, objections, and risks. This does not require deck rendering inputs.
51
- 9. If the workspace has explicit slide/deck information, existing HTML, or a user-requested deck task, you may also call \`upsertDeck\` and \`upsertSlides\` for explicit deck information. The tool projects canonical narrative state back to compatibility \`narrativeBrief\` when a deck record exists. Do not pass or ask for a deck key; the tool uses the workspace folder name internally. Do not mark deck readiness ready during init.
52
- 10. When adopting an existing HTML deck, analyze the artifact and create one conservative \`SlideSpec\` per identifiable slide/page only if the artifact is clearly the current workspace artifact. Record only visible source notes or explicit source information as evidence; do not infer original evidence that is not present in the artifact.
53
- 11. When a read or extracted source material clearly supports a specific narrative or slide claim, preserve compact evidence trace such as \`sourcePath\`, \`location\`, \`extractedTextPath\`, or \`extractedManifestPath\`. Attach extraction cache paths only when they support that specific claim, not to every claim or slide by default.
54
- 12. Treat \`workspace.sourceMaterials\` as a reusable candidate index, not proof by itself. A source material record alone is not narrative evidence or slide evidence.
55
- 13. Report what was initialized or updated and list the smallest open narrative questions needed to proceed.
34
+ Expected tool use during init:
35
+ - \`revela-decks init\` and \`revela-decks initNarrativeVault\` are expected controlled workspace-state/vault boundaries. Empty-looking optional fields in tool UI are a schema display artifact, not user-provided evidence.
36
+ - Treat \`authoringContract\` returned by \`read(summary: true)\`, \`initNarrativeVault\`, or \`narrativeInventory\` as the Markdown authoring guide: valid node types, plain id convention, inline relation syntax, forbidden compatibility actions, and optional helper templates.
37
+ - Treat \`markdownQa\` returned by \`read(summary: true)\`, \`compileNarrativeVault\`, or \`revela-decks markdownQa\` as post-authoring repair feedback that is separate from compiler diagnostics. Fix \`repairCards\` by smallest repair; do not invent missing claims, evidence, source paths, URLs, quotes, or caveats just to clear QA. If \`compileNarrativeVault\` output does not visibly include \`markdownQa\`, call \`revela-decks markdownQa\` before final reporting.
38
+ - Before authoring claims, evidence, relations, objections, risks, or research gaps, inspect \`narrativeInventory\` from \`read(summary: true)\` or call \`revela-decks narrativeInventory\`. Reuse existing ids and relation targets. Do not invent evidence ids, claim ids, or relation targets before checking inventory unless you are intentionally creating the missing node in Markdown.
39
+ - Create/update content nodes first. Add graph edges afterward in the source node's \`## Relations\` section with plain node-id wikilinks. Do not use \`relations.md\`, typed wikilinks, or hand-written relation ids.
40
+ - You may directly maintain \`revela-narrative/**/*.md\` knowledge nodes. Use structured vault helpers only when they reduce schema risk or express a narrow lifecycle/evidence-binding action: \`bindResearchFindings\`, \`upsertVaultEvidence\`, \`upsertVaultResearchGap\`, \`updateVaultResearchGap\`, or similar targeted helpers.
41
+ - Use targeted vault helpers only when you have a complete payload for that node/action. If a helper returns missing fields, report the gap or repair Markdown directly; do not invent fields.
42
+ - Do not use JSON-era compatibility actions such as \`upsertResearchGaps\`, \`deriveResearchGaps\`, \`updateResearchGap\`, \`closeResearchGap\`, \`applyEvidenceCandidates\`, or \`upsertNarrative\` in vault workspaces. Follow the tool error and \`authoringContract\` replacement action.
43
+ - Direct Markdown patches must update existing sections in place. Do not duplicate stable headings such as \`## Evidence\`, \`## Caveats\`, \`## Relations\`, \`## Response\`, or \`## Mitigation\`.
44
+ - Do not append a second frontmatter block. A vault Markdown file must have one leading \`---\` frontmatter block only.
45
+
46
+ Minimum vault authoring contract:
47
+ - Supported \`type\` values are \`index\`, \`audience\`, \`decision\`, \`thesis\`, \`claim\`, \`evidence\`, \`objection\`, \`risk\`, and \`research-gap\`. Use \`research-gap\`, not \`researchGap\` or \`research_gap\`.
48
+ - New graph relations belong in node-local \`## Relations\` sections, for example \`- supports: [[claim-belief-change-purpose]] - Optional rationale.\` Compiler-generated ids are deterministic; never hand-write relation ids.
49
+ - Relation wikilinks reference plain frontmatter node ids directly. Do not write typed targets such as \`[[claim:claim-belief-change-purpose]]\`.
50
+ - Evidence nodes require source trace (\`source\`, \`sourcePath\` or \`url\` when known, \`location\` when known), \`supportScope\`, \`unsupportedScope\`, \`caveat\`, \`strength\`, a quoted/snippet body, and a \`## Relations\` line such as \`- supports: [[claim-id]]\` when the supported claim is explicit. Keep \`claimId\` only as compatibility fallback for existing vaults or helper outputs.
51
+ - When fixing a new node created earlier in the same turn, patch the broken line or section. Do not delete and recreate existing nodes just to fix \`type\`, frontmatter, or relation syntax.
52
+
53
+ Required workflow:
54
+ 1. If ${DECKS_STATE_FILE} exists, call \`revela-decks read\` with \`summary: true\`. If \`migration.available: true\`, prefer \`exportNarrativeVault\`; if no vault exists, call \`initNarrativeVault\` before recording narrative meaning.
55
+ 2. Call \`revela-workspace-scan\` with no \`path\` and \`max_depth: 2\`. Scan deeper only when the user points to a workspace-relative folder or expected files are missing.
56
+ 3. Search workspace-local generated artifact history only when useful: \`decks/**/*.html\`, \`slides/**/*.html\`, \`presentations/**/*.html\`, \`decks/**/*.pdf\`, and \`slides/**/*.pdf\`.
57
+ 4. Register scan results with \`revela-decks init\`. Treat returned \`ingest.suggestedTasks\` as the authoritative init task list. Each task includes \`path\`, \`reason\`, \`materialType\`, \`needsExtraction\`, and \`suggestedAction\`.
58
+ 5. For selected relevant tasks, read directly when \`suggestedAction: "read_directly"\`; call \`revela-extract-document-materials\` first when \`suggestedAction: "extract_then_read"\`. Do not extract every document by default.
59
+ 6. Before writing narrative meaning, inspect \`narrativeInventory\` from the latest \`read(summary: true)\` result or call \`revela-decks narrativeInventory\`. Then distill stable findings into \`revela-narrative/**/*.md\` using the Markdown authoring guide. Completeness is not a gate: write partial claims, caveats, unsupported scope, and research gaps rather than waiting for a complete story. Use optional helpers such as \`upsertVaultResearchGap\`, \`upsertVaultEvidence\`, or \`bindResearchFindings\` only when they fit the exact update. Preserve frontmatter ids and existing section headings when editing Markdown. Write nodes first; add inline \`## Relations\` edges afterward only when explicit.
60
+ 7. After Markdown changes, rely on the vault write hook or call \`revela-decks markdownQa\`, then \`revela-decks compileNarrativeVault\`; keep \`markdownQa.repairCards\` separate from compiler blockers and fix both before treating the narrative as usable. If no explicit \`markdownQa\` result is visible after compile, call \`revela-decks markdownQa\` as a manual fallback. Do not use \`upsertNarrative\`.
61
+ 8. If explicit deck/artifact information exists, record conservative deck specs only from visible information. Do not infer hidden evidence from generated artifacts.
62
+ 9. Report initialized/updated/migrated state plus counts and paths for added, changed, newer-than-vault, unchanged, \`ingest.ingestCandidates\`, and \`ingest.suggestedTasks\`. Always include \`Markdown QA: clean\` or \`Markdown QA blockers:\` in the final report. If Markdown QA blockers remain, do not say the workspace initialized cleanly; say the vault was initialized but Markdown repairs remain.
63
+
64
+ Evidence boundary:
65
+ - \`workspace.sourceMaterials\` and ingest task hints are candidate context, not proof.
66
+ - A finding becomes canonical only when a vault node preserves source trace, quote/snippet, support scope, unsupported scope, caveat, and strength.
67
+ - Preserve graph meaning by writing explicit edges in node-local \`## Relations\` sections after nodes exist. Use plain node-id wikilinks and optional inline rationale.
68
+ - Intent briefs, proposals, and user-authored plans may support audience, decision, thesis, stakeholder framing, and stated internal intent. They do not by themselves prove market size, competitor performance, product-market fit, operating-model effectiveness, or external factual claims.
69
+ - If a source states an intended strategy but not its external factual basis, record the strategy as a claim with partial or missing support and add a research gap instead of binding it as strong evidence.
70
+ - A successful vault compile means the vault is structurally valid. It is not evidence readiness, narrative approval, or permission to make a deck/brief.
56
71
 
57
72
  Narrative questions to ask only when missing:
58
73
  - Who is the primary audience?
@@ -6,6 +6,8 @@ import { hasDecksState, readDecksState } from "../decks-state"
6
6
  import { buildNarrativeMap, formatNarrativeMap } from "../narrative-state/map"
7
7
  import { renderNarrativeMapHtmlWithDisplay } from "../narrative-state/map-html"
8
8
  import { emptyDisplayModel, type NarrativeViewLanguage, type ValidatedNarrativeDisplayModel } from "../narrative-state/display"
9
+ import type { NarrativeApproval } from "../narrative-state/types"
10
+ import { compileNarrativeVault, formatVaultDiagnosticMarkdown, formatVaultDiagnosticReport, hasNarrativeVault } from "../narrative-vault"
9
11
 
10
12
  export interface NarrativeArgs {
11
13
  language: NarrativeViewLanguage
@@ -82,7 +84,8 @@ export async function handleNarrative(
82
84
 
83
85
  const state = readDecksState(options.workspaceRoot)
84
86
  const map = buildNarrativeMap(state)
85
- const markdown = formatNarrativeMap(map)
87
+ const diagnosticsMarkdown = vaultDiagnosticsMarkdown(options.workspaceRoot, state.narrative?.approvals ?? [])
88
+ const markdown = [diagnosticsMarkdown, formatNarrativeMap(map)].filter(Boolean).join("\n\n")
86
89
 
87
90
  if (options.openBrowser) {
88
91
  const htmlPath = writeNarrativeMapHtml(map, options.display ?? emptyDisplayModel(options.language ?? "en"))
@@ -102,16 +105,35 @@ export async function handleNarrative(
102
105
  }
103
106
  }
104
107
 
108
+ function vaultDiagnosticsMarkdown(workspaceRoot: string, fallbackApprovals: NarrativeApproval[]): string {
109
+ if (!hasNarrativeVault(workspaceRoot)) return ""
110
+ const result = compileNarrativeVault(workspaceRoot, { fallbackApprovals })
111
+ return formatVaultDiagnosticMarkdown(formatVaultDiagnosticReport(result.diagnostics))
112
+ }
113
+
105
114
  export function buildNarrativeViewPrompt(options: { workspaceRoot: string; language: NarrativeViewLanguage }): string {
106
115
  if (!hasDecksState(options.workspaceRoot)) {
107
116
  return "No `DECKS.json` found. Tell the user to run `/revela init` before opening the narrative view. Do not call any tool."
108
117
  }
109
118
 
110
- const map = buildNarrativeMap(readDecksState(options.workspaceRoot))
119
+ const state = readDecksState(options.workspaceRoot)
120
+ const map = buildNarrativeMap(state)
121
+ const vaultDiagnostics = hasNarrativeVault(options.workspaceRoot)
122
+ ? formatVaultDiagnosticReport(compileNarrativeVault(options.workspaceRoot, { fallbackApprovals: state.narrative?.approvals ?? [] }).diagnostics)
123
+ : undefined
111
124
  const projection = {
112
125
  narrativeHash: map.snapshot.narrativeHash,
113
126
  language: options.language,
114
127
  snapshot: map.snapshot,
128
+ vaultDiagnostics: vaultDiagnostics
129
+ ? {
130
+ ok: vaultDiagnostics.ok,
131
+ errorCount: vaultDiagnostics.errorCount,
132
+ warningCount: vaultDiagnostics.warningCount,
133
+ blockers: vaultDiagnostics.blockers.map((diagnostic) => ({ file: diagnostic.file, nodeId: diagnostic.nodeId, code: diagnostic.code, message: diagnostic.message, suggestedAction: diagnostic.suggestedAction })),
134
+ warnings: vaultDiagnostics.warnings.map((diagnostic) => ({ file: diagnostic.file, nodeId: diagnostic.nodeId, code: diagnostic.code, message: diagnostic.message, suggestedAction: diagnostic.suggestedAction })),
135
+ }
136
+ : undefined,
115
137
  claims: map.claimFlow.map((claim) => ({
116
138
  id: claim.id,
117
139
  kind: claim.kind,
@@ -125,7 +147,7 @@ export function buildNarrativeViewPrompt(options: { workspaceRoot: string; langu
125
147
  relations: map.claimRelations.map((relation) => ({ id: relation.id, fromClaimId: relation.fromClaimId, toClaimId: relation.toClaimId, relation: relation.relation, rationale: relation.rationale, inferred: relation.inferred })),
126
148
  objections: map.objections.map((objection) => ({ id: objection.id, claimId: objection.claimId, priority: objection.priority, text: objection.text, response: objection.response })),
127
149
  risks: map.risks.map((risk) => ({ id: risk.id, claimId: risk.claimId, severity: risk.severity, text: risk.text, mitigation: risk.mitigation })),
128
- researchGaps: map.researchGaps.map((gap) => ({ id: gap.id, targetType: gap.targetType, targetId: gap.targetId, status: gap.status, priority: gap.priority, question: gap.question })),
150
+ researchGaps: map.researchGaps.map((gap) => ({ id: gap.id, targetType: gap.targetType, targetId: gap.targetId, status: gap.status, priority: gap.priority, question: gap.question, findingsFile: gap.findingsFile, evidenceBindingIds: gap.evidenceBindingIds, notes: gap.notes })),
129
151
  artifactCoverage: map.artifactCoverage.map((artifact) => ({ type: artifact.type, outputPath: artifact.outputPath, stale: artifact.stale, coverageStatus: artifact.coverageStatus, affectedClaimIds: artifact.affectedClaimIds, missingClaimIds: artifact.missingClaimIds, slideRefs: artifact.slideRefs.map((ref) => ({ claimId: ref.claimId, slideIndex: ref.slideIndex, role: ref.role, match: ref.match, location: ref.location })) })),
130
152
  }
131
153
 
@@ -143,16 +165,27 @@ Hard rules:
143
165
  - Do not invent new claims, evidence, relations, slide coverage, source paths, findings files, quotes, or caveats.
144
166
  - Preserve every claimId exactly.
145
167
  - Preserve every relation endpoint exactly: fromClaimId, toClaimId, relation.
146
- - You may only organize and localize display copy for the UI: pageTitle, summaryLine, section labels, claim card displayTitle, roleLabel, narrativeJob, evidenceSummary, supportRationale, supportedScope, unsupportedScope, objectionsSummary, risksSummary, riskOrGapSummary, researchGapsSummary, relation displayLabel, and relation displayRationale.
168
+ - You may only organize and localize display copy for the UI: pageTitle, summaryLine, section labels, claim card displayTitle, roleLabel, narrativeJob, evidenceSummary, supportRationale, supportedScope, unsupportedScope, objectionsSummary, risksSummary, riskOrGapSummary, researchGapsSummary, research gap displayQuestion, relation displayLabel, and relation displayRationale.
147
169
  - For inferred relations, do not provide relation displayLabel or displayRationale; inferred relations are unconfirmed order notes, not causal/support/dependency judgments.
148
170
  - relation displayRationale may only localize or clarify an existing canonical relation rationale. If relation.rationale is missing or the relation is inferred, do not provide displayRationale; the UI will show the missing or inferred status.
149
171
  - Keep source paths, findings files, claim IDs, narrative hash, and numbers unchanged.
150
- - Translate normal UI/display text into the target language request: pageTitle, summaryLine, labels, claim displayTitle, roleLabel, narrativeJob, evidenceSummary, supportRationale, supportedScope, unsupportedScope, objectionsSummary, risksSummary, riskOrGapSummary, researchGapsSummary, relation displayLabel, and relation displayRationale.
172
+ - Translate normal UI/display text into the target language request: pageTitle, summaryLine, labels, claim displayTitle, roleLabel, narrativeJob, evidenceSummary, supportRationale, supportedScope, unsupportedScope, objectionsSummary, risksSummary, riskOrGapSummary, researchGapsSummary, research gap displayQuestion, relation displayLabel, and relation displayRationale.
151
173
  - For every claim in a non-English target language, provide displayTitle so the selected-claim panel does not fall back to canonical English claim text.
152
- - For every selected-claim detail field that has canonical user-facing text, provide the matching localized display field when it exists: supportedScope for supported scope, unsupportedScope for evidence boundaries, supportRationale for why the evidence supports the claim, objectionsSummary for objections, risksSummary for risks, and researchGapsSummary for research gaps.
174
+ - For every evidence/detail field that has canonical user-facing text, provide the matching localized display field when it exists: supportedScope for supported scope, unsupportedScope for evidence boundaries, supportRationale for why the evidence supports the claim, objectionsSummary for objections, risksSummary for risks, and researchGapsSummary for canonical research gaps.
153
175
  - Do not translate claim IDs, relation endpoints, narrative hash, source paths, findings files, URLs, numbers, or quoted/source facts.
176
+ - For every canonical research gap in a non-English target language, provide researchGapCards[].displayQuestion so gap cards do not fall back to canonical English question text. Preserve gapId exactly and do not change the gap meaning.
154
177
  - Use natural business and manufacturing terminology in the target language, not word-by-word machine translation.
155
178
  - If a fact is missing, describe it as missing instead of filling it in.
179
+ - If vaultDiagnostics.blockers is present in the compact map, keep Story read-only but surface the blocker state in summaryLine and the relevant claim card riskOrGapSummary when applicable. Include diagnostic file/nodeId/code/message/suggestedAction in display copy; do not invent missing evidence, source trace, quotes, or caveats to hide the blocker.
180
+ - Do not turn Story into a workflow dashboard: diagnostic copy is for reading context only, not command suggestions or mutation planning.
181
+ - Story UI is evidence-first: clicking a claim shows evidence/gap cards; evidence cards must carry the evidence description, why it supports the claim, and source trace; clicking evidence shows only canonical gaps linked to that evidence.
182
+ - The selected-claim panel is only an evidence/research-gap card list. Do not repeat canonical claim text there; the claim itself is already visible in Claim Flow.
183
+ - Claim cards should not explain gaps or risks through riskOrGapSummary when the same topic belongs in evidence/gap cards. Keep claim cards focused on role, narrative job, and evidence summary.
184
+ - Do not make evidence detail a schema dump. Do not default to unsupportedScope, caveat, IDs, target fields, or evidenceBindingIds for evidence cards; evidence cards should explain what the source says, why it supports the claim, and where it came from.
185
+ - Do not invent, infer, or soften new gaps in display copy. Show research gaps only when they exist in compactMap.researchGaps; do not turn unsupportedScope, weak evidence, caveats, objections, risks, or your own judgment into a gap.
186
+ - researchGapsSummary and riskOrGapSummary may only summarize existing canonical research gaps or diagnostics. If no canonical gap exists for the claim, leave gap-specific display copy empty instead of implying a gap.
187
+ - Localize new Story labels when useful: selectedEvidence, evidenceList, gap, gaps, noEvidence, selectEvidencePrompt, sourceTrace, evidenceSource, whyThisSupports, linkedGaps, selectedGap, and noLinkedGaps.
188
+ - Gap detail may only use canonical research gap fields from the compact map: id, targetType, targetId, status, priority, question, findingsFile, evidenceBindingIds, and notes.
156
189
 
157
190
  Chinese localization rules when the target language request is Chinese, zh, zh-CN, --cn, 中文, or Simplified Chinese:
158
191
  - Use natural business/manufacturing Chinese, not word-by-word machine translation.
@@ -11,12 +11,12 @@ export function buildResearchPrompt({
11
11
  ? `${DECKS_STATE_FILE} exists. Read it through the revela-decks tool before researching.`
12
12
  : `${DECKS_STATE_FILE} does not exist yet. Do not start broad internet research; initialize the workspace first with /revela init unless the user supplied a specific research question in chat.`
13
13
 
14
- return `Run Revela closed-loop research.
14
+ return `Run Revela research from deterministic state.
15
15
 
16
16
  Goal:
17
17
  - Reduce open gaps, unsupported scope, weak evidence, unattached findings, and overextended relation rationale for the current story.
18
18
  - Drive research from canonical narrative gaps: unsupported central claims, objections, risks, decision questions, explicit researchGaps, and claim_chain_gap warnings.
19
- - Treat /revela research as authorization to bind clearly supported findings into canonical evidence without asking for item-by-item user confirmation.
19
+ - Treat /revela research as authorization to bind clearly supported findings through the safe \`bindResearchFindings\` boundary without asking for item-by-item user confirmation.
20
20
  - Preserve evidence boundaries: eliminate caveats only when evidence or narrower wording actually resolves them; otherwise keep precise caveats visible.
21
21
  - Do not write decks, briefs, or design artifacts during research.
22
22
 
@@ -24,20 +24,32 @@ Current state:
24
24
  - ${state}
25
25
  ${workspaceRoot ? `- Current workspace root: \`${workspaceRoot}\`` : ""}
26
26
 
27
- Closed-loop workflow:
28
- 1. Call \`revela-decks\` action \`read\`, then \`reviewNarrative\`, then \`deriveResearchTargets\`. Treat the returned \`selected\` target as the deterministic first target unless it is clearly blocked by user-only information.
29
- 2. If current research gaps are missing or stale, call \`deriveResearchGaps\` when useful, then call \`deriveResearchTargets\` again. Do not invent gaps that are not tied to a claim, objection, risk, decision, or narrative issue.
30
- 3. Run up to 3 research loops unless the stop conditions below are met earlier.
31
- 4. At the start of each loop, use \`deriveResearchTargets\` as the target order. Work the \`selected\` target first, then the next 1-2 highest-priority targets only when they are related. Do not repeat searches for claims already strongly supported.
32
- 5. If a target has \`findingsFile\` or \`kind: "unattached_findings"\`, inspect \`bindingDiagnostic\` before doing external search. Prefer existing findings before external research.
33
- 6. When \`bindingDiagnostic.bindable\` is false, do not bind or package the findings as strong evidence. Report the exact \`failureReasons\` such as \`missing_quote\`, \`unclear_source\`, \`unsupported_scope\`, \`caveat_conflict\`, \`weak_source\`, \`source_mismatch\`, or \`context_only_finding\`, then either narrow the claim safely or run targeted research for the missing fields.
34
- 7. For targets needing external evidence, mark matching gaps \`in_progress\` with \`revela-decks updateResearchGap\`, then delegate search to the \`revela-research\` subagent. Ask it for source URLs, quotes/snippets, dates or locations when available, caveats, remaining gaps, and a \`## Recommended evidence bindings\` section with claimId, quote, source, supportScope, unsupportedScope, caveat, and strength. Save findings with \`revela-research-save\` under \`researches/{topic}/{axis}.md\` using \`## Data\`, \`## Cases\`, \`## Images\`, and \`## Gaps\` sections as applicable.
35
- 8. After findings are saved or existing findings are selected, read or inspect the findings file. Attach it with \`revela-decks attachResearchFindings\` when it maps to an existing research axis. Re-run \`deriveResearchTargets\` so the next loop sees updated \`bindingDiagnostic\` and target order.
36
- 9. Automatically bind evidence only when all binding criteria are met and the diagnostic is \`bindable: true\` or the same fields are explicit in the findings. Use \`revela-decks applyEvidenceCandidates\` for concrete candidate ids when available. Do not use \`upsertNarrative\` during research to add evidence or update narrative arrays.
37
- 10. Binding criteria: claimId exists; quote/snippet is traceable to the source and is not invented; source URL or workspace source path is present; supportScope and unsupportedScope are explicit; strength is strong or useful partial; caveat is preserved; binding does not expand the claim beyond the evidence.
38
- 11. If a claim or relation is broader than the evidence, do not mutate canonical claims during research. Report the needed claim/relation narrowing in \`Narrative changes\`, keep unsupported scope visible, and make \`/revela story\` or explicit user confirmation the next action when strategic wording must change.
39
- 12. Update matching gaps after binding: use \`evidence_bound\` when canonical evidence was added, \`closed\` when the gap is resolved or non-researchable, \`findings_saved\` only when findings exist but binding criteria are not met, and \`open\` with notes when more external research is still warranted.
40
- 13. Re-run \`reviewNarrative\` and \`deriveResearchTargets\` after each loop. Compare against the previous loop: fewer open gaps, fewer unattached findings, stronger evidence, narrower unsupported scope, or clearer internal-data caveats should count as progress.
27
+ Required first calls:
28
+ 1. Call \`revela-decks read\` with \`summary: true\`.
29
+ 2. If the workspace has a Markdown narrative vault, inspect \`narrativeInventory\` from the read summary or call \`revela-decks narrativeInventory\` before editing claims, gaps, evidence, or relations. If \`markdownQa.repairCards\` are present, fix structural repair cards before binding or research mutations unless the selected target is the exact repair.
30
+ 3. Call \`revela-decks reviewNarrative\`.
31
+ 4. Call \`revela-decks deriveResearchTargets\` and treat \`selected\`, \`bindingDiagnostic\`, and target order as deterministic inputs, not LLM judgement.
32
+
33
+ Tool-driven research contract:
34
+ - If \`selected\` or any high-priority target references a \`findingsFile\`, call \`revela-decks evaluateResearchFindings\` before external search.
35
+ - If \`bindingEval.status === "bindable"\`, call \`revela-decks bindResearchFindings\` with that \`findingsFile\`. Do not hand-author evidence Markdown for bindable findings.
36
+ - If findings are not bindable, report \`missingFields\` and \`failureReasons\`; then run only targeted research for those missing fields.
37
+ - Treat \`markdownQa\` as structural authoring feedback only. It does not prove evidence strength; \`bindingEval\`, \`bindingDiagnostic\`, and compiled claim \`evidenceStatus\` remain the trust/evidence boundary.
38
+ - For external research, use the \`revela-research\` subagent and save findings with \`revela-research-save\`. Ask for source URLs/paths, quotes/snippets, supportScope, unsupportedScope, caveat, strength, and the supported claim id/relation target when available.
39
+ - Re-run \`deriveResearchTargets\` after attachment, binding, or explicit vault edits. Stop after at most 3 rounds.
40
+ - After explicit Markdown edits, rely on the write hook feedback or call \`revela-decks markdownQa\`, then \`compileNarrativeVault\`; keep Markdown QA repair cards separate from compiler diagnostics and repair both before treating the edit as usable research state.
41
+ - For relation changes, update content nodes first, then add explicit edges in the source node's \`## Relations\` section using plain node-id wikilinks. Do not use \`relations.md\`, typed wikilinks, or hand-written relation ids.
42
+
43
+ Allowed mutations:
44
+ - Canonical evidence: use \`bindResearchFindings\` for bindable saved findings; the safe boundary writes \`revela-narrative/evidence/*.md\` and compiles the vault.
45
+ - Research gap lifecycle: after checking inventory and reading the target node, edit \`revela-narrative/research-gaps/*.md\` or use \`updateVaultResearchGap\` when the update is explicit.
46
+ - Safe claim narrowing: after checking inventory and reading the target node, edit \`revela-narrative/claims/*.md\` only when it preserves strategic meaning and evidence boundaries.
47
+ - Relation rewrites must patch node-local \`## Relations\` lines and be reported in \`Narrative changes\`; broader strategic claim changes require Story/user confirmation.
48
+ - Initialize the vault with \`initNarrativeVault\` if a canonical vault is needed and missing.
49
+ - Never call \`upsertNarrative\` during research.
50
+
51
+ Binding criteria:
52
+ - supported claim id exists and is expressed as \`## Relations\` with \`- supports: [[claim-id]]\` for new evidence; quote/snippet is traceable and not invented; source URL/path/findingsFile is present; supportScope and unsupportedScope are explicit; caveat is preserved; strength is strong or useful partial; binding does not expand the claim. Frontmatter \`claimId\` is compatibility fallback, not the preferred graph source.
41
53
 
42
54
  Stop conditions:
43
55
  - No open externally researchable gaps remain.
@@ -50,7 +62,10 @@ Report format:
50
62
  - Start with \`Research loop completed after <n> round(s).\`
51
63
  - Then use these exact sections in order:
52
64
  - \`Selected target\`: report \`kind\`, \`priority\`, \`reason\`, \`question\`, \`targetId\`, \`claimId\`, and any \`findingsFile\`.
53
- - \`Existing findings inspected\`: for each file, report \`findingsFile\`, \`bindingDiagnostic.bindable\`, \`failureReasons\`, and which explicit fields were present: \`source\`, \`quoteOrSnippet\`, \`supportScope\`, \`unsupportedScope\`, \`caveat\`, \`strength\`. If none were inspected, write \`none\`.
65
+ - \`Vault diagnostics\`: if \`vaultDiagnostics\` or a mutation \`diagnosticReport\` was returned, list blockers first with file/node/code/message and the suggested next action; otherwise write \`clean\` or \`not a vault workspace\`. If blockers exist, pause binding and research mutations unless the selected target is the exact diagnostic fix.
66
+ - \`Markdown QA\`: if \`markdownQa.repairCards\` was returned, list repair cards by severity, file, nodeId, issueCode, message, and smallestRepair. If no cards were returned, write \`clean\` or \`not checked\`.
67
+ - \`Evidence trust\`: report \`bindingEval.status\`, \`bindingDiagnostic.bindable\`, and compiled claim \`evidenceStatus\` separately from Markdown QA so structurally valid weak/partial evidence remains visible as weak/partial/missing support.
68
+ - \`Existing findings inspected\`: for each file, report \`findingsFile\`, \`bindingEval.status\` when available, \`bindingDiagnostic.bindable\`, \`missingFields\`, \`failureReasons\`, and which explicit fields were present: \`source\`, \`quoteOrSnippet\`, \`supportScope\`, \`unsupportedScope\`, \`caveat\`, \`strength\`. If none were inspected, write \`none\`.
54
69
  - \`Attachments\`: list findings attached with axis/status, or \`none\`.
55
70
  - \`Evidence bound\`: list evidence bindings by claim id, source, quote/snippet, supportScope, unsupportedScope, caveat, and strength, or \`none\`.
56
71
  - \`Unbound findings\`: list every inspected but unbound findings file with structured failure reasons such as \`missing_quote\`, \`unclear_source\`, \`unsupported_scope\`, \`caveat_conflict\`, \`weak_source\`, \`source_mismatch\`, or \`context_only_finding\`. If none, write \`none\`.
@@ -63,12 +78,13 @@ Report format:
63
78
  Rules:
64
79
  - Do not use primary-agent broad websearch. Use the \`revela-research\` subagent for external search.
65
80
  - Do not invent quotes, source paths, URLs, page references, locations, or caveats.
81
+ - Do not invent claim ids, evidence ids, research-gap ids, or relation targets before checking \`narrativeInventory\` unless you are intentionally creating the missing node in Markdown.
66
82
  - Do not treat \`researches/**/*.md\` as canonical evidence until attached or evidence-bound, but do not stop at findings_saved when binding criteria are met.
67
- - Do not bypass \`deriveResearchTargets\`; target selection, \`selected\`, and \`bindingDiagnostic\` are deterministic inputs, not LLM judgement.
83
+ - Do not bypass \`deriveResearchTargets\` or \`evaluateResearchFindings\`; target selection, \`selected\`, \`bindingDiagnostic\`, and \`bindingEval\` are deterministic inputs, not LLM judgement.
68
84
  - Do not mutate canonical claims merely to fit a source; narrow only to preserve evidence boundaries and avoid overstated claims.
69
- - Do not call \`upsertNarrative\` during research. Research may update gaps, attach findings, and apply explicit evidence candidates; broader narrative rewrites must be reported for Story/user confirmation.
85
+ - Do not call \`upsertNarrative\` during research. Initialize the Markdown vault with \`initNarrativeVault\` if needed; research should author bindable canonical evidence through \`bindResearchFindings\`, then use explicit Markdown edits for \`research-gaps/*.md\` and safe \`claims/*.md\` when needed. Targeted vault actions are fallback helpers, not the primary writing path. Broader narrative rewrites must be reported for Story/user confirmation.
70
86
  - Do not ask the user to approve each evidence binding. Ask only when binding would change strategic meaning, downgrade a central claim, rely on suspicious sources, or require narrative approval.
71
87
  - Do not store secrets, credentials, tokens, or sensitive personal information.
72
88
 
73
- Start now by reading ${DECKS_STATE_FILE} through \`revela-decks\`, reviewing current readiness, deriving research targets, and running the first research/binding loop from the selected target.`
89
+ Start now by reading ${DECKS_STATE_FILE} through \`revela-decks\`, inspecting narrative inventory when a vault exists, reviewing current readiness, deriving research targets, and running the first research/binding loop from the selected target.`
74
90
  }