Functional Testing — Cycle 4

Date: 2026-04-16 Working directory: C:\Users\keen4\WxManBran\tools\tropical-update-publisher\build_v2\v1\tools\tropical-update-publisher Source state: unchanged from cycle 3 (most-recent src/tests file mtime = 2026-04-08).

Summary

Metric Value
Total features 111
Tested this cycle 77
PASS 76
FAIL 0
BLOCKED 0
PARTIAL 1
REGRESSION 0
MISSING 34
UNTESTED 0
Health Score 98.7%
Delta vs Cycle 3 Identical: 76 PASS / 1 PARTIAL / 34 MISSING. F084 dialog flake reproduced; no new regressions. One new PASS-but-flaky observation on useGitPublish fake-timer test (see New Discoveries).

Notes:

  • Phase 0 compile sweep (0 errors found, no fixes needed):
    • npm run typecheck: PASS, 0 errors (refinement-state/functional-cycle-4-artifacts/typecheck.log)
    • npm run build (renderer + main): PASS, 0 errors (refinement-state/functional-cycle-4-artifacts/build.log)
    • npm run lint: PASS, 0 errors (refinement-state/functional-cycle-4-artifacts/lint.log)
  • Full repo verification (3 runs per cycle 3’s pattern):
    • Run 1: 554/555 PASS — 1 fail in shadcn-smoke.test.tsx (dialog visibility, same as cycle 3)
    • Run 2: 552/555 PASS — 3 fails: 2 in shadcn-smoke.test.tsx (dialog open/escape) + 1 in useGitPublish.test.tsx (fake-timer unknownAfterTimeout assertion)
    • Run 3: 554/555 PASS — 1 fail in shadcn-smoke.test.tsx (dialog visibility)
    • Isolated rerun of shadcn-smoke.test.tsx: 16/16 PASS
    • Isolated rerun of useGitPublish.test.tsx: 2/2 PASS
    • Evidence: refinement-state/functional-cycle-4-artifacts/test-run-1.log, test-run-2.log, test-run-3.log, shadcn-smoke-isolated.log, usegitpublish-isolated.log
  • Direct service smoke checks (cycle 4 new evidence):
    • FileValidator.validateDocxFilename + parseFilename: 18 cases (valid new, valid new w/o time, minutes, invest ID, legacy auto-convert x2, invalid slug, invalid month, invalid ext, empty, Feb 30, path separator, year boundary 2020, year boundary 2100, year out-of-range 2019 and 2101, day 0, day 32) — all return expected ok/code/message. Timezone label rotates correctly through ET/CT/UTC/PT/GMT. New boundary cases added vs. cycle 3 prove R4 year range enforcement and day range. Evidence: refinement-state/test-fixtures/cycle-4/file-validator-smoke.json
    • determineFolderName: 11 cases (cycle 3 + 3 new: ptc-beats-invest, td-beats-invest, named-beats-td-and-ptc) all produce spec-correct targetFolderName + appliedRuleId. Priority Named > TD > PTC > Invest exercised across all ordered pairs. Evidence: refinement-state/test-fixtures/cycle-4/folder-name-smoke.json
    • FileCopyService.copyFiles per-file YouTube metadata (R2): 3 files copied, 2 with distinct YouTube IDs, 1 without. Verified sidecar files contain the correct per-file youtube_id values (dQw4w9WgXcQ, aBc12345678) and that the third file produced no sidecar. This reconfirms F028 R2 acceptance criterion (“User can queue 3 files, enter 3 different YouTube URLs, publish, and each .meta.json contains the correct video ID for its file”) at the service layer. Evidence: refinement-state/test-fixtures/cycle-4/file-copy-perfile-yt-result.json
  • Missing-feature inventory unchanged from cycles 2 and 3:
    • Launchers (launcher.bat, launcher.vbs): still absent (F008)
    • assets/ directory with WMB_Logo.png, icon.ico: still absent (F009)
    • No src/main/services/{nhc,ai,email} directories (F093, F097, F100 and dependents still MISSING)
    • No renderer file-queue/commit-message/status-log/footer components beyond drop zone (F030–F035 still MISSING)
    • Renderer features/publish/ still only has DropZone.tsx + dropZoneModel.ts (no queue UI)

Detailed FAIL List

No FAIL entries in this cycle. The shadcn smoke flakiness remains tracked as PARTIAL on F084 rather than FAIL because the underlying dialog behavior passes reliably in isolation (16/16). The useGitPublish fake-timer flake observed in run 2 is captured as a New Discovery; the hook still passes in isolation (2/2) and the F027 UI feature it backs remains PASS.

Partial Features

MEDIUM — F084 Sidebar, Button, Dialog, And Input Accessibility/Polish — reconfirmed PARTIAL

  • Status: PARTIAL (unchanged from cycle 3; same root cause)
  • What works:
    • Accessible buttons, inputs, sidebar focus ring, dialog role, and icon-only button labeling all still render correctly.
    • tests/renderer/shadcn-smoke.test.tsx PASSES 16/16 when run in isolation (refinement-state/functional-cycle-4-artifacts/shadcn-smoke-isolated.log).
  • What is still missing:
    • In the full npm test run, 1–2 of the dialog tests flake intermittently. Exact failures observed this cycle:
      • Run 1: App + Dialog smoke > opens the dialog and shows the titled input field (happy path) (line 88–96) — toBeVisible() failed; Radix has data-state="open" but the fade-in transition had not completed before the assertion.
      • Run 2: same test above PLUS closes the dialog when Escape is pressed (Radix modal contract) (line 119–129) — findByRole('dialog') timed out.
      • Run 3: same single test from Run 1.
    • No runs flaked on the focus-trap case this cycle (cycle 3 saw that one flake as well); otherwise the behavior is identical to cycle 3.
  • Evidence:
    • Failing (full suite): refinement-state/functional-cycle-4-artifacts/test-run-1.log, test-run-2.log, test-run-3.log
    • Passing (isolated): refinement-state/functional-cycle-4-artifacts/shadcn-smoke-isolated.log
  • Root cause (unchanged from cycle 3): Framer-motion / Radix Dialog animation duration + fireEvent.click (sync) vs. findByRole’s default 1 s timeout, amplified by parallel thread-pool load during the full suite run. The unmodified code in tests/renderer/shadcn-smoke.test.tsx lines 88–129 still uses fireEvent.click instead of the userEvent.click + waitFor pattern applied to the (now-passing) focus-trap case.
  • Priority: MEDIUM (test-suite stability only — no user-visible regression; dialog still renders correctly in the live app and in isolated test runs). No new remediation attempted this cycle — confirming a stable reproduction pattern, not fixing.

Blocked Features

None in this cycle.

Regressions

None this cycle. F084 was already PARTIAL in cycle 3 and remains PARTIAL here with the same root cause and impact — no new regression.

New Discoveries

  • useGitPublish fake-timer flake (non-blocking): tests/renderer/useGitPublish.test.tsx > sets unknownAfterTimeout when publish hangs past the 60s ceiling failed once out of three full-suite runs (run 2) with expected false to be true. The test uses vi.advanceTimersByTimeAsync(IPC_PUBLISH_FAMILY_TIMEOUT_MS) then asserts result.current.unknownAfterTimeout === true. When the full suite runs under parallel load, the React state update queued by the hook’s timeout handler doesn’t always flush before the assertion. Isolated re-run: npx vitest run tests/renderer/useGitPublish.test.tsx → 2/2 PASS (refinement-state/functional-cycle-4-artifacts/usegitpublish-isolated.log). The backing UI feature (F027 Publish Timeout Unknown-State Banner) remains PASS — this is a test-fidelity issue, not a feature regression. Suggested remediation for a future cycle: wrap the assertion in waitFor(() => expect(...).toBe(true)) to allow React scheduling to flush under load.
  • FileValidator boundary-year enforcement is tight: verified that 2019-01-01-Tropical-Update.docx and 2101-01-01-Tropical-Update.docx are rejected with FILENAME_DATE_INVALID + message “Year must be between 2020 and 2100 (inclusive).” This closes a previously untested corner of Section 5.1. Boundary years 2020 and 2100 are accepted.
  • FileValidator day-out-of-range enforcement: day-zero (2025-01-00-...) and day-32 (2025-01-32-...) both correctly rejected with FILENAME_DATE_INVALID / “Day must be between 01 and 31.” Invalid-calendar-date rejection (e.g. 2025-02-30) additionally carries “Invalid date: 2/30/2025 does not exist.” — two-layer date validation confirmed.
  • Configurable timezone label breadth: FileValidator.parseFilename correctly emits the supplied timezone suffix for ET, CT, UTC, PT, and GMT on the same filename. No canonical-list enforcement — any non-empty string is passed through.
  • determineFolderName R3 priority: full priority matrix Named > TD > PTC > Invest verified across every pairwise ordering (named-beats-ptc, td-beats-ptc, ptc-beats-invest, td-beats-invest, named-beats-td-and-ptc). The RULE_NAMED_BEATS_TD and RULE_TD_BEATS_PTC rule IDs surface correctly in diagnostics.
  • F028 R2 acceptance test at service layer: reproduced the exact scenario called out in Section 19 R2 (“queue 3 files, enter 3 different YouTube URLs, publish, and each .meta.json contains the correct video ID for its file”) at the FileCopyService layer. 2 files with IDs → 2 sidecars with distinct IDs; 1 file without → no sidecar. The metaWritten result flags accurately match whether a sidecar was written. (The UI-level R2 acceptance remains gated on F032 which is MISSING — no renderer per-file YouTube input exists yet.)
  • Source code unchanged since cycle 3: find src tests -newer ... shows the most recent file mtime is 2026-04-08, consistent with cycle 3’s inventory. No new implementation between cycles 3 and 4. This cycle exercises the same artifact surface but with broader smoke-test coverage.

Remaining Missing Features (unchanged from cycles 2 and 3)

Implementation gaps, not test blockers:

  • F008F009: launchers + assets directory
  • F030F035: full publish queue / commit-message / YouTube UI / status log / footer destination / existing-files listing
  • F039: document-creator renderer section
  • F045: quick-browse renderer section
  • F050: header logo + git-status indicator widget
  • F087F090: command palette, shortcut wiring, context menus, designed empty states
  • F093F111: Phase 2 NHC monitor, AI backends, email review, draft queue, rich dashboard, historical views, notifications, QoL features, audit/compliance enhancements

Evidence Highlights

  • Compile sweep: refinement-state/functional-cycle-4-artifacts/typecheck.log, build.log, lint.log
  • Full suite runs: refinement-state/functional-cycle-4-artifacts/test-run-1.log, test-run-2.log, test-run-3.log
  • Shadcn smoke isolated rerun: refinement-state/functional-cycle-4-artifacts/shadcn-smoke-isolated.log
  • useGitPublish isolated rerun: refinement-state/functional-cycle-4-artifacts/usegitpublish-isolated.log
  • FileValidator smoke: refinement-state/test-fixtures/cycle-4/file-validator-smoke.json (generator: smoke-file-validator.js)
  • determineFolderName smoke: refinement-state/test-fixtures/cycle-4/folder-name-smoke.json (generator: smoke-folder-name.js)
  • FileCopyService per-file YT smoke: refinement-state/test-fixtures/cycle-4/file-copy-perfile-yt-result.json (generator: smoke-file-copy-perfile-yt.js)

Git Safety

No live git-publish E2E was re-executed in this cycle — F029 coverage is derivative on the static test suite (publishService.test.ts 12 tests, gitService.mocks.test.ts 11 tests, publishHistoryService.test.ts 2 tests, gitGetStatusHandlers.test.ts 7 tests) all passing in npm test, plus the cycle-2 disposable-branch E2E artifact (refinement-state/test-fixtures/cycle-2/publish-e2e-result.json) remains the authoritative live evidence. The repo was inspected with git branch --show-current (on tropical-publisher-v2) and git status --short (working-tree modifications present but all in unrelated _site/ static output); no disposable branches were created and no remote refs were touched. No git tests touched the live main branch; no test branches were created or left behind this cycle.