Skip to content

fix(reliability): fail closed for stale toolbar image uploads - #158

Draft
seonghobae wants to merge 13 commits into
mainfrom
fix/toolbar-image-lifecycle-20260811
Draft

fix(reliability): fail closed for stale toolbar image uploads#158
seonghobae wants to merge 13 commits into
mainfrom
fix/toolbar-image-lifecycle-20260811

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Closes #157.

Current boundary

Protected shipped truth is independently resolved as main@128a239f8b71ca16add4b9e15e21752d1ad63ff0. Current exact Draft head is 4f4f7db37f2ff488e061f9b69d6a0c4b019e0c0d on fix/toolbar-image-lifecycle-20260811.

The branch is non-destructively synchronized with that exact protected tip. The synchronization commit keeps the previous #158 head as first parent and protected main as the second parent; no force push or destructive rebase was used. Fresh comparison resolves the merge base exactly to protected main, reports ahead_by=13, behind_by=0, and exactly five intended changed paths:

  • src/components/Toolbar.tsx;
  • src/components/Toolbar.test.tsx;
  • src/components/ToolbarCustomerCopy.test.tsx;
  • src/components/ToolbarImageLifecycle.test.tsx; and
  • src/components/ToolbarLinkPolicy.test.tsx.

The customer-facing image-action label/accessibility contract formerly duplicated by #391 is now represented only by this earlier canonical Toolbar writer; #391 is closed unmerged. The synchronization inherited current protected-main release controls rather than reviving historical release-workflow snapshots.

This lane owns adjacent Toolbar.tsx trust/lifecycle boundaries: stale asynchronous image upload continuations, hostile conversion-value redaction, host image-error observer isolation, toolbar SafeLink preflight, and the customer-facing image-action accessible name. It adds no transport, persistence, credentials, tenancy, collaboration-provider, durable audit, model, database, network, or deployment authority.

Stale image-upload lifecycle lineage (#157)

RED — 3f3afc373c4a23951e40963bb5d7d4bdfea53fcd. Hosted CI failed the new lifecycle regressions because the alternative-text prompt still ran after the editor became read-only or was destroyed while conversion was pending.

GREEN — 6da5eab43f4a05918df5ce520b5f3ce90d9144cf. Production rechecks editor.isDestroyed || !editor.isEditable after asynchronous conversion and before prompt/focus/image insertion.

Hostile conversion-value redaction lineage

RED — 6e767611315e7427f9c7b1c5018cc81aab200413. A hostile thrown Proxy from image conversion could cross the host onImageError boundary by identity.

GREEN — 84cb2b1e5fb94b587bf29dd9024c5288f54c7636. Conversion failures are replaced with stable Error('Image processing failed.'); hostile thrown values are neither reflected nor propagated. Genuine Blob size is read intrinsically so typed oversize rejection does not trust a caller-owned accessor.

Toolbar SafeLink preflight lineage

RED — 98ee151ee52d5792765f71f35408dee8550e3505. CI 31933462011 failed the new toolbar-link regression while Security 31933462001 and SAST 31933462012 succeeded. The test requires javascript:alert(1) to be rejected before setLink() or editor command execution.

GREEN — 0693ba351c2b325e59e45a41e36c861800b1f732. The toolbar calls the existing isSafeLinkHref(url) policy before any link editor command; safe-link behavior and empty-input unlink behavior remain intact.

Host observer isolation lineage

A later reliability sweep found another defect on the same owned image-failure boundary: both oversize rejection and conversion rejection invoked host onImageError directly. Because image conversion is asynchronous, a throwing host observer could turn an otherwise-contained rejection into an unhandled Promise rejection and alter Inkspan control flow.

RED — exact test-only head 041e726b010e96cc8b9b4946de52012d719c3141. CI 31949613767 checked out that exact SHA, passed immutable install and typecheck, and ran all 143 test files / 823 tests successfully, but Vitest correctly failed the run because it caught one unhandled rejection: Error: private toolbar observer sentinel, originating from contains host image-error observer failures after conversion rejection. The production coverage table still reached 100% statements/branches/functions/lines; Office Python 3.11–3.14 succeeded on the same RED generation. Those parallel successes do not convert the intentional RED to passing evidence.

GREEN source repair — predecessor d448a9dd8296fca5f905a7371d22abf75f647f75. A narrow reportImageError() helper invokes the host observer inside a fail-closed best-effort boundary. Both typed oversize rejection and stable conversion-error delivery use the helper. No image conversion, size, lifecycle, prompt, editor-command, transport, persistence, or policy semantics changed.

Exact-current-head evidence

The synchronization moved the exact contributor head to 4f4f7db37f2ff488e061f9b69d6a0c4b019e0c0d; all predecessor workflow/review results are historical and are not transferred. Current-head required workflows must become terminal and must be inspected down to required steps and checkout/source SHA before they count. Pending, queued, skipped-required, cancelled, absent, neutral, failed, stale, predecessor, status-only, model-only, wrong-checkout, synthetic-source-only, or otherwise vacuous evidence is non-passing.

Formal qualifying approvals on this exact head: 0. Unresolved inline review threads: 0.

Integration boundary

Keep this PR Draft and unmerged while #118 owns exact protected v0.6.0 publication/provenance/digest operational acceptance and qualifying independent approval remains absent. Live governance requires a qualifying approval of the latest push by someone other than the pusher, stale-review dismissal after pushes, review-thread resolution, and the applicable central required workflows. Revalidate exact head, protected main, reviews/threads, rules and every required workflow before any later Ready/merge transition. Do not self-approve, weaken gates, transfer predecessor evidence, or fabricate tag/release identity.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@opencode-agent opencode-agent Bot added priority: medium Normal-priority or P2 work status: draft Draft pull request type: bug Defect or incorrect behavior labels Aug 22, 2026
@seonghobae

Copy link
Copy Markdown
Contributor Author

Validation for exact current head 1f5b6f5:\n\n- Updated the two Toolbar keyboard tests to match the PR's intentional customer-facing title change from Insert inline (base64) image to Insert inline image.\n- TypeScript typecheck passed.\n- Toolbar.test.tsx and ToolbarCustomerCopy.test.tsx passed: 2 files, 15 tests.\n- A full local coverage run reached 146 passed files / 829 passed tests and one existing SafeClipboard.wordCapacity test timed out at the default 5 seconds; this is not claimed as full local coverage proof. Hosted checks are re-running on this head.\n\nThe prior build-and-test annotations for this PR were the two stale-label assertions; no implementation behavior was reverted.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Hosted validation update for exact current head 1f5b6f5: build-and-test and Cross-engine Clipboard / Playwright 1.62.0 both passed in run 33148143891. No completed required check is failing at this head; remaining checks are queued or in progress. Current-head formal reviews and approvals remain 0, and the PR remains Draft/blocked pending the remaining gates.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Hosted gate update for exact current head 1f5b6f5: coverage-evidence completed successfully in run 33148142331 (job 98774679606). There are no completed required-check failures at this head; Strix remains the only substantive gate in progress. The PR remains Draft/blocked with 0 current-head approvals.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Terminal current-head OpenCode update for 1f5b6f5: the required opencode-review job failed closed at Fail closed without a current-head OpenCode verdict, job https://github.com/ContextualWisdomLab/inkspan/actions/runs/33148142331/job/98775377775. This is not a source finding or a review approval. Build-and-test, cross-engine, and coverage-evidence passed at this head; current-head formal reviews and approvals remain 0, so the Draft PR remains blocked.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Terminal current-head Strix update for 1f5b6f5: required job https://github.com/ContextualWisdomLab/inkspan/actions/runs/33148142409/job/98774461877 failed during Run Strix (quick). The uploaded artifact records provider-side failures: contextual-orchestrator HTTP 400 invalid_tools (tool.function.description over 1024 characters), followed by HTTP 500 internal_error and STRIX_PROVIDER_UNAVAILABLE. No usable scan verdict was emitted; the displayed Vulnerabilities 0 is not vulnerability-clear evidence. Build-and-test, cross-engine, and coverage-evidence passed at this head. Current-head approvals remain 0 and the Draft PR stays blocked.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: medium Normal-priority or P2 work status: draft Draft pull request type: bug Defect or incorrect behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(reliability): suppress stale toolbar image upload after editor lifecycle changes

1 participant