Skip to content

feat: add blast radius documentation (CM-1371) - #4462

Merged
ulemons merged 4 commits into
mainfrom
feat/blast-radious-adr
Aug 12, 2026
Merged

feat: add blast radius documentation (CM-1371)#4462
ulemons merged 4 commits into
mainfrom
feat/blast-radious-adr

Conversation

@ulemons

@ulemons ulemons commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds ADR-0017 documenting the final architecture of the blast-radius analysis pipeline
(services/apps/packages_worker/src/blast-radius): the 4-stage Temporal workflow, how it
was generalized across 7 package ecosystems, the local-testing setup using a personal
Claude Code token, and the dedicated Kubernetes node pool / scaling strategy.

Changes

  • Add docs/adr/0017-blast-radius-pipeline-architecture.md, covering:
    • The 4 pipeline stages (intel → dependents → reachability → report/finalize), with a
      Mermaid diagram showing the strictly sequential flow (no cross-stage parallelism).
    • Clarifies that stage 4 ("report") does not render a human-readable report — it
      aggregates cost and finalizes the blast_radius_analyses row for the polling API to
      read. Kept the existing stage = 'report' naming for continuity with the DB enum,
      but documented it as a naming mismatch worth a low-risk follow-up rename.
    • The EcosystemConfig registry pattern (stages/ecosystems.ts) that generalizes all 7
      ecosystems (npm, go, maven, cargo, nuget, rubygems, pypi) behind one interface, and the
      prepareSource asymmetry (npm has a pre-resolved tarball URL vs. every other ecosystem
      resolving a version at reachability time) as the one genuinely ecosystem-specific axis.
    • Local development flow: generate a personal OAuth token with claude setup-token and
      set CROWD_AKRITES_CLAUDE_CODE_DEV_OAUTH_TOKEN to run the full agent pipeline locally
      without AWS credentials.
    • Infra: the dedicated pg-blast-radius node pool (vs. the shared pg-packages pool
      used by every other packages worker), sized for the CPU/memory-bursty agent workload,
      and the horizontal (replicas) / vertical (resources + NODE_OPTIONS) scaling headroom
      it enables independently of the rest of the packages pipeline.
  • Update docs/adr/README.md index with the new ADR-0017 entry.

Type of change

  • Bug fix
  • New feature
  • Refactor / cleanup
  • Performance improvement
  • Chore / dependency update
  • Documentation

JIRA ticket

CM-1371

@ulemons ulemons self-assigned this Aug 11, 2026
Copilot AI balanced review requested due to automatic review settings August 11, 2026 09:41
@cursor

cursor Bot commented Aug 11, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Documentation-only ADR addition with no code, infra, or behavioral changes.

Overview
Adds ADR-0017 documenting the accepted blast-radius analysis architecture: the 4-stage Temporal workflow (intel → dependents → reachability → finalize), multi-ecosystem EcosystemConfig generalization across 7 package ecosystems, Claude credential resolution for local vs production runs, and the dedicated pg-blast-radius node pool / scaling model.

Also indexes the new ADR in docs/adr/README.md. No runtime or application code changes.

Reviewed by Cursor Bugbot for commit 4dac3c6. Bugbot is set up for automated code reviews on this repo. Configure here.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds an ADR describing the blast-radius pipeline’s workflow, ecosystem abstraction, local authentication, and deployment strategy.

Changes:

  • Documents pipeline stages, scaling, and operational trade-offs.
  • Adds ADR-0017 to the documentation index.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 8 comments.

File Description
docs/adr/README.md Adds ADR-0017 to the index.
docs/adr/0017-blast-radius-pipeline-architecture.md Documents the blast-radius architecture and operations.
Suppressed comments (1)

docs/adr/0017-blast-radius-pipeline-architecture.md:93

  • This parenthetical again makes the source download sound retryable, but only the agent loop has MAX_ATTEMPTS = 3; each source is downloaded once. Please state the retry scope explicitly.
3. **Reachability** (`stages/reachabilityStage.ts`, 1 hour timeout) — downloads each
   candidate's source (4 concurrent, up to 3 attempts each) and runs a **Claude Sonnet**
   agent (`model: 'claude-sonnet-5'`) to judge whether the vulnerable symbol is actually
   reachable, under the same tool/turn/timeout constraints as intel above. Persists a

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread docs/adr/0017-blast-radius-pipeline-architecture.md Outdated
Comment thread docs/adr/0017-blast-radius-pipeline-architecture.md Outdated
Comment thread docs/adr/0017-blast-radius-pipeline-architecture.md Outdated
Comment thread docs/adr/0017-blast-radius-pipeline-architecture.md Outdated
Comment thread docs/adr/0017-blast-radius-pipeline-architecture.md Outdated
Comment thread docs/adr/0017-blast-radius-pipeline-architecture.md
Comment thread docs/adr/0017-blast-radius-pipeline-architecture.md Outdated
Comment thread docs/adr/0017-blast-radius-pipeline-architecture.md Outdated
Copilot AI review requested due to automatic review settings August 11, 2026 09:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (7)

docs/adr/0017-blast-radius-pipeline-architecture.md:19

  • This is not exclusive to the Public API: backend/src/bin/scripts/blastRadiusLoadTest.ts is a developer CLI that starts analyzeBlastRadius workflows directly. Scope the statement to production consumers and acknowledge the harness so the ADR does not contradict the documented local execution path.
(CM-1358). It is consumed exclusively through a public, asynchronous Public API
(`submitBlastRadiusJob(Batch)` / `getBlastRadiusJob(Batch)` in
`backend/src/api/public/v1/packages/`) — there is no CLI or batch-report consumer.

docs/adr/0017-blast-radius-pipeline-architecture.md:34

  • Stage 3 is not the pipeline's only concurrent stage. The npm dependents scan calls forEachWithConcurrency with SCAN_CONCURRENCY, which defaults to 32 in production (dependentsScan.ts:19-20,287-290). Distinguish sequential stage execution from concurrency within stages.
parallelism between stages; the only concurrency in the whole pipeline is *within* stage 3
(up to 4 dependents downloaded/analyzed at once).

docs/adr/0017-blast-radius-pipeline-architecture.md:64

  • The three attempts apply only to the Claude agent call. Source preparation/download happens before the retry loop, and a download failure immediately persists an error verdict (reachabilityStage.ts:97-138). The diagram currently implies that downloads are retried.
        R1["Download each dependent's source<br/>(4 concurrent, up to 3 attempts each)"]
        R2["Claude Sonnet judges reachability<br/>of the vulnerable symbol"]

docs/adr/0017-blast-radius-pipeline-architecture.md:92

  • This wording again applies the three attempts to source download, but only the agent query is retried; download failures return an error verdict without retry. It also presents the configurable concurrency as a fixed value.
3. **Reachability** (`stages/reachabilityStage.ts`, 1 hour timeout) — downloads each
   candidate's source (4 concurrent, up to 3 attempts each) and runs a **Claude Sonnet**
   agent (`model: 'claude-sonnet-5'`) to judge whether the vulnerable symbol is actually

docs/adr/0017-blast-radius-pipeline-architecture.md:110

  • Public API submissions do not reuse an analysisId when force is set: both single and batch handlers always call generateUUIDv4() before persisting the request. Therefore a forced resubmission cannot resume prior stage runs as documented here.
Each stage is independently resumable: it checks its own `stage_run` status first and
no-ops if already `succeeded`, so a retried workflow (Temporal-level retry, or a re-submitted
job reusing the same `analysisId` via `force`) skips whatever already completed. Stages run

docs/adr/0017-blast-radius-pipeline-architecture.md:287

  • This binary distinction is inaccurate. PyPI and RubyGems consume persisted dependent versions; Go and Maven prefer persisted versions when present; Cargo resolves canonical metadata; and NuGet resolves its version. Documenting these variants matters for the new-ecosystem guidance.
- The `prepareSource` contract's asymmetry (npm has a pre-resolved tarball URL, every other
  ecosystem resolves a version at reachability time) means a new ecosystem's author must
  understand this distinction rather than copy any single existing ecosystem verbatim —
  mitigated by the existing 7 implementations covering both shapes as reference examples.

docs/adr/0017-blast-radius-pipeline-architecture.md:162

  • The linked PR moved one shared blast-radius agent/runner.ts into the shared library; the ecosystem intel files already imported that runner, and PR #4452's merged code did not yet contain the personal OAuth-token branch. Avoid attributing the complete current chain and removal of per-ecosystem auth duplication to that PR.
This resolution chain was centralized in `services/libs/anthropic-aws` in
`feat: centralize anthropic usage (CM-1357)` (#4452), replacing per-ecosystem duplicated
auth logic that previously lived alongside each `intel{Ecosystem}.ts`.

Copilot AI review requested due to automatic review settings August 11, 2026 10:00
@ulemons
ulemons requested a review from joanagmaia August 11, 2026 10:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (4)

docs/adr/0017-blast-radius-pipeline-architecture.md:111

  • This repeats the wrong analysis cost column and overstates what the polling API reads. The API does not select or expose total_cost_usd; it uses status='done' to expose results and returns completed_at. Please document the stored field separately from the API completion signal.
   every stage's recorded `cost_usd` (`getStageRunsCost`) and finalizes the
   `blast_radius_analyses` row (`completed_at`, `cost_usd`, `status='done'`). The public API's
   `getBlastRadiusJob` polls exactly these fields, so this stage is required — it is the

docs/adr/0017-blast-radius-pipeline-architecture.md:292

  • Adding an ecosystem requires more than this registry entry: the Public API has its own Zod ecosystem list and OpenAPI enums, and the worker's SUPPORTED_ECOSYSTEMS must also be extended. Documenting this as “only” three functions risks shipping worker support that the public API rejects or omits from its contract.
- Adding an 8th ecosystem requires only a new `EcosystemConfig` entry plus its 3 functions —
  no changes to `workflows.ts`, `ecosystems.ts`'s dispatch logic, or the report/finalize stage.

docs/adr/0017-blast-radius-pipeline-architecture.md:83

  • The diagram names a column that does not exist on blast_radius_analyses. finalizeAnalysis writes the aggregate to total_cost_usd; leaving cost_usd here makes the documented persistence contract incorrect.

This issue also appears on line 109 of the same file.

        F2["Set completed_at, cost_usd, status = 'done'<br/>on blast_radius_analyses"]

docs/adr/0017-blast-radius-pipeline-architecture.md:167

  • The PR description still presents prepareSource as an npm-versus-all-others split, while this section correctly documents that RubyGems and PyPI also require pre-resolved versions. Update the PR description so the stated architecture matches this ADR.
not a clean npm-vs-everyone-else split. npm and RubyGems require an already-resolved
`version`/`tarball_url` from the dependents stage and return `null` (→ `unclear` verdict)
if it's missing; PyPI is the same shape (`version` required, no resolution attempted). Go,
Maven, Cargo, and NuGet instead resolve a version when the dependents stage only recorded a
constraint (`dep.version ?? resolveXVersion(...)`), each against a different registry API.

@joanagmaia joanagmaia added the Documentation Created by Linear-GitHub Sync label Aug 11, 2026
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
Copilot AI review requested due to automatic review settings August 11, 2026 10:18
@ulemons
ulemons force-pushed the feat/blast-radious-adr branch from 9112bd5 to 03cf587 Compare August 11, 2026 10:18
Comment thread docs/adr/0017-blast-radius-pipeline-architecture.md Outdated
Comment thread docs/adr/0017-blast-radius-pipeline-architecture.md

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (2)

docs/adr/0017-blast-radius-pipeline-architecture.md:180

  • The local worker does not load a generic .env file. Both the Compose service (scripts/services/blast-radius-worker.yaml:19-23,37-41) and dev:blast-radius-worker:local load backend/.env.override.local, so following this instruction can leave the OAuth token unavailable to the worker. Name the actual override file here.
   set it in the local `.env`), forwarded to the agent SDK as `CLAUDE_CODE_OAUTH_TOKEN` —

docs/adr/0017-blast-radius-pipeline-architecture.md:165

  • This section correctly documents that the strategy is not npm-versus-everyone-else, but the PR description still says every non-npm ecosystem resolves a version during reachability. RubyGems and PyPI instead require the recorded version, as shown here and in their reachabilityConfig.ts implementations. Please update the PR description to match the ADR.
not a clean npm-vs-everyone-else split. npm and RubyGems require an already-resolved
`version`/`tarball_url` from the dependents stage and return `null` (→ `unclear` verdict)
if it's missing; PyPI is the same shape (`version` required, no resolution attempted). Go,

Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
Copilot AI review requested due to automatic review settings August 12, 2026 07:22
@ulemons
ulemons merged commit f020dd9 into main Aug 12, 2026
10 checks passed
@ulemons
ulemons deleted the feat/blast-radious-adr branch August 12, 2026 07:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (5)

docs/adr/0017-blast-radius-pipeline-architecture.md:117

  • This repeats the wrong analysis column name and overstates the polling contract. getAnalysisDetail does not select the total cost, and getBlastRadiusJob uses status to determine completion; it only exposes completed_at from this list.
   `blast_radius_analyses` row (`completed_at`, `cost_usd`, `status='done'`). The public API's
   `getBlastRadiusJob` polls exactly these fields, so this stage is required — it is the
   step that makes a run visible as complete to the API. The name is a holdover from an

docs/adr/0017-blast-radius-pipeline-architecture.md:300

  • The “only” claim omits a required change: Ecosystem is derived from SUPPORTED_ECOSYSTEMS, so an eighth ecosystem must be added there before its registry entry type-checks. Document that contract so the stated extension path is complete.
- Adding an 8th ecosystem requires only a new `EcosystemConfig` entry plus its 3 functions —
  no changes to `workflows.ts`, `ecosystems.ts`'s dispatch logic, or the report/finalize stage.

docs/adr/0017-blast-radius-pipeline-architecture.md:83

  • The diagram names a nonexistent analysis column. finalizeAnalysis writes the aggregate to blast_radius_analyses.total_cost_usd, so using cost_usd here gives readers the wrong schema.

This issue also appears on line 115 of the same file.

        F2["Set completed_at, cost_usd, status = 'done'<br/>on blast_radius_analyses"]

docs/adr/0017-blast-radius-pipeline-architecture.md:183

  • These variables configure Claude Platform on AWS, not Amazon Bedrock (credentials.ts:23-32 sets CLAUDE_CODE_USE_ANTHROPIC_AWS plus an Anthropic workspace/API key). Calling this Bedrock is operationally misleading because Bedrock uses a different authentication path.
1. Claude on AWS Bedrock via `CROWD_AKRITES_ANTHROPIC_AWS_{REGION,WORKSPACE_ID,API_KEY}` —
   production path. This key is purchased through the AWS Marketplace (Bedrock), not a

docs/adr/0017-blast-radius-pipeline-architecture.md:172

  • The PR description says every non-npm ecosystem resolves a version during reachability, but this ADR and the implementation show that RubyGems and PyPI require a version already recorded by the dependents stage. Update the PR description to reflect this three-way split rather than the npm-vs-everyone-else claim.
not a clean npm-vs-everyone-else split. npm and RubyGems require an already-resolved
`version`/`tarball_url` from the dependents stage and return `null` (→ `unclear` verdict)
if it's missing; PyPI is the same shape (`version` required, no resolution attempted). Go,
Maven, Cargo, and NuGet instead resolve a version when the dependents stage only recorded a
constraint (`dep.version ?? resolveXVersion(...)`), each against a different registry API.

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

Labels

Documentation Created by Linear-GitHub Sync

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants