@agentskit/doc-bridge 1.7.45 → 1.9.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.
Files changed (213) hide show
  1. package/CHANGELOG.md +465 -0
  2. package/CONTRIBUTING.md +23 -0
  3. package/README.md +87 -40
  4. package/SECURITY.md +7 -0
  5. package/action.yml +1 -1
  6. package/bin/ak-docs.js +2 -2
  7. package/bin/ak-verify.js +13 -7
  8. package/dist/cli/program.d.ts +3 -1
  9. package/dist/cli/program.js +15861 -6223
  10. package/dist/cli/program.js.map +1 -1
  11. package/dist/config/index.d.ts +1 -1
  12. package/dist/config/index.js +86 -6
  13. package/dist/config/index.js.map +1 -1
  14. package/dist/{index-BUL0q7s8.d.ts → index-Beor6Yhi.d.ts} +133 -1
  15. package/dist/index.d.ts +9871 -1062
  16. package/dist/index.js +16126 -6125
  17. package/dist/index.js.map +1 -1
  18. package/docs/MARKETPLACE.md +1 -1
  19. package/docs/PRD-documentation-efficiency-study.md +406 -0
  20. package/docs/PRD-knowledge-retrieval-and-enrichment.md +466 -0
  21. package/docs/adr/0002-documentation-audit-boundary.md +22 -0
  22. package/docs/adr/0003-study-protocol-and-historical-evidence.md +40 -0
  23. package/docs/adr/0004-controlled-study-runner.md +25 -0
  24. package/docs/adr/0005-documentation-quality-and-criticality.md +20 -0
  25. package/docs/adr/0006-registry-semantic-grounding.md +20 -0
  26. package/docs/adr/0007-longitudinal-study-metrics.md +21 -0
  27. package/docs/adr/0008-study-verification-boundary.md +21 -0
  28. package/docs/adr/0009-study-provider-cli-adapter.md +25 -0
  29. package/docs/agent-corpus/INDEX.md +12 -1
  30. package/docs/agent-corpus/OVERVIEW.md +25 -0
  31. package/docs/agent-corpus/chat.md +5 -1
  32. package/docs/agent-corpus/cli.md +16 -0
  33. package/docs/agent-corpus/conformance.md +12 -0
  34. package/docs/agent-corpus/doc-bridge.md +47 -0
  35. package/docs/agent-corpus/doctor.md +8 -0
  36. package/docs/agent-corpus/gates.md +4 -0
  37. package/docs/agent-corpus/mcp.md +13 -0
  38. package/docs/agent-corpus/memory.md +4 -0
  39. package/docs/agent-corpus/query.md +33 -0
  40. package/docs/bench/README.md +122 -0
  41. package/docs/bench/retrieval-baseline-v1.json +28 -0
  42. package/docs/bench/retrieval-suite-v1.json +1033 -0
  43. package/docs/chat-and-rag.md +3 -2
  44. package/docs/for-agents.md +9 -1
  45. package/docs/getting-started.md +4 -11
  46. package/docs/guides/gate-ci.md +11 -1
  47. package/docs/guides/install-and-run.md +9 -65
  48. package/docs/index.md +22 -1
  49. package/docs/knowledge-engine-runbook.md +38 -3
  50. package/docs/landing/assets/context-payload-reduction.svg +21 -0
  51. package/docs/landing/assets/controlled-ab-comparison.svg +30 -0
  52. package/docs/landing/index.html +119 -5
  53. package/docs/loop-workflow.md +117 -0
  54. package/docs/mcp.md +6 -1
  55. package/docs/parity/public-claims-v1.json +145 -0
  56. package/docs/playbook/doc-bridge-pattern.md +1 -1
  57. package/docs/query.md +90 -2
  58. package/docs/recipes/index-pipeline.md +1 -1
  59. package/docs/schemas/agent-handoff-v1.md +15 -0
  60. package/docs/schemas/doc-bridge-index-v1.md +65 -0
  61. package/docs/spec/benchmark-v1.md +33 -1
  62. package/docs/spec/cli.md +30 -10
  63. package/docs/spec/config-v1.md +147 -8
  64. package/docs/spec/documentation-audit-v1.md +61 -0
  65. package/docs/spec/enrichment-overlay-v1.md +241 -0
  66. package/docs/spec/graph-signals-v1.md +92 -0
  67. package/docs/spec/incremental-scan-v1.md +102 -0
  68. package/docs/spec/markdown-analyzer-v1.md +73 -0
  69. package/docs/spec/mcp-knowledge-tools-v1.md +147 -0
  70. package/docs/spec/measured-enrichment-v1.md +229 -0
  71. package/docs/spec/public-parity-v1.md +119 -0
  72. package/docs/spec/registry-agents.md +6 -0
  73. package/docs/spec/render-v1.md +122 -0
  74. package/docs/spec/retrieval-index-v1.md +164 -0
  75. package/docs/spec/study-metrics-v1.md +58 -0
  76. package/docs/spec/study-protocol-v1.md +46 -0
  77. package/docs/spec/study-provider-cli-v1.md +116 -0
  78. package/docs/spec/study-runner-v1.md +35 -0
  79. package/docs/spec/study-task-suite-v1.md +41 -0
  80. package/docs/spec/study-verification-v1.md +40 -0
  81. package/docs/study/README.md +84 -0
  82. package/docs/study/ab-adjudicated-cost-analysis-v1.md +29 -0
  83. package/docs/study/ab-adjudicated-cost-plan-v1.json +33 -0
  84. package/docs/study/ab-adjudicated-cost-plan-v2-v1.json +33 -0
  85. package/docs/study/ab-adjudicated-cost-result-v1.json +80 -0
  86. package/docs/study/ab-baseline-analysis-v1.md +21 -0
  87. package/docs/study/ab-baseline-plan-v1.json +33 -0
  88. package/docs/study/ab-baseline-recovery-plan-v1.json +33 -0
  89. package/docs/study/ab-baseline-result-v1.json +79 -0
  90. package/docs/study/documentation-audit-round-2026-08-31.json +183 -0
  91. package/docs/study/historical-evidence-v1.json +252 -0
  92. package/docs/study/observation-ledger-v1.json +30632 -0
  93. package/docs/study/phase3-task-coverage-v1.json +34 -0
  94. package/docs/study/phase4-public-pilot-ledger-v1.json +1344 -0
  95. package/docs/study/phase4-public-pilot-result-v1.json +52 -0
  96. package/docs/study/phase4-public-pilot-run-plan-v1.json +26 -0
  97. package/docs/study/phase4-public-pilot-task-suite-v1.json +71 -0
  98. package/docs/study/pilot-round-2026-08-31.json +46 -0
  99. package/docs/study/protocol-v1.json +90 -0
  100. package/docs/study/publication-gate-v1.md +45 -0
  101. package/docs/study/quality-scorecard-cycle-plan.md +545 -0
  102. package/docs/study/quality-scorecard-v1.json +38 -0
  103. package/docs/study/round-1-adjudicated-smoke-v1.json +30642 -0
  104. package/docs/study/round-1-instrumentation-plan-v1.md +39 -0
  105. package/docs/study/round-2-expanded-adjudication-v1.json +91 -0
  106. package/docs/study/round-2-expanded-validation-v1.md +58 -0
  107. package/docs/study/round-3-evidence-contract-v1.json +75 -0
  108. package/docs/study/round-3-evidence-contract-v1.md +57 -0
  109. package/docs/study/round-4-confirmation-v1.json +75 -0
  110. package/docs/study/round-4-confirmation-v1.md +55 -0
  111. package/docs/study/run-plan-v1.json +33 -0
  112. package/docs/study/semantic-adjudication-cycle-8.md +20 -0
  113. package/docs/study/task-suite-v1.json +96 -0
  114. package/docs/study/token-efficiency-plan-v1.md +337 -0
  115. package/docs/study/token-efficiency-protocol-v2.json +62 -0
  116. package/docs/study/verification-binding-v1.json +27 -0
  117. package/docs/validation-cycle-plan.md +14 -0
  118. package/docs/verification-harness.md +11 -6
  119. package/ecosystem-claims.json +2 -2
  120. package/ecosystem-upstream.json +2 -2
  121. package/ecosystem.json +4 -4
  122. package/mcpb/manifest.json +9 -1
  123. package/package.json +25 -6
  124. package/scripts/check-ecosystem-upstream.mjs +34 -6
  125. package/skills/doc-bridge-handoff/fixtures/synthetic-repo/docs/for-agents/packages/payments.md +7 -0
  126. package/skills/doc-bridge-handoff/scripts/resolve-handoff.mjs +1 -1
  127. package/src/agents/registry-adapter.ts +192 -24
  128. package/src/audit/documentation.ts +513 -0
  129. package/src/bench/baseline.ts +198 -0
  130. package/src/bench/overlay-delta.ts +139 -0
  131. package/src/bench/retrieval.ts +319 -0
  132. package/src/budget/compile.ts +91 -0
  133. package/src/budget/sections.ts +70 -0
  134. package/src/cli/program.ts +684 -74
  135. package/src/cli/usage.ts +71 -0
  136. package/src/config/defaults.ts +1 -0
  137. package/src/config/index.ts +4 -0
  138. package/src/config/schema.ts +117 -2
  139. package/src/conformance/documentation-standard-v1.ts +8 -6
  140. package/src/discovery/areas.ts +182 -0
  141. package/src/discovery/documentation.ts +211 -5
  142. package/src/discovery/identity.ts +24 -0
  143. package/src/discovery/incremental.ts +314 -0
  144. package/src/discovery/inputs.ts +110 -0
  145. package/src/discovery/markdown.ts +481 -0
  146. package/src/discovery/repository.ts +484 -101
  147. package/src/doctor/run-doctor.ts +244 -12
  148. package/src/enrich/approvals.ts +190 -0
  149. package/src/enrich/cache.ts +93 -0
  150. package/src/enrich/context-pack.ts +272 -0
  151. package/src/enrich/overlay.ts +255 -0
  152. package/src/enrich/review.ts +106 -0
  153. package/src/enrich/stage.ts +374 -0
  154. package/src/enrich/stats.ts +100 -0
  155. package/src/enrich/validate.ts +410 -0
  156. package/src/federation/llms.ts +2 -4
  157. package/src/findings/report.ts +103 -0
  158. package/src/graph/build.ts +356 -0
  159. package/src/graph/memory.ts +208 -0
  160. package/src/index-builder/build-handoffs.ts +22 -11
  161. package/src/index-builder/build-index.ts +132 -3
  162. package/src/index-builder/llms-txt.ts +48 -8
  163. package/src/index-builder/project-corpus.ts +111 -0
  164. package/src/index.ts +630 -2
  165. package/src/lib/fuzzy-match.ts +235 -0
  166. package/src/mcp/knowledge.ts +554 -0
  167. package/src/mcp/server.ts +113 -18
  168. package/src/metrics/benchmark.ts +21 -0
  169. package/src/parity/check.ts +309 -0
  170. package/src/parity/claims.ts +259 -0
  171. package/src/parity/resolve.ts +160 -0
  172. package/src/query/handoff.ts +326 -0
  173. package/src/query/load-index.ts +53 -1
  174. package/src/query/query.ts +92 -59
  175. package/src/query/search.ts +289 -92
  176. package/src/query/text.ts +155 -0
  177. package/src/reconciliation/reconcile.ts +101 -10
  178. package/src/render/data.ts +356 -0
  179. package/src/render/engine.ts +398 -0
  180. package/src/render/generated.ts +77 -0
  181. package/src/render/render.ts +209 -0
  182. package/src/render/template-source.ts +52 -0
  183. package/src/render/templates.ts +289 -0
  184. package/src/report/html.ts +2 -2
  185. package/src/retrieval/bm25.ts +161 -0
  186. package/src/retrieval/project.ts +495 -0
  187. package/src/retrieval/rank.ts +383 -0
  188. package/src/retrieval/weights.ts +39 -0
  189. package/src/retriever/doc-bridge-retriever.ts +100 -15
  190. package/src/rules/engine.ts +30 -10
  191. package/src/schemas/agent-handoff.ts +56 -0
  192. package/src/schemas/budget.ts +37 -0
  193. package/src/schemas/doc-bridge-index.ts +53 -2
  194. package/src/schemas/enrichment.ts +369 -0
  195. package/src/schemas/json-schemas.ts +39 -2
  196. package/src/schemas/knowledge.ts +14 -1
  197. package/src/schemas/retrieval-index.ts +152 -0
  198. package/src/shims/graphology.d.ts +91 -0
  199. package/src/study/adjudication.ts +196 -0
  200. package/src/study/execution.ts +350 -0
  201. package/src/study/expectations.ts +219 -0
  202. package/src/study/metrics.ts +467 -0
  203. package/src/study/protocol.ts +271 -0
  204. package/src/study/provider-cli.ts +115 -0
  205. package/src/study/provider-telemetry.ts +47 -0
  206. package/src/study/quality-scorecard.ts +164 -0
  207. package/src/study/runner.ts +461 -0
  208. package/src/study/task-suite.ts +321 -0
  209. package/src/study/verification.ts +134 -0
  210. package/src/validate.ts +1 -4
  211. package/src/version.ts +1 -1
  212. package/src/workflow/engine.ts +36 -11
  213. package/scripts/verification-harness.mjs +0 -482
