Functional Testing — Cycle 5

Date: 2026-04-16 Working directory: C:\Users\keen4\WxManBran\tools\tropical-update-publisher\build_v2\v1\tools\tropical-update-publisher Source baseline: unchanged from refinement-state/refinement-functional-verify-4.md (post-fix snapshot). Between the verify-4 snapshot and cycle 5, src/main/ + tests/ did not gain new product features; only the F084/F035/useGitPublish fixes from refinement-functional-fixes-4.md remain the latest authored code.

Summary

Metric Value
Total features 111
Tested this cycle 78
PASS 78
FAIL 0
BLOCKED 0
PARTIAL 0
REGRESSION 0
MISSING 33
UNTESTED 0
Health Score 100.0%
Delta vs Cycle 4 (original) +2 PASS / -1 PARTIAL / -1 MISSING (F084 PARTIAL → PASS, F035 MISSING → PASS — already reflected in verify-4; cycle 5 re-confirms the transition with fresh evidence)
Delta vs Verify-4 Identical (78/0/0/0/33/100%). No new code since verify-4; cycle 5 is a pure stability re-verification.

Health Score formula: PASS / (PASS + FAIL + BLOCKED + PARTIAL) = 78 / 78 = 100.0%.

Phase 0: Mechanical Completeness Sweep

All three sweep commands PASS with 0 errors and 0 warnings (aside from the pre-existing Tailwind informational warning about duration-[var(--motion-duration-medium)] — not an error and unchanged since cycle 2).

Command Result Log
npm run typecheck exit 0 refinement-state/functional-cycle-5-artifacts/typecheck.log
npm run build exit 0 (Vite → dist/renderer/, tsc → dist/main/) refinement-state/functional-cycle-5-artifacts/build.log
npm run lint exit 0 refinement-state/functional-cycle-5-artifacts/lint.log

No compile errors to fix before feature testing. The toolchain is healthy for cycle 5.

Full-Suite Test Runs (× 3 consecutive)

All three runs produced identical results: Test Files 53 passed (53) / Tests 564 passed (564) with 0 flakes.

Run Files Tests Duration Log
1 53/53 564/564 50.65s refinement-state/functional-cycle-5-artifacts/test-run-1.log
2 53/53 564/564 ~50s refinement-state/functional-cycle-5-artifacts/test-run-2.log
3 53/53 564/564 ~50s refinement-state/functional-cycle-5-artifacts/test-run-3.log

The previously-flaky files remain stable under parallel CPU pressure this cycle:

  • tests/renderer/shadcn-smoke.test.tsx — no dialog timing flakes (was 1–2 flakes/run in cycle 4)
  • tests/renderer/useGitPublish.test.tsx — no fake-timer flake (was 1 flake in cycle 4 run 2)

Isolated Reruns (regression check on formerly-flaky specs)

Test File Result Duration Log
tests/renderer/shadcn-smoke.test.tsx 16/16 PASS 15.14s refinement-state/functional-cycle-5-artifacts/shadcn-smoke-isolated.log
tests/renderer/useGitPublish.test.tsx 2/2 PASS ~6s refinement-state/functional-cycle-5-artifacts/usegitpublish-isolated.log

Both isolated reruns confirm the cycle 4 fixes landed cleanly: the openDialogReliably(user, triggerName) helper in tests/renderer/shadcn-smoke.test.tsx:18-34 and the vi.waitFor(() => expect(...).toBe(true)) wrapper at tests/renderer/useGitPublish.test.tsx:37-39 continue to prevent the previously observed races.

Direct Service Smoke Evidence (Cycle 5 — new artifacts)

Generated fresh test-fixture evidence against the latest build artifacts in dist/main/:

FileValidator — tests/shared/fileValidator.test.ts backing + direct smoke

Fixture: refinement-state/test-fixtures/cycle-5/file-validator-smoke.json (generator: smoke-file-validator.js)

Exercises 22 cases and 7 timezone labels.

  • Happy paths (11 ok): NEW-format with time / without time / with minutes, invest 94L (both L and lowercase l), legacy Imelda_12pm_9-29-25.docxparseFilename returns null correctly for legacy inputs that have not been converted, boundary years 2020 and 2100, boundary months Jan and Dec, year-inside-range base case. Title formatting preserves Invest storm-ID casing (94l94L).
  • Rejection paths (11 ok): short slug → FILENAME_SLUG_INVALID; month 13 / month 0 → FILENAME_DATE_INVALID “Month must be between 01 and 12.”; extension .txtFILENAME_EXTENSION_INVALID; empty string → FILENAME_INVALID “Filename must be non-empty.”; Feb 30 → FILENAME_DATE_INVALID “Invalid date: 2/30/2025 does not exist.”; path separator → FILENAME_INVALID “Filename must not contain path separators.”; year 2019 / year 2101 → FILENAME_DATE_INVALID “Year must be between 2020 and 2100 (inclusive).”; day 00 / day 32 → FILENAME_DATE_INVALID “Day must be between 01 and 31.”
  • Timezone label breadth (7 ok): ET, CT, UTC, PT, GMT, MT, AKT all emit correctly as the suffix on "12:00 PM <TZ>". R4 (timezoneLabel config) confirmed end-to-end for the full dropdown scope. Cycle 4 tested 5 labels; cycle 5 adds MT + AKT.

determineFolderName — src/main/services/storms/determineFolderName.js

Fixture: refinement-state/test-fixtures/cycle-5/folder-name-smoke.json (generator: smoke-folder-name.js)

Exercises 12 cases (cycle 4’s 11 + 1 new named-beats-invest-only).

  • Positive priority matrix (10 ok): named-stormRULE_NAMED_ONLY09L_Imelda; tropical-depressionRULE_TD_ONLY07L_TD7; ptcRULE_PTC_ONLY08L_PTC8; invest-onlyRULE_INVEST_ONLY94L; named-beats-ptcRULE_NAMED_ONLY10L_Andrew; td-beats-ptcRULE_TD_BEATS_PTC11L_TD11; ptc-beats-investRULE_PTC_BEATS_INVEST12L_PTC12; td-beats-investRULE_TD_ONLY13L_TD13; named-beats-td-and-ptcRULE_NAMED_BEATS_TD14L_Bonnie; new named-beats-invest-onlyRULE_NAMED_ONLY15L_Chris.
  • Error paths (2 ok): empty-filesSTORM_FOLDER_NO_CANDIDATES; mismatched-stormNumberDETERMINE_FOLDER_STORM_NUMBER_MISMATCH.

R3 priority (Named > TD > PTC > Invest) reconfirmed, now with a named-beats-invest pair covering the remaining ordered-pair gap in the matrix.

FileCopyService per-file YouTube metadata (R2 acceptance)

Fixture: refinement-state/test-fixtures/cycle-5/file-copy-perfile-yt-result.json (generator: smoke-file-copy-perfile-yt.js)

Three files copied; per-file YouTube IDs applied individually:

  • 2025-10-01-...: youtube_id = "dQw4w9WgXcQ" (sidecar written)
  • 2025-10-02-...: youtube_id = "aBc12345678" (sidecar written)
  • 2025-10-03-...: no youtubeId supplied → no sidecar (expected)
  • metaWritten flags: [true, true, false] — matches the per-file input.
  • distinct_youtube_ids: true — the two sidecars carry different IDs (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”).

IncomingFilesService (F035) — service + structured error

Fixture: refinement-state/test-fixtures/cycle-5/incoming-files-smoke.json (generator: smoke-incoming-files.mjs)

  • Happy path: directory with 2025-10-03-Update.docx, 2025-10-01-Update.docx, 2025-10-02-Update.DOCX, 2025-10-01-Update.meta.json, notes.txt, .docx (5-char), z.docx (6-char) → returns ["2025-10-01-Update.docx","2025-10-02-Update.DOCX","2025-10-03-Update.docx","z.docx"].docx (length 5) rejected, z.docx (length 6) accepted, case-insensitive extension matched, meta.json and .txt excluded, alphabetical sort preserved.
  • ENOENT: missing dir → { names: [] }.
  • Empty dir: existing empty dir → { names: [] }.
  • EACCES: simulated permission denial → rejected with { code: "FILES_LIST_INCOMING_IO_ERROR", hasMessage: true } matching the service’s FILES_LIST_INCOMING_IO_ERROR constant.

Service contract (Section 7.2 listExistingFiles()) verified end-to-end at the shipped build artifact level, on top of the 7 vitest unit tests that cover the same surface with mocks.

MISSING Feature Inventory (unchanged from Verify-4)

Filesystem sweep confirms 33 MISSING features remain as file-absence gaps rather than test-surface gaps:

Path / feature Status
assets/ (F009 WMB_Logo.png, icon.ico, asset docs) absent
launcher.bat, launcher.vbs (F008) absent
src/main/services/nhc/, src/main/services/ai/, src/main/services/email/ (F093–F102, F104) absent
src/renderer/features/publish/ (F030–F034) contains only DropZone.tsx + dropZoneModel.ts — no FileQueue, CommitMessage, YouTubeUrlInput, StatusLog, Footer components
src/renderer/features/doc-creator/ (F039) absent
src/renderer/features/quick-browse/ (F045) absent
Header logo + git-status indicator widget (F050) absent
Command palette / shortcut wiring / context menus / designed empty states (F087–F090) absent
Rich dashboard sections (F103), publishing intelligence (F105), multi-destination (F106), content quality (F107), historical/season (F108), notifications (F109), QoL workflow (F110), audit enhancements (F111) absent

None of these gaps block the tested features — they are acknowledged multi-session deliverables per the master list and spec Sections 19, 20, 23, 24.

Detailed FAIL List

No FAIL entries in this cycle.

Partial Features

No PARTIAL entries in this cycle. F084 transitioned PARTIAL → PASS in verify-4 and remains PASS with three consecutive full-suite green runs and a clean isolated 16/16 rerun in cycle 5.

Blocked Features

None.

Regressions

None. Every feature marked PASS in verify-4 remained PASS in cycle 5 across three consecutive full-suite runs.

New Discoveries

  • Timezone label passthrough is fully generic. Cycle 4 confirmed 5 labels (ET, CT, UTC, PT, GMT); cycle 5 adds MT and AKT and confirms the label is a pure string passthrough in FileValidator.parseFilename (src/shared/validation/FileValidator.ts:474). No canonical-list enforcement — any non-empty label flows through. R4 is spec-compliant and broadly usable beyond the “ET” default.
  • determineFolderName named-beats-invest gap closed. Every ordered pair in the priority matrix (Named > TD, Named > PTC, Named > Invest, TD > PTC, TD > Invest, PTC > Invest) now has a positive test case in refinement-state/test-fixtures/cycle-5/folder-name-smoke.json. The new named-beats-invest-only case reinforces the invariant that any named-storm candidate wins over a pure invest folder even when the invest candidate appears first.
  • F035 IncomingFilesService .docx length boundary is tight. Cycle 5 independently reproduces the length-boundary contract: a filename equal to .docx (length 5) is rejected, while z.docx (length 6) is accepted. This matches the comment in tests/main/incomingFilesService.test.ts:69 and the predicate at src/main/services/publish/IncomingFilesService.ts:37-41.
  • Full suite runs 564/564 × 3 with zero flakes. Cycle 4 best run was 554/555 (1 flake); cycle 4 worst was 552/555 (3 flakes). Cycle 5 is perfectly stable after the verify-4 fixes, even under pool: 'threads' parallel load. No new stability concerns surfaced.
  • Source-tree unchanged since verify-4. find src tests -newer refinement-state/functional-cycle-4-artifacts/typecheck.log -type f returns only the files already accounted for in refinement-functional-fixes-4.md (router.ts, IncomingFilesService.ts, incomingFilesService.test.ts, ipcRouter.test.ts, shadcn-smoke.test.tsx, useGitPublish.test.tsx, main/index.ts). No unrecorded edits between verify-4 and cycle 5.

Remaining Missing Features (unchanged from Cycles 2–4)

Implementation gaps — each carries the same priority as it held in verify-4:

  • F008 launcher scripts (launcher.bat, launcher.vbs) — LOW (alternate launch paths; npm start + NSIS work)
  • F009 asset directory + WMB_Logo.png / icon.ico — MEDIUM (installer icon path referenced; app runs but title-bar icon falls back)
  • F030–F034 publish queue rows / commit-message input / YouTube UI / status log / footer destination path — HIGH (core publish-view UX)
  • F039 document-creator renderer section — HIGH (spec §6.2)
  • F045 quick-browse renderer section — HIGH (spec §6.3)
  • F050 header logo + git-status indicator widget — MEDIUM (spec §6.1)
  • F087–F090 command palette / keyboard shortcut wiring / context menus / designed empty states — MEDIUM
  • F093–F111 Phase 2 (NHC monitor, AI backends, email review, draft queue, rich dashboard, historical views, notifications, QoL, audit/compliance) — deferred multi-session scope (spec §20, §23, §24)

Testing Priority (Applied)

  1. ✓ App compiles: typecheck + build + lint all PASS.
  2. ✓ Core navigation works: AppShell + routing tests (F010–F020) still green under full suite.
  3. ✓ Primary workflow end-to-end: F028 file copy + R2 per-file YouTube + F029 git publish workflow all PASS via publishService.test.ts (12 tests), fileCopyService.test.ts (18 tests), direct smoke fixture this cycle.
  4. ✓ Secondary features: FileValidator (55 tests), determineFolderName (16 tests), stormFolderService (20 tests), quickBrowseService (22 tests), docHandlers (24 tests), wordDocumentService (17 tests), first-run (F006/F054/F080), settings (F055–F060), credential vault (F061), CSP (F062), audit log (F065), publish history (F066), all green.
  5. ✓ Error handling: F071–F081 all PASS via existing tests; F084 dialog accessibility PASS under parallel and isolated runs.
  6. ✓ Polish features tested where applicable; F091/F092 (theme/sidebar persistence) PASS.

Evidence Highlights

  • Compile sweep: refinement-state/functional-cycle-5-artifacts/typecheck.log, build.log, lint.log
  • Full suite runs: refinement-state/functional-cycle-5-artifacts/test-run-1.log, test-run-2.log, test-run-3.log — 564/564 × 3
  • Isolated reruns: shadcn-smoke-isolated.log (16/16), usegitpublish-isolated.log (2/2)
  • FileValidator smoke: refinement-state/test-fixtures/cycle-5/file-validator-smoke.json (generator smoke-file-validator.js)
  • determineFolderName smoke: refinement-state/test-fixtures/cycle-5/folder-name-smoke.json (generator smoke-folder-name.js)
  • FileCopyService per-file YT smoke: refinement-state/test-fixtures/cycle-5/file-copy-perfile-yt-result.json (generator smoke-file-copy-perfile-yt.js)
  • IncomingFilesService smoke: refinement-state/test-fixtures/cycle-5/incoming-files-smoke.json (generator smoke-incoming-files.mjs)

Git Safety

No live git-publish E2E was re-executed in this cycle — F029 coverage is derivative on the stable static test surface (publishService.test.ts 12 tests, gitService.mocks.test.ts 11 tests, publishHistoryService.test.ts 2 tests, gitGetStatusHandlers.test.ts 7 tests, all PASS in npm test). 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 are all in unrelated _site/ static output paths. No disposable branches were created, no remote refs were touched, no test branches exist locally or on origin. No git tests touched main.

Screenshots

No GUI launch was attempted this cycle because the prior cycles’ screenshots are still representative and the source tree is unchanged since verify-4 (screenshots in refinement-state/screenshots/cycle-2/interactive-first-run-before.png and interactive-after-continue.png remain valid visual evidence for F005/F006/F010/F011/F012). The cycle-5 screenshot directory refinement-state/screenshots/cycle-5/ was created for future GUI-launch runs but intentionally left empty to avoid launching the Electron shell (which could show a blocking first-run modal under the current %APPDATA% config state).

Verification That State Is Accurately Recorded

Master list totals audited directly via grep:

  • Total features: 111 (matches legend)
  • Status: PASS: 78
  • Status: MISSING: 33
  • Status: PARTIAL / FAIL / UNTESTED / BLOCKED: 0 each

Totals sum: 78 + 33 + 0 + 0 + 0 + 0 = 111 ✓

Health Score: 78 / (78 + 0 + 0 + 0) = 100.0% ✓


End of cycle 5 report. No regressions, no new PARTIAL/FAIL/BLOCKED, no state transitions required. The codebase is in the same 100% health state as verify-4 with additional, fresh cycle-5 evidence reconfirming the four primary service-layer contracts (FileValidator, determineFolderName, FileCopyService, IncomingFilesService) and the two previously-flaky renderer test files.