LearnNewsExamplesServices
Frontmatter
id15714
titleHarden packaged first-paint receipt guards
stateClosed
labels
documentationenhancementaitestingbuild
assigneesneo-gpt-emmy
createdAtJul 22, 2026, 3:05 PM
updatedAtJul 22, 2026, 5:02 PM
githubUrlhttps://github.com/neomjs/neo/issues/15714
authorneo-gpt-emmy
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[x] 15723 Packaging guard needs syntax-accurate literal import scanning
closedAtJul 22, 2026, 5:02 PM

Harden packaged first-paint receipt guards

Closed Backlog/active-chunk-8 documentationenhancementaitestingbuild
neo-gpt-emmy
neo-gpt-emmy commented on Jul 22, 2026, 3:05 PM

Context

PR #15708 turned the packaged cold-first-paint bar from an informal visual check into an exact-head semantic receipt. Its independent review approved the implementation and identified three non-blocking decay risks in the same owning substrate:

  1. the authoritative firstPaintMs name can be misread as renderer paint time even though it is main-process uptime when the IPC report is accepted;
  2. the preload tests address the first-paint timer as intervals[1], coupling the fixture to registration order;
  3. the packaging closure guard discovers local .mjs dependencies only through a static from './…' regex, so a literal side-effect or dynamic local import can bypass the builder-file assertion.

Review evidence: https://github.com/neomjs/neo/pull/15708#pullrequestreview-4754357025

Live latest-open sweep: checked the latest 20 open issues plus recent A2A lane claims on 2026-07-22; no equivalent ticket or in-flight claim was found. Knowledge Base and exact archived-issue searches likewise found no packaged-first-paint guard equivalent.

The Problem

The implementation is correct today, but its regression guards encode three avoidable ambiguities:

  • harness/main.mjs assigns firstPaintMs from Math.round(process.uptime() * 1000) only after a non-null renderer report arrives. This is intentionally launch-to-receipt timing; rendererFirstPaintMs remains the renderer-relative ready clock. The current JSDoc does not state that distinction.
  • test/playwright/unit/harness/preload.spec.mjs invokes and inspects intervals[1]. Adding an unrelated interval before the product reporter would fail the fixture for registration-order reasons instead of product semantics.
  • test/playwright/unit/harness/pack.spec.mjs matches only from './<file>.mjs'. A future import './local.mjs' or literal import('./local.mjs') can recreate the app.asar missing-module dead end without tripping the closure test.

These are prevention gaps, not evidence that the merged product witness is false.

The Architectural Reality

  • harness/preload.cjs owns the renderer-relative semantic snapshot and rendererFirstPaintMs.
  • harness/main.mjs::sanitizeFirstPaintReport() owns sender-independent sanitization and the authoritative shell-launch-relative receipt clock.
  • harness/electron-builder.yml is the packaged shell file allowlist.
  • test/playwright/unit/harness/pack.spec.mjs is the co-located mechanical guard that keeps the local module graph closed over that allowlist.
  • The harness remains a diagnostic/product-witness surface. It must not acquire Fleet provider authority or weaken the honest residual tracked by #15706.

The Fix

  1. Clarify the timing semantics in intent-level JSDoc: firstPaintMs is shell launch to accepted first-paint receipt; rendererFirstPaintMs is renderer load to semantic readiness.
  2. Make the preload fixture locate the first-paint reporter by a stable semantic or named seam, never a numeric registration index. Include a regression witness that an earlier unrelated interval does not change the selected reporter.
  3. Extend the pack-closure helper and its synthetic fixtures to discover literal local .mjs dependencies across:
    • static import/export from forms;
    • bare side-effect imports;
    • literal dynamic import() forms.
  4. Keep the assertion fail-loud: every discovered local dependency must appear in the builder file list.

Contract Ledger

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
firstPaint.firstPaintMs harness/main.mjs::sanitizeFirstPaintReport() Document shell launch → accepted receipt semantics; retain the existing value and ≤60s bar No schema rename or timing change Intent-level JSDoc in harness/main.mjs Focused unit assertion preserves both clocks
First-paint timer test seam harness/preload.cjs product reporter Select by stable semantic/name rather than array position Fail with an explicit missing/ambiguous reporter assertion Test helper/name Regression fixture adds an earlier interval and still selects the product reporter
Packaged local-module closure harness/pack.mjs comment-stripped import-specifier scanner + harness/main.mjs literal local dependencies + harness/electron-builder.yml Cover static, side-effect, and literal dynamic local .mjs imports Non-literal runtime expressions remain outside this bounded guard Test title/failure message Synthetic import-shape matrix plus builder-closure assertion

Decision Record impact

None. This hardens the already-accepted ADR-0034-compatible harness boundary without changing authority or runtime topology.

Acceptance Criteria

  • JSDoc explicitly distinguishes shell launch-to-receipt firstPaintMs from renderer-relative rendererFirstPaintMs.
  • First-paint preload tests contain no numeric interval-index dependency.
  • A regression witness proves an unrelated interval registered earlier cannot redirect the first-paint assertions.
  • The pack closure discovers literal local .mjs dependencies from static import/export-from, side-effect import, and literal dynamic-import forms.
  • Every discovered local dependency is asserted present in harness/electron-builder.yml.
  • Focused harness unit tests pass under the canonical Playwright unit config.
  • The receipt schema, 60-second product bound, provider authority, and #15706 behavior are unchanged.

Out of Scope

  • Renaming receipt fields or changing the 60-second acceptance threshold.
  • Parsing non-literal dynamic import expressions.
  • Fixing the App Worker transport defect tracked by #15706.
  • Adding a general-purpose JavaScript parser dependency for this bounded harness guard.
  • Changing Fleet acquisition, credential, or public-roster authority.

Avoided Traps

  • Do not conflate the dual clocks into one value; they answer different questions.
  • Do not make the test “stable” by relying on a different numeric interval index or delay value.
  • Do not force the broader smoke green by weakening its fleetRoster falsifier.
  • Do not introduce a second import parser; extend and reuse the existing comment-stripped scanner in harness/pack.mjs.

Related

Origin Session ID: cb60301d-74a4-4024-b80d-2f7efdbf9cd1

Retrieval Hint: packaged first-paint receipt guard launch-to-receipt intervals dynamic local import PR 15708