rte: opt-in 'table' token with GFM-constrained round-trip (no creation UI yet) #94

Closed
opened 2026-07-18 02:25:55 +02:00 by dominik.polakovics · 1 comment

What to build

Add table as a ninth rte formatting token — opt-in only. The default allow-set stays the current 8 tokens; table must be named explicitly in an element's allow: list. Enable it in text.yaml by giving text an explicit allow list (the 8 defaults + table).

Editor side: wire tiptap's table extension GFM-constrained so pipe tables stored in bodies render in the rte editor and survive an edit/save cycle losslessly. Constraints: no merged cells (merge/split disabled), cells hold inline content only, first row is always the header row, no column resizing persisted. Serialization target is a plain GFM pipe table in the markdown body — the no-raw-HTML server gate is untouched.

This slice ships no table-creation UI — its value is that agent-authored pipe tables render correctly and are not destroyed when a human edits the surrounding text. Creation/editing affordances are the follow-up slice.

Contract updates in the same change (per CLAUDE.md): Go allow-set (internal/element/schema.go), TS mirror (web/src/rte/allow.ts), scaffold/site/AGENTS.md — including rewording "omitting allow = full set" to "omitting allow = default set (all tokens except table)" — and the agentsdoc_test.go drift expectations.

Acceptance criteria

  • table is a valid rte token in Go and TS allow-sets; drift test passes
  • Default allow-set unchanged (8 tokens); elements omitting allow do NOT gain tables
  • text.yaml explicitly allows the 8 defaults + table
  • A hand-authored GFM pipe table in a text body renders as a table in the rte editor and in Hugo output (responsive scroll wrapper in the theme)
  • Editing unrelated text in a body containing a table, then saving, reproduces the pipe table byte-equivalently (modulo markdown normalization already applied to bodies)
  • Tiptap constraints enforced: no merge/split, inline-only cells, first row header
  • An element whose allow-set lacks table rejects/strips table content per existing rte enforcement
  • AGENTS.md documents the token, the opt-in rule, and the new default-set wording

Blocked by

None - can start immediately

## What to build Add `table` as a ninth rte formatting token — **opt-in only**. The default allow-set stays the current 8 tokens; `table` must be named explicitly in an element's `allow:` list. Enable it in `text.yaml` by giving `text` an explicit allow list (the 8 defaults + `table`). Editor side: wire tiptap's table extension **GFM-constrained** so pipe tables stored in bodies render in the rte editor and survive an edit/save cycle losslessly. Constraints: no merged cells (merge/split disabled), cells hold inline content only, first row is always the header row, no column resizing persisted. Serialization target is a plain GFM pipe table in the markdown body — the no-raw-HTML server gate is untouched. This slice ships **no table-creation UI** — its value is that agent-authored pipe tables render correctly and are not destroyed when a human edits the surrounding text. Creation/editing affordances are the follow-up slice. Contract updates in the same change (per CLAUDE.md): Go allow-set (`internal/element/schema.go`), TS mirror (`web/src/rte/allow.ts`), `scaffold/site/AGENTS.md` — including rewording "omitting allow = full set" to "omitting allow = default set (all tokens except table)" — and the `agentsdoc_test.go` drift expectations. ## Acceptance criteria - [ ] `table` is a valid rte token in Go and TS allow-sets; drift test passes - [ ] Default allow-set unchanged (8 tokens); elements omitting `allow` do NOT gain tables - [ ] `text.yaml` explicitly allows the 8 defaults + `table` - [ ] A hand-authored GFM pipe table in a text body renders as a table in the rte editor and in Hugo output (responsive scroll wrapper in the theme) - [ ] Editing unrelated text in a body containing a table, then saving, reproduces the pipe table byte-equivalently (modulo markdown normalization already applied to bodies) - [ ] Tiptap constraints enforced: no merge/split, inline-only cells, first row header - [ ] An element whose allow-set lacks `table` rejects/strips table content per existing rte enforcement - [ ] AGENTS.md documents the token, the opt-in rule, and the new default-set wording ## Blocked by None - can start immediately
Author
Owner

This was generated by AI during triage.

Triage confirmed — enhancement, ready-for-agent. The issue body is the authoritative agent brief.

Verified against the codebase: the current 8-token allow-set is confirmed in both internal/element (defaultRTEAllow) and the TS mirror web/src/rte/allow.ts, whose doc comment carries exactly the "omitting allow = full set" wording this issue says to reword. The issue already names every contract surface CLAUDE.md requires (Go set, TS mirror, AGENTS.md, drift test) — treat that list as binding.

> *This was generated by AI during triage.* **Triage confirmed — enhancement, ready-for-agent.** The issue body is the authoritative agent brief. Verified against the codebase: the current 8-token allow-set is confirmed in both `internal/element` (`defaultRTEAllow`) and the TS mirror `web/src/rte/allow.ts`, whose doc comment carries exactly the "omitting allow = full set" wording this issue says to reword. The issue already names every contract surface CLAUDE.md requires (Go set, TS mirror, AGENTS.md, drift test) — treat that list as binding.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Cloonar/deckle#94
No description provided.