Promote: staging -> develop#859
Merged
Merged
Conversation
## Problem Every push to `staging` currently runs the "RealUnit Build" workflow twice on the same SHA: 1. once from the `push: staging` trigger, and 2. once from the permanently-open auto-PR "Promote: staging → develop" (#841) via `pull_request`. Those two runs use different concurrency groups (PR number vs. `github.ref`), so `cancel-in-progress` never cancels one against the other. Both compete for the single self-hosted runner slot used by Visual Regression / `golden-tests`. ## Fix Map that same-repo staging-head PR (`pull_request` + `head_ref == 'staging'` + head repo matches this repository) into the same constant concurrency group as `push: staging` (`refs/heads/staging`). `cancel-in-progress` then cancels the duplicate, and exactly one real run survives per staging-lane commit. ## Fail-closed (not skip-as-success) This is deliberately **not** the skip-as-success approach previously proposed and rejected in #850. A step/job that is merely skipped and treated as green can mask a red `push: staging` result. Here there is no `if:` skip and no success-without-running path: both triggers still schedule real work; the concurrency group collapses the pair so one run is cancelled. A red stays red. Worst case is a plain `cancelled` check — fail-closed and fixable by re-running — never a masked green. ## Fork-identity guard The group remapping requires `github.event.pull_request.head.repo.full_name == github.repository`, so a fork branch that happens to be named `staging` cannot cancel the real staging lane. ## Feature PRs Unaffected. They keep the existing PR-number concurrency group (with `github.ref` fallback for push / workflow_dispatch).
…858) ## Summary Follow-up to #854 (which fixed 25 sticky-CTA surfaces). An **empirical** audit of the surfaces the original grep missed — they use `Column(mainAxisSize: .min)`, not `Spacer()`, so no text search finds them — proved **4 more bottom sheets** clip their CTA out of the hit-test region at large system text scale (dead button, no red stripe in release): | Sheet | breaks at | impact | |---|---|---| | `sell_confirm_sheet` | text scale 2.0 | cannot confirm a sale | | `sell_executed_sheet` | **~1.2** | success sheet not closable — it was shown **without** `isScrollControlled`, so clamped to 9/16 of screen height | | `forgot_pin_bottom_sheet` | 2.0 | cannot reset the PIN | | `enable_biometric_bottom_sheet` | 2.0 | cannot enable/skip biometrics | ## What changed - New `shrinkWrap` mode on `ScrollableActionsLayout`: sizes to content up to the available height, scrolls the body past it, keeps the actions pinned — so a short sheet is not forced to full height but never clips its CTA. With `shrinkWrap:false` (default) the 25 screens from #854 are **byte-identical** (their whole test suite re-run unchanged). - The 4 sheets migrated to `ScrollableActionsLayout(shrinkWrap: true)` bounded at 0.9× screen; `sell_executed`'s call site fixed to `isScrollControlled: true`; `sell_confirm`'s info-row horizontal overflow fixed (both label and value shrink-safe). - Each sheet gated by a matrix test pumped through a **real** `showModalBottomSheet` (so the screen-height bound is faithful); every test verified to fail against the pre-fix code. - Catalog now lists all **29** surfaces; `welcome_page` audited → safe (scrolls). Docs state honestly that no further sticky-CTA surface of this shape is known. ## Test plan - [x] `flutter analyze` clean - [x] `flutter test` — **4432 passed** incl. goldens (rebased on current staging with #855/#856) - [x] 3 sell-sheet goldens regenerated & visually inspected; pin sheets render pixel-identical - [ ] CI on this PR
…rmed-email quote gate (#860) ## Problem A buy confirm that the share register rejects with the `PrimaryEmailRequired` error code (HTTP 400) currently falls into `BuyConfirmError.unknown` and shows the generic technical-problem snackbar — the buyer gets no hint that an email confirmation is outstanding. This is the error path a real buyer hit repeatedly last week. ## Changes - **Confirm path:** `BuyConfirmError.primaryEmailRequired` — mapped from the API error code (never from message text), 503 precedence unchanged and pinned by a test. The snackbar reuses the existing `buyPaymentConfirmFailedAktionariat` copy, which describes exactly the required action (check your inbox for the pending confirmation); no new ARB keys. - **Quote path (forward-compatible):** handles the upcoming `PrimaryEmailNotConfirmed` quote error (`isValid:false`). The action button routes to the KYC page — which auto-resolves to its confirm-email step — instead of the email-capture flow, then re-fetches the quote. Unreachable until the API starts emitting the code, so this PR is fully backward-compatible. - Tests: cubit mappings (incl. 503-precedence pin), state props, snackbar copy, action-button routing (pushes KYC, not email capture), plus golden coverage for the new gate state and snackbar. ## Merge order This app change must be released **before** the API starts emitting `PrimaryEmailNotConfirmed` — older app versions would otherwise degrade to the generic retry dead-end on the quote screen. The confirm-path fix is effective immediately with the current API. --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Summary - isolate staging-push routing from canonical required checks - let the ready `staging → develop` PR own normal CI - dispatch the full `RealUnit Build` as a fail-safe when the promotion PR is missing, draft, stale, or cannot be queried - preserve per-lane cancellation for obsolete SHAs without any cross-event cancellation - upgrade first-party Actions to Node.js 24-compatible majors and disable the inapplicable Go module cache - document trigger ownership and fallback guarantees ## Root cause `push: staging` and the promotion PR previously shared one concurrency group. When the PR event arrived after the push event, `cancel-in-progress: true` cancelled the push run on the same head SHA. GitHub attached the cancelled `Analyze & Test`, `Coverage Floor Gate`, `Visual Regression`, and `BitBox quirks audit` checks to the current promotion PR, leaving it visibly red even though the replacement PR run succeeded. ## Design Canonical jobs remain in `pull-request.yaml` with their stable required-check names. That workflow now handles PRs, `push: develop`, and manual dispatches only. The new `staging-ci-fallback.yaml` workflow handles `push: staging`: 1. Query open `staging → develop` PRs using an exact base, head owner/branch, repository, draft-state, and head-SHA match. 2. If a ready same-repository PR already points at the pushed SHA, do nothing: its `synchronize` event owns canonical CI. 3. If the PR is missing, draft, stale, or the API lookup fails, dispatch `pull-request.yaml` on `staging` via `workflow_dispatch`. 4. Keep router concurrency isolated from `RealUnit Build`, so routing can never cancel required PR checks. This removes duplicate heavy macOS/self-hosted work in the normal promotion path while failing safe to a full build whenever PR ownership cannot be proven. ## Required-check safety The initial same-workflow approach was deliberately replaced after live verification showed that GitHub renders expressions in skipped job names literally. Keeping routing in a separate workflow means: - canonical required-check names are stable - the router never emits skipped checks with canonical names - a skipped job cannot accidentally satisfy a required check - no raw expression-based check names appear in the staging-push path ## Additional CI cleanup - `actions/checkout@v6` - `actions/setup-go@v6` with `cache: false` because this repository has no `go.mod`/`go.sum` - `actions/upload-artifact@v6` - `actions/download-artifact@v7` These versions use the Node.js 24 runtime. The self-hosted golden runner reported version `2.335.1`, above the Actions minimum of `2.327.1`. ## Validation - `actionlint -ignore 'label ".+" is unknown' .github/workflows/pull-request.yaml .github/workflows/staging-ci-fallback.yaml` - Ruby YAML parse for both workflows - `git diff --check` - exact embedded router script exercised with mocked GitHub responses: - ready PR at current SHA → no fallback dispatch - draft PR → full fallback dispatch - stale PR SHA → full fallback dispatch - GitHub API failure → full fallback dispatch - manual invocation → full dispatch The ignored `actionlint` diagnostics are the repository's existing custom self-hosted labels (`m3-ultra`, `realunit-app`). ### End-to-end result [Manual `RealUnit Build` run 29418489339](https://github.com/RealUnitCH/app/actions/runs/29418489339) completed successfully on commit `69e86893`: - `Analyze & Test` — success - `Coverage Floor Gate` — success, including artifact upload/download on the upgraded Actions - `Visual Regression` — success on the self-hosted runner - `BitBox quirks audit` — success without the previous `go.sum` cache warning - no Node.js 20 deprecation annotation
#862) ## Why RealUnitCH/web#23 adds a dedicated confirm-page end state (`no-registration`) with four new Playwright baselines (18 → 22 PNGs). The handbook deploy stages those baselines behind the `EXPECTED_WEB_BASELINE_COUNT` guard, which requires the count bump and the matching gallery cards in the same change. ## Changes - `handbook.yaml`: `EXPECTED_WEB_BASELINE_COUNT` 18 → 22. - `docs/handbook/de/index.html` (`#spec-web`): four cards for the new views (desktop de/en, tablet, mobile), mirroring the confirm-invalid card group. ## Coupling Merge together with RealUnitCH/web#23 — the guard fails the next handbook deploy if either side lands alone. The PR-level `Handbook Build Check` does not stage web baselines, so this PR's CI is unaffected either way.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Automatic Staging PR
This PR was automatically created after changes were pushed to staging.
Commits: 1 new commit(s)
Checklist