# Changelog

## Score

- CAI 54 → 49 (-4.4)
- Rubric changed (rubric-2026.10.1 → rubric-2026.10.5) — scores are not directly comparable.

## Lenses

- Code Health 88 → 68 (-19.7)
- Architecture 83 → 84 (+1.1)
- Maturity 53 → 46 (-6.5)
- Readiness 59 → 59 (+0.0)
- Security 48 → 42 (-5.3)
- Domain Modelling 66 → 66 (+0.0)
- Accessibility 60 → 60 (+0.0)

## Resolved (7)

- Duplicate intent across API and Web controllers. Shipit.Api.DeploysController handles the API surface while Shipit.DeploysController handles the Web UI surface. Both expose 'create', 'rollback', and 'revert' operations. While technically distinct namespaces (API vs Web), the duplication of complex business logic entry points (especially rollback/revert) suggests a lack of shared service layer or clear separation of concerns, leading to potential drift in behavior between API and Web clients.
- Fork-triggerable workflow runs with an unscoped write token
- Inconsistent HTTP method usage for similar actions. Shipit.Api.MergeRequestsController uses 'update' (likely PUT/PATCH) for modifying merge requests, while Shipit.MergeRequestsController uses 'destroy' (DELETE) for removal. This is standard REST, but looking at Shipit.Api.MergeRequestsController, it also has 'destroy'. The inconsistency is not here, but rather in the fact that Shipit.MergeRequestsController (Web) does NOT have an 'update' method, only 'create' and 'destroy'. This implies the Web UI cannot update merge requests via this controller, or it uses a different mechanism, whereas the API can. This is a functional inconsistency in capability exposure.
- Inconsistent naming for equivalent operations. Shipit.Api.TasksController uses 'trigger' to start a task, while Shipit.TasksController (Web) uses 'create' to start a task. These appear to be the same domain operation (initiating a task execution) but are named differently in the API vs Web context.
- Off-boarding risk: anonymized user #1
- PR-triggered workflow without a permissions block
- While consistent in name, the existence of both API and Web controllers for Tasks (and Deploys, Stacks, etc.) creates a maintenance burden. However, the more significant inconsistency is within Shipit.TasksController itself: it has both 'create' and 'trigger' is not present, but 'abort' is. Compare with Shipit.Api.TasksController which has 'trigger' and 'abort'. The API uses 'trigger' to start, Web uses 'create'. This inconsistency in the 'start' operation name is the primary issue.

## New (39)

- Both controllers expose 'lookup', which is consistent. However, Shipit.TasksController also exposes 'tail', which is not present in the API controller. 'tail' is likely a streaming operation for logs, which might not fit the RESTful API pattern, but if the API is meant to be feature-complete, this is a gap.
- Both controllers expose 'refresh', which is good. However, Shipit.StacksController also exposes 'lookup' and 'all_tasks', while Shipit.Api.StacksController does not. This suggests the API controller is a subset of the web controller's functionality, which is acceptable but should be intentional. The inconsistency lies in the fact that 'lookup' is a common pattern for finding resources, yet it's missing from the API.
- Duplicate intent across API and Web controllers. Shipit.Api.DeploysController and Shipit.DeploysController both expose 'create'. Furthermore, Shipit.DeploysController exposes 'rollback' and 'revert' as distinct actions, while Shipit.Api.DeploysController only exposes 'create'. This suggests the API controller is either incomplete or the domain model for 'rollback' vs 'revert' is not consistently exposed via the API.
- Fork-triggerable workflow runs with an unscoped write token (.github/workflows/cla.yml)
- Further sole-owners (lower concentration)
- High CVE: [GHSA redacted] (Gemfile.lock)
- Inconsistent naming for starting a task. The API controller uses 'trigger' to start a task, while the web controller uses 'create'. This forces consumers of the API to use a different verb than the internal web application logic, creating cognitive load.
- Off-boarding risk: anonymized user #1
- Orphaned file (app/controllers/shipit/api/base_controller.rb)
- Orphaned file (app/controllers/shipit/merge_status_controller.rb)
- Orphaned file (app/helpers/shipit/stacks_helper.rb)
- Orphaned file (app/models/concerns/shipit/deferred_touch.rb)
- Orphaned file (app/models/shipit/commit.rb)
- Orphaned file (app/models/shipit/continuous_delivery_schedule.rb)
- Orphaned file (app/models/shipit/deploy_spec/file_system.rb)
- Orphaned file (app/models/shipit/deploy_spec/lerna_discovery.rb)
- Orphaned file (app/models/shipit/deploy_spec/npm_discovery.rb)
- Orphaned file (app/models/shipit/hook.rb)
- Orphaned file (app/models/shipit/merge_request.rb)
- Orphaned file (app/models/shipit/review_stack.rb)
- …and 19 more

## Changes since last survey

- 7 commits — 6 feature/other, 1 fixes

## By area

- (repo) — 3 commits
- (root) — 2 commits
- app/models — 1 commit
- test/jobs — 1 commit

## Notable commits

- fix: Merge pull request #1505 from Shopify/gulkaran/fix-status-webhook-repository-scope
- change: Avoid duplicate inserts when updating existing check runs (#1506)
- change: Back off GitHub server errors before exhausting job retries
- change: Merge pull request #1507 from Shopify/release/0.45.5
- change: Merge pull request #1508 from Shopify/gulkaran/backoff-github-server-errors
- change: Scope status webhooks to their repository
- change: v0.45.5

## Architecture

- 0 containers · 1 bounded contexts · 0 dependency edges (baseline)
