@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.
- package/CHANGELOG.md +465 -0
- package/CONTRIBUTING.md +23 -0
- package/README.md +87 -40
- package/SECURITY.md +7 -0
- package/action.yml +1 -1
- package/bin/ak-docs.js +2 -2
- package/bin/ak-verify.js +13 -7
- package/dist/cli/program.d.ts +3 -1
- package/dist/cli/program.js +15861 -6223
- package/dist/cli/program.js.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.js +86 -6
- package/dist/config/index.js.map +1 -1
- package/dist/{index-BUL0q7s8.d.ts → index-Beor6Yhi.d.ts} +133 -1
- package/dist/index.d.ts +9871 -1062
- package/dist/index.js +16126 -6125
- package/dist/index.js.map +1 -1
- package/docs/MARKETPLACE.md +1 -1
- package/docs/PRD-documentation-efficiency-study.md +406 -0
- package/docs/PRD-knowledge-retrieval-and-enrichment.md +466 -0
- package/docs/adr/0002-documentation-audit-boundary.md +22 -0
- package/docs/adr/0003-study-protocol-and-historical-evidence.md +40 -0
- package/docs/adr/0004-controlled-study-runner.md +25 -0
- package/docs/adr/0005-documentation-quality-and-criticality.md +20 -0
- package/docs/adr/0006-registry-semantic-grounding.md +20 -0
- package/docs/adr/0007-longitudinal-study-metrics.md +21 -0
- package/docs/adr/0008-study-verification-boundary.md +21 -0
- package/docs/adr/0009-study-provider-cli-adapter.md +25 -0
- package/docs/agent-corpus/INDEX.md +12 -1
- package/docs/agent-corpus/OVERVIEW.md +25 -0
- package/docs/agent-corpus/chat.md +5 -1
- package/docs/agent-corpus/cli.md +16 -0
- package/docs/agent-corpus/conformance.md +12 -0
- package/docs/agent-corpus/doc-bridge.md +47 -0
- package/docs/agent-corpus/doctor.md +8 -0
- package/docs/agent-corpus/gates.md +4 -0
- package/docs/agent-corpus/mcp.md +13 -0
- package/docs/agent-corpus/memory.md +4 -0
- package/docs/agent-corpus/query.md +33 -0
- package/docs/bench/README.md +122 -0
- package/docs/bench/retrieval-baseline-v1.json +28 -0
- package/docs/bench/retrieval-suite-v1.json +1033 -0
- package/docs/chat-and-rag.md +3 -2
- package/docs/for-agents.md +9 -1
- package/docs/getting-started.md +4 -11
- package/docs/guides/gate-ci.md +11 -1
- package/docs/guides/install-and-run.md +9 -65
- package/docs/index.md +22 -1
- package/docs/knowledge-engine-runbook.md +38 -3
- package/docs/landing/assets/context-payload-reduction.svg +21 -0
- package/docs/landing/assets/controlled-ab-comparison.svg +30 -0
- package/docs/landing/index.html +119 -5
- package/docs/loop-workflow.md +117 -0
- package/docs/mcp.md +6 -1
- package/docs/parity/public-claims-v1.json +145 -0
- package/docs/playbook/doc-bridge-pattern.md +1 -1
- package/docs/query.md +90 -2
- package/docs/recipes/index-pipeline.md +1 -1
- package/docs/schemas/agent-handoff-v1.md +15 -0
- package/docs/schemas/doc-bridge-index-v1.md +65 -0
- package/docs/spec/benchmark-v1.md +33 -1
- package/docs/spec/cli.md +30 -10
- package/docs/spec/config-v1.md +147 -8
- package/docs/spec/documentation-audit-v1.md +61 -0
- package/docs/spec/enrichment-overlay-v1.md +241 -0
- package/docs/spec/graph-signals-v1.md +92 -0
- package/docs/spec/incremental-scan-v1.md +102 -0
- package/docs/spec/markdown-analyzer-v1.md +73 -0
- package/docs/spec/mcp-knowledge-tools-v1.md +147 -0
- package/docs/spec/measured-enrichment-v1.md +229 -0
- package/docs/spec/public-parity-v1.md +119 -0
- package/docs/spec/registry-agents.md +6 -0
- package/docs/spec/render-v1.md +122 -0
- package/docs/spec/retrieval-index-v1.md +164 -0
- package/docs/spec/study-metrics-v1.md +58 -0
- package/docs/spec/study-protocol-v1.md +46 -0
- package/docs/spec/study-provider-cli-v1.md +116 -0
- package/docs/spec/study-runner-v1.md +35 -0
- package/docs/spec/study-task-suite-v1.md +41 -0
- package/docs/spec/study-verification-v1.md +40 -0
- package/docs/study/README.md +84 -0
- package/docs/study/ab-adjudicated-cost-analysis-v1.md +29 -0
- package/docs/study/ab-adjudicated-cost-plan-v1.json +33 -0
- package/docs/study/ab-adjudicated-cost-plan-v2-v1.json +33 -0
- package/docs/study/ab-adjudicated-cost-result-v1.json +80 -0
- package/docs/study/ab-baseline-analysis-v1.md +21 -0
- package/docs/study/ab-baseline-plan-v1.json +33 -0
- package/docs/study/ab-baseline-recovery-plan-v1.json +33 -0
- package/docs/study/ab-baseline-result-v1.json +79 -0
- package/docs/study/documentation-audit-round-2026-08-31.json +183 -0
- package/docs/study/historical-evidence-v1.json +252 -0
- package/docs/study/observation-ledger-v1.json +30632 -0
- package/docs/study/phase3-task-coverage-v1.json +34 -0
- package/docs/study/phase4-public-pilot-ledger-v1.json +1344 -0
- package/docs/study/phase4-public-pilot-result-v1.json +52 -0
- package/docs/study/phase4-public-pilot-run-plan-v1.json +26 -0
- package/docs/study/phase4-public-pilot-task-suite-v1.json +71 -0
- package/docs/study/pilot-round-2026-08-31.json +46 -0
- package/docs/study/protocol-v1.json +90 -0
- package/docs/study/publication-gate-v1.md +45 -0
- package/docs/study/quality-scorecard-cycle-plan.md +545 -0
- package/docs/study/quality-scorecard-v1.json +38 -0
- package/docs/study/round-1-adjudicated-smoke-v1.json +30642 -0
- package/docs/study/round-1-instrumentation-plan-v1.md +39 -0
- package/docs/study/round-2-expanded-adjudication-v1.json +91 -0
- package/docs/study/round-2-expanded-validation-v1.md +58 -0
- package/docs/study/round-3-evidence-contract-v1.json +75 -0
- package/docs/study/round-3-evidence-contract-v1.md +57 -0
- package/docs/study/round-4-confirmation-v1.json +75 -0
- package/docs/study/round-4-confirmation-v1.md +55 -0
- package/docs/study/run-plan-v1.json +33 -0
- package/docs/study/semantic-adjudication-cycle-8.md +20 -0
- package/docs/study/task-suite-v1.json +96 -0
- package/docs/study/token-efficiency-plan-v1.md +337 -0
- package/docs/study/token-efficiency-protocol-v2.json +62 -0
- package/docs/study/verification-binding-v1.json +27 -0
- package/docs/validation-cycle-plan.md +14 -0
- package/docs/verification-harness.md +11 -6
- package/ecosystem-claims.json +2 -2
- package/ecosystem-upstream.json +2 -2
- package/ecosystem.json +4 -4
- package/mcpb/manifest.json +9 -1
- package/package.json +25 -6
- package/scripts/check-ecosystem-upstream.mjs +34 -6
- package/skills/doc-bridge-handoff/fixtures/synthetic-repo/docs/for-agents/packages/payments.md +7 -0
- package/skills/doc-bridge-handoff/scripts/resolve-handoff.mjs +1 -1
- package/src/agents/registry-adapter.ts +192 -24
- package/src/audit/documentation.ts +513 -0
- package/src/bench/baseline.ts +198 -0
- package/src/bench/overlay-delta.ts +139 -0
- package/src/bench/retrieval.ts +319 -0
- package/src/budget/compile.ts +91 -0
- package/src/budget/sections.ts +70 -0
- package/src/cli/program.ts +684 -74
- package/src/cli/usage.ts +71 -0
- package/src/config/defaults.ts +1 -0
- package/src/config/index.ts +4 -0
- package/src/config/schema.ts +117 -2
- package/src/conformance/documentation-standard-v1.ts +8 -6
- package/src/discovery/areas.ts +182 -0
- package/src/discovery/documentation.ts +211 -5
- package/src/discovery/identity.ts +24 -0
- package/src/discovery/incremental.ts +314 -0
- package/src/discovery/inputs.ts +110 -0
- package/src/discovery/markdown.ts +481 -0
- package/src/discovery/repository.ts +484 -101
- package/src/doctor/run-doctor.ts +244 -12
- package/src/enrich/approvals.ts +190 -0
- package/src/enrich/cache.ts +93 -0
- package/src/enrich/context-pack.ts +272 -0
- package/src/enrich/overlay.ts +255 -0
- package/src/enrich/review.ts +106 -0
- package/src/enrich/stage.ts +374 -0
- package/src/enrich/stats.ts +100 -0
- package/src/enrich/validate.ts +410 -0
- package/src/federation/llms.ts +2 -4
- package/src/findings/report.ts +103 -0
- package/src/graph/build.ts +356 -0
- package/src/graph/memory.ts +208 -0
- package/src/index-builder/build-handoffs.ts +22 -11
- package/src/index-builder/build-index.ts +132 -3
- package/src/index-builder/llms-txt.ts +48 -8
- package/src/index-builder/project-corpus.ts +111 -0
- package/src/index.ts +630 -2
- package/src/lib/fuzzy-match.ts +235 -0
- package/src/mcp/knowledge.ts +554 -0
- package/src/mcp/server.ts +113 -18
- package/src/metrics/benchmark.ts +21 -0
- package/src/parity/check.ts +309 -0
- package/src/parity/claims.ts +259 -0
- package/src/parity/resolve.ts +160 -0
- package/src/query/handoff.ts +326 -0
- package/src/query/load-index.ts +53 -1
- package/src/query/query.ts +92 -59
- package/src/query/search.ts +289 -92
- package/src/query/text.ts +155 -0
- package/src/reconciliation/reconcile.ts +101 -10
- package/src/render/data.ts +356 -0
- package/src/render/engine.ts +398 -0
- package/src/render/generated.ts +77 -0
- package/src/render/render.ts +209 -0
- package/src/render/template-source.ts +52 -0
- package/src/render/templates.ts +289 -0
- package/src/report/html.ts +2 -2
- package/src/retrieval/bm25.ts +161 -0
- package/src/retrieval/project.ts +495 -0
- package/src/retrieval/rank.ts +383 -0
- package/src/retrieval/weights.ts +39 -0
- package/src/retriever/doc-bridge-retriever.ts +100 -15
- package/src/rules/engine.ts +30 -10
- package/src/schemas/agent-handoff.ts +56 -0
- package/src/schemas/budget.ts +37 -0
- package/src/schemas/doc-bridge-index.ts +53 -2
- package/src/schemas/enrichment.ts +369 -0
- package/src/schemas/json-schemas.ts +39 -2
- package/src/schemas/knowledge.ts +14 -1
- package/src/schemas/retrieval-index.ts +152 -0
- package/src/shims/graphology.d.ts +91 -0
- package/src/study/adjudication.ts +196 -0
- package/src/study/execution.ts +350 -0
- package/src/study/expectations.ts +219 -0
- package/src/study/metrics.ts +467 -0
- package/src/study/protocol.ts +271 -0
- package/src/study/provider-cli.ts +115 -0
- package/src/study/provider-telemetry.ts +47 -0
- package/src/study/quality-scorecard.ts +164 -0
- package/src/study/runner.ts +461 -0
- package/src/study/task-suite.ts +321 -0
- package/src/study/verification.ts +134 -0
- package/src/validate.ts +1 -4
- package/src/version.ts +1 -1
- package/src/workflow/engine.ts +36 -11
- 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.
|