Functional Testing — Cycle 6
Functional Testing — Cycle 6
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-5.md. Between verify-5 and cycle 6, no src/ code was authored. The only filesystem additions since verify-5 are this cycle’s artifact directories (refinement-state/functional-cycle-6-artifacts/, refinement-state/test-fixtures/cycle-6/, refinement-state/screenshots/cycle-6/) and the per-cycle smoke scripts that reference the shipped dist/ build artifacts without touching source.
Summary
| Metric | Value |
|---|---|
| Total features | 111 |
| Tested this cycle | 79 |
| PASS | 79 |
| FAIL | 0 |
| BLOCKED | 0 |
| PARTIAL | 0 |
| REGRESSION | 0 |
| MISSING | 32 |
| UNTESTED | 0 |
| Health Score | 100.0% |
| Delta vs Cycle 5 (pre-fix) | +1 PASS / -1 MISSING (F008 MISSING → PASS — landed in verify-5; cycle 6 reconfirms) |
| Delta vs Verify-5 | Identical (79/0/0/0/32/100%). No new code since verify-5; cycle 6 is a pure stability re-verification. |
Health Score formula: PASS / (PASS + FAIL + BLOCKED + PARTIAL) = 79 / 79 = 100.0%.
Totals sum audit (via grep on master list): ^### F\d{3} → 111, ^- Status: PASS → 79, ^- Status: MISSING → 32, ^- Status: (FAIL|BLOCKED|PARTIAL|UNTESTED) → 0. Totals: 79 + 32 + 0 = 111 ✓.
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-6-artifacts/typecheck.log |
npm run build |
exit 0 (Vite → dist/renderer/, tsc → dist/main/, tsc → dist/preload/) |
refinement-state/functional-cycle-6-artifacts/build.log |
npm run lint |
exit 0 | refinement-state/functional-cycle-6-artifacts/lint.log |
No compile errors to fix before feature testing. The toolchain is healthy for cycle 6.
Full-Suite Test Runs (× 3 consecutive)
| Run | Test Files | Tests | Duration | Log |
|---|---|---|---|---|
| 1 | 54/54 PASS | 567/567 PASS | 59.23s | refinement-state/functional-cycle-6-artifacts/test-run-1.log |
| 2 | 54/54 PASS | 567/567 PASS | ~60s | refinement-state/functional-cycle-6-artifacts/test-run-2.log |
| 3 | 53/54 + 1 flake | 566/567 + 1 flake | 66.39s | refinement-state/functional-cycle-6-artifacts/test-run-3.log |
Runs 1 and 2 were fully green. Run 3 reproduced the known parallel-load flake on tests/renderer/shadcn-smoke.test.tsx > App + Dialog smoke > closes the dialog when Done is activated — the same test that flaked in verify-5 run 2. Isolated rerun of shadcn-smoke.test.tsx is 16/16 PASS (refinement-state/functional-cycle-6-artifacts/shadcn-smoke-isolated.log, 2289ms). This flake is a known parallel-load race on the Dialog close control under pool: 'threads', not a regression; F084 remains PASS under the existing “isolated rerun clean” exit criterion established in verify-4.
Isolated Reruns (regression check on formerly-flaky specs)
| Test File | Result | Duration | Log |
|---|---|---|---|
tests/renderer/shadcn-smoke.test.tsx |
16/16 PASS | 9.09s (tests 2.29s) | refinement-state/functional-cycle-6-artifacts/shadcn-smoke-isolated.log |
tests/renderer/useGitPublish.test.tsx |
2/2 PASS | 4.74s (tests 168ms) | refinement-state/functional-cycle-6-artifacts/usegitpublish-isolated.log |
Both isolated reruns confirm the cycle 4 fixes continue to hold: 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 still prevent the previously observed races when the specs run without parallel-CPU contention.
Direct Service Smoke Evidence (Cycle 6 — fresh artifacts against dist/ build)
Five service-level smokes regenerated this cycle against the latest build artifacts in dist/main/:
FileValidator — tests/shared/fileValidator.test.ts backing + direct smoke
Fixture: refinement-state/test-fixtures/cycle-6/file-validator-smoke.json (generator: smoke-file-validator.js)
Exercises 22 cases and 8 timezone labels (cycle 5 had 7 labels; cycle 6 adds HST).
- 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 (8 ok):
ET,CT,UTC,PT,GMT,MT,AKT,HSTall emit correctly as the suffix on"12:00 PM <TZ>". R4 (timezoneLabelconfig) confirmed end-to-end across the full continental + Alaska + Hawaii dropdown scope.
determineFolderName — src/main/services/storms/determineFolderName.js
Fixture: refinement-state/test-fixtures/cycle-6/folder-name-smoke.json (generator: smoke-folder-name.js)
Exercises 13 cases (cycle 5’s 12 + 1 new named-beats-td-only).
- Positive priority matrix (11 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;named-beats-invest-only→RULE_NAMED_ONLY→15L_Chris; newnamed-beats-td-only→RULE_NAMED_BEATS_TD→16L_Dorian. - Error paths (2 ok):
empty-files→STORM_FOLDER_NO_CANDIDATES;mismatched-stormNumber→DETERMINE_FOLDER_STORM_NUMBER_MISMATCH.
R3 priority (Named > TD > PTC > Invest) reconfirmed with every ordered pair (Named>TD, Named>PTC, Named>Invest, TD>PTC, TD>Invest, PTC>Invest) now represented by at least one positive case. The new named-beats-td-only case tightens the Named>TD binding that was previously only exercised through the 3-way named-beats-td-and-ptc triple.
FileCopyService per-file YouTube metadata (R2 acceptance)
Fixture: refinement-state/test-fixtures/cycle-6/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”).all_copied: 3 — every source was copied regardless of whether it supplied a YouTube ID.
IncomingFilesService (F035) — service + structured error
Fixture: refinement-state/test-fixtures/cycle-6/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.
F008 launcher scripts — direct structural smoke
Fixture: refinement-state/test-fixtures/cycle-6/launchers-smoke.json (generator: smoke-launchers.js)
launcher.bat(424 bytes): exists, callsnpm start,cd /d "%~dp0", preserves%ERRORLEVEL%exit code.launcher.vbs(697 bytes): exists, referenceslauncher.bat,shell.Run ..., 0, ...(hidden window style), usesScripting.FileSystemObject, non-blocking (bWaitOnReturn = False).create-shortcut.ps1(1374 bytes): exists, targetslauncher.vbs, writesTropical Update Uploader.lnkunderGetFolderPath('Desktop'), usesWScript.Shell, graceful absent-icon handling (Test-Path $iconPath),$ErrorActionPreference = 'Stop'.allStructuralChecksPass: true.
Complements the 3 vitest assertions in tests/shared/launchers.test.ts that ran green in all three full-suite runs this cycle.
MISSING Feature Inventory (unchanged from Verify-5)
Filesystem sweep confirms 32 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 |
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 |
F008 was on this list in cycle 5; verify-5 landed launcher.bat, launcher.vbs, create-shortcut.ps1, and their backing test, moving it to PASS.
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.
Blocked Features
None.
Regressions
None. Every feature marked PASS in verify-5 remained PASS in cycle 6. The single run-3 flake on shadcn-smoke > closes the dialog when Done is activated is the same race documented in verify-5 and cycle-4 (isolated rerun 16/16 green both times), not a regression.
New Discoveries
- Timezone label breadth now covers HST. Cycle 5 confirmed 7 labels (
ET,CT,UTC,PT,GMT,MT,AKT); cycle 6 addsHST. Total label coverage: 8 distinct strings all flowing throughFileValidator.parseFilenameatsrc/shared/validation/FileValidator.ts:474without canonical-list enforcement. R4 acceptance continues to hold for any non-empty timezone string. determineFolderNameNamed>TD-only binding directly covered. Cycle 5 exercised Named>TD via the 3-waynamed-beats-td-and-ptccase (where PTC is also present). Cycle 6 addsnamed-beats-td-only(16L_DorianoverTD16) to isolate the pairwise Named>TD invariant. The smoke fixture now contains a positive case for every ordered priority pair.- Full suite stability is ~2/3 green, 1/3 shows known flake. Cycle 5: 3/3 green runs. Verify-5: 3/4 green runs, 1 flake. Cycle 6: 2/3 green runs, 1 flake — consistent with the verify-5 pattern that the cycle-4 fix reduced but did not fully eliminate the parallel-load race on the Dialog close control. Isolated rerun is clean, so F084 stays PASS. No action needed; the flake rate is within the existing exit criterion (≤33% with isolated-clean).
- Source tree fully stable since verify-5.
find src tests -newer refinement-state/functional-cycle-5-artifacts/typecheck.log -type f -name '*.ts' -o -name '*.tsx' -o -name '*.js'returns onlytests/shared/launchers.test.ts— the F008 test that landed during verify-5. No unrecorded source edits between verify-5 and cycle 6. - Test-count growth reconciled. Cycle 5: 53 files / 564 tests. Cycle 6: 54 files / 567 tests (+1 file, +3 tests). The delta is entirely attributable to
tests/shared/launchers.test.ts(3 assertions:.batexistence + npm-start call,.vbsexistence + hidden-window run,.ps1existence + Desktop shortcut) authored during verify-5. - F008 physical backing audit complete. All three launcher files exist at the tool root with the structural invariants the spec demands:
launcher.bat→ 424 bytes, callsnpm start;launcher.vbs→ 697 bytes, hidden window (style 0), non-blocking;create-shortcut.ps1→ 1374 bytes, writesTropical Update Uploader.lnkto Desktop, graceful missing-icon fallback. Direct structural smoke this cycle (launchers-smoke.json) confirmsallStructuralChecksPass: truefor all 14 boolean checks across the three files.
Remaining Missing Features (unchanged from Verify-5)
Implementation gaps — each carries the same priority as it held in verify-5:
- F009 asset directory +
WMB_Logo.png/icon.ico— MEDIUM (installer icon path referenced inpackage.jsonbuild.win.icon; app runs but title-bar icon falls back to Electron default) - 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), launchers (F008, 3 tests), all green.
- ✓ Error handling: F071–F081 all PASS via existing tests; F084 dialog accessibility PASS under isolated run and 2/3 full-suite runs, known-flaky run 3 reproduces verify-5’s pattern.
- ✓ Polish features tested where applicable; F091/F092 (theme/sidebar persistence) PASS.
Evidence Highlights
- Compile sweep:
refinement-state/functional-cycle-6-artifacts/typecheck.log,build.log,lint.log - Full suite runs:
refinement-state/functional-cycle-6-artifacts/test-run-1.log,test-run-2.log,test-run-3.log— 567/567 + 567/567 + 566/567 - Isolated reruns:
shadcn-smoke-isolated.log(16/16),usegitpublish-isolated.log(2/2) - FileValidator smoke:
refinement-state/test-fixtures/cycle-6/file-validator-smoke.json(generatorsmoke-file-validator.js) - determineFolderName smoke:
refinement-state/test-fixtures/cycle-6/folder-name-smoke.json(generatorsmoke-folder-name.js) - FileCopyService per-file YT smoke:
refinement-state/test-fixtures/cycle-6/file-copy-perfile-yt-result.json(generatorsmoke-file-copy-perfile-yt.js) - IncomingFilesService smoke:
refinement-state/test-fixtures/cycle-6/incoming-files-smoke.json(generatorsmoke-incoming-files.mjs) - F008 launcher smoke:
refinement-state/test-fixtures/cycle-6/launchers-smoke.json(generatorsmoke-launchers.js)
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.
Repo inspected this cycle: git branch --show-current → tropical-publisher-v2 (unchanged); git status --short → only _site/* static output modifications outside this tool’s scope, unrelated to tropical-update-publisher code. No disposable test branches were created this cycle, no remote refs were touched, no test branches exist locally or on origin. No git tests touched main.
GUI / Screenshots
No GUI launch was attempted this cycle because (a) the prior cycles’ screenshots (refinement-state/screenshots/cycle-2/interactive-first-run-before.png and interactive-after-continue.png) are still representative, (b) the source tree is unchanged since verify-4/verify-5 apart from the F008 text files at the tool root (which have no renderer surface), and (c) a live Electron launch could show a blocking first-run modal under the current %APPDATA% config state, per the GUI App Launch Safety guardrail. The cycle-6 screenshot directory refinement-state/screenshots/cycle-6/ was created for future GUI-launch runs but intentionally left empty in this cycle.
Verification That State Is Accurately Recorded
Master list totals audited directly via grep against refinement-state/refinement-functional-master-list.md:
- Total feature sections (
^### F): 111 (matches legend) ^- Status: PASS: 79^- Status: MISSING: 32^- Status: PARTIAL/FAIL/UNTESTED/BLOCKED: 0 each
Totals sum: 79 + 32 + 0 + 0 + 0 + 0 = 111 ✓
Health Score: 79 / (79 + 0 + 0 + 0) = 100.0% ✓
End of cycle 6 report. No regressions, no new PARTIAL/FAIL/BLOCKED, no state transitions required, no master-list edits necessary (verify-5 already landed F008 MISSING → PASS and the master list reflects it). The codebase is in the same 100% health state as verify-5 with additional, fresh cycle-6 evidence reconfirming the four primary service-layer contracts (FileValidator, determineFolderName, FileCopyService, IncomingFilesService) plus the F008 launcher-script contract. The single run-3 flake on the Dialog close control is the known parallel-load race; isolated rerun is clean.