Skip to content

test(app): pin the template install-failure polarity as a pure function (#10074)#10170

Open
aryanorastar wants to merge 4 commits into
BasedHardware:mainfrom
aryanorastar:refactor/10100-template-creation-seam
Open

test(app): pin the template install-failure polarity as a pure function (#10074)#10170
aryanorastar wants to merge 4 commits into
BasedHardware:mainfrom
aryanorastar:refactor/10100-template-creation-seam

Conversation

@aryanorastar

@aryanorastar aryanorastar commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Summary

The regression test #10100 deferred. #10100 fixed the quick-template sheet so a failed install is surfaced as an error instead of a false success (#10074), but shipped without a regression test — the decision lived inline in the widget's post-await branch, unreachable by a hermetic test without a full widget harness (five stubbed API calls plus path_provider platform channels).

This extracts only that decision — the success/error polarity of the terminal outcome — into templateCreationOutcomeIsError, a pure function the sheet now derives its install-branch snackbar from. Everything else is byte-identical to #10100.

  • New TemplateCreationOutcome enum + templateCreationOutcomeIsError (one pure file, no Flutter deps).
  • The sheet's install branch sources its success/error choice from the classifier instead of an inline bool; the arm order flips (error-first) but the behavior is identical.
  • Unit tests pin the full outcome table, including installFailed → error — the Bug: summary template set as standard/default is not being applied #10074 guarantee — so the failed-install-reads-as-success regression cannot be silently reintroduced.

Behavior identity (verified line-by-line)

Diff is the import line + the install-branch arm-swap; nothing else in _createTemplate changed. Confirmed unchanged vs the #10100 baseline: quickTemplateCreated analytics timing (still fires on submit success, before install), getApps() ordering (still before install), the if (mounted && createdApp != null) gating (so a mid-flow sheet dismissal still cancels install exactly as before), the createdWithoutInstall/submitFailed branches, and the catch block.

  • success → installed → not error → appCreatedAndInstalled + summarized-apps sheet
  • !success → installFailed → error → failedToInstallApp (provider already showed its dialog)

Failure class

Failure-Class: none

test: commit — adds the regression coverage a prior fix: (#10100) deferred; no new triggering defect.

Product invariants affected

none (verified with scripts/pr-preflight --suggest)

Validation

Out of scope, named

  • The submitFailed/createdWithoutInstall outcomes are classified and tested but the sheet's other two branches still snackbar inline (they were never the Bug: summary template set as standard/default is not being applied #10074 surface and have a single, unconditional polarity). Routing them through the classifier too would be ceremony, not safety.
  • A broader flow-orchestration extraction was considered and dropped: it drifted analytics timing, getApps() ordering, and mid-dismiss install behavior for no gain over this focused pin.

Review in cubic

…on (BasedHardware#10074)

BasedHardware#10100 fixed the quick-template sheet so a failed install is reported as
an error instead of a false success, but shipped without a regression
test: the decision was inline in the widget's post-await branch, which a
hermetic test can't reach without a full widget harness (five stubbed
API calls plus path_provider channels).

This extracts only that decision — the success/error polarity of the
terminal outcome — into templateCreationOutcomeIsError, a pure function
the sheet now derives its install-branch snackbar from. Orchestration,
analytics timing, getApps ordering, and the mounted gating are all
byte-identical to BasedHardware#10100; the only change is that the install branch
sources its success/error choice from the tested classifier instead of
an inline bool, so the failed-install-reads-as-success regression cannot
be silently reintroduced.

Tests pin the full outcome table, including installFailed -> error (the
BasedHardware#10074 guarantee) and installed/createdWithoutInstall -> success. Pure
unit tests, no widget pumping, no plugin channels.

Not run locally (no Flutter SDK on this machine); hermetic, app CI lane
runs them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Replace hardcoded datetime(2026, 6, 20, 12, 0, tzinfo=timezone.utc)
with datetime.now(timezone.utc) so the test does not fail as wall-clock
time advances past the frozen date.
@Git-on-my-level

Copy link
Copy Markdown
Collaborator

Nice follow-up to #10100 — this cleanly closes the deferred-test gap: the install-failure polarity is now a pure, hermetically-testable function, and the sheet derives its snackbar from it.

What I verified:

  • Behavior identity holds. The install branch is an arm-swap (error-first) with the same snackbar calls and the same mounted && createdApp != null gating: success → installed → success snackbar + summarized sheet, !success → installFailed → error snackbar. Identical to fix(app): stop reporting a failed template install as success #10100.
  • The classifier is exhaustive and correct. installFailed and submitFailed read as errors; installed and createdWithoutInstall read as success — exactly the Bug: summary template set as standard/default is not being applied #10074 guarantee.
  • The five unit tests pin the full table, including installFailed → error, so the failed-install-reads-as-success regression cannot be silently reintroduced. Flipping the classifier breaks them.
  • Checks are green on the current head (Android Compile Smoke, Dart Analyze ratchet, Flutter Tests, Generated Files all pass; the earlier cancelled/skipped preflight runs were from prior pushes).
  • Leaving submitFailed/createdWithoutInstall snackbar-ing inline is a reasonable call — single unconditional polarity, never the Bug: summary template set as standard/default is not being applied #10074 surface — and the classifier still handles them for future-proofing.

Small, cohesive, low-risk. I am leaving a positive signal rather than formal approval (automation is gated from approving on this one); a maintainer can merge this with confidence. Thanks @aryanorastar for closing the test gap properly.


by AI on behalf of David — if you need David’s attention urgently, please @Git-on-my-level and escalate with need human response.

The polarity assignment fit within the 120-col limit; dart format
collapses the manual line break. Fixes the Formatting check.

@kodjima33 kodjima33 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test-only (app): pins template install-failure polarity as a pure function (#10074) — approve only per policy (mobile area, not a bug fix to merge)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants