Skip to content

test(fork): VerifySession is never instantiated in a test — measure()/commitVerified() orchestration is unguarded #80

Description

@NoahHendrickson

Problem

apps/web/src/custom/designMode/engine/verifySession.ts is the fork-owned core of sent-change verification and is never instantiated in a test. Its correctness is currently asserted only by CI passing — nothing would fail if the orchestration broke.

Shipped in #77.

What is covered today

  • verdictFor, summarizeVerifyReport, verifySummaryLine, parseVerifyReport — pure, well covered in designVerify.test.ts, including the cross-field rejections a forged console line would exploit.
  • withTransitionsSuppressed (the restore window) and expandCollapsedProperty — pinned in __fork_guards__/forkDesignMode.test.ts via the esbuild-bundle + inline-style-shim harness.

What is not

Everything that makes those pieces a verifier. measure() and commitVerified() are only exercised end to end by hand:

  • Strict resolution — connected seed → exact source index → unique css-path hit, and null otherwise. The whole point is that a deleted list row reports missing instead of silently measuring a sibling; regressing locateBySourceExact back to a first-match fallback would pass every existing test.
  • Suppression scope — every css draft on every drafted element comes off together, not just the measured element's. Suppressing one property while a parent's drafted display: flex stays painted gives wrong readings, and nothing pins that the suppressed set is drafted ∪ resolved.
  • The credit/prune rule — commit only keys the live DraftStore holds, and prune a check only when nothing of it is still painted. This is the rule that stops a silent commit no-op from dropping a change out of the ledger while its preview stays on the page; it has no test.
  • Ledger lifecycle — recordSend → toPersisted → restore round-trip, including sentMeta.verifying resuming after a reload and the SENT_PERSIST_MAX_CHARS cap shedding sent rather than the drafts.
  • The settle loop — change-gated emit, suspend/resume around the measurement pass so the observer never sees our own writes, and the max-wait firing on a page that never goes quiet.

Why it matters here

These are exactly the paths where a regression produces a confident false claim — "didn't land" over an edit that landed, or a dropped preview on an element nobody verified — rather than a visible crash. That is the one failure mode the feature exists to prevent, and it is invisible to the user who would have to catch it.

The vendored modules underneath (drafts.ts, lifecycle.ts, lifecycle-store.ts, request.ts) are re-synced from upstream periodically. vendor/README.md lists the load-bearing edits, but a list is a prompt, not a check.

Shape of the fix

A jsdom harness that builds a real DOM, a real DraftStore, and a VerifySession, then drives it. The precedent is already in the repo: the #74 restore-original guard and the new verification guard in forkDesignMode.test.ts both bundle the engine with esbuild and import it, shimming the inline-style surface jsdom does not fully model. This wants the same approach but with the session assembled rather than a single seam called.

Acceptance

  • VerifySession is constructed in at least one test and driven through recordSend → measure → commitVerified.
  • Each bullet under "What is not" has a test that fails when that behavior is reverted.
  • Tests run from apps/web and stay in the existing design-mode test files rather than adding a new runner.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions