Editing a document that contains an indented MDX component block…#177
Merged
Conversation
* [wip] claim PRD-7110: CRDT bridge bloat on indented MDX <Steps> (fix-bug)
* test(open-knowledge): RED tests for indented-JSX bridge fixed-point (PRD-7110)
Pin the contract that the gamma dirty serializer must reach a byte-stable
fixed point WITHIN normalizeBridge tolerance for indented-children MDX JSX
blocks (Steps/Step, Tabs/Tab, custom components).
The existing I13 idempotence PBT misses this class: flush-left output is
already a serializer fixed point while still being beyond normalizeBridge
tolerance, and loadBuiltInFixtures carries no indented-children JSX shape
(the Steps fixture was rewritten flush-left). The three within-tolerance
assertions fail now and should pass once the serializer reaches a
within-tolerance fixed point. The byte-stable fixed-point guards pass now and
must stay green. No production code changed.
* fix(open-knowledge): keep indented MDX JSX children within bridge tolerance on edit
The mdxJsxFlowElement dirty-path serializer rebuilt a component block's
children flush-left with blank-line wrapping, dropping the authored
2-space-per-depth indentation of fumadocs <Steps>/<Step>, <Tabs>/<Tab>,
and any component with indented markdown children. The flush form is
beyond normalizeBridge tolerance versus the indented source, so the
server-authoritative bridge never settled per drain and re-derived under
divergence, growing the Y.Doc past the 512 KiB open limit until the
document refused to load.
Changes:
- Group 1: delegate the children-bearing dirty path to the upstream
mdast-util-mdx-jsx flow serializer for depth-based indentation and
single-newline wrapping (the authoring form the comparator accepts).
Pre-normalize the one attribute case where upstream diverges from OK
(a double quote inside a string value) through a shared helper so
attribute bytes stay identical to serializeMdxJsxAttrs. Correct the
obsolete docstring: micromark-extension-mdx-jsx consumes the
container-relative leading whitespace, so indented children are not
read as a CommonMark indented code block.
- Group 2: in reconstructAttrs, keep a preserved raw expression
attribute when the structured prop value is parse-equal to it, so
re-serializing an unchanged attribute (items={["npm", "bun"]}) does
not mint a within-meaning-but-different byte form.
Pinned by the indented-children bridge fixed-point tests in
invariant-i13.test.ts.
Refs PRD-7110.
* fixup! local-review: address findings (pass 1)
* fixup! local-review: address findings (pass 2)
* test(open-knowledge): lock in <details> serializer safety as PRD-7110 sibling
The html-boundary <details> (HtmlDetailsAccordion) path shares the gamma
path's synthetic-root-flush shape but is NOT subject to the bug: canonical
<details> bodies are flush-left, so depth-0 flush is the correct, within-
normalizeBridge-tolerance form. Applying the gamma indent fix here would be
harmful (serializes '### H' -> ' ### H', which normalize.ts step 7f does not
fold). Adds green coverage + anti-regression guards so a future refactor can't
wrongly route <details> through the indenter.
* test(open-knowledge): address PR 1904 cloud-review polish (PRD-7110)
Non-blocking suggestions from the PR 1904 review (APPROVE WITH SUGGESTIONS,
1 Minor + 6 Consider). No behavior change; the landed fix stays as-is.
Substantive item (Consider 1): empirically resolved whether the upstream
mdast-util-mdx-jsx delegation path entity-encodes more than the double quote.
It does not. The full divergence set between OK's serializeMdxJsxAttrs and the
upstream handler is exactly the double quote, confirmed three ways: upstream
calls stringifyEntitiesLight(value, subset:['"']) (default quote, no options),
stringify-entities only escapes the subset, and direct probes show &, <, >, ',
braces, backslash, backtick, newline all pass through byte-identical. Kept a
regression guard (string-attr entity divergence on the delegation path) that
fails loud if a library bump ever widens the subset, and tightened the
normalizeAttrForUpstream docstring to state the verified set. No fix extension.
Other items:
- Minor: explicit positive-path test for expressionMatchesValue (an unchanged
JSON-array expression attr is kept verbatim, not recompacted), instead of
only transitive coverage via the Tabs fixture.
- Consider 2: reuse the TO_MARKDOWN_EXT singleton (now exported from
remark-mdx-agnostic.ts) for the dirty-path delegation instead of minting a
fresh mdxToMarkdown() instance, so the dirty path and the pipeline can no
longer drift. Cycle-safe; remark-mdx-agnostic is a leaf module.
- Consider 3: added a depth-3 nested-component fixture (6-space indent) to
exercise upstream inferDepth past the existing depth-2 fixtures.
- Consider 4: restated the line-309 idempotence comment as a standing invariant
and dropped the now-stale flush-left wording.
- Consider 5: removed PRD-7110 ticket refs from pure comments per the repo
comment-discipline rule, keeping them only in describe() names (load-bearing
test selector).
- Consider 6: rewrote the "reported trigger" fixture comment as a behavioral
description.
Verification: invariant-i13 PRD-7110 scope 19 pass / 0 fail (was 6); full file
47 pass; bun run check green (23/23, fidelity 1302, md-conformance 1490, 0 fail);
bun run lint clean. No STOP-ruled files touched (built-ins.json, normalize.ts,
server-observers.ts); no normalizeBridge tolerance change; no test weakened.
GitOrigin-RevId: c8fb42ed509587f044bee39016b5d9f2f2e1af55
Contributor
There was a problem hiding this comment.
Automated approval from agents-private public-mirror-sync (run: https://github.com/inkeep/agents-private/actions/runs/27677717636). Source of truth is the monorepo; direct edits on inkeep/open-knowledge are overwritten on next sync.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Editing a document that contains an indented MDX component block (fumadocs
<Steps>/<Step>,<Tabs>/<Tab>, or any component authored with indented markdown children) no longer corrupts the document. The serializer used to rewrite an edited block's children flush-left with extra blank lines, a shape the collaboration bridge could not reconcile with the on-disk source, so under concurrent editing the document could grow without bound until it crossed the open-size limit and refused to reopen. Edited blocks now preserve the canonical two-spaces-per-level indentation (the fumadocs/Obsidian convention) exactly, and an unchanged structured attribute such asitems={["npm", "bun"]}is no longer rewritten with different whitespace. Blocks authored with a different indentation width normalize to the two-space form on the first edit and then stay stable — a one-time change, not the previous unbounded growth.