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:
- which repository owns each behavior now;
- whether the extracted API is neutral and reproducible;
- 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:
| Artifact | Contents | Gate |
|---|---|---|
public-api.txt | donor public item paths/signatures | no unclassified item |
consumer-map.tsv | file, crate, imported item, interaction surface | no unknown caller |
extraction-ledger.csv | item/module, decision, target owner, dependencies, tests, docs, reviewer | every row decided |
story-manifest.json | story ID, component, dimensions, fixture, product terms | every moved story is neutral |
render-manifest.json | SVG/hash/size and buffer fixture hashes | baseline reproducible |
dependency-tree.txt | normal/all-feature dependency trees | no hidden product/runtime dependency |
provenance.toml | donor URL, revision, retained paths, filter command, license decision | independently reviewed |
compatibility.toml | Rust, Ratatui core, Crossterm, OS, consumer revision | every advertised cell tested |
quality-backlog.md | known rendering defects carried bug-compatible through extraction | every 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 — points at a lookbook binary and in-crate story module that no longer exist, and the crate root documents a COMPONENTS.mdTheme 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:
- 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.
- 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
termrockas its own reviewed change with regenerated fixtures and a migration note afterjackin❯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 notesNo 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
- terminal text sanitization and display-column slicing;
- logical keys, modifiers, keymaps, and action/hint descriptors;
- focus and hover ownership;
- scroll axes, offsets, cursor following, and scrollbar geometry;
- generic responsive rectangles and hit-test primitives;
- 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 mergeDuring 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:
| Consumer | Files |
|---|---|
jackin-console | 105 |
jackin-capsule | 42 |
jackin-launch-tui | 26 |
root jackin package | 11 |
jackin-console-oppicker | 4 |
jackin-runtime | 2 |
jackin-diagnostics | 2 |
jackin-core | 2 |
jackin-host | 1 |
This is a file-reference inventory, not an estimate of edit size. Use it to order migration:
- migrate lower-level
jackin-core/runtime definitions and remove dependency inversion; - migrate the lookbook and launch TUI as bounded consumers;
- migrate console-op-picker and product-local picker facades;
- migrate the host console in vertical slices by shared component family;
- migrate Capsule after raw-byte-to-logical-key and bottom-chrome parity is explicit;
- 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
| Concern | Evidence before move | Evidence after move |
|---|---|---|
| exact cells/styles | Ratatui TestBackend fixtures | same buffer assertions |
| browser preview | 29 committed donor SVGs | neutral external SVG + product-local compositions |
| key dispatch | keymap unit tests and hint derivation | logical action + adapter contract tests |
| focus/hover | interaction unit tests | component state and hit-test parity |
| Unicode | display-column tests | narrow/wide/grapheme corpus |
| resize | current layout/render fixtures | min/normal/wide plus zero/tiny-area no-panic tests |
| terminal cleanup | mode/guard tests | partial-init, explicit restore, drop fallback, PTY tests |
| process policy | rich-surface/diagnostics tests | remains entirely in jackin❯ |
| OSC 8/22/52 output | raw overlay bytes emitted post-frame by host loops | typed osc regions/requests with pure-encoder unit tests and layout-derived region parity |
| dependency graph | donor Cargo tree | no product, Tokio, or Crossterm in base graph |
| feature additivity | no equivalent donor boundary | same component inventory and buffer hashes with/without crossterm; only integration API is added |
| docs | jackin❯ generic lookbook pages | external 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
NOTICEattribution ship in the repository and package artifacts; TermRock'sREUSE.tomlnames 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
termrockbuilds with no product, Tokio, or Crossterm dependency. - Every component and logical interaction API builds without features; enabling
crosstermadds 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-coreor 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-tuiandjackin-tui-lookbookare 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
mainprotection 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.