# 05 - Decision Record (https://jackin.tailrocks.com/reference/research/shared-tui-extraction/05-decision-record/)



# 05 - Decision Record [#05---decision-record]

Every decision in this chapter is closed. The remaining work is execution: the delivery checklist implements these decisions, and nothing below waits on an unanswered design question. Reopening an entry requires a new operator decision recorded here — the plan itself carries no open questions.

## Decisions at a glance [#decisions-at-a-glance]

| Decision                    | Outcome                                                                                                                                                        |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Product shape               | independent Rust component/design project                                                                                                                      |
| Donor                       | neutral portions of `jackin-tui` and `jackin-tui-lookbook`                                                                                                     |
| License                     | Apache-2.0 with preserved history/attribution                                                                                                                  |
| Renderer                    | Ratatui only; Crossterm backend where needed                                                                                                                   |
| First consumer              | `jackin❯` compatibility migration                                                                                                                              |
| Other consumers             | separate future work; not touched or validated by this roadmap                                                                                                 |
| Domain boundary             | no product models, effects, persistence, secrets, or telemetry ownership                                                                                       |
| Component graduation        | second concrete consumer or clearly foundational primitive                                                                                                     |
| Project identity            | `termrock`                                                                                                                                                     |
| Repository                  | `tailrocks/termrock`                                                                                                                                           |
| Packages and CLI            | `termrock` and `termrock-lookbook`                                                                                                                             |
| Documentation               | same-repository Fumadocs catalog backed by committed CLI-generated SVG previews                                                                                |
| Initial consumption         | Git dependencies are sufficient; crates.io publication is optional                                                                                             |
| Durable dependency identity | full commit revision or immutable release, never a moving branch head                                                                                          |
| Terminal baseline           | modern truecolor terminals (Ghostty-class); the library ships no capability-degradation paths                                                                  |
| Extraction sequencing       | bug-compatible extraction and byte-identical `jackin❯` parity first; recorded quality fixes land afterwards                                                    |
| Runtime contracts           | executor-neutral update/view/subscription contracts and the frame driver live in a base module that is optional by use; Tokio integration stays consumer-local |
| Component scope             | the existing donor component set only; new components are explicit post-extraction roadmap work                                                                |
| Text editing                | extended grapheme-cluster boundaries plus standard `unicode-width` display columns                                                                             |
| Path display                | environment-aware helpers remain in `jackin-core`; TermRock owns no `$HOME` or path policy                                                                     |
| Delivery unit               | one future `jackin❯` branch and PR for the whole roadmap; TermRock bootstrap commits go directly to its `main`                                                 |
| Delivery scope              | TermRock creation/extraction plus `jackin❯` migration only                                                                                                     |
| Repository launch           | public, empty `tailrocks/termrock`; publish only `main`, after the standalone neutral head passes pre-publish review                                           |
| Inherited history           | preserve path-level donor provenance; product terms may exist in inherited snapshots, never in the first advertised TermRock API/head                          |
| Initial API dispositions    | phosphor is the default theme; filter is a `TextInput` composition; no shared modal stack; logical scroll units use `usize`                                    |
| First tag                   | the reviewed API report becomes the first semver baseline; comparisons begin after that tag                                                                    |

## Naming [#naming]

The approved lowercase project name is `termrock`. It identifies the Ratatui library, lookbook CLI, generated visual catalog, and Fumadocs site without embedding `jackin❯` or implying a general-purpose non-terminal UI framework.

```text
Repository: tailrocks/termrock
Core crate: termrock
Lookbook:   termrock-lookbook
CLI:        termrock-lookbook
Descriptor: Ratatui components, lookbook, and documentation for Tailrocks applications
```

Alternatives considered were `Tailrocks TUI`, `Clast TUI`, `Quarry TUI`, and `Rockface`. `termrock` provides a distinct identity while still signaling terminal use and its Tailrocks origin.

GitHub's repository search (`termrock in:name`) and `cargo search termrock` on 2026-07-15 found no exact repository or crate match. Namespace state is time-sensitive, so Stage 0 revalidates both names and records the intended owners immediately before creation or publication. This evidence is not trademark advice: the operator records the trademark disposition before public launch. A dedicated domain is not an initial requirement because the catalog is hosted with the repository.

