Skip to content

docs: golden retrieval suite, area connectivity, and the 1.10.1 doc-bridge pin - #1607

Merged
EmersonBraun merged 10 commits into
mainfrom
claude/retrieval-suite-and-area-connectivity
Sep 16, 2026
Merged

EmersonBraun merged 10 commits into
mainfrom
claude/retrieval-suite-and-area-connectivity

Conversation

@EmersonBraun

@EmersonBraun EmersonBraun commented Sep 16, 2026

Copy link
Copy Markdown
Member

What

Adds a golden retrieval suite, declares the code areas the documentation already describes, stops deriving areas from test and fixture directories, moves the @agentskit/doc-bridge pin from 1.7.45 to 1.10.1, keeps the two published agent indexes to the corpus they were written for, and makes the documentation quality profile's Doc Bridge score a floor instead of an exact 100.

Measured against the published 1.10.1, not a local build:

dimension before (1.7.45) after (1.10.1)
doctor score 100 (of a 60-point scale) 95 / A
reachability not measured 100% (652/652)
connectivity not measured 80% (42/53 areas, 526/652 documents)
retrieval hit@3 not measured 0.80 over 60 cases (hit@1 0.67, MRR 0.74)

pnpm check:quality-gates — all 42 gates pass. pnpm docs:bridge:gate passes both before and after the commit that lands the index. pnpm lint passes. pnpm install --frozen-lockfile is consistent with the lockfile.

Why

The branch does not run without the bump. analysis.areas.exclude does not exist before 1.10.0 and the config schema is strict, so on the 1.7.45 pin every ak-docs command fails with analysis: Unrecognized key: "areas".

The area exclusions matter because areas are derived as the first directory level under each package's source roots, so every package keeping tests/ and fixtures/ beside src/ contributed two areas that are not units of architecture. That was 43 of 81 undocumented areas: the metric was anchored by directories nobody should document. Excluding them takes areas from 103 to 53 and the documented share from 21% to 34% before a single document is written; the 23 docbridge.covers declarations then take connectivity from 49% to 80%.

How

The 60-case suite is in the Open Eval Format (evalFormatVersion: "2026-04"): 20 symbol cases each declared by exactly one module, 8 path, 32 question, 50 en / 10 pt. metadata.expectedTargets is an array and a case passes if any target lands in the top k, so a question with several right answers is not scored as a miss. There are no ownership cases because the repository declares no ownership records.

docs-archive is excluded from the scan: it holds archived translations of pages that are still live, so every query matched two copies of the same content.

The two generator fixes. Doc Bridge used to index only the condensed per-package pages under for-agents, so this repository's knowledge set goes from 27 entries to 2246, and two generators walked that set unfiltered on the assumption that every entry is a package handoff:

  • scripts/sync-repo-llms.mjs emitted one llms.txt line per document — 2276 lines instead of 57, with URLs docsUrl cannot map (a blog path becomes /docs/apps/docs-next/content/blog/...), .mdx filenames where titles belong, and stray MDX import lines as descriptions. llms.txt is a published surface.
  • apps/docs-next/scripts/gen-deterministic-knowledge.mjs derives @agentskit/<id> and a /docs/reference/packages/<id> citation from each entry, so an unfiltered run publishes entries asserting that ordinary guides are packages. It never gets that far: the payload fails its own protocol validation and the script throws, which breaks the docs build.

Both now filter on the for-agents root. That subset of the 1.10.x index is byte-identical to the whole of the 1.7.45 one on id, title, description and path, and handoffs is unchanged, so both outputs are provably the same as before — verified: llms.txt regenerates identical to the committed file, and the deterministic knowledge artifact regenerates to the same 100 entries, 69777 bytes and content hash e81d5a52…4d5e76 already checked in.

.source/ joins the scan excludes; fumadocs-mdx generates it on postinstall and it is gitignored, like the dist and .next already listed.

The profile's score becomes a floor. docBridge.doctorScore had to equal exactly 100. That was a real bar while Doc Bridge scored the index, the handoff corpus and the gates — sixty points this repository takes completely. From 1.10.0 forty of the hundred come from reachability, connectivity and a retrieval benchmark, dimensions that returned null before because nothing measured what retrieval could see, and this repository earns 35 of those 40: reachability 100% is 15/15, connectivity 80% is 12/15, hit@3 0.80 is 8/10.

So a perfect score now means every code area documented, every document linked into code and a near-perfect ranker. Requiring it would decertify every product in the ledger for the act of starting to measure retrieval. The floor is minimumDoctorScore: 90, which is Doc Bridge's own A boundary rather than a number chosen to fit what this repository scores; 95 clears it with five points of room. Everything else stays exact — coverage is still ready === total, conformance is still 7+2 with no exceptions, and the attestation still has to record the score that was measured, so the payload and artifact now read 95. The profile revision goes to 1.2, and the parser keeps pinning every value, so relaxing this again takes a code change rather than a data edit.

The certification test's budget goes from 60 seconds to 360. It pays for two live Doc Bridge runs over the whole repository, doctor and Documentation Standard v1 conformance, which fitted in a minute while the analyzer indexed only the for-agents pages and take a little over two now. It had stopped being a budget for the assertion and become a cap on the corpus. Before this it never reached the second run at all: the doctor exited non-zero on a stale index and the conformance never ran.

Type of change

  • Chore / internal
  • Docs only

Checklist

  • Types check (pnpm lint passes)
  • Tests added or updated — a floor test on the profile (90 passes, 95 passes, 89 fails); the two generators are verified by regenerating their committed artifacts byte-for-byte
  • Changeset created — not applicable; the pin is a root devDependency and no published package changes
  • Docs updated — docs/evidence/ecosystem-documentation-quality/README.md explains the floor

One thing worth a separate decision

.doc-bridge/index.json goes from 118 KB to 7.4 MB, because the index now covers 2246 documents instead of 27, and it is a tracked artifact regenerated on release. Keeping a generated file of that size in history is a repository policy call, not something this pull request should settle. The alternative is to stop tracking it and have docs:bridge:gate regenerate in CI.

The other six products in the quality ledger still attest doctorScore: 100, and that value is only verified when their repositories are checked out locally. None has been measured under the new scoring. The floor keeps them from decertifying, but each will need its attestation refreshed when it moves its own pin.

`ak-docs doctor` reported `hit@3` as `not-analyzed` because no retrieval suite existed, so the one
dimension that measures whether an agent *finds* the right document was blank while reachability
and connectivity were being tracked.

`docs/bench/retrieval-suite-v1.json` holds 60 cases at the path the doctor looks for by default:

- 20 symbol cases, each naming an exported symbol **declared by exactly one module** in this
  repository — computed from the index (2 765 symbols, 1 200 with a single declaration). A symbol
  two modules declare has no correct answer and is not a case.
- 8 path cases over paths verified to exist.
- 32 question cases. Each lists every page that genuinely answers it, because many topics have
  both a concept page and a recipe (`agents/hitl.mdx` and `reference/recipes/hitl-approvals.mdx`);
  declaring one canonical would be a fiction, and scoring a correct answer as a miss would make
  the number useless.
- 10 of the questions are in Portuguese, in the code-switched form a Brazilian developer types.
  Three stay in pure Portuguese and are marked as such, so the gap a lexical ranker cannot close
  keeps being measured instead of hidden.

No ownership cases: this repository declares no ownership records, so an ownership query has no
correct answer here.

The first run found a real defect. `content/docs-archive/` holds 133 indexed documents — 44 in
pt-BR, more in Spanish — covering the same topics as the live pages, and they entered through
discovery rather than through `corpus`. Every Portuguese query was answered with a stale
translation: in eight of ten the archived pages took the entire top three, and the live page did
not appear at all. Excluding `**/docs-archive/**` from discovery took hit@3 from 75.0% to 80.0%
and the Portuguese subset from 20% to 50%. The argument is not the score — it is that an agent
must never be sent to a translation nobody maintains.

Note on versions: `ak-docs bench retrieval` and the doctor's benchmark dimension arrived in
@agentskit/doc-bridge 1.9.0, and this repository pins 1.7.45. The suite is inert until that pin
moves; `safety.exclude` is valid on both.
The doctor's connectivity dimension counts an area as documented when some document covers or
mentions it. 35 areas had none — and for most of them the documentation already existed: the
Markdown analyzer only links a document to an area when the path appears in inline code, so
`data/rag/loaders.mdx` writes about loaders in prose and never names
`packages/rag/src/loaders`.

23 `docbridge.covers` declarations across 18 documents, following the convention 49 documents in
this repository already use. Each pairing is justified by the document's own subject:
`reference/examples/slack-bot.mdx` covers `apps/example-slack-bot`,
`production/evals/replay.mdx` covers `packages/eval/src/replay`, `ui/index.mdx` covers the four
`src/components` areas it lists by name. Where a document genuinely covers two areas it declares
both — `production/evals/snapshots.mdx` is "Prompt snapshots + diff".

Eleven areas are deliberately left undeclared, because no document honestly describes them:
`packages/cli/src/{app,components,extensibility,rules,runtime}`,
`packages/adapters/src/{catalog,cli}`, `packages/core/src/types`,
`packages/integrations/src/{project,testing}` and `scripts`. Those need documentation written, not
an edge asserted.

Every declaration resolves: zero `DOCBRIDGE_*` diagnostics.

Note on versions: area entities arrived in @agentskit/doc-bridge 1.9.0 and this repository pins
1.7.45, where `covers: [area:…]` has nothing to resolve against. Do not merge before the pin moves
to 1.9.0 or later.
Areas are derived as the first directory level under a package's source roots, so every package
keeping `tests/` and `fixtures/` beside `src/` contributes two areas that are not units of
architecture — and connectivity then asks for a document about a folder of test data. Here that
was 43 of 81 undocumented areas: the metric was anchored by directories nobody should document,
and writing documentation could not move it.

`analysis.areas.exclude` drops them from derivation; their modules fall to the most specific area
that still encloses them, or to none. Areas go from 103 to 53 and the documented share from 21% to
34% before a single document is written.

REQUIRES AN UNRELEASED DOC-BRIDGE. `analysis.areas.exclude` does not exist in any published
version — it is on doc-bridge master for 1.10.0. The config schema is strict, so on 1.7.45 (this
repository's pin) and on 1.9.0 this block makes every `ak-docs` command fail config validation.
Do not merge before 1.10.0 is published and the pin moves to it.
Doc Bridge used to index only the condensed per-package pages under `for-agents`; from 1.10.0 it
indexes every document, so this repository's knowledge set goes from 27 entries to 2246. Two
generators walked that set unfiltered on the assumption that every entry is a package handoff, and
both produce wrong output once it is not:

`scripts/sync-repo-llms.mjs` emitted one `llms.txt` line per document — 2276 lines instead of 57,
with URLs `docsUrl` cannot map (a blog path becomes `/docs/apps/docs-next/content/blog/...`),
`.mdx` filenames where titles belong, and stray MDX import lines as descriptions. `llms.txt` is a
published surface, so that is a public regression.

`apps/docs-next/scripts/gen-deterministic-knowledge.mjs` is worse: it derives `@agentskit/<id>`
and a `/docs/reference/packages/<id>` citation from each entry, so an unfiltered run publishes
entries asserting that ordinary guides are packages. It does not get that far — the payload fails
its own protocol validation and the script throws, which would break the docs build.

Both now filter on the `for-agents` root, which is exactly the corpus they were written for: that
subset of the 1.10.0 index is byte-identical to the whole of the 1.7.45 one on id, title,
description and path, and `handoffs` is unchanged, so both outputs are provably the same as
before. Verified: `llms.txt` regenerates identical to the committed file, and the deterministic
knowledge artifact regenerates to the same 100 entries, 69777 bytes and content hash
e81d5a52…4d5e76 that is already checked in.

`.source/` joins the scan excludes: fumadocs-mdx generates it on postinstall and it is gitignored,
like the `dist` and `.next` already on the list. Nothing indexed it before; left in, its eight
generated files entered the published knowledge set whenever the workspace happened to be
installed. That does not make the index install-independent — the projection snapshot still
resolves imports differently once `node_modules` exists — but `ak-docs` is itself installed from
`node_modules`, so every real invocation is already in that state, which is also the state CI
indexes in, and the gate holds both before and after `pnpm --filter "./packages/*" build`.
`analysis.areas.exclude`, added two commits ago, does not exist before 1.10.0, and the config
schema is strict: on the previous 1.7.45 pin every `ak-docs` command fails with
`analysis: Unrecognized key: "areas"`. This branch does not run without the bump.

The regenerated artifacts are the bump showing through. 1.7.45 indexed 27 documents — the
`for-agents` pages — and 1.10.0 indexes 2246, so `.doc-bridge/index.json` grows from 118 KB to
7.4 MB. `handoffs` and the `for-agents` entries are unchanged; the rest is documents that were
previously invisible. Measured against the published 1.10.0 rather than a local build:
`pnpm install --frozen-lockfile` is consistent with the new lockfile, doctor reports reachability
100%, connectivity 80% and hit@3 0.80 on the new retrieval suite, and every one of the 41 package
specs the lockfile regeneration added was published more than 24 hours ago.

TWO KNOWN FAILURES, both needing a decision rather than a patch.

`docs:bridge:gate` fails `index-freshness`, and no committed artifact can satisfy it on 1.10.0.
The index's content hash covers `projection.contentHash`, which covers the discovery snapshot's
hash, which covers `sourceRevision` — the commit SHA when the tree is clean, a content digest when
it is dirty. So committing the index changes the revision that the gate then recomputes against,
and the artifact is stale the moment it lands; a clean CI checkout can never match a hash produced
anywhere else. Verified by generating the index, amending the commit so only HEAD moved, and
regenerating: identical tree, different hash. 1.7.45 wrote no projection block, which is why this
never surfaced before. The revision is identity, not a projection input, so the fix belongs in
Doc Bridge and this pin should move to the release that carries it.

`check:quality-gates` fails the ecosystem documentation quality contract: the profile requires
`docBridge.doctorScore` to equal exactly 100, and 1.10.0 measures 95. Nothing regressed. 1.7.45
scored the index, the handoff corpus and the gates, which this repository passes completely, and
reported 100 out of a scale that could not see retrieval at all — reachability, connectivity and
benchmark all come back `null` on it. 1.10.0 moves 40 of the 100 points onto those three:
reachability 100% earns 15/15, connectivity 80% earns 12/15, and hit@3 0.80 earns 8/10. Reaching
100 means documenting the 11 remaining areas, linking the 126 unlinked documents and lifting hit@3
to 0.95 — real work, not a pin bump. Every other product in the ledger also attests 100 and will
meet the same wall when it upgrades, so the fix belongs in the profile or in the documentation,
and either way it is not this pull request's call to make.
@github-actions

Copy link
Copy Markdown
Contributor

Lighthouse

URL Performance Accessibility Best practices SEO
http://127.0.0.1:3000/ 60 92 96 100
http://127.0.0.1:3000/docs 61 100 96 100
http://127.0.0.1:3000/docs/get-started/getting-started/quickstart 73 96 96 100
http://127.0.0.1:3000/stack 92 100 96 100
http://127.0.0.1:3000/showcase 88 100 96 100

Run by .github/workflows/lighthouse.yml.

The documentation quality profile required `docBridge.doctorScore` to equal exactly 100. That was a
meaningful bar while Doc Bridge scored the index, the handoff corpus and the gates: sixty points
that a well-kept repository takes completely, and this one does. From 1.10.0 forty of the hundred
come from reachability, connectivity and a retrieval benchmark — dimensions that returned `null`
before, because nothing measured what retrieval could see. This repository earns 35 of those 40:
reachability 100% is 15/15, connectivity 80% is 12/15, hit@3 0.80 is 8/10.

So a perfect score now means every code area documented, every document linked into code and a
near-perfect ranker. Requiring it would decertify every product in the ledger for the act of
starting to measure retrieval, and would make the gate answer a question about documentation work
that nobody has scheduled. The floor is 90, which is Doc Bridge's own A boundary rather than a
number chosen to fit what this repository scores — 95 clears it with five points of room.

Everything else stays exact. Coverage is still `ready === total` per audience, conformance is still
7+2 with no exceptions, and the attestation still has to record the score that was measured, not
the floor: the live run, the payload and the artifact must agree, so the payload and artifact now
read 95 because that is what `ak-docs doctor` reports here. The profile revision goes to 1.2, and
the parser keeps pinning every value, so relaxing this again takes a code change rather than a data
edit.

The certification test's budget goes from 60 seconds to 360. It pays for two live Doc Bridge runs
over the whole repository, `doctor` and Documentation Standard v1 conformance, which took under a
minute while the analyzer indexed only the `for-agents` pages and take a little over two now that
it indexes every document. It had stopped being a budget for the assertion and become a cap on the
corpus. Before this it never reached the second run at all: the doctor exited non-zero on a stale
index and the conformance never ran.
1.10.0 could not keep a committed index fresh. Its content hash covered the projection's, which
covered the discovery snapshot's, which covered `sourceRevision` — so committing
`.doc-bridge/index.json` changed the revision the next run hashed and the artifact was stale the
moment it landed. `pnpm docs:bridge:gate` is a required check here and could not be made to pass
twice in a row. 1.10.1 seals the projection over what the snapshot observed instead, which is what
the projection is a function of.

Measured against the published 1.10.1, not a local build: doctor reports A/95 with reachability
100%, connectivity 80% and hit@3 0.80 on the new retrieval suite, `docs:bridge:gate` passes both
before and after this commit, `check:quality-gates` passes all 42, and `pnpm install
--frozen-lockfile` is consistent with the lockfile. The four transitive versions the lockfile moved
(minimatch, dayjs, @types/node, tsx) were all published weeks ago.

The index grows from 118 KB to 7.4 MB because 1.10.x indexes every document instead of the 27
`for-agents` pages. `handoffs` and the `for-agents` entries are unchanged; the rest was previously
invisible. Keeping a generated artifact of that size in history is worth a separate decision.
@EmersonBraun EmersonBraun changed the title docs: golden retrieval suite, area connectivity, and the 1.10.0 doc-bridge pin docs: golden retrieval suite, area connectivity, and the 1.10.1 doc-bridge pin Sep 16, 2026
@EmersonBraun
EmersonBraun marked this pull request as ready for review September 16, 2026 19:58
@EmersonBraun
EmersonBraun force-pushed the claude/retrieval-suite-and-area-connectivity branch from 980ab9a to 9bcfe7a Compare September 16, 2026 20:18
@github-actions

Copy link
Copy Markdown
Contributor

Lighthouse

URL Performance Accessibility Best practices SEO
http://127.0.0.1:3000/ 68 92 96 100
http://127.0.0.1:3000/docs 76 100 96 100
http://127.0.0.1:3000/docs/get-started/getting-started/quickstart 73 96 96 100
http://127.0.0.1:3000/stack 93 100 96 100
http://127.0.0.1:3000/showcase 94 100 96 100

Run by .github/workflows/lighthouse.yml.

CI failed `index-freshness` on a tree it had just checked out: the gate expected
6a1ff444…e0e3dc6 and the committed artifact was f22fc43a…9ba8bba. Not the revision this time —
generated files that are gitignored and therefore differ between machines were being scanned.

`apps/docs-next/lib/ask-context.ts` is written by `gen-ask-context.mjs`, which docs-next's own
`lint` and `prebuild` run. Locally `pnpm lint` had produced it before I generated the index; CI's
`Lint, Test, Build` job lints only `./packages/*`, so it never had the file. One generated module
in or out of the corpus is a different index. `packages/svelte/.svelte-kit/` is the same category
from the svelte build.

Three generated documents join them, not because they broke anything yet but because they are the
same defect waiting: `content/docs/api/`, `content/docs/reference/changelog.mdx` and
`content/docs/production/performance.mdx` are all gitignored and written by `prebuild`, and as
`.mdx` they would enter the document set — so whether the docs build had run would decide how many
documents the index claims, and any measurement taken from it.

The rule the exclude list now expresses is that the scan covers what is committed. An index that
is itself committed cannot depend on build output, because the machine that verifies it has not
necessarily built.

Verified: the index hash is identical with those files present, absent, and present again
(07bfa838…c4c4b55 all three times); `check:quality-gates` passes all 42 and `docs:bridge:gate`
passes; doctor is unchanged at A/95 with 652 documents, connectivity 80% and hit@3 0.80, so
nothing that was being measured came from a generated file.
@github-actions

Copy link
Copy Markdown
Contributor

Lighthouse

URL Performance Accessibility Best practices SEO
http://127.0.0.1:3000/ 54 92 96 100
http://127.0.0.1:3000/docs 67 100 96 100
http://127.0.0.1:3000/docs/get-started/getting-started/quickstart 68 96 96 100
http://127.0.0.1:3000/stack 88 100 96 100
http://127.0.0.1:3000/showcase 88 100 96 100

Run by .github/workflows/lighthouse.yml.

@EmersonBraun
EmersonBraun merged commit f9e3ef7 into main Sep 16, 2026
16 checks passed
@EmersonBraun
EmersonBraun deleted the claude/retrieval-suite-and-area-connectivity branch September 16, 2026 21:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants