@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
@@ -0,0 +1,119 @@
1
+ ---
2
+ title: Public parity v1
3
+ description: A registry of the claims this repository makes in public, the repository facts they stand for, and the gate that fails when a public surface states something the repository has moved past.
4
+ ---
5
+
6
+ # Public parity v1
7
+
8
+ Documentation drifts silently, and the drift reaches readers before it reaches anyone who could fix it.
9
+
10
+ Four figures from the published A/B round appear in `README.md` and again in `docs/study/README.md`.
11
+ They agree today. Nothing made them agree: an edit to one of them, or a new round replacing the
12
+ artifact both quote, would leave two public surfaces stating a number the repository no longer
13
+ measures — and the only mechanism for noticing was a person happening to read both pages on the same
14
+ day.
15
+
16
+ `ak-docs parity` is that mechanism. A registry names each public claim and the repository fact it
17
+ stands for; the checker resolves the fact, finds the claim's occurrences, and reports the difference
18
+ with a file, a line, an owner and a remediation.
19
+
20
+ ## The registry
21
+
22
+ `docs/parity/public-claims-v1.json` is a sealed artifact — `createPublicClaims` computes its content
23
+ hash, `parsePublicClaims` refuses a tampered one — holding claims and exceptions.
24
+
25
+ | Field | Meaning |
26
+ | --- | --- |
27
+ | `claimId` | A slug. Stable across rounds, because findings are keyed on it. |
28
+ | `statement` | What the claim asserts, for a reader of the report. Never a path or a URL. |
29
+ | `owner` | Who answers for it: an ownership id, a team, a handle. Every finding carries it. |
30
+ | `valueType` | `number`, `percent`, `semver` or `text`. Decides the capture. |
31
+ | `template` | How the value appears in prose, with exactly one `{value}`. Omitted for a presence claim. |
32
+ | `templates` | Per-surface wording, when one fact is stated differently in different places. |
33
+ | `evidence` | Where the canonical value comes from. Below. |
34
+ | `required` | Surfaces that must state the claim. One that omits it is a `missing` finding. |
35
+ | `optional` | Surfaces that may. Checked when present, never required. |
36
+ | `severity` | `error` blocks the gate; `warn` is reported and does not. |
37
+ | `remediation` | What to do about a finding. Written once, in the registry, not per finding. |
38
+
39
+ ### Evidence
40
+
41
+ Every resolver is deterministic and local. Nothing reaches the network, and nothing asks a model.
42
+
43
+ | Kind | Resolves to |
44
+ | --- | --- |
45
+ | `package-field` | A scalar field in `package.json` — `version`, `description`. |
46
+ | `artifact-field` | A dotted path into a committed JSON artifact: `arms.1.completedRate`. |
47
+ | `artifact-sum` | The sum of one numeric field across an array in an artifact: prose states a total where the artifact stores the parts. |
48
+ | `snapshot-count` | Entities of one kind in the snapshot this run produced. |
49
+ | `doctor-metric` | A figure the doctor measured: the grade, the score, reachability, connectivity, hit@3, agent-doc coverage. |
50
+ | `cli-command` | Whether the CLI's own usage offers a command. A presence claim: no template, no value to read. |
51
+
52
+ A numeric value can be rendered the way prose states it: `round`, `percent-1dp`, `percent-0dp`, and
53
+ two signed transforms. `negative-percent-2dp` and `negative-seconds-2dp` render the magnitude of a
54
+ negative measurement — "18.46% fewer", "39.75 seconds lower" — and **refuse to render a positive
55
+ one**. The direction of those claims lives in a word the checker cannot read, so a measurement that
56
+ turns stops resolving instead of matching the same digits for the opposite result.
57
+
58
+ ## The four outcomes
59
+
60
+ They are kept apart because they need different actions.
61
+
62
+ | Code | Meaning | Blocks |
63
+ | --- | --- | --- |
64
+ | `PARITY_STALE` | A surface states a value the repository has moved past. | At `error` |
65
+ | `PARITY_MISSING` | A required surface does not state the claim at all. | At `error` |
66
+ | `PARITY_CONTRADICTION` | Two public surfaces state different values for one claim. | Always |
67
+ | `PARITY_NOT_ANALYZED` | The canonical value could not be resolved. | Never |
68
+
69
+ A contradiction is decided over the whole claim rather than per surface: two pages disagreeing is a
70
+ finding even when neither matches the repository, and it is the one an agent reading the
71
+ documentation cannot resolve on its own.
72
+
73
+ `PARITY_NOT_ANALYZED` is reported and never counted as a pass. A claim nobody could check is not a
74
+ claim anybody verified, and passing it quietly is how a parity report becomes decoration.
75
+
76
+ ## Exceptions
77
+
78
+ An exception accepts a finding for one claim on one surface, and it must carry a `reason` of at
79
+ least eight characters and an `acceptedBy`. The finding still appears in the report, marked
80
+ `accepted` with its reason, and stops blocking. There is no way to silence a claim without saying
81
+ why in the artifact — silence is what drift needs.
82
+
83
+ ## The gate
84
+
85
+ ```bash
86
+ ak-docs parity # JSON: { ok, parity }
87
+ ak-docs parity --text # one line per finding, with its remediation
88
+ ak-docs parity --claims <file> # a registry somewhere else
89
+ ```
90
+
91
+ Exit 1 when any finding blocks, 0 otherwise, 2 on a broken registry or an unreadable surface. CI runs
92
+ it in the dogfood step, next to the index, the gate, the doctor and the retrieval benchmark, so a
93
+ pull request that edits a public number and not its siblings fails before review.
94
+
95
+ The doctor is measured only when a claim asks for one of its figures: that costs an index and a
96
+ benchmark run, and most registries never need it.
97
+
98
+ ## Publication safety
99
+
100
+ The report is publication-safe by construction. It carries claim ids, repository-relative surface
101
+ paths, line numbers, the stated and canonical values, and a bounded excerpt of the matching line —
102
+ at most 160 characters, with secrets redacted through the same scanner the enrichment validators
103
+ use. It never carries a document's contents and never an absolute path: the registry's surface
104
+ paths are validated as repository-relative, so an operator's home directory cannot reach an
105
+ artifact that is meant to be shareable. A test asserts all of it against a fixture whose README
106
+ contains a secret-shaped string and a four-hundred-character line.
107
+
108
+ ## Invariants
109
+
110
+ - The registry is sealed; a tampered hash is refused before anything is checked.
111
+ - A template's literal halves are escaped, so a registry cannot smuggle a pattern into the checker,
112
+ and `{value}` becomes one bounded capture: no nesting, no ambiguity, nothing to backtrack over.
113
+ - A claim that states a value has a template; a presence claim has none. The schema enforces both.
114
+ - An exception needs a reason and an approver, and applies to one claim on one surface.
115
+ - A signed transform refuses a value whose sign no longer matches the prose.
116
+ - Two runs over one unchanged repository produce the same report content hash: findings are sorted,
117
+ and nothing in the report is a timestamp.
118
+ - `missingSurfaces` names a surface the registry addresses that the checkout does not contain, so a
119
+ claim cannot pass by pointing at nothing.
@@ -68,3 +68,9 @@ mergePolicy:
68
68
  - `knowledge-promoter` may draft PR content, but must never merge.
69
69
  - `code-review` runs after gates so reviewers see deterministic failures first.
70
70
  - Future RAG mode should inject `createDocBridgeRetriever(index)` and keep exact handoff resolution ahead of semantic results.
71
+
72
+ ## Grounding and approval boundary
73
+
74
+ The adapter accepts only a typed `AgentProposalV1` whose base snapshot and report hashes match the supplied artifacts. A proposal must identify the configured Registry agent and exact installed version, reference known diagnostics, and include evidence present in the supplied snapshot or reconciliation report. When `ak-docs suggest --documentation` is used, the bounded documentation-audit context is also supplied; the proposal must bind `baseDocumentationAuditHash` and may reference audit finding IDs and evidence. Unknown diagnostics, out-of-scope evidence, malformed output, timeout, response limits, and token limits fail closed.
75
+
76
+ The adapter returns advisory evidence only. It does not apply documentation changes, mark findings resolved, or approve its own output. Convert an accepted suggestion into the existing human-gated fix-proposal flow, run post-apply verification, and treat the new source revision as a new evidence run. An alternate Registry agent is selected by changing `intelligence.registry.agentId` and installing matching metadata under `agentRoot`; the common adapter and evidence contract remain unchanged.
@@ -0,0 +1,122 @@
1
+ ---
2
+ title: Render v1
3
+ description: The canonical artifacts rendered as Markdown people can read, from templates a project can replace.
4
+ ---
5
+
6
+ # Render v1
7
+
8
+ Doc Bridge writes JSON for agents and HTML for browsing. `ak-docs render` writes the Markdown for
9
+ people: the same artifacts, through templates rather than string concatenation, so a project can
10
+ change the house style without a code change and every rendering is a function of its inputs.
11
+
12
+ ```bash
13
+ ak-docs render llms.txt
14
+ ak-docs render area --output docs/areas
15
+ ak-docs render ownership --output docs/agent-corpus/generated
16
+ ak-docs render change-digest --data .doc-bridge/previous-snapshot.json
17
+ ak-docs render overlay-review --output review.md
18
+ ak-docs render area --print-template > templates/area.md
19
+ ```
20
+
21
+ Rendering never calls an agent and never reads the Registry. Its inputs are the index, built in
22
+ memory from the working tree or read from the artifact `--data` names, the workflow's last
23
+ reconciliation report and snapshot, and an overlay file. Lists are sorted, nothing carries a
24
+ timestamp, and equal inputs render to equal bytes — every bundled template has a golden file, and
25
+ a test renders the same data twice.
26
+
27
+ ## Templates
28
+
29
+ | Name | Renders | `--data` |
30
+ | --- | --- | --- |
31
+ | `llms.txt` | the curated reading order for agents, exactly as `ak-docs index` writes it | a `DocBridgeIndex` |
32
+ | `area` | one page per code area: purpose, modules, documents, related areas, checks, open findings | a `DocBridgeIndex` |
33
+ | `ownership` | one sidecar per ownership record: start page, what to read, edit roots, checks, related areas | a `DocBridgeIndex` |
34
+ | `change-digest` | entities and documents whose content hash moved since the last scan, and the documents that should have moved with them | the previous snapshot |
35
+ | `overlay-review` | pending agent proposals with their evidence links, for a human to judge | an enrichment overlay |
36
+
37
+ Without `--output`, the pages go to standard output; `--json` wraps them as `{ template, source,
38
+ pages: [{ path, content }] }`. With `--output`, a single page is written to that path and a
39
+ multi-page template under it as a directory; the command prints what it wrote.
40
+
41
+ Templates use [knap](https://github.com/obsidianmd/knap) syntax: `{{ variable }}`, `{% if %}`,
42
+ `{% for item in list %}`, and knap's standard filters. They parse to an abstract syntax tree and
43
+ are interpreted without `eval`; the application computes every variable before rendering, and a
44
+ template cannot call anything. knap renders asynchronously and the index pipeline is synchronous,
45
+ so Doc Bridge walks knap's AST with a synchronous evaluator of its own; a test renders every
46
+ bundled template through knap's engine as well and holds the two to byte-identical output.
47
+
48
+ ## Overriding a template
49
+
50
+ ```json
51
+ {
52
+ "render": {
53
+ "templates": {
54
+ "area": "templates/area.md"
55
+ }
56
+ }
57
+ }
58
+ ```
59
+
60
+ The path is relative to the project root. `ak-docs render <name> --print-template` prints the
61
+ bundled template to start from, and the variables each template sees are the exported view types
62
+ (`AreaPageView`, `OwnershipPageView`, `ChangeDigestView`, `OverlayReviewView`, `LlmsTxtVariables`).
63
+ An override replaces the bundled template entirely and is compiled by the same engine, so one that
64
+ does not parse fails before anything is written. The `llms.txt` override is also what
65
+ `ak-docs index` writes and what the documentation-standard profile re-renders to check freshness:
66
+ the two always agree.
67
+
68
+ ## Generated regions
69
+
70
+ Every Markdown page carries a marker around what the generator owns:
71
+
72
+ ```markdown
73
+ <!-- doc-bridge:generated hash=2dc9b98ec7b986b0 -->
74
+ …
75
+ <!-- /doc-bridge:generated -->
76
+ ```
77
+
78
+ A template places the markers with `{{ region.open }}` and `{{ region.close }}`; a template that
79
+ prints neither is wrapped whole. The hash is the first sixteen hex characters of the SHA-256 of
80
+ the lines between the markers, with line endings normalised, so an editor converting a file to
81
+ CRLF has not changed what the generator wrote.
82
+
83
+ The marker is what closes the loop with the rest of the pipeline. The Markdown analyzer skips
84
+ mentions and links inside a generated region (`docs/spec/markdown-analyzer-v1.md`), so Doc Bridge
85
+ never reads its own output back in as evidence about the repository. The documentation audit
86
+ recomputes the hash of every region and reports one that no longer matches its marker as
87
+ `GENERATED_REGION_EDITED` under `generated-freshness`, with the region's lines as evidence: a
88
+ manual edit inside a region is a finding, never something a regeneration silently discards. Text
89
+ outside the markers is a person's and is left alone.
90
+
91
+ `llms.txt` carries no marker. It is a whole-file artifact with consumers of its own — the
92
+ federation retriever and the freshness gate — and its bytes are unchanged from before.
93
+
94
+ ## The change digest
95
+
96
+ The digest compares two discovery snapshots by the content hash each file-backed entity carries
97
+ (`docs/spec/incremental-scan-v1.md`): an entity in both with a different hash is *changed*, one
98
+ only in the current snapshot is *added*, one only in the previous is *removed*. An entity without
99
+ a hash — an external package, an area — has nothing to move and is not listed.
100
+
101
+ "Documentation to review" answers which documents this change should have touched: every document
102
+ that covers, mentions, links to or references a symbol of something that moved, and did not move
103
+ itself. A document that changed alongside its subject is in *changed*, not there.
104
+
105
+ The previous snapshot is the one `--data` names, otherwise the last `ak-docs scan` (the
106
+ workflow's `normalize` output under `.doc-bridge/workflow`). The current one is a cold scan of the
107
+ working tree. Rendering does not move the baseline — only a scan does — so the digest can be
108
+ rendered as many times as a review needs. With no previous snapshot the command says so and
109
+ exits 2.
110
+
111
+ ## The overlay review page
112
+
113
+ The page reads an enrichment overlay's `pending` proposals — id, kind, entity, reason, confidence
114
+ and evidence locations — and renders each with links of the form `path#L10-L12`. It is
115
+ deliberately loose about the overlay's shape, which the enrichment workstream owns. With no
116
+ overlay it renders an explicit empty state rather than failing; `.doc-bridge/enrich/overlay.json`
117
+ is read when it exists, and `--data` names any other file.
118
+
119
+ ## Boundaries
120
+
121
+ Nothing under `src/render` imports anything under `src/agents`; a test walks the imports.
122
+ Rendering works with the Registry disabled, because it never consults it.
@@ -0,0 +1,164 @@
1
+ ---
2
+ title: Retrieval index v1
3
+ description: The retrieval index as a projection of the snapshot, the ranking that reads it, and the handoffs derived from its graph.
4
+ ---
5
+
6
+ # Retrieval index v1
7
+
8
+ The retrieval index is what search ranks. It is a projection of the discovery snapshot — a pure
9
+ function of the snapshot, the accepted enrichment overlay and the effective configuration — and it
10
+ has no scanner of its own.
11
+
12
+ That sentence closes a gap that had been in the design since the first index. `buildDocBridgeIndex`
13
+ walked the repository a second time, parsed every module and document again, and produced records
14
+ that shared nothing with the snapshot but a file path. Two views of one repository, built by two
15
+ pipelines, could disagree; the index held eleven sidecars while the snapshot held hundreds of
16
+ entities. Now an entity retrieval can find is an entity discovery observed — same id, same content
17
+ hash, same evidence — and the routes the configuration declares (intents, changes, ownership) are
18
+ projected next to them.
19
+
20
+ ## The artifact
21
+
22
+ `RetrievalIndexV1` lives inside `DocBridgeIndexV1` as `projection`, so every reader of the index
23
+ receives it with the same freshness check. `knowledge[]` is still written for every reader that
24
+ predates it and now carries every projected document and module — without body text, which lives
25
+ once in the projection.
26
+
27
+ ```json
28
+ {
29
+ "type": "retrieval-index",
30
+ "schemaVersion": 1,
31
+ "contentHash": "…",
32
+ "snapshotHash": "…",
33
+ "overlayHash": "…",
34
+ "configurationHash": "…",
35
+ "lexiconVersion": 1,
36
+ "graphMetricsVersion": "1.0.0",
37
+ "weights": { "title": 4, "headings": 3, "symbols": 3, "path": 2, "aliases": 2, "summary": 2, "body": 1 },
38
+ "params": { "k1": 1.2, "b": 0.75 },
39
+ "lexical": { "version": 1, "documentCount": 364, "fieldNames": ["…"], "averageFieldLength": { "…": 0 } },
40
+ "entries": [
41
+ {
42
+ "id": "module:src/query/search.ts",
43
+ "kind": "module",
44
+ "path": "src/query/search.ts",
45
+ "title": "search.ts",
46
+ "aliases": [],
47
+ "symbols": ["searchIndex"],
48
+ "tags": ["module", "ts", "query"],
49
+ "fields": { "title": "search.ts", "headings": "", "path": "src/query/search.ts", "symbols": "searchIndex", "summary": "", "body": "", "aliases": "module ts query" },
50
+ "graph": { "pagerank": 0, "inboundLinks": 3, "coveredBy": ["document:docs/agent-corpus/query.md"], "mentionedBy": ["…"], "areaId": "area:src/query", "packageId": "package:@agentskit/doc-bridge", "inbound": [], "outbound": [] },
51
+ "contentHash": "…",
52
+ "provenance": "observed",
53
+ "confidence": "observed",
54
+ "ownershipId": "doc-bridge-query"
55
+ }
56
+ ]
57
+ }
58
+ ```
59
+
60
+ `contentHash` is over the inputs — snapshot hash, overlay hash, configuration hash, lexicon and
61
+ graph-metrics versions, weights and parameters — because the projection is a function: equal
62
+ inputs, equal artifact. `IndexStaleError` keeps working from the same three hashes.
63
+
64
+ Every entry carries the entity's own `contentHash`, its `provenance`, and a `confidence`. An entry
65
+ kind is one of `document`, `module`, `area`, `package`, `intent`, `change`. An ownership record
66
+ attaches to the entity at its path and lends it its id as an alias; the unit then inherits its
67
+ agent document's title, headings, summary and body, because that document is the documentation of
68
+ that unit. A record whose path matches no entity is projected as a declared `package` entry, so a
69
+ query for it still has an answer.
70
+
71
+ The postings are not stored. `fields` already is the serialised index: tokenisation is versioned
72
+ (`lexiconVersion`) and deterministic, so the postings a reader rebuilds are the postings the writer
73
+ would have stored, and `lexical` records the shape of the collection so a reader can check it
74
+ rebuilt the same one.
75
+
76
+ The one thing read from disk is the body of a document the snapshot already names — bounded by the
77
+ same text budget as before — and the read is verified against the entity's content hash. A file
78
+ that changed since the scan is projected from what the snapshot recorded about it, not from what is
79
+ on disk now.
80
+
81
+ ## Ranking
82
+
83
+ `src/retrieval/rank.ts` replaces the internals of `searchIndex` and keeps its signature. The score
84
+ has named parts:
85
+
86
+ ```
87
+ score = lexical × prior
88
+ + exactId + exactPath + exactSymbol
89
+ + graphProximity + canonicality + audienceFit + acceptedAgentSignals
90
+ ```
91
+
92
+ - **lexical** — BM25 over the projected fields, with the weights above. Configurable under
93
+ `retrieval.weights`; recorded in the artifact.
94
+ - **prior** — the query-shape heuristics, as a multiplier: a curated (agent-audience) document, an
95
+ ownership record for a routing question, an intent or change route whose title covers the query,
96
+ a module for a symbol- or path-shaped query. A prior can only amplify evidence that exists.
97
+ - **exactId / exactPath / exactSymbol** — the query names the thing: an alias or id, a path or
98
+ filename, an exported symbol. Per-token identity applies to queries of at most two tokens; a
99
+ sentence does not name a thing by containing one of its tokens.
100
+ - **graphProximity** — within two hops of one of the ten strongest lexical hits, over covers,
101
+ mentions, links and imports. Scaled by the anchor's share of the best score, so a hub page that
102
+ barely matched cannot lift everything it links to.
103
+ - **canonicality** — log-scaled PageRank over `links-to` and `covers`: the page other pages point
104
+ at outranks the leaf that mentions the same thing. A tie-breaker among answers, never an answer:
105
+ it applies only to lexical hits.
106
+ - **audienceFit** — the `--agent` prior for documentation written for an agent.
107
+ - **acceptedAgentSignals** — the overlay hook, carried at zero weight until the overlay workstream
108
+ lands, so the code path and the explain view already exist.
109
+
110
+ A result that only a relation surfaced earns proximity and nothing else. Results below a third of
111
+ the best score are dropped; a caller assembling a neighbourhood rather than an answer passes
112
+ `floor: 0`.
113
+
114
+ **Confidence** on a result is the entry's own when the query matched it directly, and the weaker
115
+ of the entry and the surfacing relation when a relation alone surfaced it — a `fuzzy` mention makes
116
+ a `fuzzy` result. Every result carries evidence (the entity's path and content hash), provenance and
117
+ confidence.
118
+
119
+ `ak-docs search <term> --explain`, or `explain: true` over the API, attaches the matched terms and
120
+ fields and every component's contribution to each result. Explaining never changes the ranking.
121
+
122
+ ```
123
+ $ ak-docs search "workflow transitions persisted" --explain --text
124
+ [module] module:src/workflow/engine.ts score=115.27 confidence=observed
125
+ src/workflow/engine.ts
126
+ why: lexical=115.27
127
+ matched: aliases: workflow | path: workflow | symbols: workflow
128
+ ```
129
+
130
+ ## Handoffs for any entity
131
+
132
+ `handoffForEntity(index, id, config, { root })` in `src/query/handoff.ts` answers for a package, an
133
+ area, a module or a document — by entity id, ownership id, alias or path — and replaces
134
+ `handoffForPackage`. `runQuery` and MCP `handoff.resolve` go through it.
135
+
136
+ | Field | Derived from |
137
+ | --- | --- |
138
+ | `editRoots` | the area or package itself; a module's area; a document's own path |
139
+ | `startHere` | the ownership record's agent document, then documents that `cover` the target, then those that `mention` it, then one `links-to` hop from those, then the corpus index; within each tier the more canonical page first |
140
+ | `readBeforeEditing` | the next two, plus `AGENTS.md` |
141
+ | `checks` | an ownership override, then what the index recorded when it merged frontmatter, package scripts and defaults, then the package-manager default for the unit's package |
142
+ | `related` | the strongest importing and imported areas, with the import that proves each |
143
+ | `explain` | which relation produced each field |
144
+ | `evidence` | the target's path and content hash, and the documents behind `startHere` |
145
+ | `metadata` | `entityId`, `kind`, `checksSource`, `confidence`, `areaId`, `packageId` |
146
+
147
+ `AgentHandoffV1` stays byte-compatible: `related`, `explain`, `evidence` and `metadata` are optional
148
+ additions, and `target.type` gains `area` and `document`. A handoff written before they existed is
149
+ still a valid handoff.
150
+
151
+ ## The retriever
152
+
153
+ `createDocBridgeRetriever(index)` returns `RetrievedDocument[]` from `@agentskit/core` — content is
154
+ the projected title, summary and body, `metadata` carries `kind`, `path`, `evidence`, `explain` and
155
+ `confidence` — so `createHybridRetriever`, `createRerankedRetriever` and `formatRetrievedDocuments`
156
+ consume Doc Bridge with no adapter. The contract is mirrored in-repo (the core package is an optional
157
+ peer) and a test asserts assignability against the real package and runs the real hybrid retriever
158
+ over it. `retrieve('query', { limit })` still works.
159
+
160
+ ## Boundaries
161
+
162
+ Nothing reachable from `search`, `query` or the projection imports anything under `src/agents`; a
163
+ test walks the imports. The deterministic layer is complete on its own, and the enrichment stage
164
+ never sits on its path.
@@ -0,0 +1,58 @@
1
+ ---
2
+ title: Longitudinal study metrics v1
3
+ description: Deterministic, content-addressed comparison of controlled study rounds.
4
+ ---
5
+
6
+ # Longitudinal study metrics v1
7
+
8
+ `ak-docs study metrics <observation-ledger.json>` calculates an anonymization-safe report from `ControlledStudyObservationV1` records. It groups observations by task, repository, category, difficulty, model, scenario, replicate, and aggregate, then compares the selected baseline and current rounds. When a round contains retries or recovery runs, pass `--baseline-run-id` and `--current-run-id` to bind each side to an exact run without rewriting ledger history.
9
+
10
+ When both sides intentionally share one round (for example, two arms of a pairwise run), the same-round selection keeps only the explicitly named run IDs. A same-round report exposes the scenario groups for arm-level analysis; it does not manufacture a round comparison.
11
+
12
+ ```bash
13
+ ak-docs study metrics docs/study/observation-ledger-v1.json --text
14
+ ak-docs study metrics docs/study/observation-ledger-v1.json --baseline-round baseline --current-round cycle-1 --json
15
+ ak-docs study metrics docs/study/observation-ledger-v1.json --baseline-round baseline --baseline-run-id baseline-run-01 --current-round cycle-1 --current-run-id cycle-1-run-01 --json
16
+ ```
17
+
18
+ ## Metric contract
19
+
20
+ The report keeps metric families separate. Counts are sums, rates are weighted ratios or means as stated below, and latency/answer-cost distributions use p95.
21
+
22
+ | Family | Metrics | Collection |
23
+ | --- | --- | --- |
24
+ | Discovery/context | `providerTokens`, `estimatedTokens`, `tokensToCorrectAnswerP95`, `timeToCorrectAnswerP95Ms`, `contextBytesP95`, `responseBytesP95`, `searchHitRate`, `evidenceCitationRate`, `averageToolCalls`, `clarificationRate` | provider or explicitly labeled observation measurements |
25
+ | Task/delivery | `successRate`, `completedRate`, `acceptanceCheckRate`, `errorRate`, `reworkRate`, `safetyRate` | adjudication and observation measurements |
26
+ | Documentation | `documentationFindingCount`, `documentationExampleRate`, `documentationFreshnessRate`, `documentationCorrectnessRate`, `documentationCompletenessRate`, `documentationClarityRate`, `documentationMaintainabilityRate` | audit or human/adjudicator measurements |
27
+ | Operations/cost | `latencyP95Ms`, `analysisCostUsd`, `agentCostUsd`, `adjudicatorCostUsd`, `totalCostUsd`, `providerTokenCostUnits`, `adjudicatorTokenCostUnits` | runner and explicitly labeled cost measurements |
28
+
29
+ Provider token totals and estimated token totals are never combined. An estimate is valid only when the observation says `tokenMethod: estimate`. Known values are retained in partial totals; if any observation is missing a value, the metric is marked with a `-partial` entry in `missingMetrics` and must not be used as a complete-round comparison. A value that was not collected at all is `null`, listed in `missingMetrics`, and excluded from its denominator.
30
+
31
+ Observations may carry additional bounded numeric values in `measurements`. The reserved keys above have the following meanings:
32
+
33
+ - `searchHitRate`, `errorRate`, and documentation `*Rate` values are ratios from `0` to `1`.
34
+ - `acceptanceChecksPassed` and `acceptanceChecksTotal` form a weighted acceptance ratio.
35
+ - `documentationFindingCount`, `analysisCostUsd`, `agentCostUsd`, `adjudicatorCostUsd`, `providerTokenCostUnits`, and `adjudicatorTokenCostUnits` are additive values. Token-unit fields are one unit per provider-reported input or output token and are not currency values. USD fields are valid only when the run records configured rates and provider-reported usage.
36
+ - `safetyOutcome` is preferred for the safety rate; `safe` is `1`, `unsafe` is `0`, and `not-applicable` is excluded.
37
+
38
+ ## Comparison rules
39
+
40
+ Each comparison contains baseline and current values, absolute change, relative change when the baseline is non-zero, sample sizes, limitations, and one of `improved`, `unchanged`, `regressed`, `inconclusive`, or `not-analyzed`.
41
+
42
+ - Fewer tokens, lower latency, less context, fewer clarifications, less rework, and lower cost are directionally better.
43
+ - Higher success, evidence, safety, acceptance, search-hit, and documentation-quality rates are directionally better.
44
+ - A lower-efficiency value cannot make a round `improved` when success, evidence citation, evidence quality, acceptance, safety, or rework regresses.
45
+ - A comparison with fewer than two observations on either side is `inconclusive`, not a pass.
46
+ - Missing baseline/current groups are `not-analyzed`; the calculator does not invent values or backfill historical data.
47
+
48
+ Wilson 95% intervals are emitted for completion and task success rates. They communicate uncertainty; they do not establish causality. Aggregate results must be read with the subgroup results because model, scenario, repository, task difficulty, and documentation changes can confound a round.
49
+
50
+ ## Provenance and immutability
51
+
52
+ The report is normalized and content-hashed with `sha256-normalized-v1`. JSON and text output expose the same group/comparison metric values and report hash. Calculating metrics never writes or replaces a baseline. Baseline approval and replacement remain explicit, audited harness operations.
53
+
54
+ The report contains identifiers, versions, hashes, counts, timings, and classifications only. It must not contain repository contents, private paths, prompts, credentials, or raw agent responses.
55
+
56
+ The CLI exits non-zero for a comparison classified as `regressed`. Structural verification that only checks report generation may pass `--allow-regressions`; regressions remain present in the report and should still fail a quality gate that is intended to enforce improvement.
57
+
58
+ The first anonymized deterministic documentation snapshot is [Audit round 2026-08-31](../study/documentation-audit-round-2026-08-31.json). It is an observational inventory, not the controlled baseline: all six consumers still require semantic review, and its missing metrics must remain missing rather than being inferred.
@@ -0,0 +1,46 @@
1
+ ---
2
+ title: Study protocol v1
3
+ description: Versioned and anonymization-safe contracts for measuring documentation quality and agent efficiency.
4
+ ---
5
+
6
+ # Study protocol v1
7
+
8
+ Phase 0 defines two content-addressed JSON artifacts:
9
+
10
+ - `StudyProtocolV1` defines the population, evidence classes, task categories, model slots, scenarios, metrics, executable outcome checks, budget, privacy policy, and stopping rules.
11
+ - `HistoricalEvidenceRegistryV1` preserves historical observations, available numeric measurements, explicit missing measurements, limitations, and validation state.
12
+
13
+ The contracts are validated by the real Doc Bridge CLI:
14
+
15
+ ```bash
16
+ ak-docs study protocol docs/study/protocol-v1.json --text
17
+ ak-docs study history docs/study/historical-evidence-v1.json --protocol docs/study/protocol-v1.json --text
18
+ ```
19
+
20
+ Both artifacts contain a SHA-256 normalized content hash. A hash mismatch, unknown cross-reference, duplicate identifier, unsafe public field, or incompatible schema fails closed.
21
+
22
+ ## Evidence classes
23
+
24
+ `historical` records preserve observations from prior cycles. They may show evolution but cannot support causal claims because the task suite, models, and metrics were not fixed.
25
+
26
+ `controlled` records belong to the approved benchmark protocol and can be compared only when the source revision, protocol, model, scenario, and validation contract match.
27
+
28
+ ## Outcome coverage
29
+
30
+ Every protocol outcome must map to one or more executable checks. An outcome outside the current phase must instead declare an explicit `notApplicableReason`; an empty mapping is never silently accepted.
31
+
32
+ ## Privacy contract
33
+
34
+ Public study artifacts use anonymized repository identifiers. They do not contain repository contents, paths, prompts, credentials, private identifiers, or raw agent responses. Publication always requires human review. The schema deliberately uses bounded identifiers and safe source references instead of arbitrary URLs or file paths.
35
+
36
+ ## Missing data
37
+
38
+ Unavailable historical metrics are represented in `missingMetrics` with one of `missing`, `not-analyzed`, `blocked`, or `not-applicable` plus a reason. The importer never derives a missing value from another metric.
39
+
40
+ ## Protocol changes
41
+
42
+ Changing task definitions, metric formulas, model identity, scenario behavior, privacy rules, or validation requirements changes the protocol hash. Existing baseline and historical evidence remains immutable; a changed protocol starts a new controlled evidence series.
43
+
44
+ ## Human authority
45
+
46
+ The protocol and historical registry can be discovered and summarized by agents, but agents cannot approve protocol changes, replace a baseline, adjudicate their own output, or publish a report. Those actions remain human-gated through the verification harness.
@@ -0,0 +1,116 @@
1
+ ---
2
+ title: Study provider CLI contract v1
3
+ description: Generic, bounded command contract for model and agent execution in controlled studies.
4
+ ---
5
+
6
+ # Study provider CLI contract v1
7
+
8
+ The provider adapter lets a study use a hosted model CLI, a vendor CLI, or an AgentsKit Registry agent without adding that provider to Doc Bridge. It does not install a model runtime and does not assume Ollama.
9
+
10
+ ## Configuration
11
+
12
+ Create a content-addressed configuration with `createStudyProviderCliConfig` or validate one with:
13
+
14
+ ```bash
15
+ ak-docs study providers path/to/provider-cli.json --text
16
+ ```
17
+
18
+ Each provider entry contains:
19
+
20
+ | Field | Meaning |
21
+ | --- | --- |
22
+ | `modelId` | Must match one pinned model in the run plan. |
23
+ | `scenarioIds` | One or more of `repository-only`, `deterministic-doc-bridge`, `registry-assisted`. |
24
+ | `command` | Executable name or path. It is launched without a shell. |
25
+ | `args` | Ordered arguments passed unchanged to the executable. |
26
+ | `envAllowlist` | Names copied from the parent environment. Credentials must be named explicitly. |
27
+ | `providerNetwork` | Audit declaration that the provider may send input to an external service. |
28
+ | `maxInputBytes` / `maxOutputBytes` | Provider-specific bounds; the lower bound wins against the run-plan budget. |
29
+ | `pricing` | Optional configured USD rates used only to derive auditable `agentCostUsd`; omitted rates produce no currency claim. |
30
+
31
+ The optional top-level `adjudicator` uses the same bounded command fields and adds `id` and `modelId`. It is a separate process from the provider under evaluation. Its output is used to record an independent rubric decision; the provider cannot approve its own result.
32
+
33
+ ```json
34
+ {
35
+ "adjudicator": {
36
+ "id": "independent-reviewer",
37
+ "modelId": "reference-model",
38
+ "command": "/absolute/path/to/adjudicator",
39
+ "args": [],
40
+ "envAllowlist": [],
41
+ "providerNetwork": true,
42
+ "maxInputBytes": 1000000,
43
+ "maxOutputBytes": 50000,
44
+ "pricing": {
45
+ "currency": "USD",
46
+ "inputPerMillionUsd": 1,
47
+ "cachedInputPerMillionUsd": 0.5,
48
+ "outputPerMillionUsd": 3
49
+ }
50
+ }
51
+ }
52
+ ```
53
+
54
+ The cost formula is `(uncached input × input rate + cached input × cached rate + output × output rate) / 1,000,000`. Rates are study configuration, not a vendor billing assertion; the report must preserve the configuration hash and run ID. Cost is emitted only when the process reports both input and output token counts. `providerTokenCostUnits` remains the provider-reported input plus output total and is never presented as currency.
55
+
56
+ The parser rejects stale content hashes, duplicate model/scenario mappings, unsafe environment names, and invalid command arguments. A command must exist and be executable before any task starts.
57
+
58
+ ## Provider process contract
59
+
60
+ The child process receives one JSON request on stdin and must emit exactly one JSON object on stdout. Human-readable logs must go to stderr. The request contains the task, scenario, expected outcome, evidence requirements, acceptance checks, allowed tools, and forbidden actions. It does not contain the configured repository path.
61
+
62
+ The generic runner does not enforce scenario tool semantics. A provider mapping must enforce its own scenario contract: a `repository-only` command must not query Doc Bridge, while a `deterministic-doc-bridge` command must execute the configured deterministic query or handoff and pass its bounded result to the model. A scenario label or `allowedTools` field alone is not evidence that Doc Bridge was used.
63
+
64
+ The response may contain the bounded metrics below. Unknown fields are ignored by the generic runner, while unknown numeric measurements are preserved by the observation schema for future metric versions. The bundled Codex adapter additionally passes a JSON Schema to the provider CLI and requires the semantic fields (`taskOutcome`, `evidenceQuality`, `safetyOutcome`, evidence IDs, clarification/rework counts, an observed latency or explicit `null`, and measurements) so missing output is visible as a provider failure rather than silently becoming an empty result. When observed, measurements must use canonical names: `searchHitRate`, `acceptanceChecksPassed`, `acceptanceChecksTotal`, `errorRate`, `documentationFindingCount`, the documentation `*Rate` fields, `analysisCostUsd`, and `agentCostUsd`.
65
+
66
+ ```json
67
+ {
68
+ "inputTokens": 1200,
69
+ "outputTokens": 340,
70
+ "tokenMethod": "provider",
71
+ "toolCalls": 4,
72
+ "firstEvidenceLatencyMs": 820,
73
+ "taskOutcome": "success",
74
+ "evidenceQuality": "high",
75
+ "safetyOutcome": "safe",
76
+ "evidenceIds": ["artifact-hash:abc123"],
77
+ "clarificationRequests": 0,
78
+ "reworkCount": 0,
79
+ "measurements": {
80
+ "searchHitRate": 1,
81
+ "timeToCorrectAnswerP95Ms": 820
82
+ }
83
+ }
84
+ ```
85
+
86
+ Raw prompts, responses, repository contents, paths, and credentials are not written to the observation ledger. The ledger stores status, hashes, timing, labeled token counts, context-token attribution, first-evidence latency when observed, tool counts, metric fields, and automated or pending human adjudication. The runner derives `providerTokenCostUnits` from provider-reported input plus output tokens; this is a transparent token-equivalent cost metric and must not be presented as currency. Context-token estimates are stored separately with `contextTokenMethod: "estimate"`; they are never combined with provider usage.
87
+
88
+ The bundled Codex adapter also records privacy-safe aggregate context telemetry: `observedToolEventCount`, `observedToolInputBytes`, `observedToolOutputBytes`, `observedProviderInputBytes`, `observedAgentMessageBytes`, `observedContextBytes`, `observedProviderDurationMs`, and (when a tool event is observed) `timeToFirstToolEventMs`. These are byte counts and durations only; commands, paths, prompts, responses, and repository content are not emitted by the adapter. The duration is wall-clock time for the isolated provider process, while `timeToFirstToolEventMs` measures the first observed tool event, not semantic answer quality. The deterministic handoff is serialized as compact JSON before it is passed to the model, and the adapter explicitly tells the model to use its `startHere` and `readBeforeEditing` paths before exploring the repository. This preserves canonical content while removing formatting-only bytes and makes the intended low-context path measurable. Gzip and a cross-process cache are intentionally not used for model context: the model must receive readable content, and the current adapter starts an isolated process per observation, so either mechanism would add complexity without reducing billed model tokens. The public `--agent` CLI path also emits compact JSON, so machine consumers do not pay for presentation-only whitespace.
89
+
90
+ ## Independent adjudication
91
+
92
+ Adjudicate a persisted ledger in a separate process:
93
+
94
+ ```bash
95
+ ak-docs study adjudicate docs/study/observation-ledger-v1.json docs/study/task-suite-v1.json \
96
+ --adjudicator path/to/provider-cli.json --output .tmp/adjudicated-ledger.json \
97
+ --run-id cycle-1 --offset 24 --limit 24 --json
98
+ ```
99
+
100
+ The adjudicator receives only anonymized task metadata and the bounded structured candidate record: outcomes, evidence IDs, per-requirement evidence presence, acceptance execution state, numeric measurements, execution status, duration, and response size. It does not receive repository paths, raw stdout, prompts, repository contents, or credentials. Automated adjudication records the adjudicator configuration hash in addition to its actor and method. A timeout, unavailable command, oversized output, or invalid JSON leaves the adjudication `pending`; no deterministic fallback silently converts that failure into a success. `--offset` and `--limit` support deterministic low-cost samples while preserving all unselected observations in the output ledger; offset counts only observations matching `--run-id`.
101
+
102
+ ## Running a study
103
+
104
+ First validate the complete plan without invoking a provider:
105
+
106
+ ```bash
107
+ ak-docs study run docs/study/run-plan-v1.json docs/study/task-suite-v1.json \
108
+ --providers path/to/provider-cli.json \
109
+ --repositories path/to/repositories.json \
110
+ --ledger path/to/observation-ledger.json \
111
+ --dry-run --text
112
+ ```
113
+
114
+ The canonical run plan dry run validates the configured 24-task balanced sample, repository roots, executable commands, and input limits. It writes no ledger and makes no provider call. To execute, omit `--dry-run`. The ledger is persisted after each observation, so an interrupted run can resume and skip completed task executions idempotently. Reduced pilots may use fewer population identifiers and tasks, but require their own hashed suite, run plan, repository configuration, run ID, and explicit pilot label. A full 288-execution matrix requires a separately hashed run plan with `sampling.sampleSize` set to 288.
115
+
116
+ Provider configuration and repository-root configuration are local operational inputs. Do not commit credentials, private paths, raw provider output, or consumer repository content to a publication artifact.