package/docs/spec/cli.md CHANGED
@@ -5,7 +5,7 @@ description: Complete command reference for indexing, querying, gates, doctor, m
5
5
 
6
6
  # ak-docs CLI
7
7
 
8
- Command-line interface for **`@agentskit/doc-bridge`**. The npm package is scoped; the **only published binary** is `ak-docs`.
8
+ Command-line interface for **`@agentskit/doc-bridge`**. The package publishes two executables: `ak-docs` is the product CLI and `ak-verify` is the verification-harness wrapper.
9
9
 
10
10
  ## Naming
11
11
 
@@ -13,11 +13,17 @@ Command-line interface for **`@agentskit/doc-bridge`**. The npm package is scope
13
13
  |------|------|
14
14
  | npm package | `@agentskit/doc-bridge` |
15
15
  | CLI binary | `ak-docs` |
16
- | Config file | `doc-bridge.config.ts` |
16
+ | Verification binary | `ak-verify` |
17
+ | Primary config filename | `doc-bridge.config.ts` |
17
18
  | GitHub repo | `AgentsKit-io/doc-bridge` |
18
19
 
19
20
  Install the package, run `ak-docs` — not `doc-bridge` on the shell.
20
21
 
22
+ The primary filename is shown for readability. Discovery also accepts
23
+ `doc-bridge.config.mts`, `.js`, `.mjs`, `.json`, and the `docBridge` field in
24
+ `package.json`; see the [configuration contract](./config-v1.md#discovery-order)
25
+ for the authoritative order.
26
+
21
27
  ## Why a separate binary
22
28
 
23
29
  | Choice | Rationale |
@@ -39,7 +45,8 @@ pnpm add -D @agentskit/doc-bridge
39
45
  {
40
46
  "name": "@agentskit/doc-bridge",
41
47
  "bin": {
42
- "ak-docs": "./bin/ak-docs.js"
48
+ "ak-docs": "./bin/ak-docs.js",
49
+ "ak-verify": "./bin/ak-verify.js"
43
50
  }
44
51
  }
45
52
  ```
@@ -58,8 +65,8 @@ pnpm add -D @agentskit/doc-bridge
58
65
  | `ak-docs doctor [--text] [--badge] [--write-badge]` | Coverage score, gaps, gates, shields.io badge |
59
66
  | `ak-docs index` | Build `DocBridgeIndex` + optional `llms.txt` |
60
67
  | `ak-docs index --watch` | Debounced rebuild on agent/human doc changes |
61
- | `ak-docs query <target> [--agent] [--text]` | Resolve package/module/intent/change → handoff JSON or text |
62
- | `ak-docs search <term> [--agent] [--text]` | Full-text search over index |
68
+ | `ak-docs query <target> [--agent] [--text]` | Resolve package/area/module/document/intent/change → handoff JSON or text |
69
+ | `ak-docs search <term> [--agent] [--explain] [--mode=<mode>] [--context-budget=<tokens>] [--text]` | Ranked search over the retrieval projection; `--explain` names every scoring component and the matched terms, and agent mode bounds the context it returns to a task-specific budget |
63
70
  | `ak-docs ask <question>` | Human-readable local consult mode: search + best match + next handoff commands; no LLM |
64
71
  | `ak-docs ask` | Interactive local REPL in a TTY; commands: `search <term>`, `read <id-or-path>`, `open <id-or-path>`, `resolve <id>`, `gate [id]`, `exit` |
65
72
  | `ak-docs retrieve <query>` | Hybrid local/federated retriever chunks; deterministic local first |
@@ -68,13 +75,26 @@ pnpm add -D @agentskit/doc-bridge
68
75
  | `ak-docs memory ingest` | Normalize local memory files (`.agent-memory/**/*.md`, `.cursor/rules/*.mdc`) into `MemoryCandidate[]` |
69
76
  | `ak-docs memory classify` | Deterministically route candidates to agent/human/playbook/discard |
70
77
  | `ak-docs memory promote` | Build draft-only promotion body with safety scan; never auto-merges |
71
- | `ak-docs memory promote --pr [--dry-run] [--force]` | Write draft + open GitHub draft PR via `gh` |
78
+ | `ak-docs memory promote --pr --dry-run [--force]` | Write a local draft and print the `git`/`gh` commands; does not execute them |
79
+ | `ak-docs memory promote --pr [--force]` | Write the draft, commit/push it, and open a GitHub draft PR via `gh` |
72
80
  | `ak-docs registry topology` | Print the `doc-curator` topology for AgentsKit/Registry composition |
81
+ | `ak-docs suggest [--documentation] --json` | Run the configured Registry agent module or CLI and persist its typed proposal; optionally include the bounded documentation-audit context |
82
+ | `ak-docs enrich [--json\|--text]` | Run the enrichment stage: context packs to the configured Registry roles, deterministic validators, the overlay at `.doc-bridge/enrich/overlay.json`. Zero agent calls over an unchanged repository |
83
+ | `ak-docs enrich list \| approve <proposalId> --by <name> \| reject <proposalId> --by <name> [--reason <text>]` | Review pending enrichment proposals; a decision is recorded through the ecosystem approval gate under `.doc-bridge/approvals/`, bound to the proposal id and the target content hash |
84
+ | `ak-docs check --enrich` | `check` with the `enrich` stage between `reconcile` and `evaluate`; a failed enrichment is reported in `enrichment` and never changes the check result |
85
+ | `ak-docs enrich --retrieval-delta [--json\|--text]` | `enrich`, then the golden suite with and without the accepted overlay on the same snapshot. Exits 1 when the overlay lowers hit@3 |
86
+ | `ak-docs bench retrieval <suite.json> --overlay [--json\|--text]` | The overlay on disk measured against a suite: both indexes projected from one snapshot, no index on disk required. Exits 1 on a hit@3 regression |
87
+ | `ak-docs study expectations <task-suite.json> --expectations <local.json> [--index <index.json>] [--repository <id>]` | Check a study round's mechanical retrieval expectations through the benchmark. Exits 1 when a reference does not resolve or a case misses |
73
88
  | `ak-docs playbook draft` | Build a draft Playbook feedback payload from local memory candidates |
74
89
  | `ak-docs playbook pattern [--text]` | Export published Doc Bridge Playbook pattern (OKF markdown / JSON) |
75
90
  | `ak-docs list <kind> [--text]` | List packages, apps, intents, … |
76
- | `ak-docs gate run [index-freshness]` | Check generated index freshness |
91
+ | `ak-docs gate run [gate-id]` | Run resolved configured documentation gates; an optional id narrows the run to one gate |
77
92
  | `ak-docs conformance run documentation-standard-v1 [--text\|--json]` | Run the stable ecosystem documentation profile with evidence and remediation |
93
+ | `ak-docs audit documentation [--text\|--json]` | Measure documentation quality and compare documentation claims with the observed project graph |
94
+ | `ak-docs parity [--claims <file>] [--json\|--text]` | Check the public claim registry against what the repository can prove: stale, missing, contradictory and not-analyzed claims, each with an owner, an exact source and a remediation. Exits 1 on a blocking finding |
95
+ | `ak-docs render <llms.txt\|area\|ownership\|change-digest\|overlay-review> [--data <artifact>] [--output <path>] [--print-template] [--json]` | Render the canonical artifacts as Markdown from bundled or project templates (`render.templates`); deterministic, no agent. See [Render v1](./render-v1.md) |
96
+ | `ak-docs bench retrieval <suite.json> [--index <file>] [--baseline <file>] [--limit <n>] [--text\|--json]` | Measure retrieval quality against a golden query suite: hit@1, hit@3, mean reciprocal rank, context bytes and approximate tokens. Exits non-zero on a hit@3 regression against the baseline. No model, no network |
97
+ | `ak-docs bench retrieval <suite.json> --baseline <file> --update-baseline --by <name> [--reason <text>]` | Record the measured figures as the approved baseline. A normal run never writes one |
78
98
  | `ak-docs mcp` | Start MCP server (stdio default) |
79
99
  | `ak-docs mcp install --cursor \| --claude` | Write MCP server config for Cursor or Claude Desktop |
80
100
 
@@ -94,7 +114,7 @@ Peers: `@agentskit/rag`, `@agentskit/ink`, `@agentskit/adapters`, `@agentskit/me
94
114
  | Flag | Description |
95
115
  |------|-------------|
96
116
  | `--config <path>` | Config file (default: auto-discover) |
97
- | `--json` / `--text` | Output format for non-agent commands (default: json); `--agent` always emits agent JSON |
117
+ | `--json` / `--text` | Output format for non-agent commands (default: formatted json); `--agent` emits compact machine-readable JSON, while `--text` remains human-readable |
98
118
  | `--chat` | Request planned intelligence-backed ask mode; errors clearly until `intelligence.adapter` and RAG/chat support are configured |
99
119
  | `--help` | Command help |
100
120
 
@@ -104,7 +124,7 @@ Peers: `@agentskit/rag`, `@agentskit/ink`, `@agentskit/adapters`, `@agentskit/me
104
124
  ak-docs index
105
125
  ak-docs query ownership auth --agent
106
126
  ak-docs query ownership auth --text
107
- ak-docs search "sidecar transport" --agent
127
+ ak-docs search "sidecar transport" --agent --mode=discovery --context-budget=256
108
128
  ak-docs list packages --text
109
129
  ak-docs gate run
110
130
  ak-docs mcp
@@ -141,7 +161,7 @@ CLI is a thin wrapper over the same exports.
141
161
  pnpm docs:internal:query … # private dogfood wrapper → ak-docs query …
142
162
  ```
143
163
 
144
- Private repo wrappers stay private. `ak-docs` is the only public binary.
164
+ `ak-docs` is the primary product CLI. `ak-verify` is the portable verification-harness entry point used to prove repository work against a declared contract.
145
165
 
146
166
  ## See also
147
167
 
@@ -5,7 +5,7 @@ description: Configure documentation corpora, ownership routing, conformance, an
5
5
 
6
6
  # doc-bridge config contract v1
7
7
 
8
- `doc-bridge.config.ts` (or `.js`, `.mjs`, `.json`, or `package.json` → `docBridge`) is the alpha integration point for any project. Layer 0 fields are sufficient to run `index`, `query`, and MCP without an LLM.
8
+ `doc-bridge.config.ts` (or `.js`, `.mjs`, `.json`, or `package.json` → `docBridge`) is the v1 integration point for any project. Layer 0 fields are sufficient to run `index`, `query`, and MCP without an LLM.
9
9
 
10
10
  Reconciliation summaries also expose deterministic `diagnosticsByCode` and
11
11
  `diagnosticsByStatus` maps. They are additive rollups for agents and dashboards;
@@ -36,7 +36,7 @@ doc-bridge.config.json
36
36
  package.json → "docBridge" field (subset, JSON only)
37
37
  ```
38
38
 
39
- TypeScript/JavaScript configs are static in v0.1 alpha: `defineConfig` imports are supported, but arbitrary imports are not. YAML config files are planned.
39
+ TypeScript/JavaScript configs are static in v1: `defineConfig` imports are supported, but arbitrary imports are not. YAML config files are planned.
40
40
 
41
41
  Dynamic-loading coverage is evidence-backed. Literal strings, constant aliases,
42
42
  parenthesized strings, and string concatenations are resolved without executing
@@ -88,9 +88,15 @@ export default {
88
88
  /** Optional reconciliation scope and orphan-document policy */
89
89
  reconciliation?: ReconciliationConfig
90
90
 
91
+ /** Optional retrieval tuning: corpus projection, field weights, BM25 parameters */
92
+ retrieval?: RetrievalConfig
93
+
91
94
  /** Optional resumable workflow state */
92
95
  workflow?: WorkflowConfig
93
96
 
97
+ /** Optional project templates for `ak-docs render`, by template name */
98
+ render?: RenderConfig
99
+
94
100
  /** Optional report publication privacy; private is the default */
95
101
  report?: { privacy?: 'private' | 'anonymized' }
96
102
  } satisfies DocBridgeConfigV1
@@ -301,7 +307,9 @@ by Nx plugins are intentionally not inferred by this read-only adapter.
301
307
  | Screen / feature | `id` in `screens/` or `features/` | MDX slug |
302
308
  | Flow / recipe | `id` in `flows/` | docs slug |
303
309
 
304
- Plugins document their join convention; gates fail on orphan links.
310
+ Plugins document their join convention. The orphan-link gate only runs when the
311
+ corresponding gate is enabled (for example, `human-guide-links`); the `minimal`
312
+ preset does not enable that gate.
305
313
 
306
314
  ---
307
315
 
@@ -347,14 +355,14 @@ type GateId =
347
355
  | Preset | Gates |
348
356
  |--------|-------|
349
357
  | `minimal` | `index-freshness` |
350
- | `standard` | + `human-guide-links` in v0.1 alpha |
351
- | `strict` | + `okf-type` in v0.1 alpha |
358
+ | `standard` | + `human-guide-links` in v1 |
359
+ | `strict` | + `okf-type` in v1 |
352
360
 
353
361
  Implemented gates include `index-freshness`, `human-guide-links`, `okf-type`, `docs-style`, and the opt-in `documentation-standard-v1`. For v1 compatibility, `link-rot`, `routing-currency`, and `bootstrap-size` remain accepted as reserved IDs; including one emits `AK_DOCS_RESERVED_GATE` and does not claim that the gate ran. Unknown IDs are rejected.
