docs/plans/2026-09-04-preserve-static-html-output.md
Objective: Preserve React's encoded static HTML output; done when regression tests, package checks, repository check, clean review, and task PR evidence pass.
Flow mode: one-shot execution
Goal plan: docs/plans/2026-09-04-preserve-static-html-output.md
Template: docs/plans/templates/task.md
Primary template: docs/plans/templates/task.md
Applied packs:
Task source:
Timed checkpoint:
Completion threshold:
serializeHtml regression fails before the fix and passes afterward.check pass.node .agents/skills/autogoal/scripts/check-complete.mjs docs/plans/2026-09-04-preserve-static-html-output.md passes.Verification surface:
serializeHtml test plus all packages/core/src/static tests.@platejs/core build/typecheck, pnpm lint:fix, and pnpm check.Constraints:
Boundaries:
packages/core/src/static/serializeHtml.tsx, its public static barrel, existing static serialization suites, and current package metadata.Output budget strategy:
Blocked condition:
Task state:
Current verdict:
Pre-solution issue challenge:
serializeHtml does not preserve the renderer's encoded representation for editor text and dynamic attributes.Completion rule:
update_goal(status: complete) while any required checklist item
remains unchecked. If an item does not apply, check it and add N/A: <reason>.update_goal(status: complete) until every completion threshold
above is satisfied, final handoff evidence is recorded, and
node .agents/skills/autogoal/scripts/check-complete.mjs docs/plans/2026-09-04-preserve-static-html-output.md passes.Start Gates:
| Gate | Applies | Evidence |
|---|---|---|
| Timed checkpoint parsed | no | N/A: none requested |
| Skill analysis before edits | yes | task, autogoal, tdd, changeset, and autoreview selected for execution, evidence, regression-first work, release prose, and closeout review |
| Active goal checked or created | yes | Exact work goal is active; detailed local evidence is kept outside the committable bundle |
| Source of truth read before edits | yes | Exact serializer, public barrel, package metadata, tests, and introduction history read |
| Tracker comments and attachments read | no | N/A: no public tracker |
| Video transcript evidence required | no | N/A: no video |
| Pre-solution issue challenge required | yes | Validity, repro, and owner-boundary verdict recorded above |
| Reproduction verdict before implementation | yes | Focused public API test failed before product-code edits |
| Repro escalation ladder selected | yes | String-level unit/integration proof is sufficient; browser layers are N/A |
| Suggested fix reviewed against durable boundary | yes | Central serializer owns the output contract; caller changes would duplicate policy |
docs/solutions checked for non-trivial existing-code work | yes | Narrow search found no applicable prior solution |
| TDD decision before behavior change or bug fix | yes | One text-encoding regression observed red then green; editor-derived attribute coverage added afterward |
| Branch decision for code-changing task | yes | Dedicated codex/preserve-static-html-output branch starts at current origin/main |
| Release artifact decision | yes | One patch changeset for @platejs/core |
| Browser tool decision for browser surface | no | N/A: returned HTML encoding is an exact string contract |
| PR expectation decision | yes | task requires a verified task PR |
| Dedicated task plan selected for exact PR | yes | This plan owns temporary review repository PR #1 only |
| Tracker sync expectation decision | no | N/A: no public tracker; PR body/readback only |
| Output budget strategy recorded | yes | Exact paths and capped output recorded above |
| Package/API pack selected | yes | Published @platejs/core runtime output changes |
| Public surface or package boundary identified | yes | serializeHtml from @platejs/core/static |
| Release artifact path selected | yes | .changeset/preserve-static-html-escaping.md |
changeset skill loaded when .changeset is required | yes | Full skill read; patch level and imperative user-impact prose used |
| Barrel/export impact decision recorded | yes | No export or file-layout change; no barrel generation needed |
Work Checklist:
<video-transcripts> XML, or marked N/A with reason.valid, not reproduced, invalid,
wont-fix, partially valid, or platform limitation. Feature, docs,
support, or cleanup requests with no bug claim may mark reproduction
N/A with reason.[@Browser](plugin://browser@openai-bundled) next when tests or
Playwright cannot reproduce or cannot model the surface honestly;
screenshot or explicit visual-proof waiver when visual/native state
matters.task invocation and dedicated plan; this plan is
not aggregate evidence for another PR.๐งญ Task plan: docs/plans/<plan>.md line, this file exists at the exact PR
head, and this plan records that exact PR number or URL..agents/**, .claude/**,
.codex/**, skills, hooks, commands, prompts, or user-action tooling..changeset, registry changelog, or explicit no-artifact reason..changeset work loads changeset and follows its package/version/prose rules.registry-changelog pack instead of adding a package changeset.main.Completion Gates:
| Gate | Applies | Required action | Evidence |
|---|---|---|---|
| Named verification threshold | yes | Run the command, proof, source audit, or artifact check named in this plan | Final exact pnpm check passed after focused, package, and integration proof |
| Pre-solution issue challenge verdict | yes | Record reporter claim, suggested fix, repro verdict, validity verdict, durable boundary, and hard-stop/pivot decision before implementation | Valid report, red repro, central serializer owner, and narrow-fix decision recorded before product edits |
| Repro escalation ladder | yes | Record test, browser, and visual outcomes or N/A reasons | Public API string repro was sufficient; browser and visual layers are N/A |
| Bug reproduced before fix | yes | Record failing test/repro or N/A with reason | Focused regression failed before the implementation change |
| Targeted behavior verification | yes | Run focused test/proof for changed behavior or record N/A | Focused suite passes 2/2 for editor text and dynamic attributes |
| TypeScript or typed config changed | yes | Run relevant typecheck | Core typecheck passed 5/5 tasks; full typecheck passed 54/54 |
| Package exports or file layout changed | no | Run pnpm brl when applicable | N/A: no export or exported file-layout change |
| Package manifests, lockfile, or install graph changed | yes | Run pnpm install and relevant package checks | Install, core build/typecheck, and full check passed |
| Agent rules or skills changed | no | Verify generated skill sync when applicable | N/A: no agent or skill files changed |
| Workspace authority proof | yes | Run proof in the owning workspace | Every command ran in /Users/zbeyens/git/plate; core and app integration owners were exercised |
| Browser surface changed | no | Capture browser proof or record waiver | N/A: deterministic returned-string contract; no app route or interaction changed |
| Browser final proof | no | Attach visual proof when applicable | N/A: no visual claim or runnable browser surface |
| CI-controlled template output changed | no | Restore generated template output or record reason | N/A: no template files changed |
| Package behavior or public API changed | yes | Add a changeset or record why none applies | Patch changeset added for @platejs/core |
| User-visible registry output changed | no | Add registry changelog when applicable | N/A: no registry UI output changed |
| Docs or content changed | yes | Apply proportional docs proof | Internal task plan only; no user-facing docs or API reference change |
| High-risk mini gate | yes | Record failure mode, proof, and owner boundary | Raw byte output can change while rendered values remain stable; text/attribute regressions and round-trip integrations prove the boundary |
| Agent-native review for agent/tooling changes | no | Run agent-native review when applicable | N/A: no agent-action or tooling contract changed |
| Local install corruption suspected | no | Reinstall once when applicable | N/A: stale built output was resolved by the required package build, not reinstall |
| Autoreview for non-trivial implementation changes | yes | Run structured autoreview until clean | Final local autoreview reports zero findings and overall correctness 0.88 |
| PR create or update | yes | Run check before PR work and sync the body | Exact pnpm check passed before repository-scoped PR #1 was created |
| Per-PR task ownership | yes | Verify one plan line, plan at exact head, and exact PR ownership | PR #1 has one task-plan line; this final plan commit is its head |
| Task-style PR body verified | yes | Read back the actual PR body | Readback confirms release block, expected emoji/table sections, no self-link, and exactly one task-plan line |
| PR proof image hosting | no | Host browser proof when applicable | N/A: no browser image is needed |
| Tracker sync-back | no | Sync public tracker when applicable | N/A: no public tracker; repository-scoped PR is the review record |
| Final handoff contract | yes | Fill exact final fields | Contract below records PR #1, confidence, proof, outcome, design, and caveat |
| Final lint | yes | Run pnpm lint:fix or scoped equivalent | pnpm lint:fix passed; final pnpm check lint passed with one pre-existing warning |
| Output budget discipline | yes | Keep command output bounded | Searches were scoped and outputs capped; long gates were polled in bounded chunks |
| Timed checkpoint | no | Close requested timing loop or record N/A | N/A: no duration requested |
| Goal plan complete | yes | Run the plan checker | Resolved plan passes check-complete.mjs |
| Public API / package boundary proof | yes | Audit the public entrypoint and package impact | serializeHtml remains exported from @platejs/core/static; signature and exports are unchanged |
| Release artifact classification | yes | Classify the published delta | Published runtime behavior correction in @platejs/core |
| Published package changeset | yes | Add a compliant changeset | One patch changeset names @platejs/core; no forbidden minor bump |
| Registry changelog | no | Use registry artifact when applicable | N/A: not registry-only work |
| No release artifact | no | Explain when no artifact applies | N/A: a package changeset is present |
| Package typecheck/build/test | yes | Run owning package checks | Focused 2/2, static 105/105, integration 22/22, core build/typecheck, and full check passed |
| Barrel/export generation | no | Run pnpm brl when applicable | N/A: no exports or exported file layout changed |
Phase / pass table:
| Phase | Status | Evidence | Next |
|---|---|---|---|
| Intake and source read | complete | Serializer owner, history, public barrel, dependency, and test patterns inspected | implementation |
| Implementation | complete | Renderer output returned directly; unused direct dependency removed; text/attribute regressions and patch changeset added | verification |
| Verification | complete | Focused/static/integration/build/typecheck/lint proof is green; final exact pnpm check passed | PR / tracker sync |
| PR / tracker sync | complete | Repository-scoped PR #1 is open; body readback is correct; final plan commit is at the PR head | closeout |
| Closeout | complete | All required gates are resolved; merge and release remain separate maintainer actions | final response |
Findings:
html-entities had no remaining @platejs/core source owner after the fix; other workspace owners still retain it.Decisions and tradeoffs:
Implementation notes:
Review fixes:
Error attempts:
| Error / failed attempt | Count | Next different move | Resolution |
|---|---|---|---|
Integration directory filter did not match .slow.* filenames | 2 | Pass ./-prefixed expanded file paths | Five intended integration files selected |
| Integration suite resolved stale built package output | 1 | Build the artifact-owning package, then rerun unchanged tests | Core build passed; integration suite passed 22/22 |
| First task branch inherited stale merged-branch history | 1 | Move working changes intact to a fresh current-main branch | Current task branch started at origin/main with no lost changes |
| First attribute test used JSX without the configured runtime binding | 1 | Fix the test harness before counting behavior evidence | Final test uses the actual editor/plugin attribute path and passes |
| Autoreview found internal context in committable plans | 2 | Remove the unrelated plan and separate local evidence from release-safe plan | This plan contains only final behavior and verification; final local autoreview passed with zero findings |
Repository check stopped at the timing budget after all functional tests passed | 2 full runs plus 1 isolated timing run | Recheck machine contention, then rerun the exact gate without changing unrelated tests | High concurrent system load was confirmed; a final exact pnpm check passed after contention dropped |
Verification evidence:
/Users/zbeyens/git/plate: focused regression -> failed before fix for the expected encoding mismatch; passes 2/2 after fix./Users/zbeyens/git/plate: bun test packages/core/src/static -> 105 pass, 0 fail./Users/zbeyens/git/plate: pnpm --filter @platejs/core build -> pass./Users/zbeyens/git/plate: core static-HTML package integration suite -> 22 pass, 0 fail./Users/zbeyens/git/plate: pnpm turbo typecheck --filter=./packages/core -> 5/5 tasks pass./Users/zbeyens/git/plate: pnpm install -> lockfile consistent; pnpm lint:fix -> clean./Users/zbeyens/git/plate: structured local autoreview -> zero findings after disclosure-safe plan separation./Users/zbeyens/git/plate: final exact pnpm check -> pass: lint, 54 builds, 54 typechecks, 3,463 fast tests, 352 slow tests, all additional functional batches, and the enforced timing budget.Final handoff contract:
Task-style PR body contract:
<!-- auto-release:start --> block. If a changeset is
part of the diff and repo policy expects auto release, include that block.๐ Fixes #123 or ๐ Fixes โ N/A, then
exactly one ๐งญ Task plan: docs/plans/<plan>.md line, then an emoji
confidence line like ๐ข 95-100% confidence. The plan must exist at the
exact PR head and identify that exact PR.| Phase | ๐งช Tests | ๐ Browser |.Reproduced and Verified rows. Mark passing proof with ๐ข, repro or
failing proof with ๐ด, and non-applicable cells with โ N/A.**โ
Outcome**, **โ ๏ธ Caveat**,
**๐๏ธ Design**, and **๐งช Verified**.Summary / Verification PR body, an
adaptive prose body from a git helper skill, plain ## Outcome sections, or
an unrelated generated badge footer unless the caller or repo template
explicitly asks for it.gh pr view --json body output or a concise source-backed summary
of that output.Final handoff / sync:
Timeline:
Reboot status:
| Question | Answer |
|---|---|
| Where am I? | Verified task PR closeout |
| Where am I going? | Maintainer review; merge and release are separate work |
| What is the goal? | Preserve encoded static HTML output without legitimate rendering regressions |
| What have I learned? | The decoder had no justified contract; direct renderer output is the narrow owner fix |
| What have I done? | Reproduced, fixed, added two regressions and a patch changeset, passed all behavior checks, and completed clean autoreview |
Open risks: