Skip to content

app: workstream pages render from editor JSON to markdown (pagedoc) - #2277

Merged
AbirAbbas merged 3 commits into
workstreams/mainfrom
workstreams/wp6c-pagemd
Nov 3, 2026
Merged

AbirAbbas merged 3 commits into
workstreams/mainfrom
workstreams/wp6c-pagemd

Conversation

@AbirAbbas

@AbirAbbas AbirAbbas commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

The Workstreams plan, WP-6c. Workstream pages are stored as editor (TipTap/ProseMirror) JSON. When a job reads a page, the engine renders that JSON to markdown at that moment. This adds the renderer as a pure package:

  • internal/workstream/pagedoc: func Markdown(doc json.RawMessage) (string, error). No I/O, no store, standard library only.
  • It follows the page document format rules exactly as the desktop app's renderer does, byte for byte: paragraphs and headings (level clamped to 1–3, line breaks to spaces, outer spaces/tabs trimmed), bullet and ordered lists (custom starts, nested and multi-block items, bare empty items), code blocks (verbatim, safe backtick fences), inline code, link runs with encoded destinations, escaping and paragraph line-start escapes, and the liveBlock marker lines ([live: jobs milestone=…], [live: waves], [live: job <factory>#<n>], [live: decision <id>]).
  • Unknown blocks render as a paragraph of their escaped descendant text (omitted when empty); unknown inline nodes contribute their own text; unknown marks are ignored. Malformed but valid JSON shapes never fail.
  • Invalid JSON returns an error starting pagedoc: . A nil, empty, whitespace-only or null document returns "". A recover guard turns any unforeseen panic into an error.
  • JavaScript semantics the reference relies on are reproduced: line starts after \r, \n, U+2028 and U+2029; \r\n precedence; numbers decoded so 1e400 is infinity rather than a decode error; JS number formatting for list starts and job numbers (-0 → 0, 1e21 → 1e+21).

Validation contract

Item Test
(a) every fixture of the desktop app's markdown tests gives the identical string (142 assertions after loop expansion, one Go test per TS test) TestMarkdownParagraphsHeadingsEmptyBlocksAndTerminalNewline, TestMarkdownInlineNewlinesAndOuterWhitespace, TestMarkdownBulletAndOrderedLists, TestMarkdownCodeBlocks, TestMarkdownInlineCode, TestMarkdownLinksAndDestinations, TestMarkdownEmptyTextAndLinkRuns, TestMarkdownLiveBlocks, TestMarkdownLiveBlockAttributeValidation, TestMarkdownEscapingAndParagraphLineStarts, TestMarkdownUnknownNodesMarksAndMalformedShapes
(b) the contract's worked example (JSON and exact markdown in testdata/, checked against an independently built document) TestMarkdownRendersTheContractExample
(c) bad JSON is an error, not a panic; absent documents are empty TestMarkdownRefusesInvalidJSON, TestMarkdownTreatsAnAbsentDocumentAsEmpty, TestMarkdownRendersADeepDocumentWithoutPanicking
(d) unknown node types give the documented fallback TestMarkdownUnknownNodesMarksAndMalformedShapes, rows 3, 6, 7, 9 of TestMarkdownMatchesTheReferenceOnEdgeCases
(e) JavaScript-specific semantics (line terminators, number formatting, coercions) TestMarkdownMatchesTheReferenceOnEdgeCases (36 rows)

The one JS fixture not ported is the NaN job number, which JSON cannot carry. Known, untestable divergences (documented in the code): lone UTF-16 surrogate escapes decode to U+FFFD in Go, and documents nested deep enough to exhaust the JavaScript stack render in Go (up to encoding/json's 10000-level limit, past which they are invalid JSON).

Left for later

CI

touched packages ran ./internal/workstream/pagedoc and passed. Build, vet, gofmt and the change entry pass. The light gate's one red is the baseline laws ratchet in internal/session (TestNoRoadInTheTaskEngineHasMoreEndingsThanItsLedgerRow, TestNoRoadInTheMemoryEngineHasMoreEndingsThanTheCeiling), which is red the same way on workstreams/main's own push runs and is not touched here.

Contract changes

None. This implements the existing page document format.

🤖 Generated with Claude Code

AbirAbbas and others added 3 commits November 2, 2026 22:03
The Workstreams plan, WP-6c: internal/workstream/pagedoc.Markdown renders a
page's editor JSON by the page document format rules, byte for byte the same
as the desktop app's renderer, so a job that reads a page sees the markdown a
person sees when they export it. Pure: no I/O and no store; invalid JSON is an
error, an absent document is empty, unknown nodes keep their text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…act example

Every assertion of the desktop app's markdown tests as a Go table row with the
identical expected string, the contract's worked example as testdata, invalid
and absent documents, and edge cases that pin JavaScript's line terminators,
number formatting and coercions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@AbirAbbas
AbirAbbas merged commit f4078a9 into workstreams/main Nov 3, 2026
4 of 6 checks passed
@AbirAbbas
AbirAbbas deleted the workstreams/wp6c-pagemd branch November 3, 2026 03:13
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.

1 participant