ResearchShared TUI Extraction

08 - Migration Evidence And Gates

08 - Migration Evidence And Gates

The migration should be driven by checked artifacts rather than a sequence of manual copy-and-fix changes. The donor and target repositories need evidence that answers three questions at every stage:

  1. which repository owns each behavior now;
  2. whether the extracted API is neutral and reproducible;
  3. whether jackin❯ still renders and behaves the same before local code is deleted.

Freeze artifacts

Create these generated, reviewable artifacts on the single jackin❯ implementation branch before filtering history:

ArtifactContentsGate
public-api.txtdonor public item paths/signaturesno unclassified item
consumer-map.tsvfile, crate, imported item, interaction surfaceno unknown caller
extraction-ledger.csvitem/module, decision, target owner, dependencies, tests, docs, reviewerevery row decided
story-manifest.jsonstory ID, component, dimensions, fixture, product termsevery moved story is neutral
render-manifest.jsonSVG/hash/size and buffer fixture hashesbaseline reproducible
dependency-tree.txtnormal/all-feature dependency treesno hidden product/runtime dependency
provenance.tomldonor URL, revision, retained paths, filter command, license decisionindependently reviewed
compatibility.tomlRust, Ratatui core, Crossterm, OS, consumer revisionevery advertised cell tested
quality-backlog.mdknown rendering defects carried bug-compatible through extractionevery defect listed with a post-parity fix note; none fixed silently

The repository need not preserve these exact filenames forever, but each field and gate needs one machine-readable owner. Generation commands should be checked into the extraction plan or xtask; do not rely on a research-session shell history.

Freeze has two prerequisites inside the donor repository. First, wire the lookbook SVG drift check (tui-lookbook --check) into jackin❯ CI: today it is only a documented CLI command, so the 29 committed SVG fixtures are not mechanically proven current, and unverified fixtures cannot serve as parity evidence. The job is added on the implementation branch and attached to the existing required aggregator, so it runs on every PR push and becomes durably required at merge without a separate branch-protection change. Second, correct the stale donor documentation — COMPONENTS.md points at a lookbook binary and in-crate story module that no longer exist, and the crate root documents a Theme type that was never implemented.

Parity-first sequencing and the quality backlog

Two gates would otherwise conflict: jackin❯ migration requires byte-identical rendering, while per-component conformance requires display-width correctness and non-color cues that the donor demonstrably violates today (character-count width math in hint spans, select-list labels, the status-footer right group, and error-dialog wrapping; a color-only panel focus border). The resolution is explicit sequencing:

  1. Extraction tier — required before the first consumer pin. Neutral naming, no product dependency, borrowed render data, stable IDs, no-panic tiny/empty rectangles, documented public items, neutral stories, and deterministic renders. Known rendering defects are carried through unchanged and bug-compatible.
  2. Quality tier — required before the first tag. Display-width correctness everywhere, non-color focus/selection/error cues, and any later non-blocking rendering defect admitted through the reviewed re-freeze protocol below. Each backlog item lands in termrock as its own reviewed change with regenerated fixtures and a migration note after jackin❯ parity passes; jackin❯ adopts it through a deliberate revision repin that reviews the visual diff.

During extraction and migration no rendering-behavior fix may ride along silently: a parity diff that traces to an unrecorded "improvement" fails the gate, and the quality backlog artifact is the only permitted list of deferred fixes.

If implementation discovers a security defect, data-loss path, or panic on a documented valid input after freeze, the same branch returns to Stage 0, fixes the donor, regenerates the affected fixtures/inventories, and freezes a new baseline before extraction resumes. A newly discovered non-blocking rendering defect is added to the reviewed quality backlog and carried through parity. This is an evidence reset inside the one implementation PR, not permission for a silent TermRock-only fix or a second PR.

Classification rules

Each public item receives one of four decisions:

  • extract: product-neutral implementation and contract move with history;
  • parameterize: implementation moves only after product data, text, theme, or runtime policy becomes an input;
  • remain: behavior belongs to jackin❯ or another consumer;
  • remove: redundant compatibility export or unused API has no future owner.

The ledger also records:

current Rust path
current source file and last meaningful donor commit
all direct consumer files
normal and feature-gated dependencies
I/O, executor, global-state, or product-vocabulary flags
unit/render/PTY tests
component docs and lookbook stories
target module and proposed public name
semver and behavior notes

No module is moved wholesale merely because most of it is neutral. crates/jackin-tui/src/geometry.rs, for example, contains reusable display-column/tab geometry and a product-specific agent-name helper. crates/jackin-tui/src/components/container_info.rs contains reusable detail-row/hit-test mechanics and a DebugInfo builder that encodes containers, agents, roles, and jackin versions.

Refactoring order

Refactor in the dependency direction so a high-level widget never becomes the accidental owner of a lower-level primitive.

Batch A - foundations

  1. terminal text sanitization and display-column slicing;
  2. logical keys, modifiers, keymaps, and action/hint descriptors;
  3. focus and hover ownership;
  4. scroll axes, offsets, cursor following, and scrollbar geometry;
  5. generic responsive rectangles and hit-test primitives;
  6. semantic theme and the Tailrocks phosphor preset.

These packages have the smallest behavioral surface and unlock removal of the five current jackin_core reference lines in the donor, measured with rg -n jackin_core on 2026-07-15.

Batch B - leaf widgets

Move simple buffer-rendering components first: panel, modal backdrop, hint bar, button/action strip, toast, and tabs. Convert them to the one stable widget convention and remove public duplicate render_* wrappers.

Batch C - stateful widgets

Move scrollable lists, select list, text input (including the filter composition/preset), dialogs, status slots, detail table, and diff view after the foundation API is exercised. This is where stable IDs, borrowed row models, configurable labels, external validation/filtering, Unicode cursor rules, and explicit state mutation must be resolved. No separate public FilterField or modal stack/router is introduced.

Batch D - terminal and lookbook adapters

Move the partial-init-safe Crossterm session, event conversion, story protocol, terminal browser, SVG backend, and catalog generator. The lookbook is a consumer of public termrock; it must not access crate-private widget helpers just to produce previews.

Batch E - consumer-only composition

Keep or rebuild locally:

  • jackin❯ wordmark and launch/closing animations;
  • container/debug information constructors;
  • exit/data-loss confirmation wording;
  • Capsule menu/status policies and host ownership atomics;
  • role, mount, source, scope, agent, workspace, and OnePassword components;
  • direct output, diagnostics routing, URL-opening, OSC emission policy, and async task spawning.

History extraction

Prepare the repository through a history-preserving path filter, then make debranding and API cleanup as new reviewable commits before the first external source push. Retain the complete history of the two donor crate paths plus exact, path-complete generic lookbook documentation, committed SVG seeds, relevant design files, and the root LICENSE/NOTICE. Do not filter a mixed jackin-core file to capture individual helpers: move or reimplement the neutral code in a new signed commit and record its source file, donor revision, and meaningful source commit in provenance.toml. The neutral bootstrap retains the applicable donor notice, may relocate the license text under LICENSES/, and creates a TermRock-specific REUSE.toml rather than inheriting jackin❯'s broad package annotation.

git-filter-repo is the maintained history-rewriting tool referenced by the plan. Run it on a dedicated clone, never on the active jackin workspace. Verify authors, timestamps, file licenses, source-revision mapping, secret scan, binary-size scan, and retained paths before publishing. Historical donor commits may contain product vocabulary and may not build outside the former monorepo; the first published TermRock head and API must be neutral, standalone, and green. Publish only main, never donor branches or tags, and treat the first TermRock tag in Stage 5 as the only initial release tag.

Imported commits are provenance and are not retroactively DCO-signed. provenance.toml records the inherited boundary; every new TermRock-authored commit after that boundary must carry DCO sign-off and build independently. Create the public GitHub repository empty and do not push the raw filtered tip. The first push contains inherited history plus the reviewed neutralization/bootstrap commits, with the scanned buildable commit as the visible main head.

No TablePro, TablePlus, Zedis, or other reference-project source belongs in this history. Those projects may inform product concepts in other repositories; termrock contains only Tailrocks-owned/donor code and compatible dependencies with reviewed licenses.

Cross-repository change graph

one jackin implementation branch + PR (open through every stage)
        |
        +--> local filtered history -> neutral standalone bootstrap
        |                                  |
        |                                  v
        |                      first/direct-main green checkpoints
        |                                  |
        |                                  v
        |                           immutable TermRock revisions
        |                                  |
        +<--------- exact `rev` repins -----+
        |
        v
jackin migration commits -> parity -> donor/docs deletion
        |
        v
TermRock first tag -> roadmap retirement -> one jackin PR merge

During this roadmap, every jackin❯ checkpoint points at the tested full TermRock main commit in Cargo's rev field and commits Cargo.lock. It never follows mutable main or a feature branch. Cargo's Git dependency syntax supports exact revisions; that revision is the reviewed build identity. Branch and fork iteration is a post-bootstrap workflow documented in chapter 03.

Do not add pub use termrock::* as a compatibility facade in jackin-tui, and do not retain duplicated types under old paths. jackin is pre-release: migrate each consumer batch to the new owning path, then remove the corresponding donor item in the same implementation branch. The old donor can coexist only for not-yet-migrated modules, with no type duplicated across both ownership boundaries. These batches are commits in the one PR, not separate PRs.

jackin❯ migration slices

On 2026-07-15 at donor revision 33896a504e19ef13adb8692550c1845cb86a9504, rg -l jackin_tui --glob '*.rs' found 195 consumer files outside the donor/lookbook. Grouping paths by workspace package produced:

ConsumerFiles
jackin-console105
jackin-capsule42
jackin-launch-tui26
root jackin package11
jackin-console-oppicker4
jackin-runtime2
jackin-diagnostics2
jackin-core2
jackin-host1

This is a file-reference inventory, not an estimate of edit size. Use it to order migration:

  1. migrate lower-level jackin-core/runtime definitions and remove dependency inversion;
  2. migrate the lookbook and launch TUI as bounded consumers;
  3. migrate console-op-picker and product-local picker facades;
  4. migrate the host console in vertical slices by shared component family;
  5. migrate Capsule after raw-byte-to-logical-key and bottom-chrome parity is explicit;
  6. remove the donor crates only when the inverse dependency query is empty.

Capsule keeps its locally painted status bar and hand-painted hint rows through migration: it re-implements tab painting today because the donor widget lacks per-tab state glyphs and click regions. The shared Tabs/HintBar contracts carry those capabilities precisely so Capsule can converge, but convergence is a tracked post-parity follow-up, never a migration requirement.

Each slice pins a tested termrock revision and runs the whole workspace because changing public Ratatui types can surface failures outside files that import jackin_tui directly.

At every stage boundary, compare the frozen donor revision with current origin/main. Before final donor deletion and again before the implementation PR merges, merge current origin/main with the normal non-rewriting merge-sync policy. If upstream touched a donor module, consumer, fixture, dependency cell, or canonical TUI document, regenerate the affected inventory/parity evidence and port the change to its decided owner before advancing.

No slice merges early. The single implementation PR remains the review surface for the cumulative migration, while its commit sequence preserves bounded review and rollback points.

Parity matrix