## 1. Git dependency and publication policy [#1-git-dependency-and-publication-policy]

**Decision:** during this roadmap's bootstrap, the single `jackin❯` PR always pins a tested TermRock `main` commit through Cargo's `rev` dependency form and commits <RepoFile path="Cargo.lock" />; it never follows a branch. After bootstrap, a consumer may use a trusted branch or fork only while iterating on a shared fix, then pins the tested full commit SHA before the consumer change becomes durable. After upstream merge, temporary fork commits are repinned to the canonical repository. An immutable Git revision is the adoption artifact for the `jackin❯` migration; a crates.io preview is optional, and registry publication happens only through a separate operator decision. Untrusted forks, floating default branches, and automated branch advancement are rejected dependency forms.

## 2. Lookbook CLI command contract [#2-lookbook-cli-command-contract]

**Decision:** `termrock-lookbook` exposes explicit `terminal`, `list`, `render`, and `check` operations. Donor flag behavior is preserved only while validating extraction parity, then removed. The pre-release external project carries no indefinite compatibility shim.

## 3. Tokio and the runtime module [#3-tokio-and-the-runtime-module]

**Decision:** no Tokio anywhere in the shared crate. Build the base library on `ratatui-core`; every component, state, logical input, focus, layout, and outcome remains available without features. The additive `crossterm` feature supplies event conversion, backend construction, and optional managed-session convenience without changing those base APIs. Ship no Tokio feature.

The executor-neutral runtime contracts — `Dirty`, `UpdateResult`, `SubscriptionPoll`, the `Subscription` trait with std-channel and closure adapters, `Component`, and `View` — plus the persistent `drive_frame` and one-shot closure-based `drive_render` drivers extract into the ordinary base `runtime` module. It is optional by use, not a Cargo feature: no widget depends on it, no application pattern must adopt it, and compiling it adds no executor dependency. Both drivers are pure Ratatui and use the same canonical draw path; `drive_render` is the bounded adapter for short-lived modal/prompt renderers rather than a second application loop. `jackin❯`'s canonical TUI rules mandate one shared frame driver across the console, Capsule, and launch surfaces, and deleting the donor would otherwise strand these drivers in a new product-local crate. Tokio receiver implementations, spawn helpers, and the fallback runtime stay in `jackin❯` with `jackin-console` as the target home. One coherence corner case is settled up front: after extraction a consumer crate cannot implement the shared `Subscription` trait directly for Tokio receiver types (foreign trait, foreign type), so the shared module ships a subscription closure adapter and consumers may additionally wrap receivers in local newtypes.

## 4. Brand API [#4-brand-api]

**Decision:** consumer-provided product name/mark/header data plus a shared default phosphor theme. Component semantics stay consistent without pretending every product is `jackin❯`. No fixed Tailrocks header ships in the library; `jackin❯` composes its wordmark locally.

## 5. History tooling [#5-history-tooling]

**Decision:** run [`git-filter-repo`](https://github.com/newren/git-filter-repo) on a dedicated clone and retain the complete history of the two donor crate paths plus exact, path-complete neutral documentation, preview assets, and the root Apache `LICENSE`/`NOTICE` files. Path filtering cannot preserve selected functions from a mixed file or make every historical snapshot product-neutral. Inherited commits under the donor paths may therefore contain historical `jackin❯` vocabulary; product neutrality is a requirement of the first advertised TermRock head and public API, not a claim about rewritten historical snapshots.

Do not filter a mixed `jackin-core` file merely because some functions move. Move or reimplement those neutral helpers in new DCO-signed TermRock commits and record their source file, donor revision, and meaningful source commit in `provenance.toml`. The first neutral bootstrap may relocate the Apache text to `LICENSES/Apache-2.0.txt`, but it retains a root `NOTICE` containing the applicable original donor notice plus any TermRock notice, and creates a TermRock-specific `REUSE.toml` rather than copying `jackin❯`'s repository-wide annotation. Record the exact filter command and retained paths, scan the filtered history for secrets, incompatible licenses, oversized binaries, and reference-project source, and publish only TermRock `main`: donor branches and tags are not pushed. No source from TablePro, TablePlus, Zedis, or another reference project enters the repository.

## 6. Testing crate [#6-testing-crate]

**Decision:** no `termrock-testing` crate. Lookbook and conformance helpers stay internal to the two initial crates. A public testing crate is created only when two consumers demand the same stable helper API, and that creation is a new recorded decision — not a pending question in this plan.

## 7. Compatibility matrix and MSRV [#7-compatibility-matrix-and-msrv]

**Decision:** exactly one tested Rust/Ratatui/Crossterm cell per revision line, aligned with the active `jackin❯` migration. The initial cell is fixed from the donor lock: `ratatui` 0.30.2 for the lookbook/application examples, `ratatui-core` 0.1.2 for the component crate, `ratatui-crossterm` 0.1.2 and `crossterm` 0.29.0 for the optional adapter. The core manifest feature is exactly `crossterm = ["dep:crossterm", "dep:ratatui-crossterm"]`; it must not introduce a second Crossterm or Ratatui core version. MSRV starts at `jackin❯`'s current floor (Rust edition 2024, `rust-version = "1.95"`, toolchain pinned to `1.97.0`); lowering the floor for a future consumer is a normal reviewed change under Cargo's rust-version rules, not a pending question. MSRV and supported platforms are published explicitly in the repository and catalog.

## 8. Theme stability [#8-theme-stability]

**Decision:** `Theme` uses private storage with a builder and documented per-token defaults, so no consumer initializes every token. For the initial revision line, `Theme::default()` and a new builder both resolve to `Theme::tailrocks_phosphor()`; this preserves donor rendering and makes the Tailrocks visual vocabulary the convenient shared default without embedding a product wordmark or domain token. Consumers may choose or override another theme explicitly. Changing a default token is a reviewed behavioral/API change with regenerated renders and a migration note. Adding an optional/defaulted token is a minor change; removing a token or changing its semantic meaning is breaking. No trait with one required method per token.

## 9. CI platform contract [#9-ci-platform-contract]

**Decision:** one Linux lane owns canonical render generation and all Rust quality/supply-chain gates. The optional Crossterm compile/behavior surface runs on Linux and macOS, the immediate Tailrocks targets. Windows is excluded from the support statement and CI; adding it later is a new operator decision, and until then the project does not advertise Windows support.

## 10. API stability baseline [#10-api-stability-baseline]

**Decision:** review and commit a generated public API report before the first immutable consumer pin. The first Git tag establishes the initial automated semver baseline; there is no nonexistent prior release to compare that tag against. `cargo-semver-checks` becomes required for every subsequent candidate against the latest tag, and every later public change carries an API diff and migration note. Pre-1.0 versioning allows deliberate breaks; it does not permit accidental root re-export or feature churn.

## 11. Build caches [#11-build-caches]

**Decision:** start minimal — warmed Cargo registry, offline compile jobs, one pinned Rust target cache per meaningful lane, Bun/Lychee download caches, and pull-request cache cleanup. Collect clean/warm timings for at least 20 runs; add `sccache` only when measurements show material benefit — an operational tuning step, not an open design point. Cache entries contain no secrets and generated previews remain artifacts, never caches.

## 12. Terminal capability baseline [#12-terminal-capability-baseline]

**Decision:** Tailrocks products run on modern terminals, and the library is allowed to require one. `termrock` assumes a Ghostty-class terminal: 24-bit truecolor SGR, alternate screen, SGR mouse reporting, OSC 8 hyperlinks, OSC 22 pointer shapes, and OSC 52 clipboard write. Components emit truecolor styles unconditionally and expose typed OSC requests as first-class data.

Out of library scope by decision: 256/16-color degradation, `NO_COLOR` handling, light-background adaptation, and RTL/BiDi text shaping. A consumer that needs any of these implements it above the library; `termrock` carries no capability-detection or fallback code. The supported-terminal statement is published in the repository README and the component catalog. Terminal *size* is not a capability assumption: tiny and empty rectangles remain valid, panic-free inputs.

## 13. Parity and quality sequencing [#13-parity-and-quality-sequencing]

**Decision:** parity wins first, quality wins second. Extraction is bug-compatible: every known rendering defect — character-count width math in hint spans, select-list label measurement, the status-footer right group, and error-dialog wrapping, plus the color-only panel focus border — is recorded in a freeze-time quality backlog and carried through extraction and migration unchanged. After `jackin❯` parity passes, each fix lands in `termrock` as its own reviewed change with regenerated fixtures and a migration note, and `jackin❯` adopts it through a deliberate revision repin that reviews the visual diff. Conformance gates split into an extraction tier (required before the first consumer pin) and a quality tier (required before the first tag).

The freeze is not permission to preserve a newly discovered security defect, data-loss path, or panic on a documented valid input. Such a blocker returns the same implementation branch to Stage 0: fix the donor, regenerate the evidence and quality backlog, and re-freeze before extraction continues. A newly discovered non-blocking visual defect is added to the reviewed backlog and carried through parity. No issue changes bytes silently, and this protocol does not create another PR. See [08 - Migration evidence and gates](/reference/research/shared-tui-extraction/08-migration-evidence-and-gates/).

## 14. Ratatui/Crossterm upgrade propagation [#14-ratatuicrossterm-upgrade-propagation]

**Decision:** `termrock` always upgrades first. Because the public API exposes `ratatui-core` types, every Ratatui minor bump is a breaking `termrock` change: after bootstrap it lands on a `termrock` branch with regenerated fixtures and a migration note, produces a new immutable revision, and `jackin❯` repins as the compatibility oracle. Future consumers follow the same library-first rule when they adopt through separately scoped work. No consumer upgrades Ratatui ahead of `termrock`, and `termrock` supports exactly one Ratatui/Crossterm pair per revision line.

## 15. Maintenance and issue routing [#15-maintenance-and-issue-routing]

**Decision:** the same operator maintains both repositories under the inherited governance and solo-maintainer review model. A defect reproducible with a neutral story or fixture is a `termrock` issue; anything requiring product state, wording, or effects is a consumer issue; cross-repository reports link both sides. The model is revisited only when contribution volume justifies more structure.

## 16. Text editing and display width [#16-text-editing-and-display-width]

**Decision:** text-input cursor movement, backspace, delete, selection boundaries, and horizontal-window boundaries operate on Unicode extended grapheme clusters. Store cursor positions as byte offsets that are always validated against extended-grapheme boundaries obtained through [`unicode-segmentation`](https://docs.rs/unicode-segmentation/latest/unicode_segmentation/trait.UnicodeSegmentation.html); never expose scalar-value or byte stepping as user-visible editing behavior. Measure painted columns with [`unicode-width`](https://docs.rs/unicode-width/latest/unicode_width/trait.UnicodeWidthStr.html) over whole grapheme/string slices using the standard non-CJK width policy, matching the fixed Linux render authority. Insertion accepts valid UTF-8 at a grapheme boundary, and tests cover combining marks, emoji ZWJ sequences, emoji modifiers, regional indicators, CJK wide characters, zero-width characters, and clipping at both ends of the viewport.

This closes the text-editing policy choice in the component catalog. Grapheme boundaries preserve what users perceive as one editable character, while display-column width remains a separate rendering concern.

## 17. API finalization and path helpers [#17-api-finalization-and-path-helpers]

**Decision:** the module boundary and API invariants in chapters 06 and 09 are fixed, while exact Rust type/function names and non-compatibility dependency patch versions not already fixed by Decision 7 are finalized during Stage 2's generated public-API review. That review may improve illustrative names and signatures but cannot add product models, a required application framework, another default feature, hidden I/O, or a second rendering path. This is bounded implementation finalization rather than an open architecture decision.

`shorten_home` remains in `jackin-core`: it reads `$HOME`, is consumed by non-TUI command formatting, and represents application path-display policy. Remove the `jackin-tui` re-export during migration. TermRock's `text` module remains limited to terminal text geometry and sanitization and never reads process environment or interprets filesystem paths.

## 18. Single-PR delivery topology [#18-single-pr-delivery-topology]

**Decision:** after this planning PR merges, implementation of the roadmap uses one new `jackin❯` feature branch and one pull request from start to finish. Stages 0 through 5 are ordered commit/checkpoint groups inside that branch, not separately merged PRs. The PR remains open until the external repository, complete extraction, `jackin❯` migration, donor deletion, deferred quality fixes, documentation transfer, and every completion gate are finished. No partial roadmap implementation merges early, and the roadmap is retired only in the final commits of that same PR.

TermRock is the explicit cross-repository exception during this bootstrap program. If `tailrocks/termrock` does not exist, the implementation creates it as an empty public repository without a generated README, license commit, donor tag, or secondary branch. The dedicated extraction clone first prepares inherited history and new neutralization commits locally. Only after the standalone neutral head passes the history/license/secret scan and local build does the implementation push `main`; it does not expose a raw filtered donor tip as the repository head.

Inherited donor commits are provenance: they may not build outside the former monorepo and are not retroactively given DCO trailers. Every new TermRock-authored commit after the recorded provenance boundary is DCO-signed, buildable, and reviewable. Those commits and every later refactoring/docs/CI checkpoint push directly to TermRock's `main`, without a TermRock pull request; each pushed head must pass the checks available at that checkpoint. No force push or published-history rewrite is allowed after the initial history-preserving push. Component source, story, SVG, and documentation changes remain atomic within the same new TermRock commit. After the final tag/checkpoint, enable normal protected-branch/pull-request governance before this roadmap closes.

The `jackin❯` implementation branch always depends on a full TermRock commit through Cargo's `rev` form and commits <RepoFile path="Cargo.lock" />. It may advance that revision repeatedly while the single PR is open, but it never follows mutable TermRock `main`. Every repin records which TermRock checkpoint it consumes and reruns the whole `jackin❯` workspace/parity gates.

No other Tailrocks product participates in delivery. Holla, Velnor, Parallax, TableRock, and future consumers may explain neutral API constraints, but the implementation does not check out, patch, build, validate, migrate, or release those repositories. Their adoption requires separately scoped future work after this roadmap closes.

## 19. Initial component dispositions [#19-initial-component-dispositions]

**Decision:** the initial public surface has no unresolved either/or components. The donor `filter_input` becomes a documented composition/preset over `TextInput`; TermRock does not publish a separate `FilterField` type. TermRock extracts `Backdrop`, generic dialog geometry, and pure inside/outside hit classification, but no modal stack, parent-chain lifecycle, or application router. Host color discovery remains entirely in `jackin❯`. Logical scroll offsets, lengths, and indices use `usize`; render code clips in logical space, then converts terminal geometry through one centralized saturating `u16` helper at the Ratatui edge, never wrapping, silently truncating, or exposing parallel integer APIs. Exact Rust names may still improve during the bounded Stage 2 API review without changing these dispositions.

## 20. Long-running branch drift [#20-long-running-branch-drift]

**Decision:** the single implementation PR may not freeze an obsolete donor. At every stage boundary, compare its recorded donor revision with current `origin/main`. Before final donor deletion and again before merge, merge current `origin/main` into the implementation branch using the repository's normal merge-sync policy. If upstream changed a donor module, consumer, fixture, dependency cell, or canonical TUI document, regenerate the affected inventory and parity evidence and port that change to the correct owner before advancing. A conflict is resolved in the implementation branch; it does not create a second extraction PR or permit an old donor change to disappear.

## 21. First-tag handoff [#21-first-tag-handoff]

**Decision:** Stage 5 creates the first annotated `v0.y.z` tag only after all recorded quality fixes are in TermRock and the `jackin❯` branch has passed the complete suite against that exact commit. `jackin❯` remains pinned by full `rev`; the tag is a release marker and future semver baseline, not a reason to change dependency form inside the migration. The compatibility record names the unmerged but tested `jackin❯` commit and reproduction commands. After the tag, TermRock branch protection is enabled, then the final `jackin❯` commits retire the roadmap and the one PR may merge. `cargo-semver-checks` comparisons begin with changes after this tag.
