test(controllers): replace covered lifecycle greps with executed tests (#310)

* test(usage): replace covered UsageController greps with executed tests

25 of the 26 UsageController source-text assertions are covered by executed
tests in tests/test_usage_controller.py each proven by breaking the
described behavior and watching a test go red. One assertion is kept with
a stated reason. No production code changes.

New coverage, written test-first before the removals:
test_shrunk_timeouts_expire_pending_work_and_drop_late_replies derives a
copy of the committed UsageController.qml with only the deadline
(120000ms to 600ms) and the expiry sweeper (1000ms to 50ms) shortened,
then observes the effect for all three command kinds against the
slow-first fixture: usage and providerConfig timeouts surface one failure
each and release loading, providerFallback timeouts degrade to a
commandFailed snapshot, late replies are dropped, and refresh(true)
recovers. It goes red when expireCommands is emptied, when the usage
timeout retires silently instead of failing, and fails closed at
derivation time when the sweeper text changes. It stays green when only
the deadline value changes, so the production value is pinned by the
existing 123s production-timeout test instead.

Evidence, per removed assertion (fragment -> mutation -> red test):

test_process_lifecycle.sh (14 removed):
- defaultCommandTimeoutMs: 120000 -> 120000 to 999999999 ->
  test_productionTimeoutsReleaseEveryKindAndRejectLateReplies red (full
  suite FAILED; the shrunk test stays green by design, T4).
- function connectUsageCommand -> skip CommandLedger.opened registration
  -> rosterCache, batchedInputs red (replies for unregistered sources are
  dropped).
- function finishUsageCommandSource -> empty body -> batchedInputs,
  resetAndMissingCommand, periodicRefresh red (retired sources stay
  connected and ledger-held; stale replies accepted).
- function retireUsageCommands -> no-op body -> resetAndMissingCommand
  red (stale reply accepted after reset).
- function expireCommands -> empty body -> new shrunk test red (T1).
- function handleCommandTimeout -> usage case retires silently, no fail
  -> new shrunk test red (T2).
- id: usageRefreshTimer -> delete the Timer block -> periodicRefresh red
  (also covers the identical parity assertion; one mutation, two rows).
- running: controller.refreshIntervalSec > 0 -> running: false ->
  periodicRefresh red.
- if (!lifecycle.hasPendingPeriodicRefreshCommands()) -> unconditional
  refreshNow -> periodicRefresh red (first snapshot reports run 2,
  expected run 1).
- function hasPendingPeriodicRefreshCommands -> return false ->
  periodicRefresh red.
- lifecycle.finishUsageCommandSource(sourceName) -> drop the usage-case
  call in onNewData -> periodicRefresh red (lingering usage entry blocks
  the periodic guard, second refresh never starts).
- import ProviderFallbackQueue.js -> drop import -> queueContinues,
  rosterCache red.
- import ProviderRosterCache.js -> drop import -> rosterCache,
  firstChecksumDoesNotCacheAnOlderRoster red.
- property var providerFallbackState: null -> drop property ->
  queueContinues, rosterCache red.

test_refresh_nonce.sh (6 removed):
- function commandWithRunNonce(command) -> return the bare command ->
  rosterCache, scopedArguments red (CLI crashes without CODEXBAR_PLASMA_RUN env).
- commandWithRunNonce(commandSource) -> bare commandSource -> periodic,
  failuresRelease red.
- commandWithRunNonce(providerConfigCommandSource) -> bare source ->
  rosterCache red.
- CommandLedger.find(activeCommandDescriptors, sourceName) -> lookup
  forced to null -> rosterCache red (every reply dropped). Note: deleting
  only the !descriptor guard stays green because the following
  descriptor.kind access throws and drops the reply anyway; the proof
  targets the lookup itself.
- var baseCommand = buildProviderUsageCommand(providerID) -> empty
  command -> scopedArguments, queueContinues red.
- sourceName: commandWithRunNonce(baseCommand) -> bare baseCommand ->
  queueContinues, scopedArguments red.

test_feature_parity.sh (3 removed):
- function selectedAccountForProvider(providerID) -> return empty ->
  scopedArguments, refreshCoalesces red (accountKey mismatch).
- id: usageRefreshTimer -> same Timer-block deletion as above.
- interval: Math.max(1, controller.refreshIntervalSec) * 1000 ->
  interval 3600000 -> periodicRefresh red.

test_security_regressions.sh (2 removed):
- maximumConcurrentProviderFallbackCommands: 8 -> 20 ->
  queueContinues red (CLI-measured peak concurrency exceeds 8,
  version bound fails).
- maximumSnapshots: maximumProviderSnapshots -> 3 -> queueContinues
  red (snapshot length 3, expected 11).

Kept (1):
- interval: 0 stays with a justifying comment: 0 -> 200 on the usage
  DataSource keeps every controller test green (polling an
  already-running executable source is a logged no-op, shown with a
  long-connected periodic source), and require_in_surface is
  existence-anywhere across ten files, so no single-file mutation can
  turn it red. Unobservable and structurally collective, per the PR #309
  model.

* test(updates): replace covered WidgetUpdateController greps with executed tests

25 WidgetUpdateController assertions triaged by mutation against
tests/test_widget_update_controller.py (real controller + synthetic
updater scripts through qmltestrunner): 21 removed as redundant, 4 kept
with a stated reason. No production code changes; git diff contents/ is
empty.

New executed tests (added before their removals, each shown red below):
- test_missingUpdaterScriptReportsPackagingError: missing-script error
  text is verbatim "Widget updater script is missing from the installed
  package."
- test_longUpdaterDetailStaysBounded: 500-char errorDetail collapses to
  exactly 500 chars of presented error text (new "longdetail" fixture).
- test_installQueuedDuringCheckKeepsRequestModes now also compares the
  installed statusText incl. the restart hint.

Removed (mutation -> red test):
test_update_widget.sh:
- L137 function missingUpdateScriptJson() -> fallback status
  error->current -> test_invalidResults(missing) red.
- L138 missing-script message literal -> error-text copy changed ->
  new packaging-error test red (payload message copy changed -> green:
  resultIntent never reads payload message, so that copy is dead).
- L139 errorCode missing_updater -> code typo -> new packaging-error
  test red (existing suite stayed green: the gap the new test closes).
- L140 widgetUpdateErrorText() -> early return "" ->
  test_invalidResults(structured, missing) red.
- L141 if [ -x guard / L142 printf fallback -> else branch dropped ->
  new packaging-error test red (falls through to "no data").
- L143 sh -c return -> bare command returned ->
  test_recentStartupStillChecksAndCoalescesRequests red.
- L144 Checking setWidgetUpdateState(..., false) -> persist flag
  dropped -> recentStartup recorded-count red (literal-only change ->
  green: transient text is i18n-owned).
- L146 Restart Plasma hint -> literal changed -> new installed
  statusText assertion red (existing queued test stayed green).
- L147 handleUpdateCommandTimeout() -> early return -> timeout test red.
- L148 updateCommandTimeoutTimer id -> id renamed -> component fails
  to load, invalidResults red.
- L149 timer restart() -> restart commented out -> timeout test red.
- L151 "operation timed out" -> literal changed -> timeout test red
  (asserts indexOf "timed out").
- L159 checkForWidgetUpdate() -> early return -> recentStartup and all
  invalidResults red.
- L160 updateCheckDue gate -> if (false) ->
  test_disabledChecksCannotBeForced red.
- L161 checkForWidgetUpdate(true) -> all 5 call sites true->false ->
  recentStartup and queued-install tests red.
test_feature_parity.sh:
- L452 updateChecksEnabled -> property deleted -> load error, all red.
- L453 buildUpdateCommand() -> mode forced to --check -> queued
  install never fires, install test red.
- L454 resultIntent(payload, installMode) -> installMode forced false
  -> disablingAutomaticInstall test red (available wrongly notified).
- L456 boundedWidgetUpdateText() / L457 bound call site -> cap
  500->2000 -> new bound test red (existing suite stayed green).
test_process_lifecycle.sh: L32-L34 covered by the same M20 run below.

Kept with reason (green full-suite mutation, comment added at the pin):
- test_update_widget.sh updateCommandTimeoutTimer.stop(): removing it
  keeps all 14 updater tests green (single-shot timer either already
  fired or fires into the empty-source guard no-op). Only pin that a
  finished command retires its deadline.
- test_process_lifecycle.sh updateRetryPending / connectedUpdateInstallMode
  / pendingAutomaticUpdateCheck initial-false: flipping all three to true
  keeps the suite green (each flag is overwritten by its request /
  completion decision before any effect). Only pins of the idle initial
  state.

Verification: make check-feature-parity, check-process-lifecycle,
check-update-widget green; python3 -m unittest
tests.test_widget_update_controller (5 tests incl. 65s production-timeout
case) OK; check-shellcheck green. check-python-lint skipped (pyflakes
absent locally, CI installs it). Full make check left to the orchestrator.

* test(providers): replace covered ProviderRosterController greps with executed tests

12 of the 16 ProviderRosterController source-text assertions are covered
by executed tests in tests/tst_provider_roster_controller.qml, each proven
by breaking the described behavior and watching a test go red. 4 assertions
are kept with a stated reason. No production code changes; git diff
contents/ is empty.

New coverage, written test-first before the removals (each shown red below):
- test_creationWithActiveQueuesSingleLoad: active-at-creation queues one
  load (completion hook and injected path coalesce).
- test_activeCreationWithoutPathSurfacesConfigurationError: active creation
  with no command path surfaces the diagnostics error without spawning.
- test_commandPathChangeQueuesReload: path change on an active controller
  queues a reload.
- test_expiredCommandsSurfaceTimeoutAndDropLateReplies: forcing expiry past
  the deadline releases loading with the timeout error and drops the late
  reply.
- test_newerRefreshRetiresStaleReply: a newer refresh mints a distinct nonce
  source; the stale reply is dropped while the current run stays pending.
- test_connectedLoadSettlesThroughDataSource: the load reaches the real
  executable DataSource and its answer settles the controller end to end.
- test_timeoutSweepTracksPendingCommands: the expiry sweep timer runs while
  a command is pending and stops once its reply settles the controller.

Evidence, per removed assertion (fragment -> mutation -> red test):

test_process_lifecycle.sh (6 removed):
- providerRosterCommandTimeoutMs: 60000 -> 60000 to 999999999 ->
  expiredCommandsSurfaceTimeoutAndDropLateReplies red (forced +120000ms
  advance no longer crosses the deadline).
- import ../CommandLedger.js as CommandLedger -> import deleted -> whole
  suite red (component fails to load); same mutation covers the
  refresh-nonce import row below.
- Component.onCompleted ... loadProviderRoster -> line deleted ->
  activeCreationWithoutPathSurfacesConfigurationError red (no path change
  ever fires there, so only the completion hook queues that first load);
  creation-with-path tests stay green via the path hook.
- onCommandPathChanged ... loadProviderRoster -> line deleted ->
  commandPathChangeQueuesReload red; creation tests stay green via
  onCompleted.
- function expireProviderRosterCommands(nowMs) -> early-return body ->
  expiredCommandsSurfaceTimeoutAndDropLateReplies red.
- id: providerRosterCommandTimeoutTimer -> Timer block deleted ->
  timeoutSweepTracksPendingCommands red (sweep timer not found).

test_refresh_nonce.sh (6 removed):
- property int commandRunSerial: 0 -> 0 to 100 -> 6 tests red, including
  both pre-existing serial assertions.
- import ../CommandLedger.js as CommandLedger -> same import-deletion
  mutation as above, whole suite red.
- commandRunSerial += 1 -> increment deleted -> newerRefreshRetiresStaleReply
  and the pre-existing deactivationRetiresRepliesAndLoadingState red
  (successive runs mint identical sources).
- withRunNonce(command, commandRunSerial) -> bare command ->
  stale-discard asserts red (stale source equals current source; the
  duplicate DataSource connect also warns).
- providerRosterCommands = CommandLedger.opened( -> registration skipped ->
  5 tests red (every reply dropped, including the end-to-end settle test).
- providerRosterSource.connectSource(sourceName) -> call deleted ->
  connectedLoadSettlesThroughDataSource red (loading never releases).

Kept (4):
- interval: 0 stays: 0 -> 200 keeps all 11 roster tests green, and the
  pin is collective across 8 surface files, so no single-file mutation can
  turn it red (same finding as the UsageController step).
- reject function commandWithRunNonce(command) stays in both scripts:
  absence assertions with no runtime equivalent; the ledger import plus the
  nonce/discard tests above pin the behavior positively.
- controller.expireProviderRosterCommands(Date.now()) stays with a
  justifying comment: neutering the sweep trigger keeps all 11 tests green
  (its effect only fires after a 60s pending window), so no fast executed
  test can pin that call; the expire function, timeout value, and timer
  wiring are pinned separately.

Verification: make check-process-lifecycle and check-refresh-nonce green;
qmltestrunner tests/tst_provider_roster_controller.qml 11/11 green;
shellcheck on both scripts clean (pre-existing SC1091 info only). Full
make check left to the orchestrator.

* test(cost): replace covered CostController greps with executed tests

4 of the 8 CostController source-text assertions are covered by executed
tests in tests/test_cost_context.py (real controller plus synthetic CLI
through qmltestrunner), each proven by breaking the described behavior and
watching a test go red. 4 assertions are kept with a stated reason. No new
tests were needed: every removable pin already goes red against the
existing suite, and the keeps are structurally unobservable or shared pins
for other steps. No production code changes; git diff contents/ is empty.

Evidence, per assertion (fragment -> mutation -> result):

test_process_lifecycle.sh (2 removed):
- import "../CostRefreshPolicy.js" as CostRefreshPolicy -> import deleted ->
  test_startupRunsWhileHiddenAndReentryKeepsFreshData red (component cannot
  load without the policy module).
- property double lastAttemptAtMs: -1 -> property deleted ->
  test_startupRunsWhileHiddenAndReentryKeepsFreshData red (load failure).
  Note: -1 -> 0 stays green (any past value starts the first attempt), so
  the removed pin covered existence, not the value.

test_feature_parity.sh (2 removed):
- if (!controller.costUsageEnabled || controller.commandPath.length === 0)
  -> guard neutered to if (false) ->
  test_disabledOrMissingCommandDoesNotStart red on both data rows.
- "--days" -> flag dropped from the commandSource parts ->
  test_startupRunsWhileHiddenAndReentryKeepsFreshData red (synthetic CLI
  rejects the argv, startup never completes).

Kept (4), each with verification:
- interval: 0 stays: collective pin across 8 surface files (same finding as
  the usage/roster steps). 0 -> 200 keeps the executed assertions green;
  the runner then segfaults at teardown after all tests PASS (3/3 runs with
  the mutation vs 0/3 clean), a harness/Qt teardown race, not a behavioral
  pin, so no executed test can replace it file-by-file.
- interval: CostRefreshPolicy.automaticRefreshIntervalMs stays: 3600000 and
  50 both keep the suite green (the hour never elapses in a fast test;
  rapid firing throttles to a no-op inside CostRefreshPolicy), so no
  mutation can prove this pin redundant.
- property bool costUsageEnabled stays: shared pin with main.qml:64, whose
  Plasmoid-backed copy belongs to the main.qml step. The cost copy is proven
  covered (property deleted -> startup test red).
- CommandLedger.withRunNonce(commandSource, runSerial) stays: shared pin
  with SessionsController.qml:101, which belongs to the sessions step. The
  cost copy is proven covered (bare commandSource ->
  test_manualRefreshSupersedesAnActiveScan red: the CLI crashes without
  CODEXBAR_PLASMA_RUN).

Verification: make check-feature-parity, check-process-lifecycle,
check-refresh-nonce green; shellcheck clean (pre-existing SC1091 info
only); python3 -m unittest tests.test_cost_context OK on the unmodified
tree (137s baseline). check-python-lint skipped (pyflakes absent locally,
CI installs it). Full make check left to the orchestrator.

* test(usage): make the shrunk-timeout fixture survive a reformat

The derivation pinned the committed QML layout: a three-line literal with
its exact indentation for the sweeper Timer, and single spaces in the
defaultCommandTimeoutMs pattern. A behaviour-preserving qmlformat run would
have failed the test before it ever exercised the timeout path — the same
change-detector defect this suite exists to remove, reintroduced inside the
replacement.

Both rewrites are now whitespace- and layout-tolerant. The sweeper interval
is located by walking back from the running: binding that asks the ledger
for pending timeouts, with an assertion that no other Timer block sits in
between, so the rewrite stays scoped to the intended timer.

Verified: reindenting that Timer and inserting a blank line between its
properties keeps the test green, where the previous literal would not have
matched at all; emptying expireCommands still turns it red.

Raised by CodeRabbit on #310.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
21fb0d5808Simone committed on 9/21/2026, 6:29:36 PM· committed by GitHubparent85a882c
8 files changedLine totals unavailable