Functional Testing — Cycle 5
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(bothLand lowercasel), legacyImelda_12pm_9-29-25.docx→parseFilenamereturns 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 (94l→94L). - Rejection paths (11 ok): short slug →
FILENAME_SLUG_INVALID; month 13 / month 0 →FILENAME_DATE_INVALID“Month must be between 01 and 12.”; extension.txt→FILENAME_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,AKTall emit correctly as the suffix on"12:00 PM <TZ>". R4 (timezoneLabelconfig) confirmed end-to-end for the full dropdown scope. Cycle 4 tested 5 labels; cycle 5 addsMT+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-storm→RULE_NAMED_ONLY→09L_Imelda;tropical-depression→RULE_TD_ONLY→07L_TD7;ptc→RULE_PTC_ONLY→08L_PTC8;invest-only→RULE_INVEST_ONLY→94L;named-beats-ptc→RULE_NAMED_ONLY→10L_Andrew;td-beats-ptc→RULE_TD_BEATS_PTC→11L_TD11;ptc-beats-invest→RULE_PTC_BEATS_INVEST→12L_PTC12;td-beats-invest→RULE_TD_ONLY→13L_TD13;named-beats-td-and-ptc→RULE_NAMED_BEATS_TD→14L_Bonnie; newnamed-beats-invest-only→RULE_NAMED_ONLY→15L_Chris. - Error paths (2 ok):
empty-files→STORM_FOLDER_NO_CANDIDATES;mismatched-stormNumber→DETERMINE_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-...: noyoutubeIdsupplied → no sidecar (expected)metaWrittenflags:[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.jsoncontains 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’sFILES_LIST_INCOMING_IO_ERRORconstant.
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 addsMTandAKTand confirms the label is a pure string passthrough inFileValidator.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. determineFolderNamenamed-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 inrefinement-state/test-fixtures/cycle-5/folder-name-smoke.json. The newnamed-beats-invest-onlycase reinforces the invariant that any named-storm candidate wins over a pure invest folder even when the invest candidate appears first.- F035 IncomingFilesService
.docxlength boundary is tight. Cycle 5 independently reproduces the length-boundary contract: a filename equal to.docx(length 5) is rejected, whilez.docx(length 6) is accepted. This matches the comment intests/main/incomingFilesService.test.ts:69and the predicate atsrc/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 freturns only the files already accounted for inrefinement-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)
- ✓ App compiles: typecheck + build + lint all PASS.
- ✓ Core navigation works: AppShell + routing tests (F010–F020) still green under full suite.
- ✓ 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. - ✓ 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.
- ✓ Error handling: F071–F081 all PASS via existing tests; F084 dialog accessibility PASS under parallel and isolated runs.
- ✓ 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(generatorsmoke-file-validator.js) - determineFolderName smoke:
refinement-state/test-fixtures/cycle-5/folder-name-smoke.json(generatorsmoke-folder-name.js) - FileCopyService per-file YT smoke:
refinement-state/test-fixtures/cycle-5/file-copy-perfile-yt-result.json(generatorsmoke-file-copy-perfile-yt.js) - IncomingFilesService smoke:
refinement-state/test-fixtures/cycle-5/incoming-files-smoke.json(generatorsmoke-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: 78Status: MISSING: 33Status: 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.