354
362
 
355
363
  ### Structural vs style validation
356
364
 
357
- Alpha gates are deterministic lint checks, not editorial grading:
365
+ These gates are deterministic lint checks, not editorial grading:
358
366
 
359
367
  | Gate | Kind | What it proves |
360
368
  |------|------|----------------|
@@ -363,7 +371,7 @@ Alpha gates are deterministic lint checks, not editorial grading:
363
371
  | `okf-type` | OKF lint | Agent docs have required `type:` frontmatter when strict/required |
364
372
  | `docs-style` | style lint | Opt-in deterministic profile checks for title, purpose, audience, examples, owner/source, task orientation, and stale wording |
365
373
 
366
- `docs-style` supports `google-dev-docs`, `playbook-okf`, and `custom` profiles. It is not part of the default alpha path and does not grade prose quality; it checks for explicit structural signals. LLM critique remains planned optional behavior.
374
+ `docs-style` supports `google-dev-docs`, `playbook-okf`, and `custom` profiles. It is not part of the default path and does not grade prose quality; it checks for explicit structural signals. LLM critique remains planned optional behavior.
367
375
 
368
376
  ---
369
377
 
@@ -413,7 +421,7 @@ report status, commands, and the recorded stable-publication HITL decision.
413
421
  ```ts
414
422
  type ReconciliationConfig = {
415
423
  /** Semantic comparison level; discovery still preserves raw file relations. */
416
- scope?: 'file' | 'module' | 'package'
424
+ scope?: 'file' | 'module' | 'area' | 'package'
417
425
  /** Observed relation kinds that require documentation declarations. */
418
426
  requiredRelationKinds?: string[]
419
427
  /** Limit missing-declaration findings to relations between internal project entities. */
@@ -425,6 +433,12 @@ type ReconciliationConfig = {
425
433
 
426
434
  Use `scope: 'package'` for monorepos where file imports should be compared as package-level architecture evidence. Omit `requiredRelationKinds` to require all observed kinds; an empty array intentionally disables undocumented-relation findings and must be treated as an explicit exemption.
427
435
 
436
+ Use `scope: 'area'` for a single-package repository. At package scope such a repository aggregates
437
+ every internal relation into one self-loop, which the comparison skips — a thousand observed
438
+ relations and nothing to report. At area scope the same relations become edges between
439
+ directories, which a declaration can confirm or fail to. On this repository that is the difference
440
+ between zero diagnostics and 177.
441
+
428
442
  Use `requiredRelationTargets: 'internal'` when the repository wants package or module architecture declarations without requiring Markdown to enumerate every external library import. External relations remain in the raw snapshot and report as evidence; they simply do not generate missing-declaration findings.
429
443
 
430
444
  The reconciliation documentation summary reports package health separately from
@@ -456,6 +470,107 @@ report?: {
456
470
 
457
471
  `private` is the default and keeps local evidence useful for debugging. `anonymized` is intended for reports shared outside the repository: it preserves counts, relation kinds, topology, and coverage status while removing project-specific identity and evidence content. The generated HTML and every lazy chunk use the same mode.
458
472
 
473
+ ## `analysis.areas` (optional)
474
+
475
+ ```ts
476
+ areas?: {
477
+ /** Directory levels below a source root that form an area. Default 1. */
478
+ depth?: number
479
+ /** Directories that contain areas rather than being one. */
480
+ roots?: string[]
481
+ }
482
+ ```
483
+
484
+ An **area** is the unit of architecture between a package and a file: a directory that groups
485
+ modules. `src` is not an area in any useful sense; `src/query` is. So `roots` names the
486
+ directories that hold areas — by default `src`, `lib`, `app`, `source`, `server`, `client`,
487
+ `packages`, `apps` — and `depth` says how many levels below such a root an area sits.
488
+
489
+ Areas are derived, never declared, with one exception that matters: **any path an ownership record
490
+ names becomes an area**, whatever the convention says. A configuration that reads
491
+ `path: "src/mcp"` is a human stating that the directory is a unit, and the graph should have an
492
+ entity for it. Such an area carries `metadata.ownershipId`, which is what lets an agent document
493
+ declaring `id` plus `editRoot` resolve to the thing it owns.
494
+
495
+ Each module belongs to exactly one area — the most specific one containing it — so containment
496
+ stays a tree and an aggregation at area scope has one answer per module. Nested areas keep their
497
+ shape: `area:src` holds what sits directly in `src`, with `area:src/query` recorded as its child.
498
+
499
+ An ownership path that no observed module or document lives under is reported as
500
+ `OWNERSHIP_PATH_UNOBSERVED` with status `stale-or-unverified`. A renamed directory is otherwise
501
+ invisible: the handoff still resolves, it just points an agent somewhere that no longer holds what
502
+ it claims.
503
+
504
+ ## `retrieval` (optional)
505
+
506
+ ```ts
507
+ type RetrievalConfig = {
508
+ corpus?: {
509
+ /** Project repository documents and modules into `index.knowledge`. Default: true. */
510
+ enabled?: boolean
511
+ }
512
+ /** Per-field BM25 multipliers. Unknown field names are ignored. */
513
+ weights?: {
514
+ id?: number
515
+ symbols?: number
516
+ title?: number
517
+ path?: number
518
+ tags?: number
519
+ description?: number
520
+ body?: number
521
+ }
522
+ /** BM25 parameters: `k1` term-frequency saturation, `b` length-normalization strength (0–1). */
523
+ params?: { k1?: number; b?: number }
524
+ }
525
+ ```
526
+
527
+ Search ranks records with field-weighted BM25 plus boosts for exact identity, so an agent that
528
+ types an exported symbol, a file path or a package name lands on that thing rather than on
529
+ whatever mentions it most. The defaults are:
530
+
531
+ | Field | Weight | Why |
532
+ | --- | --- | --- |
533
+ | `id` | 8 | The query names the record |
534
+ | `symbols` | 7 | An agent that types an exported name wants the module that defines it |
535
+ | `title` | 6 | A heading is what a document is about |
536
+ | `path` | 4 | Location is identity for a module |
537
+ | `tags` | 3 | Audience and kind |
538
+ | `description` | 2 | A summary a human wrote |
539
+ | `body` | 1 | A passing mention is the weakest evidence |
540
+
541
+ Tuning is configuration, not code: the resolved weights, parameters and stopword-lexicon version
542
+ are recorded in `index.retrieval`, so a retuned ranking is a different artifact with a different
543
+ content hash rather than a silent behaviour change. Re-run `ak-docs index` after changing them,
544
+ and re-approve the [retrieval benchmark](../bench/README.md) baseline if you gate on it.
545
+
546
+ `corpus.enabled: false` keeps the index to the curated agent corpus only. The index is then
547
+ smaller and builds faster, at the cost of the retrieval it exists for: an exported-symbol or
548
+ file-path query has nothing to resolve against. Turn it off only for a repository whose source is
549
+ not the thing agents ask about.
550
+
551
+ ## `render` (optional)
552
+
553
+ ```ts
554
+ type RenderConfig = {
555
+ /** Project templates that replace the bundled ones, by name, as paths relative to the project root. */
556
+ templates?: Partial<Record<'llms.txt' | 'area' | 'ownership' | 'change-digest' | 'overlay-review', string>>
557
+ }
558
+ ```
559
+
560
+ `ak-docs render <name>` renders the canonical artifacts as Markdown from a bundled template; a
561
+ path under `templates` replaces that template entirely, without a code change. Templates use
562
+ knap syntax and see only the variables Doc Bridge computes — see [Render v1](./render-v1.md) for
563
+ each template's variables and `ak-docs render <name> --print-template` for the bundled source.
564
+ The `llms.txt` override is also what `ak-docs index` writes.
565
+
566
+ ```json
567
+ {
568
+ "render": {
569
+ "templates": { "area": "templates/area.md" }
570
+ }
571
+ }
572
+ ```
573
+
459
574
  ## `safety` (optional)
460
575
 
461
576
  ```ts
@@ -610,14 +725,38 @@ type IntelligenceConfig = {
610
725
  agentId?: string
611
726
  agentRoot?: string
612
727
  runnerModule?: string
728
+ cli?: {
729
+ /** Executable name or absolute path; arguments are passed without a shell. */
730
+ command: string
731
+ args?: string[]
732
+ }
613
733
  deterministic?: boolean
734
+ maxInputBytes?: number
614
735
  timeoutMs?: number
615
736
  maxTokens?: number
616
737
  maxResponseBytes?: number
617
738
  maxConcurrency?: number
739
+ /** Byte budget of one enrichment context pack. Default 65536 (4096..4000000). */
740
+ maxPackBytes?: number
741
+ /**
742
+ * Which installed agent plays which enrichment role (see Enrichment overlay v1).
743
+ * Default: the configured agent as curator only. The adjudicator must be a
744
+ * different identity from the curator and the reviewer.
745
+ */
746
+ roles?: {
747
+ curator?: EnrichmentRole
748
+ reviewer?: EnrichmentRole
749
+ adjudicator?: EnrichmentRole
750
+ }
618
751
  }
619
752
  }
620
753
 
754
+ type EnrichmentRole = {
755
+ enabled?: boolean // default: true when the role is declared; curator on by default
756
+ agentId?: string // default: intelligence.registry.agentId
757
+ promptVersion?: string // default: '1'; part of every proposal id and cache key
758
+ }
759
+
621
760
  type MemoryAdapterId =
622
761
  | 'playbook-memory' // .agent-memory/MEMORY.md layout
623
762
  | 'cursor-rules' // .cursor/rules/*.mdc
@@ -0,0 +1,61 @@
1
+ ---
2
+ title: Documentation audit v1
3
+ description: Configurable deterministic checks for documentation quality and agreement with repository structure.
4
+ ---
5
+
6
+ # Documentation audit v1
7
+
8
+ Run the repository audit after discovery and reconciliation:
9
+
10
+ ```bash
11
+ ak-docs audit documentation --json
12
+ ak-docs audit documentation --text
13
+ ```
14
+
15
+ The JSON report is versioned and content-hashed. It includes criterion-level evidence, metrics, blocking findings, generated-document freshness boundaries, and limitations.
16
+
17
+ ## Configuration
18
+
19
+ Configure the optional `audit.documentation` block in `doc-bridge.config.json`:
20
+
21
+ ```json
22
+ {
23
+ "audit": {
24
+ "documentation": {
25
+ "criticalPaths": ["src/cli/**", "src/mcp/**"],
26
+ "generatedPaths": ["docs/generated/**"],
27
+ "minWords": 20,
28
+ "requiredSections": ["Usage", "Examples"],
29
+ "requireExamples": true,
30
+ "exactDuplicates": true,
31
+ "defaultTier": "tier-2",
32
+ "tierRules": [
33
+ { "pattern": "docs/agent-corpus/**", "tier": "tier-0", "critical": true },
34
+ { "pattern": "docs/adr/**", "tier": "tier-1" }
35
+ ],
36
+ "requiredCriticalMetadata": ["owner", "lifecycle", "sourceOfTruth", "validationPath"]
37
+ }
38
+ }
39
+ }
40
+ ```
41
+
42
+ - `criticalPaths` makes high-confidence contradictions and missing structure documentation blocking.
43
+ - `generatedPaths` excludes generated documents from manual quality checks and reports freshness as `not-analyzed`; configure the generator's real check separately.
44
+ - `requiredSections`, `minWords`, and `requireExamples` are opt-in to avoid false positives for indexes and short reference files.
45
+ - `exactDuplicates` detects identical normalized bodies. It does not claim that similar prose is redundant.
46
+ - `defaultTier` and ordered `tierRules` classify every included document as `tier-0`, `tier-1`, or `tier-2`. A document may override the configured tier with `tier` frontmatter; `critical: true` frontmatter or a rule marks it critical.
47
+ - Critical documents are checked for `owner`, `lifecycle`, `sourceOfTruth`, and `validationPath` metadata. `requiredCriticalMetadata` can reduce this list for a declared project profile.
48
+
49
+ The audit reuses the canonical discovery snapshot and reconciliation report. A finding is not proof that prose is wrong unless its evidence and confidence say so. `not-analyzed` is intentional and includes semantic contradiction, unnecessary content, and agent-review boundaries. A document title is satisfied by a Markdown level-one heading, a `title` frontmatter field, or a visible HTML `<h1>` used by README-style documents.
50
+
51
+ ## Independent quality dimensions
52
+
53
+ Each document receives an assessment instead of one opaque quality score. The machine-readable report exposes `documentAssessments` and independent status counts for:
54
+
55
+ - correctness: deterministic reconciliation can expose evidence, but semantic correctness remains `not-analyzed` until code, configuration, tests, and applicable runtime behavior are reviewed;
56
+ - completeness: structural signals such as title and configured required sections are reported as `partial`, never as semantic completeness;
57
+ - clarity: title and basic structure are measurable, while human readability remains `not-analyzed`;
58
+ - agent efficiency: title and example presence are signals only; retrieval usefulness and task success require the controlled study;
59
+ - maintainability: owner, lifecycle, source-of-truth, and validation-path metadata are directly measurable.
60
+
61
+ Example presence and example correctness are separate. The audit reports `example.present`; `example.validation` remains `not-analyzed` unless a real validation flow supplies evidence. Similar prose, unnecessary content, and document/document semantic contradictions are intentionally deferred to the Registry-agent and human-adjudication path.
@@ -0,0 +1,241 @@
1
+ ---
2
+ title: Enrichment overlay v1
3
+ description: Typed agent proposals, the deterministic validators that decide them, the overlay that stores the decisions, and how little of it the deterministic layer is allowed to feel.
4
+ ---
5
+
6
+ # Enrichment overlay v1
7
+
8
+ A Registry agent may enrich the knowledge graph. It may never become an authority over it.
9
+
10
+ `AgentProposalV1` could say "review this finding". It could not say that a document is canonical
11
+ for an area, that an alias should resolve to an entity, or that a relation exists with a given
12
+ confidence — and nothing stored what it said, nothing consumed it, the deterministic cache was an
13
+ in-process `Map`, and `ak-docs suggest` sent the whole redacted snapshot, 740 KB on this
14
+ repository, in one call. This document is the replacement: proposals typed per claim, decided by
15
+ validators that have no judgement to exercise, stored in an overlay bound to the content hash of
16
+ what each entry describes, and projected into retrieval with an influence that is bounded by
17
+ construction.
18
+
19
+ ## Typed proposals
20
+
21
+ `EnrichmentProposalV1` in `src/schemas/enrichment.ts` is a discriminated union on `kind`. The
22
+ envelope is the same for every kind:
23
+
24
+ | Field | Meaning |
25
+ | --- | --- |
26
+ | `proposalId` | The hash of kind, entity, target content hash, agent identity, prompt version — and, for kinds one entity can carry several of, the payload field that tells them apart (`alias`, `phrase`, the relation's `to` and `kind`, `against`, `with`, `area` and `missing`, `directories`). A re-run over unchanged inputs produces the same id; a summary is a slot, an alias is a set. |
27
+ | `entity` | Must exist in the snapshot the proposal was made against. |
28
+ | `targetContentHash` | The entity's content hash at proposal time: the file hash for a file-backed entity, a hash of the entity as recorded for an area. The entry expires when it moves. |
29
+ | `confidence`, `reason` | 0..1, and up to 1 000 characters. |
30
+ | `evidence` | At least one item, and every item present — by source, path and lines — in the snapshot or the report. |
31
+ | `relatedDiagnosticIds` | Optional; every id must exist in the report. |
32
+ | `origin` | `agentId`, `agentVersion`, `promptVersion`, and optionally `model` and `provider`. |
33
+ | `baseSnapshotHash` | The snapshot it was made against. |
34
+ | `payload` | Per kind, below. |
35
+
36
+ | Kind | Payload | Deterministic validator | Policy |
37
+ | --- | --- | --- | --- |
38
+ | `classify-document` | `type`, `audience`, `lifecycle`, `criticality` | enumerated values; the entity is a document | accept by policy |
39
+ | `summarize` | `summary` ≤ 400 chars, `language` | length; redaction scan; differs from the current summary | accept by policy |
40
+ | `add-alias` | `alias` ≤ 64 chars | no collision with an id, name, title, filename stem or alias — exact, or Jaro-Winkler ≥ 0.95 | accept by policy |
41
+ | `add-intent` | `phrase` ≤ 120 chars, `language` | length; language tag present | accept by policy |
42
+ | `mark-canonical` | `scope` | the scope exists; the entity is a document; at most one canonical document per scope after the merge — a second one is a `canonical-conflict` | human approval |
43
+ | `propose-relation` | `from`, `to`, `kind`, `detection` | both endpoints exist; the kind is one of `covers`, `mentions`, `links-to`, `depends-on`, `related-to`, `documents`; not already observed; every evidence item lies inside one endpoint | human approval |
44
+ | `flag-contradiction` | `against`, `claim`, `observed` | both entities exist; evidence inside both | human approval |
45
+ | `flag-redundancy` | `with` | both are documents; not already exact duplicates | human approval |
46
+ | `flag-gap` | `area`, `missing` | the area exists; not already flagged with the same text | accepted as a finding, never as a fact |
47
+ | `rank-hint` | `relevance`: `strong` or `weak` | the entity exists | accept by policy, bounded weight |
48
+ | `suggest-area` | `directories`, `name` | every directory exists; no overlap with an existing area | human approval, then configuration, never an entity |
49
+
50
+ Any other kind is recorded as rejected with reason `invalid-kind`. The full reason list is
51
+ `ENRICHMENT_REJECTION_REASONS`; every rejection carries one of them, so a run's rejections are a
52
+ histogram and not a log.
53
+
54
+ Envelope checks run before the kind's own rule, in a fixed order: `invalid-kind`, `no-evidence`,
55
+ `schema`, `base-snapshot-mismatch`, `unknown-entity`, `stale-target`, `unknown-diagnostic`,
56
+ `evidence-outside-artifacts`, `proposal-id-mismatch`. A proposal that fails the envelope never
57
+ reaches a kind validator.
58
+
59
+ ## The overlay
60
+
61
+ `EnrichmentOverlayV1` lives at `.doc-bridge/enrich/overlay.json`:
62
+
63
+ ```json
64
+ {
65
+ "type": "enrichment-overlay",
66
+ "schemaVersion": 1,
67
+ "contentHash": "…",
68
+ "baseSnapshotHash": "…",
69
+ "accepted": [{ "proposal": { "…": "…" }, "acceptedAt": "2026-09-14T00:00:00.000Z", "acceptedBy": "policy" }],
70
+ "pending": [{ "proposal": { "…": "…" }, "approvalId": "…", "note": "canonical-conflict" }],
71
+ "rejected": [{ "proposalId": "…", "kind": "propose-relation", "entity": "…", "reason": "unknown-endpoint", "detail": "…" }],
72
+ "stats": { "byKind": { "summarize": { "proposed": 4, "accepted": 4, "pending": 0, "rejected": 0 } }, "rejectionReasons": {}, "agentRuns": 1, "cacheHits": 0, "packs": 4, "inputBytes": 0, "outputBytes": 0, "expired": 0 }
73
+ }
74
+ ```
75
+
76
+ `acceptedBy` is `policy` for accept-by-policy kinds and a person's name otherwise; the schema
77
+ refuses `policy` on a human-approval kind and refuses an `acceptedBy` equal to the proposal's
78
+ `origin.agentId`. `contentHash` is over the decisions — every accepted, pending and rejected entry
79
+ and the hashes they bind to — and not over `acceptedAt` or `stats`, because two runs over one
80
+ unchanged repository must produce one overlay hash and a timestamp is not a fact about the
81
+ repository.
82
+
83
+ Reading never writes. `readEnrichmentOverlay` returns nothing for a missing, unreadable, malformed
84
+ or hash-mismatched file, and a reader that got nothing behaves as if there were no overlay.
85
+
86
+ **Staleness is per entry.** At projection time an accepted entry whose `targetContentHash` no
87
+ longer matches its entity — or whose other endpoint no longer exists — is expired in the result
88
+ and excluded from ranking; its siblings for unchanged entities survive. The file is untouched by a
89
+ read; the next `ak-docs enrich` moves the expired entries to `rejected` with reason `expired`.
90
+
91
+ **Reproducible acceptance.** `revalidateEnrichmentOverlay` re-runs the validators over the stored
92
+ proposals and returns the partition they produce; a test asserts it equals the stored one. An
93
+ overlay whose partition does not reproduce was edited by hand or outlived its validators, and
94
+ either way it is no longer evidence of a decision.
95
+
96
+ ## The stage
97
+
98
+ `enrich` is a workflow stage between `reconcile` and `evaluate`, run only by `ak-docs enrich` or
99
+ `ak-docs check --enrich`. A plain `check` leaves its step pending and `evaluate` reads a null
100
+ previous output. A missing, failed, timed-out or stale enrichment never changes a `check` result:
101
+ `check --enrich` reports `enrichment.status: failed` with the error and carries on.
102
+
103
+ ```
104
+ $ ak-docs enrich --text
105
+ Roles: curator=ecosystem-doc-bridge-corpus-scanner
106
+ Packs: 92 (agent calls 3, cache hits 89, re-run 3)
107
+ Accepted: 180 Pending: 4 Rejected: 7 Expired: 3
108
+ summarize: accepted 89, pending 0, rejected 1
109
+ …
110
+ Overlay: 7c1e… (overlay.json)
111
+ ```
112
+
113
+ The stage:
114
+
115
+ 1. builds one context pack per target entity for each configured role and batches them by area;
116
+ 2. answers each pack from the cache or from the agent, caching what the agent said per pack —
117
+ including nothing, so silence is not asked for twice;
118
+ 3. validates everything through the partition against the snapshot, the report and the overlay
119
+ already on disk; policy kinds are accepted, human kinds are requested from the approval gate;
120
+ 4. adjudicates what two roles could not settle, if a third identity is configured;
121
+ 5. merges with the stored overlay — decisions people made survive while their target does — and
122
+ writes it.
123
+
124
+ The step's workflow input names the overlay it attaches (`{ reportHash, overlayHash }`), because
125
+ an approval changes the overlay without changing the report, and the engine refuses a step whose
126
+ input did not move but whose output did.
127
+
128
+ ## Context packs and the cache
129
+
130
+ Agents never receive the snapshot. `buildContextPacks` in `src/enrich/context-pack.ts` builds
131
+ one pack per target entity:
132
+
133
+ | Section | Content | Bound |
134
+ | --- | --- | --- |
135
+ | `target` | id, kind, name, path, content hash, aliases, its own evidence items, bounded metadata | — |
136
+ | `neighbours` | the other end of every relation touching the target, with kind, path, content hash, the relation and its direction; sorted by kind then id | 32 |
137
+ | `diagnostics` | open diagnostics naming the target or citing its file | 16 |
138
+ | `evidence` | the target's own file, redacted, read only if it still hashes to what the snapshot recorded | 12 KB |
139
+ | `budget` | `maxBytes`, `bytes`, `dropped` | 64 KB default, `intelligence.registry.maxPackBytes` |
140
+
141
+ Over budget, sections are dropped in a declared order — excerpt bytes (halved until it fits, then
142
+ dropped), then diagnostics from the end, then neighbours from the end — and the target is never
143
+ dropped. This mirrors `compileBudget` from `@agentskit/core` with a byte counter and the
144
+ `drop-oldest` strategy over sections ordered least-important-first; a test cross-checks the two,
145
+ and the mirror is what runs, because a pack must be the same pack whether or not an optional peer
146
+ is installed. Every string in a pack passes `redactSecrets`, asserted by test.
147
+
148
+ `packHash` covers the target's and every neighbour's content hash and nothing else. The cache key
149
+ is the hash of task, agent identity and version, prompt version and pack hash; entries live under
150
+ `.doc-bridge/enrich/cache/<key>.json`. An unchanged repository therefore makes zero agent calls,
151
+ and a one-document change re-runs only the packs whose hash moved — the changed document's, and
152
+ any pack it was a neighbour of.
153
+
154
+ ## Protocol v2
155
+
156
+ The adapter (`src/agents/registry-adapter.ts`) keeps `run` for `AgentProposalV1` over protocol
157
+ `doc-bridge.registry-agent.v1` — `ak-docs suggest` still works — and gains `enrich(task, packs)`
158
+ over `doc-bridge.registry-agent.v2`:
159
+
160
+ ```json
161
+ { "protocol": "doc-bridge.registry-agent.v2", "task": "curate", "role": "curator", "promptVersion": "1", "packs": [ … ], "capabilities": ["pack.read", "proposal.write"], "network": false, "shell": false, "deterministic": true }
162
+ ```
163
+
164
+ The answer is one JSON object `{ "proposals": [ … ] }`. `task` is `curate`, `review` or
165
+ `adjudicate`; for `adjudicate` the packs are followed by one `adjudication-request` item listing
166
+ the disputed proposals, and `proposals` carries `EnrichmentAdjudicationV1` values. The adapter
167
+ checks transport and budget and returns the raw array; grounding is the validators' job, and
168
+ keeping it there is what makes a stored overlay reproducible from its proposals. The same CLI or
169
+ local runner module serves both protocols and tells them apart by `protocol`.
170
+
171
+ ## Roles
172
+
173
+ | Role | Task | Targets | Kinds it is for |
174
+ | --- | --- | --- | --- |
175
+ | curator | `curate` | documents | classification, summaries, aliases, intents, canonical markers, redundancy, gaps |
176
+ | reviewer | `review` | documents, areas | relations, contradictions, gaps, rank hints, area suggestions |
177
+ | adjudicator | `adjudicate` | the disputed entities | canonical conflicts and disputed contradictions only |
178
+
179
+ Roles are configuration under `intelligence.registry.roles`; the default is the configured agent
180
+ as curator only. The adjudicator must be a different agent identity from both others —
181
+ `resolveEnrichmentRoles` refuses the configuration otherwise — and the validator rejects any
182
+ adjudication whose origin matches a proposal it judges as `self-adjudication`. An adjudication
183
+ judges; it never approves: the losers are rejected as `adjudicated`, the winner stays pending for
184
+ the person the kind's policy requires, and a settled dispute is not reopened by the cache
185
+ replaying the proposals that caused it.
186
+
187
+ ## Approvals
188
+
189
+ Human approval goes through `createApprovalGate` from `@agentskit/core/hitl` over a file-backed
190
+ `ApprovalStore` under `.doc-bridge/approvals/`, one JSON record per approval. The gate contract is
191
+ mirrored in-repo (`src/enrich/approvals.ts`) for the same reason every ecosystem contract is —
192
+ `@agentskit/core` is an optional peer — and the real gate is used through `importPeer` when it is
193
+ installed; a test writes through both over one store and reads the same records.
194
+
195
+ An approval id is the hash of `proposalId` and `targetContentHash`, so an approval given for one
196
+ version of a document cannot be replayed against the next. `ak-docs enrich approve <proposalId>
197
+ --by <name>`, MCP `docbridge.proposals { action: "enrich-approve" }` and a rendered review page
198
+ call the same `decideEnrichment`: the gate decides first, the overlay moves second, and if the
199
+ gate refuses — already decided, unknown — the overlay is untouched. An approver equal to the
200
+ proposal's author is refused; `policy` is not a person. `ak-docs fix approve` records its
201
+ approval through the same gate under `doc-bridge.fix`, bound to the fix proposal id and its
202
+ content hash.
203
+
204
+ ## Projection and bounded influence
205
+
206
+ `projectEnrichmentOverlay(overlay, snapshot)` turns the live accepted set into what
207
+ `projectRetrievalIndex` reads:
208
+
209
+ | Accepted kind | Effect in the projection |
210
+ | --- | --- |
211
+ | `add-alias` | one more alias on the entry |
212
+ | `summarize` | the entry's summary, only when the entity has none of its own |
213
+ | `add-intent` | an `intent` entry with `provenance: proposed` |
214
+ | `mark-canonical` | the `canonical` tag, and 0.8 of the signal |
215
+ | `rank-hint` | 1 (strong) or 0.5 (weak) of the signal |
216
+ | `propose-relation` | one more edge with `confidence: proposed`; a `covers` edge counts toward `coveredBy` and canonicality |
217
+ | `flag-*`, `suggest-area` | nothing: findings and suggestions are for a reviewer, not for ranking |
218
+
219
+ The signal is a per-entry share in 0..1, carried on the entry as `agentSignal`, and the ranker
220
+ multiplies it by `ACCEPTED_SIGNALS_WEIGHT` = 15% of the exact-id boost (30 of 200). It applies to
221
+ lexical hits only, like every other tie-breaker. An accepted signal can therefore reorder near-ties
222
+ and can never lift an entry past one the query named exactly — asserted by test. Without an
223
+ overlay, `ACCEPTED_SIGNALS_WEIGHT × 0` is what it always was, and the projection is byte-identical.
224
+
225
+ The projection's `overlayHash` is the hash of the live accepted set — `EMPTY_OVERLAY_HASH` when
226
+ nothing is live — so it is part of the projection's identity and `IndexStaleError` sees a changed
227
+ overlay. `withAcceptedRelations` merges live proposed relations into a snapshot for the graph, the
228
+ HTML report and the memory view, and `assertObservedSurvive` checks that every observed entity and
229
+ relation is present and unchanged afterwards; the report draws a proposed edge dashed.
230
+
231
+ The index builder consults the overlay only while `intelligence.registry.enabled` is true:
232
+ switching the Registry off restores the deterministic baseline exactly.
233
+
234
+ ## What never happens
235
+
236
+ - No overlay entry deletes or alters observed data. The projection asserts that every observed
237
+ entity and relation survives enrichment.
238
+ - No agent is called from `check`, `index`, `search`, `query`, `render` or MCP. The enrich stage
239
+ runs only on request, and nothing reachable from the query path imports `src/agents`.
240
+ - No agent approves anything — its own output, another agent's, or an adjudication's winner.
241
+ - No read writes. A corrupt overlay is no overlay.