From 5b681aa677b840e077a3f4e88914ac2e3feb7cf3 Mon Sep 17 00:00:00 2001 From: Yunfei He Date: Sat, 30 May 2026 16:56:49 +0800 Subject: [PATCH] =?UTF-8?q?chore(parity):=20close=20out=20the=20Ink-parity?= =?UTF-8?q?=20loop=20=E2=80=94=20reconcile=20ledger,=20record=20stop=20dec?= =?UTF-8?q?ision=20(#66)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 13 mediums fixed+merged across sweeps 1-10 (G32, G33, G39, G44, G45, G46, G52, G58, G59, G63, G64, G68) plus the ~22 earlier gaps. Maintainer paused the open-ended loop at diminishing returns: latest sweeps surface byte-level/ edge-case divergences (G68 ANSI order is visually identical; G67 refuted as an unavoidable Vue-vs-React semantic). Open mediums G69/G70 and the LOW tail are recorded but deferred by decision. Co-authored-by: Claude Opus 4.8 --- .agents/docs/parity-ledger.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.agents/docs/parity-ledger.md b/.agents/docs/parity-ledger.md index 99327e1..d2530a4 100644 --- a/.agents/docs/parity-ledger.md +++ b/.agents/docs/parity-ledger.md @@ -21,6 +21,8 @@ Refuted (NOT gaps): ~~`exit()` second-wins — vue-tui is already guarded~~ **REVERSED by sweep-4: it IS last-wins vs Ink first-wins → now tracked as G33**; kitty key-release printable-text suppression — Ink behaves the same. +> **🛑 LOOP STOPPED by maintainer (2026-05-30) — diminishing returns.** 13 mediums fixed+merged (G32, G33, G39, G44, G45, G46, G52, G58, G59, G63, G64, G68 — plus the ~22 earlier gaps G01–G05, G08–G23). The high-value, user-visible parity is done. The maintainer paused the open-ended "run until a sweep is medium-clean" loop after observing that the latest sweeps surface byte-level / edge-case divergences (e.g. G68 ANSI nesting order is visually identical; G67 was refuted as an unavoidable Vue-vs-React semantic; G64/G67 were corrections of vue-tui's own earlier fixes), and that a byte-level audit between a Vue and a React runtime may never return "clean." **Open mediums deferred by decision (NOT done): G69 (Static immediate render), G70 (non-interactive SR hard-wrap).** LOW tail (G25–G31, G34–G43, G47–G51, G53–G57, G60–G62, G65–G66, G71–G73 + the SR squashTextContent transform-drop note) remains recorded and unfixed by maintainer decision. To resume: pick up G69/G70 (sketches in their rows) or re-triage under a stricter "observable user-facing impact only" bar. + ## Decisions log Non-obvious calls made while fixing gaps, recorded for review in the final report. @@ -116,7 +118,7 @@ Non-obvious calls made while fixing gaps, recorded for review in the final repor | G65 | app-exit-instances-animation-sr | SR unchanged-frame skip compares WRAPPED output, not Ink's UNWRAPPED linearization — diverges on resize with identical content — sweep-9 LOW | P3 | todo | — | — | | G66 | app-exit-instances-animation-sr | app.waitUntilRenderFlush() lacks Ink's unmount/unmounting short-circuit to awaitExit() — sweep-9 LOW | P3 | todo | — | — | | G67 | box-layout-border | ~~flexDirection/flexWrap reset on dynamic removal vs Ink keep-stale~~ **REFUTED (codex, sweep-10):** Ink's `` injects row/nowrap defaults BEFORE the style spread, so OMITTING the prop → row (common case, which vue-tui's G19 reset already matches); Ink keeps stale ONLY for explicit `flexDirection={undefined}` (rare), which Vue CANNOT distinguish from omission. Keeping stale would break the common case. UNAVOIDABLE Vue-vs-React semantic — KEEP G19's reset-to-default. **FLAG for maintainer.** | P1 | refuted | — | — | -| G68 | text-wrap-transform | Text style ANSI nesting/order: vue-tui builds ONE chained chalk (color→bg→dim→bold…); Ink applies each style as a SEPARATE nested wrap in a different order (dim→color→bg→bold…) — bytes diverge for multi-style Text (MEDIUM, sweep-10) | P1 | pr-open | `fix/parity-text-ansi-order` | #65 | +| G68 | text-wrap-transform | Text style ANSI nesting/order: vue-tui builds ONE chained chalk (color→bg→dim→bold…); Ink applies each style as a SEPARATE nested wrap in a different order (dim→color→bg→bold…) — bytes diverge for multi-style Text (MEDIUM, sweep-10) | P1 | merged | `fix/parity-text-ansi-order` | #65 | | G69 | render-lifecycle-reconciler | `` output is throttled, not immediate; Ink has an isStaticDirty/onImmediateRender escape hatch that paints freshly-appended Static children synchronously at commit before they can be sliced out (MEDIUM, sweep-10) | P1 | todo | — | — | | G70 | app-exit-instances-animation-sr | Non-interactive (and debug) screen-reader output is hard-wrapped at terminal width; Ink keeps it unwrapped (wrap only in the interactive SR branch) — diverges from vue-tui's own renderToString (MEDIUM, sweep-10) | P1 | todo | — | — | | G71 | focus | useFocusManager().activeId is null (not undefined) when nothing is focused — sweep-10 LOW | P3 | todo | — | — |