Review: [Ch 9] CI/CD — add lint, security scan, and test steps

review-1949-2026-08-01 Review

review needs-refinement

Verdict: NEEDS_REFINEMENT

Template Completeness

  • [x] Type — Feature
  • [x] Lineage — present
  • [x] Repo — present (ldraney/mdview)
  • [x] User Story — present
  • [x] Context — present
  • [x] File Targets — present
  • [x] Feature Flag — present (none)
  • [x] Acceptance Criteria — present (4 items)
  • [x] Test Expectations — present
  • [x] Constraints — present
  • [x] Checklist — present
  • [x] Related — present

Traceability

  • [x] story:full-stack label — "Register READMEs via CLI, browse on phone via iOS app with Keycloak auth"
  • [x] story note verified — found in project-mdview user-stories section (status: TBD)
  • [x] arch:mdview-app label — present on board item
  • [ ] arch note MISSING — [SCOPE] Create architecture note arch-mdview-app for component mdview-app
  • [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/ldraney/mdview/issues/18, open

File Targets

  • [x] .woodpecker.yaml — verified: exists, currently contains only clone and build-and-push steps. No lint/security steps yet, matching issue description.
  • [x] Dockerfile — correctly listed as "should NOT touch"
  • [x] Gemfile — correctly listed as "should NOT touch"; gems verified present: rubocop-rails-omakase (line 43), brakeman (line 40), bundler-audit (line 37). All confirmed in Gemfile.lock.
  • [x] .rubocop.yml — exists, inherits from rubocop-rails-omakase
  • [x] config/bundler-audit.yml — exists with placeholder ignore list

Repo Placement

OK. Issue filed on ldraney/mdview, fix targets ldraney/mdview. Single-repo change.

Dependencies

  • Board item #1242 "Add .woodpecker.yaml CI pipeline" — done. This is the existing pipeline this ticket extends.
  • No other board items block or are blocked by #1949.

Acceptance Criteria

4 criteria, all agent-verifiable by checking Woodpecker pipeline output after push to main. Criteria are clear and measurable. No missing criteria detected.

Blast Radius

  • Image name conflict: The constraint says harbor.tail5b443a.ts.net/library/rails-base:latest but the landscaping-assistant pattern (also referenced in constraints) uses harbor.tail5b443a.ts.net/library/ruby-rails-build:latest. These are different images. The agent implementing this will not know which to use.
  • Missing bundle-install step: The landscaping-assistant CI pattern has a separate bundle-install step that copies pre-cached gems from the image (cp -a /usr/local/bundle/. vendor/bundle/) before lint can run. The mdview issue does not mention this step. Without it, rubocop/brakeman/bundler-audit gems will not be available in the lint step unless the specified image already has them installed. This is a critical implementation detail.
  • 10+ sibling repos have Woodpecker CI configs. No blast radius beyond mdview — this is a self-contained CI change.

Decomposition Assessment

1 file target in 1 repo. 4 acceptance criteria. Estimated agent work well under 5 minutes. No decomposition needed.

Recommendation

  • [SCOPE] Create architecture note arch-mdview-app for component mdview-app in pal-e-docs.
  • [BODY] Fix image name conflict in Constraints section: constraint says rails-base:latest but the landscaping-assistant pattern uses ruby-rails-build:latest. Clarify which image to use, or confirm they are the same.
  • [BODY] Add bundle-install step to File Targets or Constraints: the landscaping-assistant pattern requires a separate bundle-install step before lint. Either (a) add it as an explicit step in the spec, or (b) confirm the lint image has all gems pre-installed and no bundle-install step is needed.