Skip to content

chore(ci): CI orchestration hygiene + dependency-review (#420, #416) - #429

Merged
thomasluizon merged 4 commits into
mainfrom
issue-420
Jul 8, 2026
Merged

chore(ci): CI orchestration hygiene + dependency-review (#420, #416)#429
thomasluizon merged 4 commits into
mainfrom
issue-420

Conversation

@thomasluizon

Copy link
Copy Markdown
Owner

Bundles #420 + the orbit-ui-mobile slice of #416.

#420 — orchestration hygiene

  • concurrency: {cancel-in-progress: true} on PR workflows (test.yml, claude-review.yml); sonarcloud.yml cancels only on PR events (never a main-push analysis). Deploy/release (smoke-prod, promote-prod, android-release) deliberately left uncancelled.
  • .turbo actions/cache on the turbo jobs.
  • nightly.yml (0 3 * * *) hosting Testing: scoped mutation testing (StrykerJS) on packages/shared critical logic #417's full-scope mutation report run.

#416 — GitHub-native scanning (ui slice)

dependency-review.yml (fail-on-severity: high). CodeQL + secret-scanning already enabled repo-side; landing-page's Dependabot was turned on too.

⚠️ Merge LAST. This references the Lint (#414/#426), Dependency Review (this PR), and mutation (#417/#427) checks. After the carrying PRs merge, register the new required checks:

gh api -X PATCH repos/thomasluizon/orbit-ui-mobile/branches/main/protection/required_status_checks \
  -F strict=true -f 'contexts[]=Build' -f 'contexts[]=Unit Tests' \
  -f 'contexts[]=Lint' -f 'contexts[]=Dependency Review'

CodeQL stays report-only (not required).

All 5 workflow files YAML-validated.

🤖 Generated with Claude Code

… review (#420, #416)

#420 — concurrency (cancel-in-progress) on PR workflows (test, claude-review, and
sonarcloud PR-only); .turbo actions/cache on turbo jobs; nightly.yml hosting #417's
full-scope mutation report; deploy/release workflows left uncancelled.

#416 (ui slice) — dependency-review.yml (fail-on-severity high) for orbit-ui-mobile.

Must merge LAST (references the Lint/Dependency-Review/mutation checks the other PRs add).

Closes #420

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
orbit-ui-mobile-web Ignored Ignored Jul 8, 2026 8:28pm

Request Review

Editing claude-review.yml makes the claude-code-action self-skip the PR
(reports pass but posts no review), which blocks the required approval. The
concurrency block stays on test.yml + sonarcloud.yml where it matters.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review: PR #429

Scope: PR #429 in thomasluizon/orbit-ui-mobile (chore(ci): CI orchestration hygiene + dependency-review (#420, #416))
Recommendation: APPROVE

Summary

Pure CI-configuration diff: adds .github/workflows/dependency-review.yml and .github/workflows/nightly.yml, and adds concurrency + turbo actions/cache steps to sonarcloud.yml and test.yml. No apps/*, packages/shared source, or orbit-api files change, so the UI/parity/i18n/contract/security/backend-hard-rule dimensions are all N/A. The workflow logic itself (cancel-in-progress scoping, cache key scoping) is correct and consistent with the repo's existing conventions. One Medium cross-PR coordination gap was found and verified.

Findings

Critical

None

High

None

Medium

[MEDIUM] nightly.yml duplicates the nightly full-scope mutation job already shipped in PR #427's mutation.yml
· dimension: 1. Correctness (cross-boundary / cross-PR)
· location: orbit-ui-mobile/.github/workflows/nightly.yml:11-35
· issue: This PR adds a new `mutation` job on `schedule: cron: '0 3 * * *'` that runs `npm run mutation` (full scope) in packages/shared and uploads an artifact named `mutation-report-nightly`. PR #427 (open, branch issue-417, same base commit 8ba9c750) independently adds `.github/workflows/mutation.yml`, which already contains a `nightly:` job (`if: github.event_name == 'schedule'`, its own `cron: '0 6 * * *'`) doing the exact same full-scope `npm run mutation` run and uploading an artifact with the identical name/path. Neither PR's diff removes or coordinates with the other's nightly job. Additionally, `packages/shared/package.json` has no `mutation` script and there is no `packages/shared/stryker.config.json` on current main (both only exist on #427) — confirmed via `git show origin/main:packages/shared/package.json` and a repo-wide search for `stryker.config*`. nightly.yml is already live on this branch's merge ref (HEAD 61c4cba0) and would fail nightly with "Missing script: mutation" until #427 lands.
· risk: If #429 merges before #427, the new nightly job fails every night (harmless — non-blocking, report-only) until #427 lands. Once both PRs are on main, main runs the identical full-scope mutation test twice nightly (03:00 and 06:00 UTC), doubling CI minutes for zero benefit and producing two same-named `mutation-report-nightly` artifacts from different workflow runs — the exact kind of redundant CI this PR's own title ("dedupe PR runs") is meant to eliminate.
· fix: Coordinate the two PRs before both land: either drop the `nightly:` job (and the `schedule:` trigger) from #427's mutation.yml now that #429's nightly.yml is meant to own it (per this PR's own body: "nightly.yml … hosting #417's full-scope mutation report run"), or drop nightly.yml's `mutation` job from this PR and let #427's mutation.yml keep owning it. Whichever PR merges second should carry the removal.
· reference: PR #429 body ("nightly.yml … hosting #417's full-scope mutation report run"); CLAUDE.md rule 10 (DRY at the right level — one nightly mutation job, not two)

Low / Info

None

Subagents

Agent Verdict
parity-checker N/A — no apps/web/** or apps/mobile/** file changed
i18n-syncer N/A — no user-facing strings or i18n JSON changed
contract-aligner N/A — no packages/shared/src/types/* / endpoints.ts, no orbit-api changes
security-reviewer N/A — no orbit-api code changed
design-reviewer N/A — no apps/* or landing-page UI files changed

Validation

Check Result
Lint N/A — diff touches only .github/workflows/*.yml, no lintable source
Type check N/A — no TS/C# source changed
Tests N/A — no source changed; nothing to exercise
Build (api) N/A — orbit-api untouched
YAML well-formedness Manually verified — all 4 files parse as valid, consistently-indented GitHub Actions YAML matching the repo's existing workflow style (automated js-yaml/python -c parse was blocked by sandbox tool approval, so this was a careful manual read rather than a tool-run check)

Deferred — N/A dimensions & files not verdicted

  • Dimensions 2 (dead/stale code), 3 (SOLID/clean-arch), 4 (comment policy), 5 (no-workaround), 6 (type safety), 7 (no console.log), 8 (DESIGN.md/AI-slop), 9 (parity), 10 (i18n), 11 (contract drift), 12 (security — frontend categories), 13 (backend hard rules), 14 (FEATURES.md parity): all N/A — this diff's only surface is .github/workflows/*.yml; none of these dimensions' trigger surfaces are touched.
  • All 4 changed files (dependency-review.yml, nightly.yml, sonarcloud.yml, test.yml) were read in full and given a verdict — nothing deferred among changed files.
  • Automated YAML parsing (python3/node -e) was blocked by sandbox permission prompts in this session; substituted with a manual structural read of all 4 files instead.
  • Writing the report to the skill's default .claude/reviews/ output path was also blocked by a sandbox sensitive-file permission gate; the report was written to /tmp/pr-429-review.md instead (the same fallback location the CI reviewer wrapper itself uses).
  • The claude-review.yml concurrency change mentioned in the PR body was investigated: it was added then reverted within this same PR's commit history (5dd3984b then 82303d1b, see commit message "Editing claude-review.yml makes the claude-code-action self-skip the PR") and nets to no diff against main — confirmed via gh pr diff 429, which correctly shows no claude-review.yml hunk. Not a gap, just resolved before the diff was cut.

What's good

  • concurrency scoping is correctly differentiated: test.yml (PR-only trigger) cancels unconditionally; sonarcloud.yml (push-to-main + PR trigger) conditions cancel-in-progress on github.event_name == 'pull_request' so a main-push SonarCloud analysis is never cancelled mid-run — exactly matches the PR body's stated intent.
  • Turbo cache steps are consistently placed (after npm ci, before the turbo command) and correctly job-scoped via ${{ github.job }} in the cache key across all four jobs they touch, avoiding cross-job cache pollution.
  • dependency-review.yml and nightly.yml both declare minimal permissions: contents: read.
  • No script-injection surface introduced (no untrusted github.event.* context interpolated into a run: block).
  • The commit history shows the author already caught and reverted one real problem mid-PR (claude-review.yml self-skip) — good self-correction.

Recommendation

Approve as-is; the one Medium finding is a cross-PR coordination item between #429 and the still-open #427, not a defect in this PR's own code, and is safe to resolve as a fast follow-up (drop the duplicate nightly: job from whichever of #429/#427 merges second) rather than blocking this PR.

thomasluizon and others added 2 commits July 8, 2026 17:27
Avoids running the full-scope mutation report twice nightly (mutation.yml 06:00
+ nightly.yml 03:00). nightly.yml is the dedicated home for slow gates.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@thomasluizon
thomasluizon merged commit 85d95a2 into main Jul 8, 2026
5 checks passed
@thomasluizon
thomasluizon deleted the issue-420 branch July 8, 2026 20:28

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review: PR #429

Scope: PR #429 in thomasluizon/orbit-ui-mobile (already merged as 85d95a22)
Recommendation: APPROVE

Summary

CI-orchestration hygiene PR: adds dependency-review.yml (fail-on-severity high), adds
concurrency/turbo-cache to test.yml and sonarcloud.yml, and splits the nightly
full-scope mutation run out of mutation.yml into a new nightly.yml. The diff touches
only .github/workflows/*.yml — no application source, no packages/shared contract
surface, no apps/* UI. All five files are internally consistent with the PR's stated
intent and with each other (action versions, cache-key shape, trigger scoping).

Findings

Critical

None.

High

None.

Medium

[MEDIUM] nightly.yml lost the concurrency guard the old nightly job had
· dimension: 3 (SOLID/clean-arch — pattern consistency) / defense-in-depth gap
· location: .github/workflows/nightly.yml:1-12
· issue: In the old mutation.yml, the nightly job was covered by the file-level
concurrency: { group: mutation-${{ github.workflow }}-${{ github.ref }}, cancel-in-progress: true }
block (schedule events all share ref = refs/heads/main, so a slow run would be
protected). The new standalone nightly.yml carries no concurrency: block at all.
· risk: A workflow_dispatch fired manually while the 03:00 cron run is still in
flight (or a cron run that overruns 24h) launches two concurrent full-scope Stryker
runs writing to the same mutation-report-nightly artifact name and consuming double
the runner minutes. Low probability, no correctness break, but the safeguard the old
file had was silently dropped in the split.
· fix: add

concurrency:
  group: nightly-mutation
  cancel-in-progress: false

to nightly.yml (queue rather than cancel, since this is a report job you don't want
to kill mid-run).
· reference: CLAUDE.md rule 10 (pattern consistency when splitting a file) / severity
ladder "defense-in-depth gap"

Low / Info

[INFO] Turbo cache keys are ${{ runner.os }}-turbo-${{ github.job }}-${{ github.sha }}
with a prefix restore-keys fallback — correct pattern for turbo's own incremental
cache (exact-sha key will always miss on a fresh run; the restore-keys prefix match is
what actually pays off). No action needed, called out because it looks at first glance
like a cache that can never hit.

[INFO] dependency-review.yml, actions/cache@v4, and actions/setup-node@v6 are
pinned by tag, not commit SHA, while sonarcloud.yml's third-party
SonarSource/sonarqube-scan-action is pinned by full SHA. This matches the repo's
existing convention (first-party actions/* by tag, third-party orgs by SHA) — not a
new deviation introduced by this PR.

Subagents

Agent Verdict
parity-checker N/A — no apps/web/** or apps/mobile/** file changed
i18n-syncer N/A — no user-facing strings or i18n JSON changed
contract-aligner N/A — no packages/shared/src/types/*/endpoints.ts, no orbit-api change
security-reviewer N/A — no orbit-api code changed
design-reviewer N/A — no apps/*/orbit-landing-page UI file changed

Validation

Check Result
Lint N/A — diff is CI-workflow YAML only, not covered by repo lint
Type check N/A — no TS/C# source in the diff
Tests N/A — no application test surface touched
Build (api) N/A — orbit-api not touched
YAML syntax (manual read of all 5 files) PASS — well-formed, consistent indentation, matches GitHub Actions schema
actionlint / automated YAML validator Not available in this sandbox — deferred, see below

Deferred — N/A dimensions & files not verdicted

  • Dimensions 8 (DESIGN.md/AI-slop), 9 (Parity), 10 (i18n), 11 (Contract drift +
    backward-compat), 13 (Backend hard rules), 14 (FEATURES.md parity): all gated N/A —
    their triggering surfaces (apps/* UI, packages/shared types, orbit-api,
    user-facing feature surface) are untouched by this diff.
  • Dimensions 6 (type safety) and 7 (console.log): N/A — no TS/C#/application code in
    the diff, only YAML.
  • All five subagents: N/A per the gate table above — none of their trigger conditions
    were met.
  • Automated workflow-syntax validation (actionlint): not installed in this sandbox,
    and shell invocations that would have run a YAML parser (python3 -c) were blocked by
    the environment's approval gate — relied on manual read-through instead. Every changed
    file was still read and given a verdict.
  • Branch-protection follow-up the PR body calls for (registering Lint /
    Dependency Review as required checks) is an operational step outside the diff itself
    — not verified here; flagged as Info, not a code-review finding.
  • This report could not be written to the repo's own .claude/reviews/ directory: the
    sandbox's file-permission layer flags anything under .claude/ as a protected path
    and blocked both mkdir and Write there without an interactive approval this
    headless run has no way to grant. Written to /tmp/pr-429-review.md instead; full
    content is also relayed in this session's final message.

Every one of the 5 changed files (dependency-review.yml, mutation.yml, nightly.yml,
sonarcloud.yml, test.yml) received an explicit verdict above — nothing changed was
skipped.

What's good

  • Correctly extracts the nightly full-scope mutation job out of the per-PR workflow
    instead of leaving a schedule: trigger bolted onto a PR-triggered file — cleaner
    separation of concerns, matches the PR's own stated intent.
  • sonarcloud.yml's conditional cancel-in-progress: ${{ github.event_name == 'pull_request' }}
    is the right call — a push-to-main SonarCloud analysis is exactly the kind of run you
    never want silently cancelled by a subsequent push.
  • Deploy/release workflows (smoke-prod, promote-prod, android-release) were deliberately
    left out of the cancel-in-progress rollout, per the PR body — correct, cancelling a
    live deploy mid-flight would be far worse than a duplicate CI run.
  • dependency-review.yml uses minimal permissions: contents: read — no
    over-provisioned token scope.

Recommendation

Approve as-is. The one Medium (missing concurrency guard on nightly.yml) is a
low-blast-radius, easily-fixed follow-up — worth a quick one-line addition in a later
commit but not worth blocking this merge over, and the PR is already merged
(85d95a22). No Critical or High findings survive review.

@sonarqubecloud

sonarqubecloud Bot commented Jul 8, 2026

Copy link
Copy Markdown

thomasluizon added a commit that referenced this pull request Jul 13, 2026
… lcov) (#463)

The Sonar job's persisted turbo cache (added #429) replayed the `test` task
instead of running vitest, so no lcov was generated and the merged
coverage/lcov.info was empty -> Sonar reported 0.0% (regressed from ~56%).
Declare coverage/** as the test task's turbo outputs and move each workspace's
vitest reportsDirectory inside its package so a cache hit restores real
coverage; repoint the sonarcloud.yml merge step at the in-package lcov paths.
Also exclude the generated Zod snapshot from coverage.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant