Wardian docs

ADR-2610080900: a suite is made of small parts

Status: Accepted Date: 2026-10-08 Drivers: The user: "we need to do a better job of splitting the app into components the splunk app looks like one big window." The Splunk table suite has one app, table: one 650-line app.js and one card that holds the search form, the AI helper, the saved lists, the facts, the filter, the table, the pager and the buttons. Arrange (SPEC.md 6.11) can do nothing with it, because there is only one panel. Make an app produces the same shape when nothing tells it otherwise.

Context#

A suite already gives each part its own frame, its own panel and its own contract, and Arrange lets each viewer reorder, move and hide panels. The loan planner shows the intended shape: inputs in the aside, a summary, a chart and an export each in their own main card, and an engine with no view. The Splunk table never used it: it was written as one page and moved into a suite unchanged.

The user's working copy (data/apps/splunk-table) and the repository copy have drifted apart: the working copy has Save search and Save table with a list of saved items; the repository copy has the background-job resume (ADR-2610072118). Each app's storage is kept per part name (state/apps/<package>.json → {<part>: {...}}), and the user's saved searches and tables live under table.

Decision#

  1. The Splunk table becomes five parts, each with one job and its own card:

    PartSlotJobContract (outline)
    searchasideStart from, words to find, the search, time range, name, Run, progress, Save search, saved searches; runs the search as a job and resumes itcaps storage, splunk, db; emits table:ready (retain); listens search:use
    askasideClaude writes the searchcaps splunk, claude:sample; emits search:use
    aboutmainWhat the table is: name, rows, time range, when, the searchlistens table:ready
    rowsmainFind in results, sort, the table, pagercaps db; listens table:ready; emits table:view (retain: the filter and sort)
    keepmainSend to other apps, Download CSV, Save table, saved tablescaps storage, db, claude:downloads; channel sends splunk.table; listens table:ready, table:view; emits table:ready when a saved table is opened

    The outline may change where the code shows a better cut, within these rules: one job per part, no part's app.js over 250 lines (claim_example_parts_stay_small; ADR-2610081041), results never wait on a hidden panel, and the message on splunk.table stays as it is so the USL lab keeps working.

  2. Both copies' features survive. The new suite has Save search, Save table and the saved lists from the working copy, and the job resume from the repository copy.

  3. No saved data is lost. When the user's copy is replaced, the entries under table in state/apps/splunk-table.json move to the parts that now own them, after a backup. A part that finds the old shape in its own storage reads it.

  4. Make an app splits by default. Its instructions say: build a suite when the app has more than one job; one part per job (inputs, each view of the result, each export); inputs in aside, results in main; no part over 250 lines. The rustle-app-factory skill says the same.

  5. wardian check warns about one big part. A suite app whose app.js is over 400 lines, or a suite with one view part whose view.html holds more than one <h2>, gets a warning that names the parts it could split into.

Consequences#

Implementation#

Enforced-By: hexa adr gates (run on demand)#

Gate#

env CARGO_TARGET_DIR=target/verify cargo test --release check

Rerun by hexa adr gates. The Splunk browser test (tests/run-splunk-e2e.sh) covers the app itself.

References#

This page is docs/adrs/ADR-2610080900-a-suite-is-made-of-small-parts.md in the repository. Something wrong or missing? Change that file.