Functional Testing — Cycle 4
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 inuseGitPublish.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
- Run 1: 554/555 PASS — 1 fail in
- 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 expectedok/code/message. Timezone label rotates correctly throughET/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.jsondetermineFolderName: 11 cases (cycle 3 + 3 new: ptc-beats-invest, td-beats-invest, named-beats-td-and-ptc) all produce spec-correcttargetFolderName+appliedRuleId. PriorityNamed > TD > PTC > Investexercised across all ordered pairs. Evidence:refinement-state/test-fixtures/cycle-4/folder-name-smoke.jsonFileCopyService.copyFilesper-file YouTube metadata (R2): 3 files copied, 2 with distinct YouTube IDs, 1 without. Verified sidecar files contain the correct per-fileyoutube_idvalues (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.jsoncontains 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 withWMB_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 hasDropZone.tsx+dropZoneModel.ts(no queue UI)
- Launchers (
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.tsxPASSES 16/16 when run in isolation (refinement-state/functional-cycle-4-artifacts/shadcn-smoke-isolated.log).
- What is still missing:
- In the full
npm testrun, 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 hasdata-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.
- Run 1:
- No runs flaked on the
focus-trapcase this cycle (cycle 3 saw that one flake as well); otherwise the behavior is identical to cycle 3.
- In the full
- 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
- Failing (full suite):
- 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 intests/renderer/shadcn-smoke.test.tsxlines 88–129 still usesfireEvent.clickinstead of theuserEvent.click+waitForpattern 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 ceilingfailed once out of three full-suite runs (run 2) withexpected false to be true. The test usesvi.advanceTimersByTimeAsync(IPC_PUBLISH_FAMILY_TIMEOUT_MS)then assertsresult.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 inwaitFor(() => expect(...).toBe(true))to allow React scheduling to flush under load. - FileValidator boundary-year enforcement is tight: verified that
2019-01-01-Tropical-Update.docxand2101-01-01-Tropical-Update.docxare rejected withFILENAME_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-...) andday-32(2025-01-32-...) both correctly rejected withFILENAME_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.parseFilenamecorrectly emits the supplied timezone suffix forET,CT,UTC,PT, andGMTon the same filename. No canonical-list enforcement — any non-empty string is passed through. - determineFolderName R3 priority: full priority matrix
Named > TD > PTC > Investverified across every pairwise ordering (named-beats-ptc,td-beats-ptc,ptc-beats-invest,td-beats-invest,named-beats-td-and-ptc). TheRULE_NAMED_BEATS_TDandRULE_TD_BEATS_PTCrule 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.jsoncontains the correct video ID for its file”) at theFileCopyServicelayer. 2 files with IDs → 2 sidecars with distinct IDs; 1 file without → no sidecar. ThemetaWrittenresult 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:
F008–F009: launchers + assets directoryF030–F035: full publish queue / commit-message / YouTube UI / status log / footer destination / existing-files listingF039: document-creator renderer sectionF045: quick-browse renderer sectionF050: header logo + git-status indicator widgetF087–F090: command palette, shortcut wiring, context menus, designed empty statesF093–F111: 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.