ConcernEvidence before moveEvidence after move
exact cells/stylesRatatui TestBackend fixturessame buffer assertions
browser preview29 committed donor SVGsneutral external SVG + product-local compositions
key dispatchkeymap unit tests and hint derivationlogical action + adapter contract tests
focus/hoverinteraction unit testscomponent state and hit-test parity
Unicodedisplay-column testsnarrow/wide/grapheme corpus
resizecurrent layout/render fixturesmin/normal/wide plus zero/tiny-area no-panic tests
terminal cleanupmode/guard testspartial-init, explicit restore, drop fallback, PTY tests
process policyrich-surface/diagnostics testsremains entirely in jackin❯
OSC 8/22/52 outputraw overlay bytes emitted post-frame by host loopstyped osc regions/requests with pure-encoder unit tests and layout-derived region parity
dependency graphdonor Cargo treeno product, Tokio, or Crossterm in base graph
feature additivityno equivalent donor boundarysame component inventory and buffer hashes with/without crossterm; only integration API is added
docsjackin generic lookbook pagesexternal catalog paths and component coverage

Every render fixture needs a stated purpose. Byte-identical parity is expected during the jackin❯ ownership migration. Intended visual changes occur only in later, explicit quality-fix commits in the same implementation PR after parity passes, never hidden inside the ownership move.

Performance gates

Record a baseline before changing data ownership:

  • clean/default and all-feature compile time;
  • first interactive lookbook frame;
  • render time and allocations for tabs, 10/1,000/100,000-row list projections, long Unicode labels, and large diffs;
  • SVG catalog generation time and output size;
  • terminal restore latency and failure behavior.

The new public component API should allow visible-window projection rather than require cloning every row per frame. Benchmark regressions are advisory during initial neutralization, then become budgeted once jackin❯ parity is established. A faster implementation is not accepted if it changes clipping, selection, focus, or key behavior without a separate decision.

Completion gates

External repository ready

  • Provenance and REUSE checks pass for every extracted and generated file.
  • The Apache license text and applicable original donor NOTICE attribution ship in the repository and package artifacts; TermRock's REUSE.toml names the new package and only its actual files.
  • The public repository contains only main; the first visible head was neutral, standalone, scanned, and buildable, with inherited commits separated from new DCO-signed commits by the recorded provenance boundary.
  • Base termrock builds with no product, Tokio, or Crossterm dependency.
  • Every component and logical interaction API builds without features; enabling crossterm adds only event/backend/session convenience and preserves canonical renders.
  • Every public item is documented and present in the reviewed API report.
  • Every public component has neutral unit, buffer, story, SVG, docs, and edge-state coverage.
  • Render generation is byte-deterministic.
  • Default, all-feature, feature-powerset, MSRV, macOS, and Linux checks pass; Windows is neither advertised nor required by this revision line.
  • Partial terminal initialization and restoration paths pass PTY tests.
  • The quality backlog is recorded and untouched: no listed defect fixed before jackin❯ parity, and no unlisted rendering change present.
  • A minimal external program builds from a full Git revision.

jackin❯ donor retired

  • The 195-file consumer inventory is regenerated and no old import remains.
  • No neutral helper remains duplicated in jackin-core or a product crate.
  • Console, Capsule, launch, picker, modal, mouse, Unicode, SVG, and terminal cleanup parity passes.
  • Product-specific widgets and policies have an explicit local owner.
  • Generic docs/previews point to the external catalog; product decisions remain in jackin docs.
  • jackin-tui and jackin-tui-lookbook are deleted only after the above checks.

Program complete

  • The compatibility matrix records the exact jackin❯ and TermRock revisions plus reproduction commands and results.
  • No other Tailrocks product repository was checked out, patched, built, validated, migrated, or released by this roadmap.
  • Every quality-backlog fix (display width, non-color cues) landed with regenerated fixtures and a migration note before the first tag.
  • The first tag has semver, package, docs, license, and jackin❯ compatibility evidence.
  • The first tag is the committed API baseline; automated semver comparison starts with subsequent candidates.
  • TermRock main protection is enabled after the final bootstrap checkpoint, before this roadmap closes.

These gates make repository extraction reversible until the donor deletion, while preventing an indefinite dual implementation after ownership changes.

On this page