Skip to content

Verify the docs organizer against a live model once the API key renews #73

Description

@khajavi

src/organize.ts ships in #72 as flowrite's fourth standalone in-place editor. tsc is clean, 105
tests pass, and every recipe in its guide is verified against the fixture — but no run has proposed a
grouping.
The feature is a judgement call, and judgement is the part no test reaches.

Blocked on the Anthropic quota reset — 2026-09-01 00:00 UTC. Tracked in the #66 umbrella alongside
#57, #59, #63, #65, #68, #70. Recorded as BACKLOG.md finding 13.


Step 0 — the fixture, free, no key needed

fixtures/tinyproject/docs/reference/ holds a single index.md, so it cannot exercise the
grouping. It is still the right first run, because it tests the bounds:

bash -c 'cd fixtures/tinyproject && flue run ../../src/organize.ts -m "Organize docs/reference into categories"'

Pass: it reports the section is too small (three pages minimum per category) and proposes no
change. Fail: it invents categories, or writes anything at all.

Cheap and worth doing first, because "proposes nothing when there is nothing to do" is the behaviour
that keeps this agent from making work for itself — and it is the same shape as the metadata
backfiller's stop conditions.

Also confirm the guide's recipes still hold, since they are the ported logic:

recipe expected on the fixture
page list with titles docs/reference/index.md → "TinyProject API Reference"
sidebar parse check passes — and note it is not proof (see below)
id resolution by text extraction 3 ids, all resolve; a planted bad id is caught

Step 1 — a real section

Judging a grouping needs a dozen or more pages. ~/sources/scala/zio-2.x-new/docs/reference has 220
— on a branch, clean tree, diff read before anything is staged.

flue run src/organize.ts -m "Organize docs/reference into categories" \
  --data '{"projectPath":"<checkout>"}'

Step 2 — what to check, in priority order

  1. Is the taxonomy any good? The whole feature, and the only part offline coverage cannot touch.
    A category is a claim about what a set of pages is for. Judge each name against the pages it
    holds, not against whether it sounds plausible — the failure mode to look for is the predecessor's
    substring heuristic, which produced categories that read fine and filed ChunkBuilder under
    Collections. A wrong taxonomy is durable in a way a wrong link is not: readers navigate by it and
    later pages get filed into it.

  2. Did anything move? git status should show only new category index pages and one sidebars.js
    edit. Any renamed or relocated page is a kill, not a tuning knob — a page's links are relative,
    so moving it breaks every reference to it and every ../ inside it.

  3. Does every sidebar id resolve? Use the guide's text-extraction recipe, not require().
    Reason, found while building this: flowrite/package.json sets "type": "module", so a .js
    sidebar under it loads as ESM and require() returns {} with no error for a file whose
    module.exports never took effect. It catches a syntax error and nothing more.

    grep -oE "(id|\"id\"): *['\"][^'\"]+['\"]|['\"](reference|guides)/[a-z0-9/-]+['\"]" docs/sidebars.js \
    | sed -E "s/.*['\"]([^'\"]+)['\"]$/\1/" | sort -u | while read -r id; do
        [ -f "docs/$id.md" ] || echo "MISSING docs/$id.md"
      done
  4. Were the bounds held? Three pages minimum per category, one home per page, leftovers left at the
    top level, and no "Miscellaneous" invented to reach full coverage. A page appearing in two
    categories renders twice and the second entry usually loses its label.

  5. Did it leave other entries alone? A page it did not group must keep its existing sidebars.js
    entry byte for byte. This is the edit that loses a sibling's work where nobody can see it is gone.

  6. Do the index pages read like documentation? They ship unreviewed — there is no review phase on a
    standalone pass — so this is the only time anyone looks at them. Two or three sentences on what the
    category covers, a linked list of its pages, no duplicated API prose.

Kill criteria, not tuning knobs

Following the pattern findings 9, 10 and 12 set:

  • any page moved or renamed
  • a page created that is not a category index — especially one written to make a sidebar entry resolve
  • a sidebar entry removed that was not part of the grouping
  • a "Miscellaneous"-style catch-all category
  • edits to any existing page's prose, frontmatter or links

Ordering

Still the #66 argument, now with four editors behind it: run #65 first. The metadata backfiller is
the cheapest test of the premise all four standalone editors share — instruct rather than wrap, and let
git diff on a clean tree be the safety net — because its invariant is mechanical (verify.sh asserts
the body comes out byte-identical). If it touches bodies, that premise is wrong, and this agent writes
prose and edits a shared file.

Note also that #70's port found git diff is not a sufficient net at scale: a link spliced inside an
inline-code span survived mdoc, onBrokenLinks, and a 94-file human review. This agent's diff is
small by construction (a few index pages and one sidebar edit), which is the main reason it is safer
than the cross-linker — but step 3's grep exists because "read the diff" was not enough there.

Done when

  • step 0: the fixture run proposes no change and writes nothing
  • the three recipes reproduce their expected results
  • a real section is grouped, and every category name survives being checked against its pages
  • no file moved; no page created but the category indexes; no foreign sidebar entry touched
  • every sidebar id resolves by text extraction; the site build passes
  • BACKLOG.md finding 13 closed, or narrowed to what actually failed

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions