0a343036d8
Completes requirement V1. A compound (multi-column) FK now routes a bus connector — each paired endpoint's stub merges into a shared vertical channel that splits to the other side — plus an explicit "(a, b) ▶ P.(x, y)" pairing line; the bus generalises the single-column jog (reproducing it exactly, so prior snapshots are unchanged). Self-referential FKs render as two same-named boxes. - output_render.rs: gutter_seg routes all endpoint pairs via a junction() bus; pairing line for compound FKs; compound, self-ref, and compound-from-data (build_diagram_table glue) tests + snapshots - compound_fk.rs: worker test that show_relationship carries both paired column lists into the diagram payload - db.rs: document do_show_one's now-app-superseded relationship prose branch (retained as a worker-API/text fallback; could back a future non-visual display option, cf. ADR-0044 OOS-7) Second /runda pass over the implementation: confirmed ADR-compliance, UTF-8/byte-range safety, and edge-case routing. The ADR §3 last-resort helper line was considered and rejected (vertical fallback + ratatui truncation cover all realistic cases). ADR-0044 marked implemented; requirements.md V1 -> [x]. Full suite 2207 pass / 0 fail / 1 ignored; clippy nursery clean.
505 lines
25 KiB
Markdown
505 lines
25 KiB
Markdown
# ADR-0044: Relationship visualization (two-table connector diagrams)
|
|
|
|
## Status
|
|
|
|
Accepted (2026-06-09); **implemented 2026-06-10** (commits: `cad90ec`
|
|
`show relationship` full diagram, `a0ee323` `show table` compact
|
|
diagrams, + compound-FK bus routing and self-referential diagrams). A
|
|
second `/runda` DA pass over the implementation confirmed
|
|
ADR-compliance, UTF-8/byte-range safety, and edge-case routing; the §3
|
|
last-resort helper line was **considered and rejected** (see §3).
|
|
Closes `requirements.md` **V1**.
|
|
|
|
Resolves **ADR-0016 OOS-1** ("Relationship visualization — two
|
|
structures side-by-side with an arrow; its own ADR; will compose
|
|
`render_structure`"). Partially **supersedes ADR-0016 §5** (the
|
|
plain-text `References:` / `Referenced by:` relationship block) and
|
|
**extends ADR-0016 §4 and §6** (adds layout width-awareness and
|
|
per-span styling). Builds on ADR-0028 (styled output runs),
|
|
ADR-0043 (compound, list-based relationship endpoints), ADR-0013
|
|
(named 1:n relationships), and the V5/V5a `show` family. Honours
|
|
ADR-0009 (DSL conventions) and ADR-0002 (no engine name in
|
|
user-facing strings).
|
|
|
|
Closes the substantive open half of requirement **V1**
|
|
(`docs/requirements.md`): "a selected relationship as two tables
|
|
joined by a line."
|
|
|
|
## Context
|
|
|
|
The table-structure half of V1 is done: `show table <T>` renders a
|
|
box-drawn structure table (columns / types / constraints / indexes),
|
|
and relationships appear **as prose** beneath it —
|
|
`References:` / `Referenced by:` blocks formatted `A.col → B.col`
|
|
(`output_render.rs render_structure`, per ADR-0016 §5). The same
|
|
prose appears in V5a's `show relationship <name>` detail view.
|
|
|
|
The open piece is the **visual** form: drawing a relationship as two
|
|
tables side by side joined by a connecting line, with cardinality and
|
|
referential actions. ADR-0016 deliberately deferred this (OOS-1) and
|
|
**pre-sized the structure renderer to compose two of itself**. This
|
|
ADR cashes that in.
|
|
|
|
Three facts from the current architecture shape the design:
|
|
|
|
1. **Rendering is App-side; the worker returns structured data.**
|
|
*(Corrected from the initial draft after direct verification — an
|
|
earlier survey had this backwards.)* The database worker (`db.rs`)
|
|
returns `TableDescription` / `DataResult`; the **App** (`app.rs`)
|
|
calls the `output_render.rs` helpers to format them into
|
|
`OutputLine`s. Verified: every `render_structure` /
|
|
`render_data_table` call site is in `app.rs` (557, 1669, 1732,
|
|
1752, 1814, 1678, …); **none in `db.rs`**. Width and theme
|
|
therefore live App-side. The **one exception** is the V5/V5a
|
|
`show <kind> [<name>]` family: `do_show_one` / `show_list` build
|
|
prose `Vec<String>` **in the worker** from `RelationshipSchema` /
|
|
index metadata, carrying *no* `TableDescription` — so
|
|
`show relationship <name>` is the path that must be restructured
|
|
(§6). The output buffer is a flat `VecDeque<OutputLine>` — a
|
|
historical log of lines, not re-renderable widgets (live
|
|
re-rendering is V4 territory).
|
|
2. **Relationships are list-based (ADR-0043).** `RelationshipSchema`
|
|
/`RelationshipEnd` endpoints are `Vec<String>` column lists,
|
|
positionally paired. Single-column FKs are the one-element case;
|
|
the diagram must render compound FKs too.
|
|
3. **Only 1:n relationships exist.** Relationships are declared 1:n
|
|
(ADR-0013); m:n (requirement C4) is unbuilt, and there is no
|
|
UNIQUE-target 1:1. So cardinality is always **1 on the parent
|
|
(referenced) side, n on the child (referencing/FK) side**.
|
|
|
|
The user has chosen the design direction across three decisions
|
|
(recorded below as made): **visual style**, **where it appears**, and
|
|
**multi-relationship layout**.
|
|
|
|
## Decision
|
|
|
|
### 1. Scope and trigger — diagrams where relationships are the subject
|
|
|
|
Relationship diagrams replace the prose relationship form on the
|
|
surfaces where **relationships are the subject of the command**; no
|
|
new command or sigil is added (ADR-0009: one sigil, keyword grammar).
|
|
This is the user-chosen **"relationship-relevant"** reach (over a
|
|
global replacement of every structure echo, or a show-commands-only
|
|
scope — see the DA pass).
|
|
|
|
Diagram surfaces:
|
|
|
|
- **`show relationship <name>`** (V5a) renders **one** diagram: the
|
|
parent and child tables as **full structure boxes** joined by a
|
|
connector. The canonical base unit.
|
|
- **`show table <T>`** keeps T's full structure box at the top
|
|
(unchanged from ADR-0016 §5), then a **Relationships** section:
|
|
**one compact connector diagram per relationship**, stacked
|
|
vertically (§4).
|
|
- **Relationship DDL auto-shows** — the structure echo after
|
|
`add 1:n relationship`, `drop relationship`, and a future
|
|
`modify relationship` (C3a) — render their relationships as
|
|
compact diagrams (§4), since the user just acted on a relationship.
|
|
|
|
Prose-retained surfaces (**unchanged** from ADR-0016 §5):
|
|
|
|
- **Incidental DDL auto-shows** — the structure echo after
|
|
`create table`, `add`/`drop`/`rename`/`change column`,
|
|
`add`/`drop index` — keep the terse `References:` /
|
|
`Referenced by:` prose. A simple `add column` on a heavily-related
|
|
table should not print a wall of diagrams.
|
|
|
|
So this **partially supersedes ADR-0016 §5**: the prose block is
|
|
replaced by diagrams on the relationship-subject surfaces and
|
|
retained on incidental ones. No information is lost on either —
|
|
relationship name, endpoints, cardinality, and `on delete` /
|
|
`on update` actions all appear in both forms.
|
|
|
|
Mechanically (§6) this is a **render mode** on `render_structure`
|
|
(`Diagram` vs `Prose`), selected by the calling command; the items/
|
|
side panel (`ui.rs render_items_panel`) is a navigation tree and is
|
|
untouched.
|
|
|
|
A future **user-configurable setting** (e.g. always-prose /
|
|
always-diagram / auto-by-width, for small-screen users) is a clean
|
|
follow-up and is **out of scope here** (OOS-7) — the per-command
|
|
default above is the v1 behaviour.
|
|
|
|
### 2. The base diagram — Style A (structure + connector)
|
|
|
|
A relationship diagram is two boxes plus a connector. Reading
|
|
convention, applied **uniformly** (this is what makes
|
|
multi-relationship lists scannable):
|
|
|
|
- **Child (FK holder) on the left, parent (referenced) on the
|
|
right.** The connector arrow always points **left → right**, in the
|
|
direction of the reference (child *references* parent).
|
|
- **Cardinality** sits at the connector ends: **`n`** at the child
|
|
(left) end, **`1`** at the parent (right) end.
|
|
- **Referential actions** (`on delete …`, `on update …`) label the
|
|
connector beneath the line. `no action` is shown verbatim
|
|
(ADR-0009 wording), abbreviated to the action keyword when space is
|
|
tight.
|
|
|
|
#### 2.1 Box anatomy — the table name must stand out
|
|
|
|
Every box (full or compact) carries the table name as a **bold title
|
|
row separated from the columns by a rule** (`├─┤`), styled in the
|
|
table-name theme class (§5). This directly addresses the requirement
|
|
that a name never read as just another column row.
|
|
|
|
Full structure box (used in `show relationship`): title row, then the
|
|
ADR-0016 column/type listing, with key markers (§2.2):
|
|
|
|
```
|
|
┌──────────────────────┐
|
|
│ orders │ ← bold title row (table name)
|
|
├──────────────┬───────┤
|
|
│ id (PK) │ int │
|
|
│ customer_id ●│ int │ ● marks the FK column in this relationship
|
|
│ total │ real │
|
|
└──────────────┴───────┘
|
|
```
|
|
|
|
Compact box (used in `show table`'s stacked list): title row, rule,
|
|
then **only the column(s) participating in this relationship** — the
|
|
focal table's full structure is already shown above, so the compact
|
|
box stays small and the focal table is not redrawn in full N times:
|
|
|
|
```
|
|
┌──────────────┐
|
|
│ orders │ ← bold title row
|
|
├──────────────┤
|
|
│ customer_id ●│ only the FK column(s) for this relationship
|
|
└──────────────┘
|
|
```
|
|
|
|
#### 2.2 Key markers
|
|
|
|
- The PK is annotated `(PK)` (consistent with the existing structure
|
|
view's constraint column).
|
|
- The **endpoint columns of *this* relationship** are marked with a
|
|
filled dot `●` adjacent to the column name — on the child FK
|
|
column(s) and the parent referenced column(s). The connector
|
|
attaches at these `●` rows.
|
|
|
|
#### 2.3 The connector (single-column)
|
|
|
|
`show relationship Customers_Orders` (child `orders.customer_id`
|
|
→ parent `customers.id`):
|
|
|
|
```
|
|
orders customers
|
|
┌──────────────────────┐ ┌─────────────────────┐
|
|
│ orders │ │ customers │
|
|
├──────────────┬───────┤ 1 ┌──●│ id (PK) │
|
|
│ id (PK) │ int │ │ ├─────────────┬───────┤
|
|
│ customer_id ●│ int │ n ───────────┘ │ name │ text │
|
|
│ total │ real │ │ email │ text │
|
|
└──────────────┴───────┘ └─────────────┴───────┘
|
|
on delete cascade · on update no action
|
|
```
|
|
|
|
**Connector routing.** The two `●` endpoint rows are generally at
|
|
different heights. The connector leaves the child box's right edge at
|
|
the child-`●` row, travels horizontally into a **gutter channel**
|
|
between the boxes, jogs vertically to the parent-`●` row, then enters
|
|
the parent box's left edge with an arrowhead. Box tops are aligned.
|
|
(Exact glyphs/spacing are pinned by insta snapshots in
|
|
implementation; the mockups here are representative, not normative.)
|
|
|
|
#### 2.4 Compound foreign keys (ADR-0043)
|
|
|
|
For an n-column FK, the n child `●` columns and n parent `●` columns
|
|
are each listed, and **one connector is routed per positional pair**.
|
|
A summary line states the pairing explicitly so it is unambiguous
|
|
even if the routed lines are visually close:
|
|
|
|
```
|
|
orders customers
|
|
┌──────────────────────────┐ ┌──────────────────────┐
|
|
│ orders │ 1 ┌●│ region (PK) │
|
|
├──────────────┬───────────┤ │ │ id (PK) │
|
|
│ cust_region ●│ text │ n ─────────┤ ├────────────┬─────────┤
|
|
│ cust_id ●│ int │ n ─────────┘ │ name │ text │
|
|
│ … │ … │ └────────────┴─────────┘
|
|
└──────────────┴───────────┘
|
|
(cust_region, cust_id) ──► customers.(region, id)
|
|
on delete cascade · on update no action
|
|
```
|
|
|
|
### 3. Width handling and the narrow-terminal fallback
|
|
|
|
The diagram is rendered **once, App-side, at the output-panel width
|
|
current when the command runs**. The `App` does **not** track the
|
|
panel width today — `note_output_viewport(visible_rows,
|
|
total_wrapped_rows)` records only row counts for scroll math
|
|
(verified; `App` has no width field). This ADR adds a
|
|
`last_output_width: u16` to `App`, set from `ui.rs` where the output
|
|
panel's `inner.width` is already computed (next to the existing
|
|
`note_output_viewport` call), with an `80` default before the first
|
|
render. The App-side render path then chooses layout per diagram:
|
|
|
|
- **Side-by-side** (§2) when both boxes plus the gutter fit the
|
|
available width.
|
|
- **Vertical stack** when they do not: parent box above, child box
|
|
below, connector running **downward** through a short vertical
|
|
channel, cardinality and actions labelling it. This keeps a real
|
|
diagram at any width instead of degrading to prose:
|
|
|
|
```
|
|
┌──────────────┐
|
|
│ orders │
|
|
├──────────────┤
|
|
│ customer_id ●│ n
|
|
└──────────────┘
|
|
│ on delete cascade
|
|
▼ on update no action
|
|
┌──────────────┐
|
|
│ customers │
|
|
├──────────────┤
|
|
│ id (PK)●│ 1
|
|
└──────────────┘
|
|
```
|
|
|
|
- **Last-resort helper — considered and rejected (2026-06-10,
|
|
implementation).** The draft proposed that, when even a single
|
|
*vertical* diagram cannot fit (a box wider than the pane), `show
|
|
table` emit a one-line `run `show relationship <name>`` pointer per
|
|
relationship. In implementation we **decided against it**: the
|
|
vertical fallback already covers every realistic narrow terminal,
|
|
and the only remaining case — a box wider than the *whole* pane —
|
|
requires an extreme combination (very long identifiers on a tiny
|
|
terminal) and is handled the same way as all other over-wide output
|
|
(ratatui's right-edge truncation, ADR-0016 §4). A dedicated pointer
|
|
would add a code path and a worse result (less information than even
|
|
a truncated diagram) for a near-unreachable case. `show relationship`
|
|
itself always renders the diagram; if its box is wider than the pane,
|
|
the same truncation applies — no new truncation logic.
|
|
|
|
**No live reflow.** Because the output buffer is a historical line
|
|
log, resizing the terminal *after* a diagram is rendered does not
|
|
reflow it — identical to how every other rendered output behaves
|
|
today. Reflow-on-resize belongs to V4's re-renderable journal and is
|
|
explicitly out of scope (OOS-2).
|
|
|
|
This **extends ADR-0016 §4**: that ADR added no width-awareness
|
|
(relying on ratatui truncation); this ADR adds width-awareness for
|
|
the **layout decision** only. It still performs **no per-cell
|
|
truncation** (ADR-0016 OOS-4 stands).
|
|
|
|
### 4. `show table` multi-relationship layout — stacked compact diagrams
|
|
|
|
After T's full structure box, a **Relationships** heading, then one
|
|
**compact** diagram (§2.1) per relationship, stacked vertically.
|
|
Ordering matches the current prose order: **outbound** (T is the
|
|
child — "References") first, then **inbound** (T is the parent —
|
|
"Referenced by"), each group ordered by relationship name. The
|
|
child-left/parent-right rule (§2) is applied per diagram, so the
|
|
focal table appears on the left for its outbound relationships and on
|
|
the right for its inbound ones — consistent with the reference
|
|
direction.
|
|
|
|
```
|
|
orders
|
|
┌──────────────┬──────┐
|
|
│ orders │ │
|
|
├──────────────┼──────┤
|
|
│ id (PK) │ int │
|
|
│ customer_id │ int │
|
|
│ total │ real │
|
|
└──────────────┴──────┘
|
|
|
|
Relationships
|
|
┌──────────────┐ n 1 ┌─────────────┐
|
|
│ orders │────────────────│ customers │
|
|
├──────────────┤ on delete ├─────────────┤
|
|
│ customer_id ●│ cascade │ id (PK) ●│
|
|
└──────────────┘ └─────────────┘
|
|
┌──────────────┐ n 1 ┌─────────────┐
|
|
│ order_items │────────────────│ orders │
|
|
├──────────────┤ on delete ├─────────────┤
|
|
│ order_id ●│ cascade │ id (PK) ●│
|
|
└──────────────┘ └─────────────┘
|
|
```
|
|
|
|
Stacking (rather than a single focal-centred subgraph with fan-out
|
|
connectors) is chosen because: it never produces crossing lines; it
|
|
scales to any number of relationships via the pane's existing
|
|
vertical scroll; each diagram is only two boxes wide, so it fits
|
|
nearly any terminal; and it keeps the per-diagram width logic of §3
|
|
trivial. The cost — the focal table name repeats per diagram — is
|
|
mitigated by the compact box showing only the participating
|
|
column(s).
|
|
|
|
### 5. Styling
|
|
|
|
Styling uses the **ADR-0028 styled-run mechanism** (`OutputSpan` /
|
|
`OutputStyleClass` on `OutputLine`), not raw text. New style classes
|
|
(theme-defined, legible light/dark per ADR-0016 §6 / NFR-7):
|
|
|
|
- **table name** — bold, accent colour (the "stand out" requirement);
|
|
- **key marker** (`●`, `(PK)`) — a distinct accent;
|
|
- **connector** (box-drawing line + arrowhead) — muted;
|
|
- **cardinality** (`1` / `n`) — emphasised;
|
|
- **referential action** label — muted/secondary.
|
|
|
|
This **extends ADR-0016 §6** (which set up `OutputKind::System`
|
|
styling but no per-element theming) by reusing the per-span
|
|
`OutputSpan` path ADR-0028 later introduced — which is **already
|
|
produced App-side** (`output_render.rs:299-332` builds styled runs
|
|
for the explain-plan tree; `app.rs` constructs `OutputLine`s with
|
|
`styled_runs: Some(..)`; `ui.rs:863` renders them). So **no
|
|
worker→UI contract change is needed**: the new `output_render`
|
|
diagram functions return styled lines directly on the App side
|
|
(§6).
|
|
|
|
### 6. Implementation
|
|
|
|
All rendering is **App-side** (per the corrected Context fact 1), in
|
|
`output_render.rs` (hand-rolled, ADR-0016 §7), returning styled
|
|
lines that `app.rs` pushes as `OutputLine`s with `styled_runs` set.
|
|
No worker `available_width` and no worker→UI contract change.
|
|
|
|
- **New renderer functions in `output_render.rs`**, composing the
|
|
existing box primitives and emitting styled spans (§5):
|
|
- `render_relationship_diagram(child, parent, rel, width, full) ->
|
|
Vec<OutputLine>` — `full` selects full vs compact boxes;
|
|
internally decides side-by-side vs vertical (§3) from `width`;
|
|
routes the connector(s) including compound pairs (§2.4).
|
|
- A shared helper for the box title row + key markers.
|
|
- The two call paths supply `width` from the new
|
|
`App::last_output_width` (§3).
|
|
- **`show table <T>` (already App-side).** The focal
|
|
`TableDescription` reaches `app.rs` and is rendered by
|
|
`render_structure` today. `render_structure` is refactored to emit
|
|
the focal structure box, then a **Relationships** section built
|
|
from the focal description's `RelationshipEnd`s (which already
|
|
carry neighbour table name + participating columns + cardinality +
|
|
actions — **enough for the compact box**; no neighbour
|
|
full-structure fetch needed). `render_structure` gains a
|
|
**relationship render mode** (`Diagram` | `Prose`); the caller
|
|
selects it (§1): `show table` and the relationship DDL echoes pass
|
|
`Diagram`, incidental DDL echoes pass `Prose`. The generic
|
|
`handle_dsl_success(command, description)` (`app.rs:1669`) already
|
|
has the `Command`, so the mode is a function of the command
|
|
variant; the incidental-only call sites (`app.rs:557/1732/1752/
|
|
1814`) pass `Prose`.
|
|
- **`show relationship <name>` (must be restructured).** Its
|
|
worker path `do_show_one` currently returns prose `Vec<String>`
|
|
from a `RelationshipSchema` only. To draw the **full** diagram the
|
|
App needs **both** endpoint `TableDescription`s. The relationship
|
|
detail reply is upgraded to carry the `RelationshipSchema` plus
|
|
both endpoints' `TableDescription`s (the worker already has
|
|
`do_describe_table`); the App renders the diagram. The
|
|
"No relationship named `X`." not-found line is preserved.
|
|
- **Self-referential FKs** (`parent_table == child_table`; supported
|
|
in the grammar): render as two boxes bearing the same table name
|
|
(child-left copy with the FK column, parent-right copy with the
|
|
referenced column), connector as usual — clearer than a self-loop
|
|
glyph in a TUI. Covered by a snapshot test.
|
|
- **Out of these surfaces:** the items/side panel (`ui.rs:582`
|
|
`render_items_panel`) is a navigation tree, not a relationship
|
|
view, and is unchanged.
|
|
- **Database engine name** never appears in any rendered string
|
|
(ADR-0002).
|
|
|
|
### 7. Testing
|
|
|
|
- **Insta snapshots** (Tier 2) pin exact rendered output for:
|
|
single-column 1:n (`show relationship`); compound FK; the
|
|
narrow-terminal vertical fallback; the last-resort helper line;
|
|
a self-referential FK; and a `show table` with both an outbound and
|
|
an inbound relationship (stacked compact list).
|
|
- **Unit tests** (`output_render.rs`): the side-by-side-vs-vertical
|
|
**width-threshold** decision at boundary widths; connector routing
|
|
for endpoints at differing row heights; compound-pair routing;
|
|
key-marker placement.
|
|
- **Tier-3 integration**: `show relationship <name>` and
|
|
`show table <T>` produce diagram output (not prose) end-to-end
|
|
through the worker.
|
|
- **Existing tests/code to update** (enumerated from a DA grep — the
|
|
supersession of ADR-0016 §5 is not abstract):
|
|
- `output_render.rs:121,135` — the `References:` / `Referenced by:`
|
|
prose-emitting code in `render_structure`;
|
|
- `output_render.rs:78` — the docstring deferral note (OOS-1);
|
|
- `output_render.rs:793` — unit test asserting `"Referenced by:"`;
|
|
- `src/snapshots/…render_structure_with_relationships.snap` — the
|
|
prose snapshot;
|
|
- `tests/it/walking_skeleton.rs:477,530` — integration asserts on
|
|
`"Referenced by:"` (and the comment at 433);
|
|
- `src/dsl/command.rs:984` — a comment referencing the prose (no
|
|
behaviour).
|
|
If the scope fork resolves to "all `render_structure` call sites,"
|
|
the DDL-echo snapshots for create-table / add-column / drop-index /
|
|
change-column auto-shows also churn — to be re-recorded with
|
|
`cargo insta`. No test is deleted to hide a regression; each change
|
|
is a deliberate format update.
|
|
|
|
### 8. Out of scope
|
|
|
|
- **OOS-1.** Live reflow-on-resize of already-rendered diagrams —
|
|
V4's re-renderable journal (requirement V4).
|
|
- **OOS-2.** Whole-database ER diagram / export (requirement V3).
|
|
- **OOS-3.** m:n relationships (requirement C4, unbuilt). Only the
|
|
existing 1:n form is rendered.
|
|
- **OOS-4.** ASCII fallback for terminals without box-drawing
|
|
(inherits ADR-0016 OOS-5).
|
|
- **OOS-5.** Per-cell colouring of column *data* values (ADR-0016
|
|
OOS-3 / NFR-5) — unrelated to relationship structure.
|
|
- **OOS-6.** Cell-level truncation with ellipsis (ADR-0016 OOS-4
|
|
stands).
|
|
- **OOS-7.** A user-configurable relationship-display setting
|
|
(always-prose / always-diagram / auto-by-width — useful for small
|
|
screens). The §1 per-command default is v1; the setting is a clean
|
|
later follow-up (user-flagged 2026-06-09).
|
|
|
|
## Consequences
|
|
|
|
- Requirement **V1** is fully satisfied: relationships render as
|
|
two-table connector diagrams in both `show relationship <name>`
|
|
(full) and `show table <T>` (stacked compact), superseding the
|
|
prose form.
|
|
- `output_render.rs` grows a relationship renderer that **composes**
|
|
the box primitives exactly as ADR-0016 anticipated; the worker→UI
|
|
show contract becomes styled-line-based, a small generalisation
|
|
reusable by other styled `show` output later.
|
|
- The worker gains an `available_width` input for `show` — the first
|
|
width-aware formatting in the codebase. The decision is a snapshot
|
|
at command time; no resize machinery is introduced.
|
|
- Compound FKs (ADR-0043) get their first dedicated visualization,
|
|
with explicit positional-pair labelling.
|
|
- The historical-log output model is preserved (no widget/reflow
|
|
model); V4 remains the home for a re-renderable journal.
|
|
- Box-drawing is required (no ASCII fallback), consistent with
|
|
ADR-0016.
|
|
|
|
## Devil's Advocate / runda pass (2026-06-09)
|
|
|
|
A planning-time DA pass (empirical, against the code) corrected three
|
|
foundational errors carried in from an initial code survey, and
|
|
surfaced one open fork:
|
|
|
|
1. **Rendering boundary was inverted** (fixed in Context 1 / §6):
|
|
`render_structure` / `render_data_table` run **App-side**
|
|
(`app.rs`), not in the worker. Rendering, width, and theme are all
|
|
App-side — simpler than the draft assumed.
|
|
2. **Width was claimed "already tracked"; it is not** (fixed in §3):
|
|
`note_output_viewport` records only rows. A new
|
|
`App::last_output_width` (set from `ui.rs`) is required.
|
|
3. **`show relationship <name>` renders prose in the worker** (fixed
|
|
in §6): `do_show_one` carries only a `RelationshipSchema`. The
|
|
detail reply must be upgraded to include both endpoint
|
|
`TableDescription`s for the full diagram.
|
|
4. **Styled-line contract was over-stated** (fixed in §5): styled
|
|
runs are already produced App-side (explain plan); no worker→UI
|
|
contract change.
|
|
|
|
**Resolved fork (user, 2026-06-09): "relationship-relevant" reach.**
|
|
Diagrams render on the surfaces where the relationship is the subject
|
|
(`show table`, `show relationship`, relationship DDL echoes);
|
|
incidental DDL echoes keep prose (§1) — avoiding a wall of diagrams
|
|
after an `add column`. A future user-configurable display setting is
|
|
noted as OOS-7. This also records V1's **deliberate scope expansion**
|
|
beyond its literal "a selected relationship" wording into
|
|
multi-relationship surfaces, to be reflected in `requirements.md`.
|
|
|
|
All design forks are now resolved and the architecture is corrected.
|
|
The user accepted this revised ADR on 2026-06-09; status is
|
|
**Accepted** and implementation proceeds test-first.
|