Settles the undo/snapshot half (U1/U2) before implementation: - every-mutation single-step undo (supersedes destructive-only model) - hybrid whole-project snapshot (db backup API + yaml/csv copy), reconciling ADR-0006 with ADR-0015's derived-db model - persisted N=50 ring; redo discarded on new work - batch ops (replay + future) record one undo step; import excluded - --no-undo disable switch Adds the implementation plan and updates README index, requirements U1/U2, and CLAUDE.md in lockstep.
28 KiB
RDBMS Playground — Requirements (Phase 1)
This document is the consolidated Phase 1 requirements
checklist for RDBMS Playground. It captures everything the
project has committed to so far, derived from the design
conversation and the ADRs in docs/adr/.
Purpose. Phase 5 verification at every milestone measures delivered work against this checklist. An item not on this list was not promised; an item silently dropped without confirmation is a process failure.
Scope. The list is intentionally coarse — each item is a unit of "satisfied / not satisfied" judgement. When an item is taken up for implementation, it is decomposed further in a backlog (initially in this repo, later in GitHub issues once the repo is pushed).
Status legend
[ ]— open, not yet implemented[x]— satisfied (implemented + tested)[~]— deferred, awaiting an ADR or further design before any implementation[-]— explicitly out of scope (rationale at the bottom)
Test baseline
After the ADR-0027 highlight / hint follow-up (precise WARNING
spans, the diagnostic overlay + hint wiring, the
LIKE-on-numeric WARNING, the debounce state machine) plus
two manual-testing bug fixes (optional trailing-flag
completion; the --resume temp-project pointer):
1131 passing, 0 failing, 1 ignored (cargo test — the one
ignored test is a long-standing ```ignore doc-test in
src/friendly/mod.rs). Clippy clean with the nursery lint
group enabled. (Earlier reference points: 1100 after ADR-0027's
initial ship; 1079 after ADR-0026 (complex WHERE expressions);
1039 after ADR-0025 (indexes); 1006 after ADR-0024 + the
handoff-14 cleanup; 449 after B2/C2.)
Distribution and install
- D1 Cross-platform binaries: Linux, macOS, Windows on x86_64 and aarch64.
- D2 Single static binary, no runtime dependencies.
- D3 Released via prebuilt binaries plus Homebrew, Scoop,
winget, andcargo binstall.
TUI shell
- S1 Three-region layout: items list (left), output panel (right), input field (bottom).
- S2 Items list shows tables and per-table indexes; designed to extend to additional element kinds (relations, views, etc.) without restructuring. (ADR-0025: the items panel renders a nested list — each table with its index names indented beneath it. The nested model is the extension point for future element kinds.)
- S3 Output panel renders a visualization of the currently selected item and supports multiple tabs.
- S4 Hint area below the input field; keyboard-toggleable for inspecting hints about the current input or last error.
- S5 Mode label and distinct border style on the input field communicate the current input mode at all times.
- S6 Input-field validity indicator: a debounced
[ERR]/[WRN]marker at the right edge of the input row, summarising — before submit — whether the current command would run. Backed by a walker diagnostics-severity model (ERROR / WARNING). Advisory only — never blocks submission. (ADR-0027:Severity/DiagnosticonWalkResult;input_verdictcombines the parse outcome, schema-existence ERRORs — unknown table / column — and the ADR-0026 §7 expression WARNINGs — type mismatch,= NULL. The runtime debounces the indicator's display ~1 s; the rightmost six columns of the input row are reserved unconditionally. Newwarningtheme colour. A follow-up pass completed §2's highlight + hint wiring — diagnostics overlaid on the input field and surfaced in the hint panel, with precise per-literal WARNING spans — and Amendment 1 adds aLIKE-on-numeric-column WARNING.)
Input field
- I1 Multi-line entry that auto-expands; Ctrl-Enter (or equivalent) submits, plain Enter inserts a newline.
- I1a In-line cursor editing in the input field: Left / Right arrows move the cursor by character (UTF-8 boundaries honoured), Home / End jump to the extremes, Delete removes the character at the cursor, Backspace removes the character before. Insertion happens at the cursor position. (Implemented; multi-line editing per I1 still pending.)
- I1b Readline-style cursor shortcuts: Ctrl-A / Ctrl-E as aliases for Home / End for users on keyboards without those keys (and for ergonomics in command-driven workflows). Likely followed by Ctrl-W (delete previous word), Ctrl-K (delete to end), Ctrl-U (delete to start). Pending.
- I2 Persistent navigable input history (project-scoped).
(Implemented across Iterations 2 + 6: per-command append to
history.log(Iter 2); on project open, the in-memory navigable history is hydrated from the tail ofhistory.logup to the same in-memory cap (Iter 6). Global rolling history is out of scope per OOS-6 / N4.) - I3 Tab completion for app commands, DSL keywords, table names, column names, and SQL keywords.
- I4 Syntax highlighting for both the DSL and SQL.
- I5 In-flight query/command cancellation (Ctrl-C in the output area or input field).
Input modes (per ADR-0003)
- M1 Simple mode is the default. It accepts DSL data commands and the canonical app-level commands; raw SQL is rejected with a friendly hint.
- M2 Advanced mode accepts SQL plus the canonical app-level commands without any sigil.
- M3 Prefixing a single line with
:in simple mode is a one-shot advanced escape (with the prompt label updated). Themode simple/mode advancedcommand switches modes persistently. - [~] M4 Execution-time mode side-channel — deferred, awaiting
its own ADR (ADR-0033 Amendment 3). Every command should know, at
execution time, which of three modes it ran under —
simple,advanced, oradvanced-one-shot(the:escape) — so execution can adjust output without changing command identity (e.g. a simple-modecreate tableechoing the generated SQL when run in advanced mode, silent in simple). Today only the rendering side-channel exists (OutputLine.mode_at_submission); theModeenum is two-way, the one-shot distinction is collapsed at submission, and neitherAction::ExecuteDslnor the worker carries any mode. The work widensModeto three-way and threads it through theAction→ worker interface. Not required for Phase 3 dispatch correctness; tracked here so it is not lost.
App-level commands (per ADR-0003)
- A1 All canonical app-level commands implemented and
available in both modes:
save,save as,load,new,rebuild,export,import,seed,replay,undo,redo,mode,help,hint,quit. (Progress:quit/q,mode simple|advanced,help,save,save as,load,new,rebuild,export,import,replayall implemented (Iterations 4 + 5;replayvia ADR-0024 Phase E — see U4).seedin the seeding iteration;undo/redoin the U-series;hintwith H2.)
DSL data commands
- C1 Table operations: create / drop / rename. (Progress: create + drop done; rename pending.)
- C2 Column operations: add / drop / rename / change
type.
drop columnandrename columnuse SQLite native ALTER TABLE (3.35+ / 3.25+);change columnroutes through the rebuild-table primitive since ALTER doesn't support type changes. PK and relationship-involved columns are refused with friendly messages (drop the relationship first); SQLite STRICT enforces type compatibility on the data copy during a type change. - C3 Schema constraints: primary key (single and
compound), foreign key with
ON DELETE/ON UPDATEreferential actions, indexes,NOT NULL,UNIQUE,CHECK,DEFAULT. (PK including compound done at create-table time; FK withON DELETE/ON UPDATEactions done (ADR-0013) — declared viaadd 1:n relationship; symmetric outbound + inbound view in the structure renderer; type compatibility validated at declaration viaType::fk_target_type(). Indexes done (ADR-0025) —add index/drop index, rebuild-preserving, persisted inproject.yaml.NOT NULL/UNIQUE/CHECK/DEFAULTdone (ADR-0029) — a constraint suffix oncreate table/add column, plusadd constraint/drop constrainton existing columns; populated-column additions are guarded by a pre-flight dry-run that refuses with a table of offending rows.) - [~] C3a Modify relationship:
modify relationship <name> [on delete <action>] [on update <action>]. Users can achieve the same via drop + add today; one-step modify is a small follow-up using the existing rebuild-table machinery. ADR pending. - C4 Convenience:
create m:n relationship from <T1> to <T2>produces an auto-named junction table the user can rename; pulls primary keys and FK definitions automatically. - C5 Data operations: insert / update / delete via DSL.
(ADR-0014. INSERT short and long forms, UPDATE/DELETE with
required WHERE plus
--all-rowsopt-in,show data <T>, per-column-type value-literal validation, FK enforcement with metadata-driven error enrichment, auto-show after writes. Bulk insert, complex WHERE expressions, and SELECT in advanced mode are explicitly tracked separately — see C5a below.) - C5a Complex WHERE expressions (AND/OR, comparison
operators, LIKE, IS NULL, IN, BETWEEN) for UPDATE/DELETE/
show-data filtering;
show dataalso gainswhereandlimit. (ADR-0026 steps 1–4: the stratified expression grammar reached through a newSubgrammarnode, the recursiveExprAST +build_expr, wiring into update / delete / show data, andExpr→ parameterised SQL with an implicit primary-keyORDER BYforlimit. Type-mismatched WHERE comparisons are permissive — they run rather than being rejected (§7). The §7 advisory flagging of type mismatches /= NULLis the seam with ADR-0027's diagnostics-severity model and is tracked there — see ADR-0026 "As-built notes".)
SQL handling
- Q1 SQL parsed via
sqlparser-rs; supported subset is defined (specifics deferred to a future ADR). (Progress: SQL handling in advanced mode is still a placeholder echo. The architecture is now decided — ADR-0030: SQL is authored as grammar within the unified grammar tree (ADR-0024) and parsed by the existing walker, not a separate batch parser — so SQL gets the same completion / highlighting / hints as the DSL. ADR-0001'ssqlparser-rsreservation is superseded. Implementation is phased and pending.) - Q2 Non-standard syntax rejected with a clear message pointing at the supported subset. (Design done — ADR-0030 §8: out-of-subset statements are refused with an engine-neutral message naming the construct. Implementation pending.)
- Q3 User-facing simplified types map transparently to SQLite STRICT types in generated DDL. (All ten types implemented and tested.)
- Q4 Supported SQL subset specification — ADR-0030.
Advanced mode is a standard-SQL surface, engine-neutral; the
supported surface —
SELECT(full query surface),INSERT/UPDATE/DELETE,CREATE/DROP/ALTER TABLE,CREATE/DROP INDEX— is authored as grammar in the unified tree. DDL routes through the typedCommandexecutor (metadata + the playground type vocabulary preserved); DML andSELECTexecute as validated SQL. Q1's implementation is now unblocked.
Database backend (per ADR-0002)
- B1 SQLite via
rusqlite; all tables createdSTRICT;PRAGMA foreign_keys = ONper connection. (Database accessed through a dedicated worker thread per ADR-0010.) - B2 Schema evolution uses the rebuild-table technique
internally where SQLite
ALTER TABLEcannot — currently the change-column-type code path. Add-column, drop-column, and rename-column take the simpler ALTER TABLE route since modern SQLite supports them natively; metadata sync into__rdbms_playground_columnsand__rdbms_playground_relationshipshappens in the same transaction either way. - B3 Query timeout and cancellation supported (no cartesian-join-of-doom can hang the app). (Progress: the worker-thread architecture is in place; the cancellation/timeout protocol on top of it is pending.)
Type system (per ADR-0005)
- T1 All ten user-facing types implemented:
text,int,real,decimal,bool,date,datetime,blob,serial,shortid. (Mapping to SQLite STRICT covered by ADR-0005; FK target type rule by ADR-0011.) - T2
shortidgeneration: base58, 10–12 characters, omits ambiguous characters; generated client-side at insert. (Implemented per ADR-0014; auto-fills omitted shortid columns and validates user-supplied values against the same alphabet and length range.) - T3 Compound primary keys handled end-to-end (DSL,
storage, display, FK reference).
(Progress: DSL grammar (
with pk a(int),b(int)), storage, and table-info description are all present; the FK iteration references single-column PKs only — compound-key FK references remain pending.)
Visualizations
- V1 Single-element views render in the output pane: a selected table as its structure (columns, types, keys, constraints); a selected relationship as two tables joined by a line. (Progress: a basic structure view (column rows with SQLite type names) is rendered after each successful DDL; pretty rendering, selection nav, and relationship line-art pending — see V4 for the broader direction.)
- V2 SQL query results render as a dynamic table view in
the output pane, with multiple result tabs supported.
(Progress: a basic aligned-column data view is rendered for
show dataand after every write (ADR-0014). Pretty box-drawing tables with truncation/scroll handling, plus multi-tab support, remain in V4 territory.) - [~] V3 Full ER-diagram export (whole-database graph, viewed outside the TUI) — low priority; design and ADR pending.
- [~] V4 Output panel as a scrollable per-session log with inline rich rendering. Direction agreed in conversation: the output area is a chronological journal of operations and selections (e.g. a "selected table X" entry with the rendered structure underneath); structure renderings choose between a compact ASCII-table form and a vertical line-per-column form based on dimensions; the log is exportable to Markdown so learners can keep a record of their session. Design and ADR pending before any implementation. (Partial: PageUp / PageDown scrolling of the existing line buffer is in, with new output snapping the view to the most recent. The full V4 scope — smart structure rendering, log styling, Markdown export, scroll indicator — remains pending.)
- V5
show <kind> [<name>]family of commands for redisplaying schema info on demand. (Progress:show table <name>andshow data <Table>implemented;show tables,show relationships, etc. pending.)
Project lifecycle (per ADR-0004)
- P1 Auto-named temp project on startup under
<data-root>/projects/. OS-standard data root viadirectoriescrate;--data-diroverrides (Iteration 1). - P2
save/save aselevate / copy + switch (Iteration 4b).saveon a named project reports "already auto-saved". - P3 Auto-save: per-command write-through to YAML +
CSV +
history.loginside the SQLite tx with commit-db-last ordering (Iteration 2). No dirty state. - P4
loadopens an in-TUI picker, sorted newest first, with[TEMP]markers and ab-to-browse path-entry sub-mode (Iteration 4b). - P5 Existence-only load + explicit
rebuildcommand with confirmation modal (Iterations 3 + 4a). - P-NAME-1 Temp project directory naming pattern:
<YYYYMMDD>-[temp]-<word>-<word>-<word>from a 161-word built-in list (Iterations 1 + 4b). Bracketed[temp]marker is unambiguous against user-named projects becausevalidate_user_namerejects brackets. - P-NAME-2 Display-name prettifier strips
YYYYMMDD-AND[temp]-; splits kebab / snake / camel; title-cases each word. - P-NAME-3 Status bar shows
Project: [TEMP] <name>for temp projects,Project: <name>for named. - P-CLEAN-1 Unmodified empty temp projects are
auto-deleted on switch and quit, gated by
safely_delete_temp_project's stacked guards (containment, symlink rejection,[temp]marker, contents allowlist).
Project file format (per ADR-0004)
- F1
project.yamlwithversion: 1field carries schema (ordered tables + columns), relationships, andcreated_at.data/<table>.csvcarries table data (UTF-8, header row, RFC 4180; NULL distinct from empty string) (Iteration 2). Empty tables produce no CSV. - F2
.gitignoretemplate (/playground.db,/.rdbms-playground.lock,/project.yaml.v*.bak) created in each new project (Iteration 1). Per ADR-0007 amendment 1,history.logis NOT in the template — user decides whether to commit it. - F3 Migration framework scaffold (Iteration 6).
MigratorRegistry+migrate_to_latest+ensure_project_yaml_migratedare wired into every project open; no migrators registered in v1 (the production registry is empty). The framework is exercised by tests that inject a fake v1→v2 migrator: registry plumbing,.v<N>.bakbackup, version-bump sanity check, and newer-than-supported / malformed-version errors are all covered. The first real migrator (when v2 ships) is a one-file change.
Undo and replay (per ADR-0006)
- U1 Auto-snapshot before every data/schema mutation
(DSL + SQL) into a persisted ring buffer (size N=50, tunable),
per ADR-0006 Amendment 1 (single-step undo, superseding the
original destructive-only model). Snapshot is a hybrid
whole-project copy (database via online backup API +
project.yaml/data/*.csvas files); staged before the mutation's transaction, finalised after the db commit (preserves ADR-0015 §6). A batch command (replay/ future batch ops) records one boundary snapshot;importtakes none. A--no-undoCLI flag disables snapshotting. (Designed + amended + planned indocs/plans/20260524-adr-0006-undo-snapshots.md; not yet implemented.) - U2
undorestores the most recent snapshot (database + text, directly);redore-applies (redo stack discarded on new work); both prompt for confirmation naming the command being undone / re-applied (Yconfirms). (Designed + amended; not yet implemented — see U1's plan.) - U3
history.logrecords every submitted command in append-only form, tagged with its outcome (Iteration 2; broadened by ADR-0034). Format:<ISO-8601 Z>|<status>|<source>per ADR-0015 §5 / ADR-0034 §1 —statusisokfor a successful command anderrfor one that failed to parse or execute. Hydration (cross-session recall) reads all records; replay readsokonly. - U4
replayruns commands from ahistory.logor.commandsfile. (Implemented via ADR-0024 Phase E:runtime::run_replayparses each non-blank, non-#-comment line in advanced mode and dispatches it through the normal pipeline; stops at the first genuine error, no rollback. ADR-0034 §3: replay reads journal records (<ts>|<status>| <source>), runningokrecords and skipping non-ok, while still accepting bare-command scripts. ADR-0034 Amendment 1: replay re-applies only schema/data write commands and skips every app-lifecycle command + nestedreplay— all skips continue (a nestedreplayis now skipped, not refused), with a[skip]warning onimport/ nested-replay. Covered bytests/replay_command.rs.)
Sharing and export (per ADR-0007)
- E1
exportproduces a zip excludingplayground.dbANDhistory.log(per ADR-0007 amendment 1); default filenameYYYYMMDD-<projectname>-export-NN.zipwith a non-clobbering two-digit sequence under the active data root (Iteration 5). The zip preserves the project's directory name as a single top-level folder.import <zip> [as <t>]is the inverse: derive target name from the zip's top folder, auto-suffix-NNon collision (ADR-0015 §11 amendment), rebuild from text on open. - E2 User documentation includes sharing recipes for git, email, and direct file transfer.
Sample data / seeding
- SD1
seed <table> [count]generates plausible fake data; junction tables are seeded with valid foreign-key references drawn from existing parent rows. - [~] SD2 Detailed seeding rules (per-type generators, locale, determinism, override hooks) — design and ADR pending.
Query analysis
- QA1
EXPLAIN QUERY PLANis run on demand for queries; output is rendered as an annotated tree highlighting full scans, index use, and join order. (Implemented per ADR-0028: theexplainprefix overshow data/update/delete, with a span-styled plan tree.EXPLAIN QUERY PLANnever executes, so explaining a destructiveupdate/deleteis safe.) - QA2 Plan rendering specifics — tree layout, annotation
taxonomy, colour scheme. Implemented per ADR-0028 (§3–§6):
a box-drawing tree, the substring-pattern taxonomy, and the
OutputLinestyled-runs mechanism.
Hints, help, errors
- H1 Friendly error-rewriting layer translates SQLite error messages into learner-friendly equivalents. (Progress: foreign-key constraint failures are enriched with both inbound and outbound relationship listings (so RESTRICT errors point at the children that still reference this table); full SQL → English translation pending.)
- H1a Strong syntax-help in parse errors. When the user
types something near-correct (e.g.
insert into T ('Oli')— forgottenvalues; orupdate T set x=1— missing WHERE), the error should name the missing keyword or clause rather than just point at the unexpected character. This is a separate effort from H1 (which targets database errors); it targets parser errors. Pending — multiple targeted fixes shipping piecemeal so far (e.g.valuesbecoming optional in INSERT removes one such case; ADR-0024's typed value slots give per-column-type rejection wording;insert into T (col)with novaluesclause now flags "looks like Form A — addvalues (...)"). A systematic pass is still pending. - H2
hintprovides contextual help for the current input or the most recent error. - H3
helpprovides general reference and per-command help. (Progress: thehelpcommand lists currently-supported commands + DSL grammar reference + types. As of ADR-0024 §help_id it is assembled by iterating the command REGISTRY and translating eachCommandNode.help_id, so a new command appears automatically. A general reference andhelp <command>-style detailed per-command help are still the missing pieces.)
CLI
- L1 Load a project via a positional CLI argument
(Iteration 1). Plus
--data-dirto override the data root and--help/-hfor the usage banner. - L1a
--resumeCLI flag opens the most recently used project (path tracked in<data-root>/last_project). Iteration 6: errors cleanly with a stderr banner above the shell prompt if no previous project is recorded or the recorded path is gone — no silent fallback; mutually exclusive with a positional path argument (ADR-0015 §7).last_projectis rewritten on every successful project open (startup, load, new, save as, import). - [~] L2 Submit a command alongside project load — deferred, not v1.
Tutorials and lessons
- [~] TU1 Tutorial / lesson system — design and ADR pending before any implementation. Out of v1 unless an ADR is written.
Documentation
- DOC1 User- and student-facing reference
documentation under
docs/: the DSL command surface, the type system, and the boundaries of simple mode.docs/simple-mode-limitations.mdis the first piece — it doubles as student explanation and as detailed reference. Distinct from in-apphelp(H3), the interactive tutorial system (TU1), and the sharing recipes underE2.
Testing (per ADR-0008)
- TT1 Tier 1:
cargo test+proptestcovering pure-logic modules (parser, dispatcher, type mapping, project I/O, snapshot ring buffer, replay log). - TT2 Tier 2: Ratatui
TestBackend+instasnapshots for representative views. - TT3 Tier 3: synthetic event-loop integration tests covering the user-facing flows in this checklist.
- TT4 Tier 4: PTY-based end-to-end for the four critical flows named in ADR-0008 (cold launch → DDL → quit; save → reopen; export → import → rebuild; undo after DROP).
- TT5 CI runs all tiers on Linux, macOS, and Windows on stable Rust.
Cross-cutting
- X1 Comprehensive logging via the project's logging
infrastructure per
CLAUDE.md(decision points, parameter values, fallback paths). - [~] X2 Language: English-only for v1; multi-language is an open question to revisit later.
- [~] X3 Accessibility: TUI screen-reader support is best-effort and not a v1 commitment; revisit if user need emerges.
Non-functional requirements
NFRs are quality bars rather than discrete features. Where a target is measurable, it is stated numerically; where it is necessarily qualitative, the criterion is named and the bar is "reviewer judgement against the criterion."
- NFR-1 Performance — startup. Cold launch to first rendered frame under 500ms on commodity hardware (developer laptop, mid-range desktop). Measured in CI on the Linux runner as a regression gate.
- NFR-2 Performance — input latency. Keystroke-to-render latency under 16ms during normal editing; long-running queries must execute off the UI thread so the interface remains responsive (typing, scrolling, mode switching) while a query is running.
- NFR-3 Performance — resource footprint. Idle memory under 50MB on the smallest target platform; no busy-loops; CPU near zero when waiting for input.
- NFR-4 Visual quality — distinctive design. Colour palette and typography are deliberate and consistent across views; layout uses Unicode box-drawing and symbols where they add clarity; rendering avoids the generic flat-default look that ships with most TUI frameworks. Criterion: a reviewer can identify the app from a screenshot of any view.
- NFR-5 Visual quality — colour use. Colour conveys information rather than decoration: mode indication, query result types (numeric vs text vs null), error severity, syntax highlighting categories. Foreground/background combinations meet WCAG-AA contrast (4.5:1 for normal text) even though we have not committed to broader accessibility.
- NFR-6 Cross-platform parity. Behaviour and visual quality are equivalent across Linux, macOS, and Windows on crossterm-supported terminals. Platform-specific divergence (e.g. font fallbacks) is documented, not silently tolerated.
- NFR-7 Light and dark background support. The colour scheme remains legible and visually coherent on both light and dark terminal backgrounds. The mechanism (auto-detect via terminal query, explicit user setting, or both) is an implementation choice, but the outcome is non-negotiable: no dark-on-dark or light-on-light readability failures on either background.
Explicitly out of scope
- [-] N1 Hosted publishing platform — per ADR-0007. Sharing is local-artifact based.
- [-] N2 Real UUID column type — per ADR-0005. The
shortidtype covers the pedagogical need at TUI-friendly width. - [-] N3 Cross-emulator visual regression coverage — per ADR-0008. Crossterm abstracts terminals adequately; we revisit only if a real regression surfaces.
- [~] N4 Global rolling input history (cross-session,
cross-project). Mentioned in I2's wording; deferred per
ADR-0015 §12 — project-scoped history (via
history.log) is the v1 surface. Revisit if real demand emerges.
Maintenance
This document is updated whenever:
- A new requirement is committed to (added as a new item with the next free ID in its section).
- A deferred item is taken up (status moves from
[~]to[ ]). - An item is satisfied (status moves to
[x], with a reference to the commit, PR, or test that demonstrates it). - An item moves out of scope (status moves to
[-]with a rationale and a link to the decision).
IDs are stable: once assigned, they are not reused. Removing a requirement leaves a "withdrawn" entry referencing the decision.