Docs site built on Flatbread, reading the repo's own Markdown - #247
Docs site built on Flatbread, reading the repo's own Markdown#247tonyketcham wants to merge 33 commits into
Conversation
The repository's guides now live at apps/docs/content/docs and the site reads those exact files. Package README symlinks under content/reference do the same for the eleven package docs, so nothing is copied. - Add apps/* to the pnpm workspace, and exclude apps/* from the root build, dev, and build:types filters. Without that, pnpm build would boot a GraphQL server and run next build inside the library build, which every CI job and pnpm test depend on. - Add frontmatter (id, title, section, order, summary, related) to the seven guides so Flatbread can validate ids and order the navigation. - Repair every link that pointed at the old docs/ path. - Add five markdown plugins the site runs through Flatbread's transformer: strip the leading H1, carry code fence titles, rewrite repo links to site routes, add heading anchors, and colour code with Shiki. Change-Id: I472065d89b0b2b3ecd7752eebe81877d4151c992
The site at apps/docs renders every guide and package README through Flatbread's GraphQL server while it builds, then exports 22 static files. Nothing calls a server once the build is done. Interface: a terminal document. One monospaced family, widths counted in character cells, every vertical step one line high, two tones and a single accent taken from the Flatbread mark. Panels use one-pixel borders with box-drawing characters at the corners so they hold their shape at any width; the navigation is a real directory tree, where the connectors never have to stretch. Motion: the hero resolves out of punctuation one cell at a time, page titles assemble character by character, the caret marking the current page slides between rows, and the content column repaints on navigation. Every one of those checks useReducedMotion first and renders its final state instead. Motion's splitText belongs to Motion+, which installs from a private registry with a secret token, so the site splits text itself. The whole string stays in aria-label and each piece is inline-block. Also adds search (scored in the browser, since Flatbread ranks nothing), a table of contents read from the rendered HTML, copy buttons added to code blocks after mount, a link checker that fails the build on a broken cross-reference, and an Ubuntu-only CI job. Change-Id: Ic1a52e34ab701be06bceeff57c5b3ea5cc6df1d9
On a phone the tree pushed the page eighteen links down. It now sits behind a 'pages' toggle below 900px and stays open above it. The open state follows a media query, because the reliable way to force a <details> open across browsers is still the open attribute. Also records what this exercise found in the Proof: one retrospective Finding listing six limits in the content model, two Issues for the real defects (a content path cannot climb above the project directory, and initial load disagrees with watch mode about capture patterns), and one Constraint explaining why the site cannot depend on Motion+. Change-Id: I8804bdab70b945675e0fe70cac889f8478883863
svimg 3.1 and 3.2 pull sharp 0.30 and 0.31. Those versions download a prebuilt binary, and on a socket hang-up they fall back to node-gyp. windows-latest ships Visual Studio 18, which node-gyp 11 does not recognise, so the fallback always fails. sharp 0.34 ships platform packages as optional npm dependencies and has no compile path. One workspace override replaces every copy. svimg only calls metadata, resize, jpeg/png/webp/avif quality, toFile, and toBuffer, which still work. Change-Id: I14e5b03cea0c3a49b5c40789128f0c0e0ff1ec78
sqlite3, pulled in by @cursor/sdk, still uses prebuild-install. A socket hang-up on Windows Node 20 falls through to node-gyp, which cannot use Visual Studio 18. Three attempts with a short pause cover that remaining flake without changing the package. Change-Id: Iff3853a4e6a4153ff39f8bac186e711d0de6826e
|
Tick the box to add this pull request to the merge queue (same as
|
There was a problem hiding this comment.
Stale comment
Review verdict
REQUEST_CHANGES — Consensus HIGH on two docs-app contracts: module-level
once()freezes nav/search under the documentedpnpm docs/ watch path, andremark-repo-linksrewrites relative links without the source file (first filesystem hit wins). GraphQL↔page wiring from #246 is fixed; merge still needs the watch memo fix, source-aware link rewrite (+ matrix test), and a thin unit net for the pure logic this app ships.Chunk-bound feedback (priority)
- HIGH
apps/docs/lib/content.ts—once()keeps the first GraphQL list forever; emptyallDocs/allSections/allPackagesstill “succeed.” Skip/invalidateonceoutside production; fail (or assert vs disk) when collections are empty but content exists on disk.- HIGH
apps/docs/plugins/remark-repo-links.mjs— Source-blind first-hit resolution can mapREADME.mdto the wrong/reference/*. Pass the Markdown base (or require a unique match) and add a rewrite matrix test.- MED
apps/docs/scripts/check-links.mjs— Scalarrelatediterates characters; nav YAML dual-id/ required fields unchecked.- MED
apps/docs/lib/toc.ts/lib/search.ts— Attribute-order TOC regex and ranking logic are pure and untested.- MED Root
pnpm docs/verify— Nopredocsbuild;verifyomitsdocs:buildwhile CIdocs-sitecatches it.- MED DX/docs paths — CONTRIBUTING omits the docs site;
@flatbread/coreREADME relative link breaks on npm; README should warnplayvsdocsport clash + symlink need.Coverage plan (must-have first)
remark-repo-links.test.mjs— root/./README.md→/reference/flatbread/(not first package); package README → matching/reference/<pkg>/lib/content.test.ts—oncerereads in non-production after mocked corpus change; graph counts match on-disk collectionscheck-links.test.mjs— scalarrelatedclear type error; required frontmatter / nav YAMLlib/toc.test.ts/lib/search.test.ts— attr-order TOC; short-query / AND / title-prefix rankingReviewer scoreboard
Perspective Verdict Signal test-coverage-robustness REQUEST_CHANGES HIGH docs-site-contracts REQUEST_CHANGES HIGH dx-and-examples COMMENT MED docs-and-positioning COMMENT MED release-discipline COMMENT MED Models:
cursor-grok-4.5-high(HIGH),composer-2.5(MED/LOW). Oven missing → Task fallback. Judge:/tmp/review-judge-final.md. Not dependency-only (93 non-lock paths).Sent by Cursor Automation: Flatbread PR Review
The docs app shipped pure logic with no tests and no place to put them. Vitest now runs in `apps/docs`, and the root `test` script includes it beside the codegen and utils suites. Two gaps in the root scripts close with it. `pnpm docs` on a fresh clone failed with an opaque `ERR_MODULE_NOT_FOUND` because nothing built the packages first; `predocs` now runs `pnpm build`. And `pnpm verify` never looked at the docs pages, so a broken link or a missing frontmatter key only showed up in the `docs-site` CI job; `verify` now ends with `pnpm docs:check`. Change-Id: Ie1d41e9fae2dba2f80d600359c6393938432b1b1
`once()` held the first answer to every list query for the life of the process. Under `flatbread start --watch -- next dev` that process outlives every file save, so the sidebar, the home page, and search kept showing the corpus as it stood when the server started, while a guide page read through `getDoc` refreshed. The memo now applies only to a production build, which is the case it was written for. An empty collection also used to build green. `allDocs` coming back empty flattened to `[]`, and the site shipped a blank home page and an empty sidebar; `check-links` could not catch it, because it reads the filesystem rather than the graph. Each list reader now fails with the collection name and the directory to look at. Change-Id: I3f30efd46aa6f684d63e8666e49bf9a555960931
Flatbread hands the markdown processor a string, not a file, so the rewriter cannot see which page a link came from. It used to resolve the link against the guides folder and every package folder in turn and take the first hit. That is a guess. A link to `./README.md` inside `packages/core/README.md` landed on `/reference/codegen/`, the first package with a README, and any `./`-relative path that exists under two packages had the same fault. The rewriter now collects every distinct file the bases point at and rewrites only when they agree on one. Bases often do agree: every package sits at the same depth, so `../../CONTRIBUTING.md` names the same file from any of them. An ambiguous link is left alone, and `check-links` reports it with the candidates and a way out, so it fails the build instead of shipping a link that only works on GitHub. Two smaller faults go with it. A scalar `related:` in frontmatter used to iterate characters and report a missing page per letter; it now reports once that `related` must be a list. And the checker's work moved into an exported `collectProblems()` so tests can call it, leaving the command-line behaviour unchanged. Change-Id: I48ecb9c80a7c904b909a7da07a8f04826fc6d8a8
The contents list read the rendered HTML with a pattern that demanded `id` be the first attribute. A heading serialized as `<h2 class="..." id="...">` produced no entry, so the page lost its contents list while the anchors beside each heading still worked. The pattern now matches the tag and looks for `id` among whatever attributes it carries. Two comments in `rehype-heading-anchors.mjs` claimed the plugin kept its slug rule in step with one in `lib/toc.ts`. There is no such rule there: the plugin is the only place a heading id is made, and `lib/toc.ts` reads those ids back out of the HTML. The comments now say that. Tests cover both files and the search ranking, which had none. Change-Id: I740c764eb050959eb2b29d791c011544ac198ddc
`CONTRIBUTING.md` sent every newcomer to `pnpm play` and `examples/nextjs`, so a contributor editing a guide had no way to learn that `pnpm docs`, `pnpm docs:build`, and `pnpm docs:check` exist. It now names them and says plainly that `pnpm verify` checks the docs pages but leaves the full docs build to CI. `packages/core/README.md` linked to the export guide with a path that climbs out of the package. That works in the monorepo and on the site, but the npm page for `@flatbread/core` ships only the package directory, so the reader most likely to follow it got a 404. It is now an absolute GitHub URL, as in `packages/flatbread/README.md`. `apps/docs/README.md` gains the two things that catch people out: `pnpm play` and `pnpm docs` both want ports 5057 and 3000, so only one may run at a time, and the `content/reference` symlinks come out as plain text on a Windows clone without symlink support. Change-Id: Idb68b48b703f33e235abdca57d05cb468d27f622
There was a problem hiding this comment.
Stale comment
Review verdict
REQUEST_CHANGES — Prior eaf20ad blockers are fixed at c3383dc (
onceno longer freezes watch chrome; empty collections throw; remark is unanimous not first-hit;relatedscalar guarded; TOCidorder-independent;predocs/ CONTRIBUTING / core README links landed). Two independent HIGHs remain, plus a non-empty coverage plan over non-test sources.Blocking / high
apps/docs/lib/content.test.ts— GraphQL mocks never assert collection counts against disk (CONTENT_DIRS). Under-count still passes unit tests.package.jsonpnpm.overrides.sharp— Workspace-wide native pin in a docs PR without release callout; affectsexamples/nextjsand other consumers.Medium (selected)
- Post-
flatMapsilent empty when all GraphQL rows are invalid (content.ts).- Hero “flat files” framing vs positioning (
app/page.tsx).apps/docs/README.mdroot vs package-local run instructions.- Untested
graphql.tsfailure paths.- CONTRIBUTING omits port collision with
pnpm play.Coverage plan
content.test.ts— graph↔disk parity; all-invalid-row throw;getPackages/getSearchEntriesempty + prodonce; missing html reject.graphql.ts— non-OK / errors / no data.remark-repo-links.test.mjs— missing target unchanged; hash on blob URL.check-links.test.mjs— dangling reference symlink; ignored schemes.- Plugin units — strip-first-H1, code-meta, rehype duplicate slug.
Reviewer scoreboard
Perspective Signal test-coverage-robustness HIGH — graph↔disk docs-site-contracts HIGH on prior resolution; residual MED post- flatMaprelease-discipline HIGH — sharpoverridedx-and-examples MED — README/CONTRIBUTING docs-and-positioning MED — hero copy Prior automation threads from eaf20ad marked fully_addressed. Oven unavailable → Task fallback (models:
cursor-grok-4.5-high/composer-2.5). Judge:/tmp/review-judge-final.md.Sent by Cursor Automation: Flatbread PR Review
The site exports to plain files, so every GraphQL read must be cacheable: a `no-store` fetch makes the route dynamic, and a dynamic route cannot be exported. Next keeps those cached answers in `.next/cache/fetch-cache`, and that directory outlives the build. Since each build sent the same URL, method, body, and headers, the second build read the first build's answers. Edit a guide, run `pnpm docs:build`, and the page kept its old title. CI never saw it, because a fresh checkout has no `.next`, so the fault only showed up after the stale page reached a reader. The request URL now carries a stamp taken once when the module loads. A new build gets a new key; repeated queries inside one build still hit the cache, which is what `force-cache` is there for. Change-Id: Ia963689e5930d1a764174c7c63f0f564a3e5d970
A package README that must read well on npm cannot use a relative path, so it writes the absolute GitHub URL instead. The rewriter only looked at relative links, so `/reference/flatbread/` — the repository README, and the busiest reference page here — threw the reader out to GitHub for the glossary, the export guide, and a dozen other guides sitting one route away. An absolute link into this repository names its file outright, so there is nothing to guess: when the site serves that file, the link now becomes the site route. A link to a file with no page here, to a file that is gone, or to another branch is left as it stands. That halves the GitHub links in the exported site, from 31 to 14. Change-Id: I72bc0d562b09f68385202650eb6c7e8f7abf2afd
There was a problem hiding this comment.
Stale comment
Review verdict
BLOCK — workspace-wide
pnpm.overrides.sharp(package.json:95-97) still has no PR body / CHANGELOG Unreleased callout (release-discipline blocker). Independently: consensus HIGH graph↔disk parity and GraphQL failure-path coverage remain open afterc3383dc…013c43c(stamp + blob only).Not dependency-only (102 non-lock paths). Oven missing → Task fallback. Models:
cursor-grok-4.5-high(HIGH),composer-2.5(MED/LOW). Perspectives: test-coverage-robustness, docs-site-contracts, dx-and-examples, docs-and-positioning, release-discipline.Prior threads (sync c3383dc)
All seven remain not_addressed: graph↔disk; sharp override; post-
flatMapsilent empty; hero “flat files”; README predocs/pnpm dev; GraphQL throw tests; CONTRIBUTING port collision.Chunk-bound feedback (priority)
- BLOCKER
package.json:95-97— document or scope thesharp@0.34.3override.- HIGH
content.test.ts/content.ts— graph↔disk count/id parity still missing.- HIGH
graphql.test.ts/graphql.ts—!ok/errors/ no-datathrows untested (stamp-only delta).- MED
content.ts—expectRecordsthenflatMapcan still yield silent[].- MED hero / README / CONTRIBUTING — same copy and DX gaps as last sync.
Coverage plan
content.test.ts— disk glob vsgetDocs/getSections/getPackages/getSearchEntriessize+ids;getDoc/getPackagehappy + miss.content.test.ts— post-flatMapall-invalid rows must fail (not silent empty).graphql.test.ts—!response.ok, GraphQLerrors, missingdata.check-links.test.mjs— dangling symlink branch.remark-repo-links.test.mjs— bad percent-encoding /..escape (LOW).Reviewer scoreboard
- test-coverage-robustness: 7 findings, 8 coverage gaps, signal:HIGH
- docs-site-contracts: 6 findings, 5 coverage gaps, signal:HIGH
- dx-and-examples: 3 findings, signal:MED
- docs-and-positioning: 3 findings, signal:MED
- release-discipline: 3 findings, signal:HIGH
Delta since last review closed cache-stamp freshness only; it did not clear the open HIGHs.
Sent by Cursor Automation: Flatbread PR Review
`pnpm docs` never started the site. pnpm has a built-in `docs` command — the same one npm has — which opens the package homepage in a web browser, and it wins over a script of that name. Following the instructions in `CONTRIBUTING.md` opened a browser tab, left ports 3000 and 5057 empty, and printed no error to explain it. The script is now `docs:dev`, with `predocs:dev` building the packages before it. A colon cannot collide with a pnpm command, so the three docs commands — `docs:dev`, `docs:build`, `docs:check` — are safe as a set. Nothing is left behind under the old name, since a shadowed script is a trap rather than a convenience. Change-Id: I196ad5591ae111a56d2aa2978683f19e8202c7da
There was a problem hiding this comment.
Stale comment
Review verdict
BLOCK — Workspace-wide
pnpm.overrides.sharp: "0.34.3"still has no CHANGELOG/CONTRIBUTING/migration note. Consensus HIGH holes also remain: post-flatMapsilent[], missing graph↔disk parity tests, and untested GraphQL!ok/errors/ missing-datathrows.Not dependency-only (99 non-dep paths of 103). Delta since
013c43c: renamedocs→docs:devonly. That closes the README redundant manual build and the pnpm script-name collision. It does not close the open BLOCKER/HIGH items.Blocking / consensus (priority)
- BLOCKER — Document or scope the workspace
sharpoverride (package.json).- HIGH — Re-guard after
flatMapincontent.ts; add all-invalid + graph↔disk tests.- HIGH — Three GraphQL throw-path unit tests.
Coverage plan
content.test.ts— all-invalid rows afterflatMapmust fail closed.content.test.ts— graph↔disk count/id parity.content.test.ts— empty/all-invalidgetPackages/getSearchEntries.graphql.test.ts— negatives for!ok,errors[], missingdata.- Remark
findTargets— reject paths outsiderepoRoot.- CHANGELOG + CONTRIBUTING note for
pnpm.overrides.sharp.Delta closed this sync
apps/docs/README.md/CONTRIBUTING.md/ root scripts:pnpm docs:dev+predocs:dev(no redundant rootpnpm buildin the quick start).Reviewer scoreboard
test-coverage-robustness: HIGH findings (content + GraphQL)docs-site-contracts: HIGH content/sharp; MED remark/check-linksrelease-discipline: BLOCKER sharp; MED pipeline/CONTRIBUTINGdx-and-examples: APPROVE (LOW CONTRIBUTING port note)docs-and-positioning: APPROVE (LOW hero/glossary; MED dual front door)Oven CLI unavailable → Task-tool fallback. Models:
cursor-grok-4.5-high(HIGH),composer-2.5(MED/LOW).Sent by Cursor Automation: Flatbread PR Review
Change-Id: Icf4cf38569a7c7a284eb0428f94e3db27b6e0746 # Conflicts: # CONTRIBUTING.md
Change-Id: I7fb714acae2f4db7d1e144927c8b016fda712f26
There was a problem hiding this comment.
Stale comment
Review verdict
COMMENT — Prior blockers look remediated at
f10ec27(sharp0.35.3scoped + CHANGELOG/CONTRIBUTING, empty collections fail loud,check-content-parity, GraphQL throw tests, remark..guard, hero “files in Git → typed relational graph”, play/docs:devport warning). No BLOCKER. Remaining work is test/contract polish on non-test sources, so this stays COMMENT rather than APPROVE.Not dependency-only (124 paths / 199 chunks vs
origin/main4e3ff43). Oven CLI unavailable → Task-tool fallback. Models: HIGHcursor-grok-4.5-high, MED/LOWcomposer-2.5.Perspectives:
test-coverage-robustness,docs-site-contracts,dx-and-examples,docs-and-positioning,release-discipline.Prior open threads (19): 16 fully_addressed, 3 partially_addressed (related soft-drop after
expectRecords— collections now throw; nestedrelatedstill quiet).Chunk-bound feedback (judge)
- MED
apps/docs/lib/content.tsrelatedflatMap— drops bad related rows → empty chips, no throw. Assert keep/drop (or fail loud) incontent.test.ts.- MED
content.test.ts— add happygetDoc, related keep/drop, missing Doc/Package →undefined, whitespacerequireText.- MED parity/export/links/sanitize/remark-blob edge tests still thin (see inlines).
- LOW graphql non-JSON body; CONTRIBUTING
docs:checkundersells package-build prereq; localverifyomitsNEXT_PUBLIC_BASE_PATH=/flatbread.Coverage plan
getDochappy + related keep/drop + undefined + whitespacerequireTextcollectParityProblemsmocked disk↔graph match/misscheck-exporttop-level[]search indexcheck-linksdangling / wrong-target reference symlink- markdown sanitize negative unsafe attr
- remark-repo-links encoded
../ bad%decode- Optional: graphql non-JSON; ATX
#stripReviewer scoreboard
Reviewer Verdict Signal test-coverage-robustness REQUEST_CHANGES HIGH (over-rated related) docs-site-contracts APPROVE HIGH release-discipline APPROVE MED dx-and-examples APPROVE LOW docs-and-positioning APPROVE LOW Disputed: related soft-drop HIGH vs LOW → judge MED (does not ship a wrong primary page;
check-linksalready gates bad related IDs).Sent by Cursor Automation: Flatbread PR Review
Change-Id: I6bad4ec806558bdd9e1c3a35436f519462789f52
There was a problem hiding this comment.
Stale comment
Review verdict
COMMENT — Prior f10ec27 residuals (related soft-drop, thin getters, parity/export/links/sanitize/remark
..) are closed in the 9097b87 delta. No BLOCKER and no HIGH remain. Residual MED/LOW items are coverage and release/DX gaps around dualbasePath(/vs/flatbread), untestedbuild-docs-base-pathexit/env, empty-basePathexport checks, undocumented non-sharpoverrides, and Unreleased docs-site silence. Non-test sources changed with a non-empty coverage plan → COMMENT (not REQUEST_CHANGES: gaps are missing tests/docs, not a broken shipped contract).Chunk-bound feedback
scripts/build-docs-base-path.mjs:1-17 — MED (test-coverage-robustness, docs-site-contracts) —
verifyruns the/flatbreadrebuild, but nothing asserts env/exit;docs:buildstill ships only the root export.package.json:32-38 — MED (docs-site-contracts) —
docs:buildstops at unprefixed HTML; Pages proof is CI/verifyonly unless documented or chained.apps/docs/scripts/check-export.test.mjs:1-213 — MED (docs-site-contracts) — every
withExporthardcodesbasePath: '/flatbread'; empty-basePathbranch untested.package.json:98-105 — MED (release-discipline) —
sharpBLOCKER closed; four other overrides still undocumented.CHANGELOG.md:6-14 — MED (release-discipline) — Unreleased omits
apps/docs, Pages deploy, and content move.LOW: CI
/flatbread-only vsverifydual build; related whitespace/nulltests; parity success-path non-JSON;next.config.tsbasePath normalize.Coverage plan
- MED —
scripts/build-docs-base-path.test.js— mockspawnSync; assertNEXT_PUBLIC_BASE_PATH: '/flatbread'; error/status → exitCode.- MED —
check-export.test.mjs—basePath: ''happy + missing-file negative.- LOW —
content.test.ts— whitespace/nullrelated; empty[]stays[].- LOW —
check-content-parity.test.mjs— success non-JSON /{ data: null }.- LOW —
remark-repo-links.test.mjs— literal/../blob segment.- LOW —
check-linksrelatedtypeof entry === 'string'.Reviewer scoreboard
- test-coverage-robustness: 3 findings, 4 coverage gaps, signal:HIGH
- docs-site-contracts: 3 findings, 3 coverage gaps, signal:HIGH
- dx-and-examples: 4 findings, 3 coverage gaps, signal:LOW
- docs-and-positioning: 4 findings, 2 coverage gaps, signal:LOW
- release-discipline: 4 findings, 4 coverage gaps, signal:MED
Oven missing → Task fallback. Models:
cursor-grok-4.5-high/composer-2.5. Not dependency-only (119 non-dep / 203 chunks).Sent by Cursor Automation: Flatbread PR Review
Change-Id: I58f015603e4d4a5f5cab64d1c897e926d98e3967
Change-Id: I489b8eb57e8e15fb8ce061ee9e4aff16d15b690c # Conflicts: # CHANGELOG.md
There was a problem hiding this comment.
Stale comment
Review verdict
COMMENT — Prior
9097b87MED residuals are closed on900a3b8. No blockers or HIGHs. Consensus MED remains on the publicrehype-sanitizewiden in@flatbread/transformer-markdown(no Unreleased Runtime note, no package-local allow/deny tests). Several single-perspective MEDs and a non-empty coverage plan on non-test source keep this above APPROVE without REQUEST_CHANGES.Closed vs last sync:
build-docs-base-pathtests +docs:build/verify/CI dual-path; empty-basePathexport; non-sharp overrides documented; Unreleased apps/docs/Pages; related whitespace/null readers; parity non-JSON success; next-config normalize.Not dependency-only (122 non-dep paths / 206 chunks). Oven missing → Task fallback. Models:
cursor-grok-4.5-high/composer-2.5. Perspectives: test-coverage-robustness, docs-site-contracts, correctness-and-contracts, docs-and-positioning, release-discipline.Chunk-bound feedback (priority)
- MED
packages/transformer-markdown/.../markdown.ts:22-34— silent public HTML allowlist widen (language-*,dataTitle) without Unreleased Runtime note or package-local tests.- MED
apps/docs/app/page.tsx— homePACKAGE_GROUPScan drop ungrouped packages (Sidebar has Other; home does not).- MED
apps/docs/scripts/check-links.mjs—related ?? []makesrelated: nullskip “must be a list”.- MED (coverage) remark blob rewrite with
basePath=/flatbread; GraphQLforce-cache/no-store; export blank search fields.- LOW
runDocsBuild --rootargv; parity whitespace ids; CONTRIBUTING Pages URL.Coverage plan
- Package-local sanitize allow/deny (+ edge
language-c++/c#)related: nullrejection; optionalcontent/notes/**link scan- remark blob+
basePath; graphql cache byNODE_ENV; export blank fields;--rootdispatchSuggested follow-ups
R100 renames left stale relatives in
apps/docs/content/notes/experiments/issue-167|168-*.md(0-addition renames — not inline-able). Extendcheck-linksto notes so moves cannot leave broken../pmf-decision-rubric.md.Reviewer scoreboard
- docs-site-contracts: high signal
- correctness-and-contracts: high signal
- test-coverage-robustness: high signal
- docs-and-positioning: medium (R100 note links)
- release-discipline: medium (APPROVE on release lens)
Canvas
Open Canvas —
/home/ubuntu/.cursor/projects/workspace/canvases/dag-review-900a3b8.canvas.tsx
Judge:/tmp/review-judge-final.mdSent by Cursor Automation: Flatbread PR Review
Change-Id: I5a506e1e5992f3536112d1a1e79454a20f7c9426
There was a problem hiding this comment.
Stale comment
Review verdict
COMMENT — No blockers on sync
c22cdf08(base76d1edb). Prior COMMENT MEDs from900a3b8look closed (package-groups “Other”, related nulls, force-cache/export/remark/basePath coverage, markdown package tests, Unreleased apps/docs/Pages). Remaining items are coverage increments on already-locked contracts, so lone coverage HIGHs were downgraded to MED under anti-pedantry (notREQUEST_CHANGES). Non-empty coverage plan + non-test source edits keep the floor at COMMENT.Not dependency-only (129 non-lock paths / 225 chunks excl. lockfile).
Coverage plan (priority)
- MED —
markdown.test.ts: fencedts/tsx(and hyphenated lang) keeplanguage-*(today only raw HTML keep is locked).- MED —
check-links.test.mjs: notes positive resolve +checkSiteRewrite: falseskips ambiguity.- MED —
check-export.test.mjs: blankid/kind/group; non-root-relativehrefnegatives.- MED —
graphql.test.ts: happy-path query returns data (cache policy already locked).- LOW — Document sanitize allowlist;
package-groupsempty/Content cases; changelogjs-yamlbump; optional notes R100 plain-path pass.Consensus
- Sanitize allowlist change is intentional, tested, and CHANGELOG’d — no silent contract break.
- Docs-site runtime contracts (expectRecords, groupPackages, remark containment, once/force-cache) look sound.
Reviewer scoreboard
test-coverage-robustness: 6 findings, 7 gaps, signal:HIGHdocs-site-contracts: 2 findings, 4 gaps, signal:MEDcorrectness-and-contracts: 0 findings, 2 gaps, signal:MEDdocs-and-positioning: 4 findings, 0 gaps, signal:LOWrelease-discipline: 3 findings, 2 gaps, signal:LOWModels:
cursor-grok-4.5-high(HIGH) /composer-2.5(MED/LOW). Oven missing → Task fallback. 0 unresolved prior threads.Sent by Cursor Automation: Flatbread PR Review
Change-Id: I16a7235f3b8afa7c169303fe9a388aaf8ca038b4
There was a problem hiding this comment.
Stale comment
Review verdict
APPROVE — five perspectives approve at
9fbcee8. Prior COMMENT residual (MED coverage afterc22cdf08) is closed by behavior asserts. No BLOCKER, no consensus HIGH, no two independent HIGHs.Not dependency-only (125 non-dep paths / 229 chunks excl. lockfile). Delta since last sync is test/README/CHANGELOG closes for the remaining coverage plan.
Chunk-bound feedback
apps/docs/lib/graphql.test.ts:66(MED)
setTimeout(2)before stamp reload can flake whenDate.nowdoes not advance. StubDate.now(or inject a clock) so the reload stamp advances without sleep.Coverage plan
(empty) — prior MED gaps closed (fenced
language-*, notescheckSiteRewrite:false, export blank/href negatives, GraphQL happy-path, package-groups empty/Content).Follow-ups (non-blocking)
- Stub
Date.nowin the GraphQL stamp-reload test.- Optional:
related: null→[]incontent.test.ts; onegetSectionsunder theonce()suite.- Notes hygiene: stale
docs/experiments/…path literals in issue-167 fenced config and issue-169 R100 prose (check-links does not catch non-link strings).- Optional: CHANGELOG sharp bullet vs lockfile
next>sharp/svimg>sharpwording.Reviewer scoreboard
- correctness-and-contracts: 0 findings, 3 coverage gaps, signal:MED
- test-coverage-robustness: 1 findings, 1 coverage gaps, signal:MED
- docs-site-contracts: 0 findings, 3 coverage gaps, signal:LOW
- docs-and-positioning: 2 findings (1 pedantry dropped), 2 coverage gaps, signal:MED
- release-discipline: 0 findings, 1 coverage gaps, signal:LOW
Oven missing → Task fallback. Models:
cursor-grok-4.5-high/composer-2.5. Judge:/tmp/review-judge-final.md.Sent by Cursor Automation: Flatbread PR Review
Change-Id: I13c67bda539ed6fe451d10ecd15c2821182aa406
There was a problem hiding this comment.
Stale comment
Review verdict
COMMENT — Prior APPROVE at
9fbcee8still holds on shipped contracts. Thefa71c71delta closedrelated: null→[],getSectionsproductiononce()coverage, note path literals, and the GraphQL stamp flake (Date.nowstub). No BLOCKER or HIGH remains.Non-empty coverage gaps on non-test sources keep this at COMMENT (edge/negative hardening), not REQUEST_CHANGES.
Not dependency-only (129 non-lock paths / 232 chunks). Oven missing → Task fallback. Models:
cursor-grok-4.5-high(HIGH),composer-2.5(MED/LOW).Perspectives: correctness-and-contracts, test-coverage-robustness, docs-site-contracts, docs-and-positioning, release-discipline.
Coverage plan (priority)
content.test.ts—allDocs/allSections/allPackages: null→ sameexpectRecordsthrow as[]content.test.ts—getSearchEntriesempty/nullallDocswith valid packagescontent.test.ts— empty-collection error includesCONTENT_DIRS+flatbread starthintcontent.test.ts— productiononce()sticky rejected promisegraphql.test.ts— customFLATBREAD_GRAPHQL_ENDPOINTon URL + 503 textcheck-export.test.mjs— searchhrefto non-HTML targetmarkdown.test.ts— one defaultSchema-kept non-codeattr through sanitizeFollow-ups (out of diff / soft)
- Effort-modeling skill glossary still cites
docs/glossary.md(not in this PR’s file list)- Optional: Node 20.x on
docs-siteCI job, or document Pages export as 22-only- CHANGELOG sharp removal wording should mirror both
svimgandnext>sharpReviewer scoreboard
- correctness-and-contracts: 0 findings, 4 coverage gaps, signal:HIGH
- docs-site-contracts: 0 findings, 6 coverage gaps, signal:HIGH
- test-coverage-robustness: 7 findings, 7 coverage gaps, signal:HIGH
- release-discipline: 6 findings, 3 coverage gaps, signal:MED
- docs-and-positioning: 3 in-diff findings, 3 coverage gaps, signal:MED
Sent by Cursor Automation: Flatbread PR Review
Change-Id: I35d49ac921be82bd0b38de43d5bf3491a5427401
There was a problem hiding this comment.
Stale comment
Review verdict
COMMENT — no blockers or consensus HIGHs. Sync
9a893bccloses the fa71c71 COMMENT residuals (home path labels,CONTENT_DIRSmessaging, GraphQL custom origin, check-export non-HTMLhref, Node 20/22docs-sitematrix, sharp CHANGELOG wording, glossary path). Remaining signal is MED coverage hardening, not a merge-blocking contract break.Not dependency-only (131 non-lock files / 234 chunks excl. lockfile). Oven unavailable → Task fallback. Models:
cursor-grok-4.5-high(HIGH) /composer-2.5(MED/LOW).Chunk-bound feedback (summary)
- MED (consensus):
transformer-markdownsanitize keep-attrs tested; dangerous URL/handler/script/data-*strip negatives still thin.- MED: docs
contentmissing-section / blank_content.raw/related ?? []asymmetry vs check-links; Shiki unknown-lang / empty-fence untested.- MED (single): load-bearing
content/referencesymlinks until core watch vs initial-load capture is fixed — do not swap topackages/[id]/README.md.- MED (publish follow-up only): Unreleased documents markdown sanitize without a package version bump — Pages merge is fine; bump if publishing
@flatbread/*from this train. Proof/filesystem Unreleased bullets have no matchingpackages/*/srcin this diff — not merge blockers.Coverage plan
packages/transformer-markdown/src/processors/markdown.test.ts— negative:javascript:href,onclick/onerror,<script>, non-dataTitledata-*stripped.apps/docs/lib/content.test.ts— negative: null/missingDoc.section; null/blank_content.raw; optionalallDocs:[null].apps/docs/plugins/markdown-pipeline.test.ts— edge: unknown language fallback; empty fence no-throw/skip.- Optional: malformed GraphQL endpoint; unicode export path; live
--watchrefresh (document if deferred).Reviewer scoreboard
Perspective Findings posture Signal correctness-and-contracts APPROVE HIGH test-coverage-robustness COMMENT HIGH docs-site-contracts COMMENT MED-HIGH docs-and-positioning APPROVE MED release-discipline COMMENT HIGH Prior automation threads were already resolved; this assessment replaces the previous visible review via cleanup.
Sent by Cursor Automation: Flatbread PR Review
Change-Id: I4bdc45c9040432a870911ad064bc6d55e7befb54
There was a problem hiding this comment.
Stale comment
Review verdict
COMMENT — No blockers or consensus HIGHs. Delta since
9a893bc(b6f0249) closes prior residuals (sanitize strip negatives, content missingsection/raw, Shiki unknown-lang / empty fence). Remaining items are publish lockstep, docs discoverability, symlink ops debt, and narrow coverage gaps — follow-ups, not merge blocks for this docs PR.Not dependency-only (131 non-lock paths / 234 chunks). Oven missing → Task fallback. Models:
cursor-grok-4.5-high(HIGH),composer-2.5(MED/LOW).Perspectives:
correctness-and-contracts,test-coverage-robustness,docs-site-contracts,docs-and-positioning,release-discipline.Consensus (MED)
- Sanitize allowlist without package bump —
@flatbread/transformer-markdownHTML contract changed at1.0.1; bump before any npm publish (publish:ciwould otherwise skip).- Package-page symlink / Windows clone debt — honest Flatbread path/watch workaround; ops residual.
- SearchDialog client paths untested — fetch failure / abort / keyboard can regress without failing CI.
Coverage plan (priority)
- MED —
content.test.ts: presentsectionwith null/blanktitle; missingsection.idonallDocs- MED —
SearchDialog: fetch non-OK / abort + keyboard- MED — Pre-publish: Unreleased ↔ version bump when package
srcchanged- LOW —
CodeCopyclipboard reject; README → published docs URL; Proof motion constraint rewriteReviewer scoreboard
- correctness-and-contracts: 1 findings, 3 coverage gaps, signal:MED
- test-coverage-robustness: 3 findings, 5 coverage gaps, signal:MED
- docs-site-contracts: 1 findings, 3 coverage gaps, signal:MED
- docs-and-positioning: 2 findings, 2 coverage gaps, signal:MED
- release-discipline: 5 findings, 2 coverage gaps, signal:MED
Canvas
Open Canvas —
dag-review-b6f0249.canvas.tsx(judge also at/tmp/review-judge-final.md)Sent by Cursor Automation: Flatbread PR Review
Change-Id: Idc8ba08b9f47fcbbcaae7fa57ed60b4d0161140b
There was a problem hiding this comment.
Stale comment
Review verdict: COMMENT
Sync review of
76d1edb...45e7c9bontoeknee/docs-site-ascii-c1d8. Not dependency-only (127 non-dep paths / 235 chunks excl. lockfile).Delta
45e7c9bclosed prior residuals: SearchDialog fetch/abort/keys, content section title/id edges, published docs URL, Proof Motion/SplitText ban. Oven CLI unavailable → Task fallback (HIGH:cursor-grok-4.5-high, MED/LOW:composer-2.5). Perspectives: correctness-and-contracts, test-coverage-robustness, docs-site-contracts, docs-and-positioning, release-discipline.Why COMMENT (not APPROVE)
Coverage plan is non-empty and non-test source changed. Consensus MED remains a publish follow-up, not a merge blocker:
@flatbread/transformer-markdownsanitize allowlist (language-[A-Za-z0-9_-]+,data-title) is in-tree at1.0.1without a package bump — npmlatestwill lag until the next release train.Chunk-bound feedback (merged)
- MED
packages/transformer-markdown/src/processors/markdown.ts:22-34(+ wiring:7-10, apply:84) — publish@flatbread/transformer-markdownon the next train so npm matches CHANGELOG/README. No bump required to merge.- LOW
markdown.test.ts— add dotted-id negative + emptylanguage-edge (optional raw-HTML vs fence).- LOW
pipeline.ymldeploy-docs — enable GitHub Pages before treating Pages URLs as live.- LOW
CHANGELOG.mdUnreleasedtransformer-yaml/js-yaml— publish follow-up when the train bumps (nosrcin this PR).Coverage plan
markdown.test.ts— dotted id / empty suffix / optional raw vs fenceSearchDialog.test.tsx—NEXT_PUBLIC_BASE_PATHfetch URL; reopen-after-abort refetchcontent.test.ts— one successful guideSearchEntryshapeCodeCopy.tsx— copy success / reject / empty code (fake timers)check-links.test.mjs— guide with no---fenceReviewer scoreboard
- correctness-and-contracts: 2 findings, 3 gaps, signal:MED
- test-coverage-robustness: 0 findings, 5 gaps, signal:MED
- docs-site-contracts: 0 findings, 2 gaps, signal:MED
- docs-and-positioning: 0 findings, 0 gaps, signal:MED
- release-discipline: 3 findings, 0 gaps, signal:HIGH
Disputed findings: none. Prior automation threads were already resolved; this post replaces the visible assessment.
Sent by Cursor Automation: Flatbread PR Review
Change-Id: Id16d8bed1ee2d09f94c39243500de212c04eed82
Change-Id: I4141aa4b1836ce03f430ef372e1e014f1493040e
There was a problem hiding this comment.
Stale comment
Review verdict
COMMENT — No BLOCKERs or consensus HIGHs. Open work is MED publish stickiness (sanitize / yaml without bumps), MED contract softness (
related ?? [], SearchDialogbasePathfetch unproven), and prior LOW coverage gaps. Coverage plan is non-empty on non-test source → COMMENT (prior LOWs alone do not escalate to REQUEST_CHANGES).Range:
76d1edb...d2af1ec(not dependency-only: 127 non-dep / 235 chunks). Delta since45e7c9b: Sidebar Motion comment cleanup +jsdom@16.7.0for SearchDialog tests — no new blockers.Oven unavailable (
@flatbread/oven404) → Task-tool fallback. Models:cursor-grok-4.5-high(HIGH),composer-2.5(MED/LOW). Perspectives: correctness-and-contracts, test-coverage-robustness, docs-site-contracts, docs-and-positioning, release-discipline.Coverage plan
- MED
SearchDialog.test.tsx—NEXT_PUBLIC_BASE_PATHfetch; reopen after failed load; non-JSON- MED
content.test.ts/ related path — frontmatterrelated:must not silently coerce GraphQL null →[]- LOW
markdown.test.ts— empty/dotted language; restrictive regex still wins on duplicateclassName- LOW CodeCopy (+ vitest include) — clipboard success/fail with fake timers
- LOW
check-links.test.mjs— no-fence / unclosed frontmatterConsensus
Sanitize allowlist + fragile
classNamemerge; publish bumps for transformer-markdown/yaml (follow-up only); SearchDialog basePath under-tested; Pages bootstrap discoverability (LOW).Suggested follow-ups
Bump
@flatbread/transformer-markdownand@flatbread/transformer-yamlbefore registry publish; maintainer note to enable Pages (GitHub Actions) before firstdeploy-docs; optionaljsdomupgrade.Disputed: coverage asked REQUEST_CHANGES on prior LOWs — judge keeps COMMENT. yaml CHANGELOG lag thread marked partially addressed (notes aligned; bump still open).
Sent by Cursor Automation: Flatbread PR Review
There was a problem hiding this comment.
Stale comment
Review verdict
COMMENT — No blockers. Disputed docs-site claims that Next nests export files under
out/flatbread/do not driveREQUEST_CHANGES(judge overrules; Next keeps artifacts atout/root; Pages serves that tree at URL/flatbread;check-exportstrip/FS design matches). Consensus MED remains a publish follow-up:@flatbread/transformer-markdownsanitize/language-*allowlist change without apackage.jsonversion bump. Non-empty coverage plan + non-test source → COMMENT (edge gaps, not merge-blocking contracts).Range:
76d1edb...82d7d98. Delta since prior sync (45e7c9b) closed CodeCopy clipboard, SearchDialog basePath/reopen, and markdown dotted-language LOWs.Chunk-bound feedback (actionable)
- MED
packages/transformer-markdown/src/processors/markdown.ts:22-34— bump@flatbread/transformer-markdownon the Unreleased publish train (correctness + release consensus).- LOW
apps/docs/lib/content.ts/content.test.ts— assert one successfulSearchEntryshape (guide + package).- LOW
apps/docs/scripts/check-links— no-fence frontmatter →{}/ missing-key messages.- LOW Pages README URLs 404 until first
deploy-docs; codegen README still documents standalonecodegen --watch.Disputed
check-exportHIGH findings are recorded in the judge write-up and overruled — no code change required for merge.Coverage plan
apps/docs/lib/content.test.ts— positive successfulSearchEntryfor guide + package.apps/docs/scripts/check-links.test.mjs— edge:no-fence frontmatter.- Soft: digit/
_language ids in markdown.test; optional realdocs:build:base-pathout-layout smoke.Reviewer scoreboard
- correctness-and-contracts: 2 findings, 2 gaps, signal:MED
- test-coverage-robustness: 4 findings, 2 gaps, signal:LOW
- docs-site-contracts: 6 findings (HIGH overruled), signal:HIGH→discounted
- docs-and-positioning: 4 findings, 0 gaps, signal:LOW
- release-discipline: 3 findings, 0 gaps, signal:MED
Oven missing → Task-tool fallback. Models:
cursor-grok-4.5-high/composer-2.5. Judge:/tmp/review-judge-final.md.Sent by Cursor Automation: Flatbread PR Review
Change-Id: I3379572cf1b4dc3a06733578721e70370eed1331
There was a problem hiding this comment.
Stale comment
Review verdict
COMMENT — No BLOCKER. One solo HIGH (Sidebar component tests) does not meet the consensus-HIGH / two-HIGH bar. Coverage gaps remain on non-test sources, so this stays COMMENT rather than APPROVE. Publish-time
@flatbread/transformer-markdownsemver (HTML allowlist still at1.0.1) is a follow-up, not a merge block for this docs-site PR.Sync
46a6c5bclosed the named prior residuals (SearchDialog non-JSON, SearchEntry shape, check-links bare frontmatter, Pages admin steps, codegen watch note, sanitizecodeREPLACE). Canonical Pages layout staysout/root + URL/flatbread— nesting-under-out/flatbread/claims stay overruled.Coverage plan (remaining)
- Sidebar:
aria-current/ trailing-slash inactive / empty section dropsearch.ts: dual-term AND success + score order; one-letter token drop- SearchDialog:
/and ⌘K open; focus return; non-array success JSONcheck-content-parity:ok: truewith errors; absent collection key- CodeCopy: clipboard undefined; remount without duplicate
.fb-copy- Shared
normalizeBasePathfixture for malformed//across next.config / remark / check-export- Sanitize lock:
*attrs besidelanguage-*+data-title(optional docs HTML E2E)Consensus
- Five perspectives → COMMENT; Pages path contract holds
- transformer-markdown public HTML change without version bump = publish hazard, not merge block
46a6c5bclosures standSuggested follow-ups
Bump
@flatbread/transformer-markdownbefore npm publish (do not reuse1.0.1). Align home hero with positioning (or document the split). Demote standalonecodegen --watchbehind unified-loop. Unify basePath normalize. Fill Sidebar/search/SearchDialog/parity/CodeCopy gaps.Perspectives
correctness-and-contracts,test-coverage-robustness(HIGH / Grok 4.5),docs-site-contracts,docs-and-positioning,release-discipline(MED/LOW / Composer 2.5). Oven unavailable → Task fallback.Sent by Cursor Automation: Flatbread PR Review
Change-Id: Ia3f9bcdae5fc967f97ac1015c6a99b555026bc42
There was a problem hiding this comment.
Stale comment
Review verdict
COMMENT — No blockers or consensus HIGH at
561a3e0. SharednormalizeBasePathcloses the Pages/out/desync hold. Remaining consensus issues are MED publish follow-up for@flatbread/transformer-markdownsanitize without a version bump, andSearchDialogstill reading rawNEXT_PUBLIC_BASE_PATH. Coverage gaps on non-test source keep this at COMMENT, not APPROVE.Delta
46a6c5b…561a3e0(fix(docs): close final production gaps) closed prior residuals: Sidebar component tests, SearchDialog non-JSON guard, CodeCopy/parity/export/basePath share, Proof-first hero rewrite. HOLD honored: do not elevateout/nesting vs/flatbreadURL.Chunk-bound feedback
See inline comments (severity order). Full judge text also covers Toc observer, related null residual, core README Pages link, and Pages ops follow-up.
Coverage plan
SearchDialog:NEXT_PUBLIC_BASE_PATH'/'and'/flatbread/'without relying on next.config rewriteSearchDialog: reject/loadError on incomplete search entry fields;/while focus is in another INPUT/TEXTAREAToc.tsx: IntersectionObserver →aria-current="location"CodeCopy.tsx: two<pre>blocks each get one.fb-copyReviewer scoreboard
- correctness-and-contracts: 2 findings, signal:HIGH
- test-coverage-robustness: 3 findings, signal:HIGH (APPROVE upstream)
- docs-site-contracts: 2 findings, signal:HIGH
- docs-and-positioning: 2 findings, signal:MED
- release-discipline: 2 findings, signal:MED
Perspectives: correctness-and-contracts, test-coverage-robustness, docs-site-contracts, docs-and-positioning, release-discipline. Oven missing → Task fallback; models
cursor-grok-4.5-high/composer-2.5.Sent by Cursor Automation: Flatbread PR Review
Change-Id: Ifbadcc7f2547f3ff9526c6ce6b00d49448bec533
There was a problem hiding this comment.
Stale comment
Review verdict
COMMENT at
b92c10a(merge-base76d1edb). Not dependency-only. No BLOCKER and no consensus HIGH.Sync
fix(docs): harden search and navigationcloses the prior SearchDialog raw-NEXT_PUBLIC_BASE_PATHresidual (normalizeBasePath), addsisSearchEntries, lands Toc/CodeCopy tests, aligns the hero lede with “typed relational graph”, and pointspackages/coreat the published Pages URL.Residual MEDs are publish-train / ops follow-ups, not merge blockers:
@flatbread/transformer-markdownsanitize allowlist still at published1.0.1@flatbread/transformer-yamljs-yamlfloor without a package bump- One-time GitHub Pages admin enable (already documented in CONTRIBUTING)
Hold stands: static export with
basePathkeeps files atout/root — do not elevate nesting claims.Coverage plan
Toc— empty list, missing headings, observer disconnect on unmountSearchDialog— mixed invalid array members / empty-string fields after the shape guardCodeCopy— overlapping timer / rapid re-click across blocksReviewer scoreboard
Perspective Findings Signal correctness-and-contracts 1 MED (publish follow-up) HIGH test-coverage-robustness coverage follow-ups only MED docs-site-contracts APPROVE HIGH docs-and-positioning LOWs dropped as pedantry LOW release-discipline 2 MED follow-ups HIGH Models: High = Cursor Grok 4.5 High; Med/Low = Composer 2.5. Oven unavailable → Task fallback.
Sent by Cursor Automation: Flatbread PR Review
Change-Id: I86dee0d7f64afd05b85a0bf8c2eb19294117e023
There was a problem hiding this comment.
Stale comment
Review verdict
COMMENT — No BLOCKER or consensus HIGH. Coverage plan is non-empty while non-test source changed under
apps/docsandpackages/transformer-markdown; ThemeToggle/NavDisclosure gaps are not documented contracts (rule: coverage plan + non-test source → COMMENT).Closed at
6c44eabSearchDialog blank-string validation now matches
check-exportrequired fields. PriornormalizeBasePathgap stays closed.out/root vs/flatbreadURL layout still holds — do not re-raise nesting.Publish follow-ups (MED, not merge blockers)
- Bump
@flatbread/transformer-markdownbefore npm publish (sanitize keeplanguage-*/data-title; CHANGELOG Unreleased already notes it).- Bump
@flatbread/transformer-yamlfor thejs-yaml^4.3.1floor (CHANGELOG already notes it).Coverage plan (COMMENT-level)
- ThemeToggle — toggle +
localStoragethrow- NavDisclosure — narrow/wide
matchMedia, pathname close,#main-contentfocus- CodeCopy missing
scopeearly-return- Heading slug Unicode / empty-after-strip
- Sanitize non-ASCII
language-…+ docs-pipelinec++/c#fallback- SearchDialog edges — whitespace-only optional fields; non-object array entries
Suggested follow-ups
- Enable GitHub Pages admin so published README docs links resolve (ops).
- Soften GraphQL-first satellite README ledes (
@flatbread/core, etc.) — positioning, not a contract break.Reviewer scoreboard
Perspective Signal correctness-and-contracts COMMENT — 2 MED publish follow-ups test-coverage-robustness COMMENT — chrome/Unicode gaps docs-site-contracts APPROVE — no contract breaks docs-and-positioning APPROVE — minor README follow-ups release-discipline APPROVE — Unreleased defer correct Perspectives: correctness, test-coverage, docs-site-contracts, docs-and-positioning, release-discipline. Models: High=
cursor-grok-4.5-high, Med/Low=composer-2.5(Oven unavailable; Task fallback).Sent by Cursor Automation: Flatbread PR Review
| /** Keep harmless fenced-code metadata for syntax highlighters after sanitize. */ | ||
| const sanitizeSchema: SanitizeOptions = { | ||
| ...defaultSchema, | ||
| attributes: { | ||
| ...defaultSchema.attributes, | ||
| code: [['className', /^language-[A-Za-z0-9_-]+$/], 'dataTitle'], | ||
| }, | ||
| }; | ||
|
|
There was a problem hiding this comment.
MED (consensus — publish follow-up) — rehype-sanitize now keeps filtered language-* / data-title on <code> while @flatbread/transformer-markdown stays at 1.0.1. CHANGELOG Unreleased already documents the behavior.
Minimal fix: At publish cut, bump the package with pnpm bump and ship the Unreleased note. Do not pre-bump in this PR. Not a merge blocker.
| "dependencies": { | ||
| "@sindresorhus/slugify": "^2.2.1", | ||
| "js-yaml": "^4.1.0" | ||
| "js-yaml": "^4.3.1" |
There was a problem hiding this comment.
MED (consensus — publish follow-up) — js-yaml floor moves ^4.1.0 → ^4.3.1 with no package version bump and no src change. Root CHANGELOG already records the dependency move.
Minimal fix: Bump @flatbread/transformer-yaml at publish cut. Leave Unreleased as-is for merge.
| 'use client'; | ||
|
|
||
| import { useEffect, useState } from 'react'; | ||
|
|
||
| type Theme = 'light' | 'dark'; | ||
|
|
||
| export const THEME_KEY = 'flatbread-docs-theme'; | ||
|
|
||
| /** | ||
| * Runs before the first paint so the page never flashes the wrong colours. | ||
| * Kept as a string because it has to be inlined in the document head. | ||
| */ | ||
| export const themeScript = ` | ||
| (function () { | ||
| try { | ||
| var stored = localStorage.getItem('${THEME_KEY}'); | ||
| var dark = stored ? stored === 'dark' | ||
| : window.matchMedia('(prefers-color-scheme: dark)').matches; | ||
| document.documentElement.dataset.theme = dark ? 'dark' : 'light'; | ||
| } catch (error) {} | ||
| })(); | ||
| `; | ||
|
|
||
| export function ThemeToggle() { | ||
| const [theme, setTheme] = useState<Theme>('light'); | ||
|
|
||
| useEffect(() => { | ||
| const current = document.documentElement.dataset.theme; | ||
| setTheme(current === 'dark' ? 'dark' : 'light'); | ||
| }, []); | ||
|
|
||
| const flip = () => { | ||
| const next: Theme = theme === 'dark' ? 'light' : 'dark'; | ||
| document.documentElement.dataset.theme = next; | ||
| try { | ||
| localStorage.setItem(THEME_KEY, next); | ||
| } catch { | ||
| // A browser that refuses storage still gets the change for this visit. | ||
| } | ||
| setTheme(next); |
There was a problem hiding this comment.
LOW (coverage) — Flip, localStorage throw, and themeScript / prefers-color-scheme paths have no unit tests.
Minimal fix: Add tests for light↔dark toggle and localStorage.setItem throw still updating the DOM. COMMENT-level only — not a documented contract.
| 'use client'; | ||
|
|
||
| import { usePathname } from 'next/navigation'; | ||
| import { useEffect, useRef, useState } from 'react'; | ||
| import type { ReactNode } from 'react'; | ||
|
|
||
| const WIDE = '(min-width: 901px)'; | ||
|
|
||
| /** | ||
| * Fold the navigation away on a narrow screen. | ||
| * | ||
| * On a wide screen the tree is always open and the toggle is hidden. On a | ||
| * phone the tree would otherwise push the page eighteen links down, so it | ||
| * starts closed. | ||
| * | ||
| * The open state is driven by a media query rather than by CSS alone, because | ||
| * the reliable way to force a `<details>` open across browsers is still the | ||
| * `open` attribute. | ||
| */ | ||
| export function NavDisclosure({ | ||
| label, | ||
| children, | ||
| }: { | ||
| label: string; | ||
| children: ReactNode; | ||
| }) { | ||
| const pathname = usePathname(); | ||
| const previousPath = useRef(pathname); | ||
| const [wide, setWide] = useState(false); | ||
| const [open, setOpen] = useState(false); | ||
|
|
||
| useEffect(() => { | ||
| const query = window.matchMedia(WIDE); | ||
| const sync = () => setWide(query.matches); | ||
| sync(); | ||
| query.addEventListener('change', sync); | ||
| return () => query.removeEventListener('change', sync); | ||
| }, []); | ||
|
|
||
| useEffect(() => { |
There was a problem hiding this comment.
LOW (coverage) — Wide/narrow matchMedia, pathname close, and #main-content focus are untested.
Minimal fix: Narrow starts closed; wide forces open; pathname change closes and focuses #main-content. COMMENT-level only.
Change-Id: Id6427c1349a7e1866ce03d64ebccc688e9db3678
Change-Id: Ie846fdd55fd9740ae16fbdab1a9883ca17d36cd9
There was a problem hiding this comment.
Stale comment
Review verdict
COMMENT — No BLOCKER and no consensus HIGH. Delta
6c44eab → f3911c2closes the prior ThemeToggle / NavDisclosure coverage plan with behavior tests. Residual merge bar is coverage:REFERENCE_ACTIONS[].nextAction.hrefis still shape-checked only while the reference page renders those hashes as live in-page links. Anchors resolve at HEAD today; the miss is regression detection, not a broken contract. Prior sanitize allowlist +js-yamlfloor are closed at package level; coordinated lockstep publish remains a MED follow-up only. Hold: do not re-elevate intentional GitHub Pagesout/-root /basePathlayout.Sync:
76d1edb...f3911c2(prior sync6c44eab). Oven CLI missing → Task-tool fallback (cursor-grok-4.5-highHIGH;composer-2.5MED/LOW).Consensus
- MED — nextAction href ↔ heading id (
test-coverage-robustness+docs-site-contracts): shape/regex is not enough once hashes render live.- ThemeToggle / NavDisclosure prior plan largely closed (residual LOW edges only).
- Sanitize +
js-yamlclosed in-tree; publish bump is follow-up, not a docs-site merge bar.- basePath / static export / search contracts sound (
docs:build:base-path+check-export).Coverage plan
- MED —
apps/docs/lib/reference-actions.test.ts: For each published package id, slugify h2/h3 fromcontent/reference/<id>.mdwithrehype-heading-anchorsrules; assertnextAction.href.slice(1)is in that set; add negative#missing-section. (Alternate: one check incheck-export.mjsagainst exported HTML — pick one home.)- LOW —
NavDisclosure.test.tsx: Wide media + pathname change stays open / no#main-contentfocus; missing#main-contentdoes not throw.- LOW —
ThemeToggle.test.tsx: Garbage stored theme +getItemthrow forthemeScript.- LOW —
markdown.test.ts: Post-sanitize HAST still exposeslanguage-tsto a customrehypePluginscallback; optional non-ASCII fence negatives.Suggested follow-ups
- Coordinated lockstep bump so sanitize behavior +
js-yaml@^4.3.1reach npm.- Confirm Proof-first docs hero / positioning order with stakeholders (solo; not a merge bar).
- Scrub or land Proof
srcbefore publishing anyPROOF_CROSS_EFFORT_RELATIONUnreleased notes.- Optional: Windows symlink steps in CONTRIBUTING;
pnpm docs:*on root README; GraphQL-default README one-liners.Reviewer scoreboard
correctness-and-contracts: 0 findings, 2 coverage gaps, signal:HIGHtest-coverage-robustness: 3 findings, 3 coverage gaps, signal:HIGHdocs-site-contracts: consensus on reference-actions + basePath OK, signal:HIGHdocs-and-positioning: link/command integrity OK; Proof-first disputed/dropped, signal:MEDrelease-discipline: publish residual MED via follow-up rule, signal:MEDSent by Cursor Automation: Flatbread PR Review
| expect(action.firstAction.success.trim()).not.toBe(''); | ||
| expect(action.firstAction.minutes).toBeLessThanOrEqual(2); | ||
| expect(action.nextAction.label.trim()).not.toBe(''); | ||
| expect(action.nextAction.href).toMatch(/^#[a-z0-9-]+$/); |
There was a problem hiding this comment.
severity: MED — flagged-by: test-coverage-robustness, docs-site-contracts
risk: This asserts href shape (^#[a-z0-9-]+$) only. A README heading rename keeps CI green while the reference “next action” CTA 404s in-page (reference/[slug]/page.tsx renders action.nextAction.href live).
minimal fix: For each PUBLISHED_PACKAGE_IDS entry, derive h2/h3 ids from content/reference/<id>.md with the same slug rules as plugins/rehype-heading-anchors.mjs, and assert nextAction.href.slice(1) is in that set. Add one negative (#missing-section). Alternate home: the same check once in check-export.mjs against exported HTML — do not duplicate thrice.
| className="fb-related" | ||
| > | ||
| <p> | ||
| <a href={action.nextAction.href}> |
There was a problem hiding this comment.
severity: MED — flagged-by: test-coverage-robustness, docs-site-contracts
risk: Live hash link depends on REFERENCE_ACTIONS staying aligned with README headings. Current HEAD anchors match for all eleven packages; coverage still cannot catch a heading rename.
minimal fix: Prefer the href↔heading assert on reference-actions.test.ts (or one check-export pass). No page change required while anchors resolve.
| @@ -0,0 +1,142 @@ | |||
| // @vitest-environment jsdom | |||
There was a problem hiding this comment.
severity: LOW — prior ThemeToggle/NavDisclosure plan is largely closed here.
residual: Wide-screen pathname change should leave <details> open and must not focus #main-content; missing #main-content must not throw.
minimal fix: One wide-pathname case + one missing-#main-content narrow path change.
Change-Id: I74e9d3d08187cafa3a446748498f3d50558b7a07
There was a problem hiding this comment.
Review verdict
COMMENT — No blockers or consensus HIGHs. Prior REFERENCE_ACTIONS nextAction.href ↔ heading-id MED is closed at fcb53f0 (check-export same-page fragment test + postbuild). Standing sanitize / js-yaml items stay publish residuals, not REQUEST_CHANGES on this non-release PR. Coverage plan still lists an optional unit-speed href↔heading pairing gap while the PR touches non-test source, so the floor is COMMENT (not APPROVE).
Delta this sync (f3911c2..fcb53f0): NavDisclosure wide-screen pathname + missing-#main-content tests; check-export missing same-page next-action fragment test.
Closed / hold
- CLOSED:
REFERENCE_ACTIONSfragment ↔ export check (detector + unit fixture). - CLOSED: NavDisclosure wide-screen / missing-main edges.
- HOLD: intentional
out/root artifacts + URL/flatbreadbasePath— do not elevate nesting without a counterexample.
Coverage plan
- MED (optional):
apps/docs/lib/reference-actions.test.ts—it.eachoverREFERENCE_ACTIONSasserting eachnextAction.href.slice(1)∈ slugified H2–H4 ids from the matching package README / heading pipeline. Postbuild already enforces; this only shortens the loop. - LOW:
apps/docs/app/reference/[slug]/page.tsxrender smoke that next-actionhrefappears in HTML. - LOW: Optionally wire
check-export.test.mjsto liveREFERENCE_ACTIONSbeyond synthetic HTML.
Suggested follow-ups
- Release PR: bump
@flatbread/transformer-markdown+@flatbread/transformer-yamltogether (sanitize +js-yamlfloor). - Optional vitest
it.eachfor href↔heading ids. - GitHub Pages deploy so
packages/flatbreadgithub.iolinks resolve. - Optional Proof vs relational section reorder if product wants relational-first.
Reviewer scoreboard
correctness-and-contracts: 0 findings, 2 coverage gaps, signal:HIGHtest-coverage-robustness: 0 findings, 1 coverage gap (optional), signal:HIGHdocs-site-contracts: 0 findings, 2 coverage gaps, signal:HIGHdocs-and-positioning: 4 findings (LOW), 0 coverage gaps, signal:MEDrelease-discipline: 2 findings (MED), 0 coverage gaps, signal:HIGH
Models: HIGH=cursor-grok-4.5-high; MED/LOW=composer-2.5. Oven missing → Task-tool fallback.
Sent by Cursor Automation: Flatbread PR Review
| /** Keep harmless fenced-code metadata for syntax highlighters after sanitize. */ | ||
| const sanitizeSchema: SanitizeOptions = { | ||
| ...defaultSchema, | ||
| attributes: { | ||
| ...defaultSchema.attributes, | ||
| code: [['className', /^language-[A-Za-z0-9_-]+$/], 'dataTitle'], | ||
| }, | ||
| }; | ||
|
|
There was a problem hiding this comment.
severity: MED (publish residual, not REQUEST_CHANGES)
Sanitize allowlist narrowing (/^language-[A-Za-z0-9_-]+$/ + dataTitle) ships in workspace/apps/docs, but @flatbread/transformer-markdown stays at 1.0.1.
Minimal fix: On the release PR, bump this package with the sanitize change; keep docs workspace:* dogfood as-is until then.
| "dependencies": { | ||
| "@sindresorhus/slugify": "^2.2.1", | ||
| "js-yaml": "^4.1.0" | ||
| "js-yaml": "^4.3.1" |
There was a problem hiding this comment.
severity: MED (publish residual, not REQUEST_CHANGES)
js-yaml floor is ^4.3.1 without a package version bump, so npm consumers do not get the dependency change yet.
Minimal fix: Bump @flatbread/transformer-yaml on the same release train as transformer-markdown.
| * framing here so each reference page starts with one bounded task and ends | ||
| * with one next action without adding deployment-specific copy to npm. | ||
| */ | ||
| export const REFERENCE_ACTIONS: Record<string, ReferenceAction | undefined> = { |
There was a problem hiding this comment.
Coverage plan (optional MED) — consensus across correctness / test-coverage / docs-site.
nextAction.href is shape-checked (/^#[a-z0-9-]+$/) and wrong fragments fail postbuild check-export, but vitest does not yet assert each href ∈ slugified H2–H4 ids from the matching package README.
Minimal fix if wanted: it.each over REFERENCE_ACTIONS running the heading slug pipeline and asserting href.slice(1) ∈ ids. Not REQUEST_CHANGES while postbuild stays mandatory.
| it('reports a missing same-page next-action fragment', () => { | ||
| const problems = withExport({ | ||
| 'reference/codegen/index.html': | ||
| '<h2 id="basic-usage">Basic usage</h2><a href="#basic-usage">Present</a><a href="#missing-section">Next action</a>', | ||
| }); | ||
|
|
||
| expect(problems).not.toContain( | ||
| 'reference/codegen/index.html: `#basic-usage` has no `#basic-usage` target in reference/codegen/index.html' | ||
| ); | ||
| expect(problems).toContain( | ||
| 'reference/codegen/index.html: `#missing-section` has no `#missing-section` target in reference/codegen/index.html' | ||
| ); | ||
| }); |
There was a problem hiding this comment.
CLOSED (prior MED) — this same-page #fragment case closes the prior REFERENCE_ACTIONS nextAction.href ↔ heading-id / export-check concern at fcb53f0.
It matches the production collectExportProblems loop that validates exported reference HTML. Do not reopen as REQUEST_CHANGES.


docs time