Qwiratry — Qwiratry-TaOP-Parity
Qwiratry TaOP Parity
Plan/Spec for TOP parity work listed in Post-SQL-TaOP-Improvements.md §F.1: behaviour the old Raku-TOP code already had (or documented as first-class) that Qwiratry still lacks — not greenfield TOP concepts (those are Post-SQL §F.5).
Status: Implemented (checklist complete).Parent backlog: Post-SQL §F.1 (items 1.1–1.2). Former Relation/TupleSet
ideas live as Maybe under Post-SQL §F.5. Body-cell / per-cell formatting
(was F.1.3) moved to Post-SQL §B.6 (order: §F.7.1).
Related archives:
Qwiratry-TaOP-Textish.md,
Qwiratry-TaOP-Basics.md,
Qwiratry-TaOP-Plan.md.
Question IDs are stable: Q1, Q2, … stay the same when an item moves from §Open Questions into §Decisions (record the answer under the same Qn). Q4 (body / per-cell formatting) left this document for Post-SQL §B.6; the ID is retired here so later parity questions do not reuse it.
1. Goals
Restore a public multi-phase Format render API matching TOP’s
prepare-table/output-header/output-row/output-footerdrive, without giving up one-shotrender-walkableas the default operator path (phases live on a common Textish role in core — Q1).Improve HalfHuman emit-side round-trip (space →
_on by default, option to disable — Q3); do not paper over Parse option misuse.
2. Non-goals
Greenfield TOP concepts not in old TOP code:
View,Section,Lot,DataDictionary,atom, etc. (Post-SQL §F.5).Query output as a
Relationwithout being aTable— stick with emitting Tables like old TOPgrep(Q6–Q8; optional Maybe later as Post-SQL §F.5 5.6).TupleSet— never implemented in old TOP; not part of this parity cut (Q9; optional Maybe later as Post-SQL §F.5 5.7).Richer Associative cell stringify beyond current
.raku(Post-SQL §F.5 / Textish §6.5 follow-up — not §F.1).Body-cell / per-cell formatting beyond today’s header-only
:header-alignment(Post-SQL §B.6 / §F.7.1; was F.1.3).Full Format
ParsePull/RenderPull/ Supply push (Post-SQL §F.7; Streaming-v2).SQL DatabaseStorage sibling and cursor mapping (Post-SQL §F.3).
Aggregate catalogue work (Post-SQL §F.8).
3. Public multi-phase formatter API
(Post-SQL §F.1 item 1.1; also §B.1 / §E.3.2)
3.1. TOP behaviour
TOP formatters are stateful multi-phase. Database::Storage.format loads a
formatter and drives:
prepare-tableoutput-headeroutput-row(per row)output-footerreturn
$formatter.output
HalfHuman and WithBorders in Qwiratry already implement the same phases
internally inside one-shot render-walkable.
3.2. Proposed Qwiratry shape
TOP has no shared formatter base/role — HalfHuman and WithBorders each
implement the same duck-typed protocol. Qwiratry already decided a shared
Textish role in core (Q1); put the public phase methods on
Qwiratry::Format::Textish::RenderWalkable (helpers already live there).
Match TOP’s surface:
| Piece | TOP | Qwiratry |
|---|---|---|
| Phases | prepare-table(), output-header(), output-row($row), output-footer | same names / arity |
| Accumulator | public $.output | public $.output |
| Options | new(table => …, show-headers => …, …) then phases take no option hash | bind options when constructing / preparing the formatter (or at start of render-walkable); phase methods stay option-free like TOP |
| Driver | Storage.format loops rows | thin render-walkable runs the same sequence and returns $.output |
| Width scan | prepare-table walks all rows (needs full table for column widths) | same — do not claim true O(1)-memory streaming for width-based Textish |
Operators and Table.format continue to call render-walkable by default.
Callers who want the TOP drive protocol can construct a Textish Render and call
the phase methods themselves.
3.3. Tradeoffs
Pro: restores TOP’s public drive protocol; one protocol across Textish Formats; callers can drive phases manually (same as TOP Storage).
Con: mutable formatter state, call-order contracts; width-based Textish still scans all rows in
prepare-table(same as TOP). Pull/RenderPullremains available long-term (Streaming-v2 / Post-SQL §F.7) but is out of scope for this Textish MVP — Q2.
Decided: Q1, Q2.
4. Stronger HalfHuman round-trip
(Post-SQL §F.1 item 1.2; also §B.5; Textish §5.3 / Non-goals)
4.1. Emit-side focus
HalfHuman Parse is whitespace-split by design. We do not try to make Parse
recover from every caller mistake (e.g. Render with :show-headers then Parse
without :headers — that is a user error). Round-trip work for this cut is
mostly on the emitting side: make Render produce text that Parse can read
back when the caller uses matching options.
4.2. Spaces in cells
Dialect rule (Textish / TOP docs): cells should not contain spaces; prefer _.
Old TOP code does not implement replacement — HalfHuman only suggests
underlines in pod; emit still passes cell strings through unchanged. WithBorders
has no such dialect rule (borders separate columns).
Decision (Q3): Qwiratry HalfHuman Render does replace spaces in cell
text with underscores; on by default, with an option to turn it off
(option name: :spaces-to-underscores, Bool, default True). WithBorders:
do not apply — not in TOP, and not needed for that dialect.
4.3. Scope for this cut
Emit-side hardening (space →
_per Q3) on HalfHuman only.Tighten Render→Parse tests for simple tables when options match (
:show-headers↔:headers).Do not promise perfect round-trip for arbitrary Unicode / quoting / multi-line cells; HalfHuman stays a simple whitespace dialect.
Do not change Qwiratry’s existing undefined-cell
'-'vs TOP HalfHuman''in this cut (pre-existing dialect difference, not part of §F.1).
Decided: Q3. Golden regressions: Q5.
5. Implementation checklist
1. Implement Textish multi-phase role + thin
render-walkabledriver; port HalfHuman / WithBorders (Q1, Q2 — Walkable MVP, no TextishRenderPullin this cut).2. HalfHuman Render space→
_on by default + option to disable (Q3); emit-side round-trip tests when Parse options match Render; on any golden string changes, notify Tim for a call (Q5).3. Docs: Extending/Adding-Formats, TaOP pod, Changelog; cross-link Post-SQL §F.1 items 1.1–1.2 as done.
6. Open Questions
(None remaining for this cut.)
7. Decisions
Q1. Multi-phase methods live on a common Textish role in core (HalfHuman / WithBorders compose it) — not Format base for all Formats, and not HalfHuman-only ad hoc methods without the shared role. Implement on existing
Qwiratry::Format::Textish::RenderWalkable. Phase names/arity and public$.outputmatch TOP (§3.2).Q2. Match old TOP for now: public multi-phase under Walkable (
render-walkableas thin driver). Do not add TextishRenderPullin this cut; Streaming Pull/Push stay long-term (Post-SQL / Streaming-v2).Q3. Space →
_on HalfHuman Render only: option:spaces-to-underscores, on by default. TOP docs suggested this but did not implement it; WithBorders does not get this transform.Q4. Retired from this document — body-cell / per-cell formatting is Post-SQL §B.6 (order §F.7.1; not old TOP parity).
Q5. Do not silently require bit-identical goldens as a hard rule. When HalfHuman/WithBorders (or related) golden strings change, notify Tim, who will decide whether each change is correct.
Q6. Stick with emitting Tables for query / relational results (as old TOP
grepdoes); no separate result-Relation concrete type in this cut.Q7. N/A for this cut — result Tables keep the usual Table/Storage face.
Q8. N/A for this cut — no distinct result-Relation discovery path.
Q9.
TupleSetis not part of this parity document (never implemented in old TOP).
8. References
Post-SQL-TaOP-Improvements.md §F.1, §B.1, §B.5, §B.6 / §F.7.1, §C.3, §E.3.2, §E.3.3
Raku-TOP:
TOP::Formatter::HalfHuman,WithBorders;Database::Storage.formatphase drive; README TupleSet note;Table.grepreturnsTable