Skip to content

T19-01 Published-post editor schema compatibility and crash containment #550

Description

@edithatogo

Problem

A published post created/updated through the CLI can render normally and remain valid in Substack's primary rich-text editor, yet make the browser edit screen unstable or crash.

Verified reproduction: https://rareinsights.substack.com/p/death-by-donation-a-repugnant-transaction (post ID 210551946). The public page is healthy, but the authenticated published-post editor logs:

Editor content error encountered: Error: [tiptap error]: Invalid JSON content
RangeError: Unknown node type: image

Differential diagnosis

Confirmed

The published-post edit screen mounts two visible Tiptap editors:

  1. The primary editor accepts the complete stored post JSON without an error.
  2. A secondary restricted editor exposes only doc, paragraph, text, and hardBreak, with basic link/bold/italic marks, but receives the full rich body.

The secondary editor rejects rich nodes present in the post:

  • image (first observed failure)
  • heading
  • blockquote
  • orderedList / bulletList via listItem

It also renders a second, very long document tree beside the primary editor. In the reproduction, the primary document was approximately 15,434 px tall and the secondary copy approximately 11,170 px tall. The schema exception plus duplicated DOM is the leading explanation for browser-tab instability.

Ruled out for this post

  • corrupted or malformed ProseMirror JSON
  • invalid content in Substack's full editor schema
  • excessive individual string/node size
  • duplicate node IDs
  • broken image URLs or failed asset requests
  • repository-relative reader links
  • public-page HTTP, console, or page errors

The body is about 51.5 KB / 536 JSON objects and all three images load.

Related but distinct compatibility defect

A scheduled control post containing a table fails in the primary editor with:

RangeError: Unknown node type: tableHeader

This is a genuine CLI/editor schema-compatibility problem and should not be conflated with the published-post secondary-editor defect.

Remaining uncertainty

The secondary editor's intended Substack function is not established. This may be a Substack regression, an undocumented published-revision representation constraint, or a post shape that triggers an otherwise latent editor bug. The CLI should therefore diagnose and contain the failure without claiming ownership of Substack's UI internals.

Detection options

A. Static capability profiles (recommended baseline)

Validate generated nodes and marks against versioned profiles:

  • full draft editor profile
  • restricted auxiliary editor profile
  • published-revision profile

Report the first incompatible node with its JSON path and all incompatible-node counts.

Trade-off: deterministic and fast, but profiles can drift when Substack changes its private editor schema.

B. Authenticated disposable-editor canary

Create or update a non-public canary, open the authenticated edit route, capture Tiptap errors, mounted editor schemas, DOM duplication, and page stability, then delete/restore the canary.

Trade-off: detects upstream drift but is slower, authentication-dependent, potentially rate-limited, and must never perform unconfirmed publication.

C. Stored-post round-trip inspection

After create/update, retrieve the post and compare draft_body, published body, metadata, and node inventory; classify published-revision risk before reporting success.

Trade-off: catches transport differences but cannot alone prove the browser editor will mount safely.

D. Payload complexity guardrails

Record body bytes, node count/depth, image/list/table counts, and estimated duplicated DOM cost.

Trade-off: useful diagnostics, not a substitute for schema validation; thresholds risk false positives.

Resolution options

1. Fail closed on known incompatible nodes for editable published revisions

Reject or require explicit override when a target profile cannot represent the body.

Benefit: safest and transparent.
Cost: blocks otherwise publishable rich posts when only Substack's auxiliary editor is defective.

2. Normalize only unsupported structures

Examples: convert tables to accessible Markdown/HTML-safe lists; preserve headings/images for the full editor; produce a paragraph-safe auxiliary representation only if the API has a distinct supported field.

Benefit: retains most formatting.
Cost: lossy and unsafe unless the secondary representation is an actual supported API concept.

3. Editor-native round trip

Serialize through the exact schema discovered from the authenticated primary editor, then verify the resulting published-revision screen.

Benefit: strongest compatibility signal.
Cost: coupled to private implementation details and still may not control the secondary editor.

4. CLI-only update fallback

When the browser editor is known unsafe, permit update-in-place through the CLI and emit a durable warning/receipt.

Benefit: immediate operational continuity.
Cost: workaround only; users remain unable to use Substack's browser editor.

5. Upstream escalation with minimal reproducer

Provide Substack a privacy-safe fixture containing one heading, image, blockquote, and list that the full editor accepts but the secondary editor rejects.

Benefit: targets the actual UI defect.
Cost: external resolution and timing are outside this project's control.

Recommendation

Implement layered protection:

  1. Add static full/restricted/published-revision schema profiles and precise JSON-path diagnostics.
  2. Treat tables unsupported by the primary editor as a hard error unless explicitly normalized.
  3. Treat secondary-editor incompatibility as a prominent published-editability risk, not silent success.
  4. Add an authenticated disposable canary to the compatibility matrix, with rate-limit, CAPTCHA/2FA, cleanup, and no-publication boundaries.
  5. Preserve CLI update-in-place as a documented contingency.
  6. Produce a minimal upstream reproduction and avoid destructive rewriting until Substack's secondary editor contract is understood.

Acceptance criteria

  • A fixture containing images/headings/lists/blockquote is valid for the full profile and reports exact incompatibilities for the restricted profile.
  • A table fixture reports tableHeader incompatibility before any live write.
  • Create/update receipts distinguish public rendering, primary-editor validity, secondary-editor/editability risk, and live browser verification.
  • Authenticated canary tests never publish or email without explicit confirmation and clean up deterministically.
  • Rate limits, auth expiry, CAPTCHA/2FA, upstream schema drift, and cleanup failure have explicit stop conditions.
  • Documentation describes CLI-only update as a contingency, not a fix.
  • A privacy-safe upstream reproduction fixture is generated.

Scope boundary

Planning and diagnostics must not silently modify published content, strip rich structures, or claim Substack UI compatibility without an authenticated verification receipt.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingconductorOwned by a Conductor track or taskconductor-trackConductor programme track issue

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions