From 2fd3de1324cf5dffc98ad951d1d708f7e24027c6 Mon Sep 17 00:00:00 2001 From: Will Tsai <28876888+willtsai@users.noreply.github.com> Date: Fri, 30 Jan 2026 10:57:35 -0800 Subject: [PATCH 01/12] modify constitution Signed-off-by: Will Tsai <28876888+willtsai@users.noreply.github.com> --- .specify/memory/constitution.md | 37 ++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/.specify/memory/constitution.md b/.specify/memory/constitution.md index be23bbe5..e77d24f3 100644 --- a/.specify/memory/constitution.md +++ b/.specify/memory/constitution.md @@ -1,8 +1,11 @@ backend + backend --> cache +\``` +``` + +## 4. Commit the Graph + +The app graph is designed to be committed alongside your Bicep files: + +```bash +git add app.bicep .radius/app-graph.json +git commit -m "Add Redis cache to application" +``` + +## 5. Set Up GitHub Action for PR Diffs + +Add `.github/workflows/app-graph-diff.yml`: + +```yaml +name: App Graph Diff + +on: + pull_request: + paths: + - '**/.radius/app-graph.json' + +permissions: + pull-requests: write + +jobs: + diff: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: radius-project/app-graph-diff-action@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} +``` + +When a PR changes the app graph, the Action posts a comment showing: +- Added/removed/modified resources +- New/removed connections +- Before/after Mermaid diagrams + +## 6. Validate Graph Freshness in CI + +Add validation to catch stale graphs: + +```yaml +name: Validate App Graph + +on: + pull_request: + paths: + - '**/*.bicep' + - '**/.radius/app-graph.json' + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Radius CLI + run: | + curl -fsSL https://get.radapp.io/install.sh | bash + rad bicep download + + - name: Validate graph is current + run: | + rad app graph app.bicep --stdout > /tmp/expected.json + diff .radius/app-graph.json /tmp/expected.json || { + echo "::error::App graph is stale. Run 'rad app graph app.bicep' and commit." + exit 1 + } +``` + +## Common Options + +| Option | Description | +|--------|-------------| +| `--stdout` | Write JSON to stdout instead of file | +| `-o ` | Write to custom output path | +| `--format markdown` | Also generate Markdown preview | +| `--no-git` | Skip git metadata (faster) | +| `--parameters ` | Use parameter file for Bicep | +| `--at ` | Generate graph at specific commit | + +## Troubleshooting + +### "Bicep CLI not found" + +```bash +rad bicep download +``` + +### "Not a git repository" + +Git metadata is optional. The graph generates successfully, but `gitInfo` fields show "not available". + +### "Stale graph detected in CI" + +Regenerate and commit: + +```bash +rad app graph app.bicep +git add .radius/app-graph.json +git commit --amend --no-edit +git push --force-with-lease +``` + +## Next Steps + +- [View graph history](./history.md) - Track architecture evolution over time +- [Compare environments](./environments.md) - See how portable types resolve differently +- [Customize the GitHub Action](./github-action.md) - Advanced configuration options diff --git a/specs/001-git-app-graph-preview/research.md b/specs/001-git-app-graph-preview/research.md new file mode 100644 index 00000000..ff1cee64 --- /dev/null +++ b/specs/001-git-app-graph-preview/research.md @@ -0,0 +1,239 @@ +# Research: Git App Graph Preview + +**Feature Branch**: `001-git-app-graph-preview` +**Date**: February 4, 2026 + +## Research Tasks + +### 1. Radius CLI Architecture + +**Decision**: Extend existing `rad app graph` command in `pkg/cli/cmd/app/graph/` + +**Rationale**: +- The existing `rad app graph ` command already follows established CLI patterns +- Command structure uses Cobra framework with Runner pattern (`NewCommand()` + `Runner.Run()`) +- Output formatting is handled through `pkg/cli/output/` utilities +- Adding file-based input preserves conceptual consistency ("both are app graphs") + +**Alternatives Considered**: +- New `rad graph` top-level command: Rejected (breaks CLI hierarchy, less discoverable) +- New `rad bicep graph` command: Rejected (conceptually these are both "app graphs", just from different sources) + +### 2. Existing App Graph Data Structures + +**Decision**: Extend `ApplicationGraphResponse` and related types in `pkg/corerp/api/` + +**Rationale**: +- Existing types (`ApplicationGraphResource`, `ApplicationGraphConnection`) capture most needed fields +- Adding git metadata fields is additive and backward-compatible +- Deterministic output requires adding `sourceHash`, `sourceFile`, `sourceLine` metadata +- Types are already JSON-serializable via auto-generated marshalling code + +**Existing Structure** (from `zz_generated_models.go`): +```go +type ApplicationGraphResponse struct { + Resources []*ApplicationGraphResource +} + +type ApplicationGraphResource struct { + ID *string + Name *string + Type *string + ProvisioningState *string + Connections []*ApplicationGraphConnection + OutputResources []*ApplicationGraphOutputResource +} +``` + +**Additions Needed**: +- `GitInfo` struct: commit SHA, author, date, message +- `SourceFile`, `SourceLine` for Bicep source tracking +- `Metadata` struct: generatedAt, sourceFiles, sourceHash, radiusCliVersion + +### 3. Bicep Parsing Approach + +**Decision**: Use official Bicep CLI for compilation, then parse ARM JSON + +**Rationale** (per Constitution Principle VII - Simplicity Over Cleverness): +- Bicep CLI provides `bicep build --stdout` to compile to ARM JSON +- Radius already has Bicep CLI integration in `pkg/cli/bicep/` +- ARM JSON is stable and well-documented; parsing it avoids Bicep grammar complexity +- External modules are resolved by Bicep CLI, not our code + +**Alternatives Considered**: +- Custom Bicep parser: Rejected (complex, maintenance burden, grammar changes) +- ANTLR-based parser: Rejected (over-engineering for this use case) +- Use Bicep language server: Rejected (heavyweight, overkill for static analysis) + +**Implementation Pattern**: +```go +// Existing pattern in pkg/cli/bicep/types.go +func (impl *Impl) PrepareTemplate(filePath string) (map[string]any, error) { + args := []string{"build", "--stdout", filePath} + // Execute bicep CLI and parse JSON output +} +``` + +### 4. Graph Extraction from ARM JSON + +**Decision**: Extract resources and connections from compiled ARM JSON template + +**Rationale**: +- ARM JSON has stable schema with `resources` array +- Radius resources use `connections` and `routes` properties for relationships +- Existing graph logic in `pkg/corerp/frontend/controller/applications/graph_util.go` shows patterns + +**Key Extraction Points**: +1. `resources[].type` - Resource type identification +2. `resources[].name` - Resource name (may contain expressions) +3. `resources[].properties.connections` - Direct connections +4. `resources[].properties.routes` - Gateway routes +5. `resources[].dependsOn` - Explicit dependencies + +### 5. Git Integration + +**Decision**: Use `git log` and `git blame` via exec, not library + +**Rationale**: +- Git is universally available in development environments +- Shell commands are simpler than CGo bindings to libgit2 +- Radius already uses exec patterns for Bicep CLI +- Graceful degradation when not in git repo or shallow clone + +**Commands Needed**: +- `git blame -l -e ` - Get commit SHA per line +- `git log -1 --format='%H|%ae|%aI|%s' ` - Get commit metadata +- `git rev-parse --show-toplevel` - Detect git repo root + +### 6. GitHub Action Architecture + +**Decision**: Lightweight Action that reads committed JSON from git history; no graph generation + +**Rationale** (per spec Committed Artifact Model): +- Action only needs git and jq, not Bicep/Radius tooling +- Works in forks without special secrets +- Fast execution (JSON comparison vs. full compilation) +- Reproducible (graph captured at commit time) + +**Implementation**: +1. Checkout base and head commits +2. Read `.radius/app-graph.json` from each +3. Compute diff using JSON comparison +4. Render diff as Markdown with Mermaid diagrams +5. Post/update PR comment using `peter-evans/create-or-update-comment` + +**Alternatives Considered**: +- GitHub App: Rejected for MVP (more complex setup, centralized management) +- Generate graph in CI: Rejected (requires Bicep tooling, slower, less reproducible) + +### 7. Diff Computation Strategy + +**Decision**: JSON-based diffing with semantic resource comparison + +**Rationale**: +- JSON is deterministic when keys are sorted +- Resource ID provides stable identity across commits +- Diff should show added/removed/modified at resource level, not line level + +**Diff Algorithm**: +1. Parse base and head JSON +2. Create resource map keyed by ID +3. Compare: + - Added: ID in head but not base + - Removed: ID in base but not head + - Modified: ID in both but properties differ +4. For connections: compare by (sourceID, targetID) tuples + +### 8. Output Formats + +**Decision**: JSON canonical, Markdown additive with embedded Mermaid + +**Rationale** (per spec): +- JSON is machine-readable, deterministic, diffable +- Markdown renders in GitHub UI without additional tooling +- Mermaid diagrams supported natively by GitHub +- Separation allows different consumers (CI vs. humans) + +**JSON Schema**: +```json +{ + "metadata": { + "generatedAt": "2026-01-30T10:15:00Z", + "sourceFiles": ["app.bicep", "modules/database.bicep"], + "sourceHash": "sha256:abc123...", + "radiusCliVersion": "0.35.0" + }, + "resources": [...], + "connections": [...] +} +``` + +**Mermaid Shapes** (per spec): +- Containers: rectangles (`[name]`) +- Gateways: diamonds (`{name}`) +- Databases: cylinders (`[(name)]`) + +### 9. Platform Abstraction for Future Integrations + +**Decision**: Separate diff computation from rendering; platform-specific rendering layer + +**Rationale** (per user input: "design choices today won't limit us in the future"): +- Core diff logic (JSON comparison) is platform-agnostic +- GitHub-specific code isolated to: + - GitHub Action (workflow YAML) + - Markdown/Mermaid rendering + - PR comment posting +- Future GitLab integration would only need new rendering layer + +**Architecture**: +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Platform-Agnostic │ +├─────────────────────────────────────────────────────────────────┤ +│ CLI (rad app graph) │ JSON Schema │ Diff Computation │ +│ Git Integration │ Data Model │ Core Rendering (MD) │ +└─────────────────────────────────────────────────────────────────┘ + │ + ┌─────────┴─────────┐ + ▼ ▼ + ┌───────────────┐ ┌───────────────┐ + │ GitHub Action │ │ GitLab CI │ + │ PR Comments │ │ MR Notes │ + │ Mermaid │ │ (Future) │ + └───────────────┘ └───────────────┘ +``` + +### 10. Radius Bicep Extension Compatibility + +**Decision**: Support Radius Bicep extension type definitions + +**Rationale**: +- Radius extends Bicep with custom types (`Applications.Core/containers`, etc.) +- These types must be recognized in ARM JSON output +- Type registry already exists in `pkg/corerp/api/` + +**Implementation**: +- Resource type detection checks for `Applications.*` prefix +- Portable types (`Radius.Data/store`) shown as-is in static graph +- Environment-resolved graph (P3) requires live Radius environment connection + +## Technology Decisions Summary + +| Area | Decision | Rationale | +|------|----------|-----------| +| CLI Framework | Cobra (existing) | Consistency with `rad` CLI | +| Bicep Parsing | Bicep CLI → ARM JSON | Simplicity, official support | +| Git Operations | Shell exec | Universal, no CGo | +| Data Structures | Extend existing types | Backward compatible | +| GitHub Integration | Action, not App | Simpler setup, fork-friendly | +| Diff Algorithm | JSON semantic diff | Deterministic, meaningful | +| Output | JSON + optional Markdown | Machine + human readable | +| Platform Abstraction | Rendering layer separation | Future GitLab support | + +## Open Questions Resolution + +1. **Bicep Compiler Integration**: ✅ Use official Bicep CLI (per Constitution Principle VII) +2. **Graph Storage**: ✅ Committed to `.radius/app-graph.json` (per spec) +3. **GitHub App vs Action**: ✅ GitHub Action for MVP (simpler, fork-friendly) +4. **Diff Visualization**: Table + Mermaid in PR comments +5. **Parameter Handling**: Use defaults if no params file; mark unknown values as `` From 05a431b695369c63866b99ebee688b629d48b289 Mon Sep 17 00:00:00 2001 From: Will Tsai <28876888+willtsai@users.noreply.github.com> Date: Wed, 4 Feb 2026 10:05:57 -0800 Subject: [PATCH 11/12] updated spec with speckit clarify Signed-off-by: Will Tsai <28876888+willtsai@users.noreply.github.com> --- specs/001-git-app-graph-preview/spec.md | 28 +++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/specs/001-git-app-graph-preview/spec.md b/specs/001-git-app-graph-preview/spec.md index ae16c2e0..28197dd9 100644 --- a/specs/001-git-app-graph-preview/spec.md +++ b/specs/001-git-app-graph-preview/spec.md @@ -5,6 +5,16 @@ **Status**: Draft **Input**: User description: "Radius currently stores the state of application deployments as an app graph within its data store. Today, the app graph does not get generated until the application is deployed. Help me build an app graph representation for applications that are defined (e.g. in an app.bicep file) but not yet deployed. Additionally, enrich the app graph representation with git changelog info (i.e. git commit data) so that I may use this data to visualize how the app graph changes over time (i.e. across commits). The ultimate goal is to be able to visualize the app graph and do diffs of the app graph in GitHub on PRs, commit comparisons, etc." +## Clarifications + +### Session 2026-02-04 + +- Q: GitHub App vs Action for PR integration? → A: GitHub Action (fork-friendly, no installation approval required, aligns with existing Radius workflow patterns) +- Q: Diff visualization format in PR comments? → A: Table + Mermaid diagrams (change table for details, before/after diagrams for visual topology) +- Q: How to handle Bicep parameters without params file? → A: Require params file (fail with error if Bicep has required parameters but no `--parameters` provided) +- Q: GitHub Action trigger events? → A: `pull_request` + `push` (PR for review comments, push to main for baseline tracking) +- Q: Monorepo support with multiple app graphs? → A: Auto-detect all `**/.radius/app-graph.json` files; each diffed independently + ## Problem Statement Radius currently generates application graphs only after deployment, which means: @@ -37,7 +47,9 @@ As a **platform engineer**, I want to review app graph changes in PRs, so I can 4. **Given** a Bicep file with parameterized values, **When** I run `rad app graph app.bicep --parameters params.json`, **Then** the graph reflects the resolved parameter values. -5. **Given** a Bicep file using the Radius Bicep extension types, **When** I run `rad app graph app.bicep`, **Then** the graph correctly identifies Radius-specific resource types and their relationships. +5. **Given** a Bicep file with required parameters (no defaults) and no `--parameters` flag, **When** I run `rad app graph app.bicep`, **Then** I receive a clear error listing the missing required parameters. + +6. **Given** a Bicep file using the Radius Bicep extension types, **When** I run `rad app graph app.bicep`, **Then** the graph correctly identifies Radius-specific resource types and their relationships. --- @@ -101,6 +113,12 @@ As a PR reviewer, I want to see a visual diff of the app graph in PR comments, s **Operational Model**: The GitHub Action reads committed `.radius/app-graph.json` files from git history — it does NOT generate graphs on-demand. This keeps the Action lightweight (no Bicep/Radius tooling required) and fast. +**Trigger Events**: The Action supports two trigger modes: +- **`pull_request`**: Posts diff comments on PRs when `.radius/app-graph.json` changes +- **`push` to main/default branch**: Updates baseline tracking for historical comparison + +**Monorepo Support**: The Action auto-detects all `**/.radius/app-graph.json` files in the repository. Each graph is diffed independently, with separate PR comment sections per application. + **Independent Test**: Create a PR with Bicep changes and updated graph JSON, verify the action posts a comment showing before/after graph comparison. **Acceptance Scenarios**: @@ -115,6 +133,8 @@ As a PR reviewer, I want to see a visual diff of the app graph in PR comments, s 5. **Given** a PR where Bicep files changed but `.radius/app-graph.json` was not updated, **When** the CI validation job runs, **Then** it fails with a message instructing the developer to run `rad app graph app.bicep` and commit the updated graph. +6. **Given** a monorepo with multiple Radius applications (e.g., `apps/frontend/.radius/app-graph.json` and `apps/backend/.radius/app-graph.json`), **When** the GitHub Action runs on a PR, **Then** it detects all graph files and posts a unified comment with separate diff sections per application. + --- ### User Story 5 - Historical Graph Timeline (Priority: P3) @@ -389,11 +409,11 @@ This feature MUST include comprehensive testing across the testing pyramid: 2. ~~**Graph Storage**: Should generated graphs be committed to the repo (e.g., `app-graph.json`)? Trade-off: visibility vs. repo noise.~~ **RESOLVED (Initial Implementation)**: Graphs are committed to `.radius/app-graph.json`. This enables lightweight GitHub Action (reads from git history, no tooling required) and provides auditable graph evolution. **Future Evolution**: External storage backends (e.g., SQLite, cloud databases) could be supported for scenarios requiring graph queries across repositories, historical analytics, or enterprise-scale graph management. -3. **GitHub App vs Action**: Should the PR integration be a GitHub Action (user-managed) or a GitHub App (centrally managed)? Trade-off: flexibility vs. ease of setup. +3. ~~**GitHub App vs Action**: Should the PR integration be a GitHub Action (user-managed) or a GitHub App (centrally managed)? Trade-off: flexibility vs. ease of setup.~~ **RESOLVED**: GitHub Action. Fork-friendly, no installation approval required, aligns with existing Radius workflow patterns, supports incremental adoption. -4. **Diff Visualization**: What's the preferred format for showing diffs in PR comments—table-based, Mermaid side-by-side, or unified text diff? +4. ~~**Diff Visualization**: What's the preferred format for showing diffs in PR comments—table-based, Mermaid side-by-side, or unified text diff?~~ **RESOLVED**: Table + Mermaid diagrams. Change table shows added/removed/modified resources with details; before/after Mermaid diagrams provide visual topology comparison. Both render natively in GitHub. -5. **Parameter Handling**: How should we handle Bicep parameters without a params file—use defaults, require params, or mark as "unknown"? +5. ~~**Parameter Handling**: How should we handle Bicep parameters without a params file—use defaults, require params, or mark as "unknown"?~~ **RESOLVED**: Require params file. If Bicep has required parameters (no defaults) but no `--parameters` flag is provided, fail with a clear error message listing the missing parameters. --- From 901b104f2d9b28bd537a548643a9f9cdaa3f7936 Mon Sep 17 00:00:00 2001 From: Will Tsai <28876888+willtsai@users.noreply.github.com> Date: Wed, 4 Feb 2026 10:34:04 -0800 Subject: [PATCH 12/12] add tasks and clarify plan details Signed-off-by: Will Tsai <28876888+willtsai@users.noreply.github.com> --- specs/001-git-app-graph-preview/quickstart.md | 5 + specs/001-git-app-graph-preview/research.md | 2 +- specs/001-git-app-graph-preview/tasks.md | 323 ++++++++++++++++++ 3 files changed, 329 insertions(+), 1 deletion(-) create mode 100644 specs/001-git-app-graph-preview/tasks.md diff --git a/specs/001-git-app-graph-preview/quickstart.md b/specs/001-git-app-graph-preview/quickstart.md index 9a6dd4ed..90bb3f65 100644 --- a/specs/001-git-app-graph-preview/quickstart.md +++ b/specs/001-git-app-graph-preview/quickstart.md @@ -167,6 +167,11 @@ on: pull_request: paths: - '**/.radius/app-graph.json' + push: + branches: + - main + paths: + - '**/.radius/app-graph.json' permissions: pull-requests: write diff --git a/specs/001-git-app-graph-preview/research.md b/specs/001-git-app-graph-preview/research.md index ff1cee64..b25cdc60 100644 --- a/specs/001-git-app-graph-preview/research.md +++ b/specs/001-git-app-graph-preview/research.md @@ -236,4 +236,4 @@ func (impl *Impl) PrepareTemplate(filePath string) (map[string]any, error) { 2. **Graph Storage**: ✅ Committed to `.radius/app-graph.json` (per spec) 3. **GitHub App vs Action**: ✅ GitHub Action for MVP (simpler, fork-friendly) 4. **Diff Visualization**: Table + Mermaid in PR comments -5. **Parameter Handling**: Use defaults if no params file; mark unknown values as `` +5. **Parameter Handling**: ✅ Require params file; fail with clear error listing missing required parameters if Bicep has required parameters (no defaults) but no `--parameters` flag provided diff --git a/specs/001-git-app-graph-preview/tasks.md b/specs/001-git-app-graph-preview/tasks.md new file mode 100644 index 00000000..0e946ed2 --- /dev/null +++ b/specs/001-git-app-graph-preview/tasks.md @@ -0,0 +1,323 @@ +# Tasks: Git App Graph Preview + +**Input**: Design documents from `/specs/001-git-app-graph-preview/` +**Prerequisites**: plan.md ✓, spec.md ✓, research.md ✓, data-model.md ✓, contracts/ ✓, quickstart.md ✓ + +**Tests**: Included per spec.md "Testing Requirements" section - comprehensive testing across the testing pyramid. + +**Organization**: Tasks grouped by user story for independent implementation and testing. + +## Format: `[ID] [P?] [Story] Description` + +- **[P]**: Can run in parallel (different files, no dependencies) +- **[Story]**: Which user story this task belongs to (US1, US2, US3, US4, US5, US6) +- Exact file paths for radius repository + +--- + +## Phase 1: Setup (Shared Infrastructure) + +**Purpose**: Project initialization and scaffolding for the static graph feature + +- [ ] T001 Create package structure `pkg/cli/bicep/` with package doc in pkg/cli/bicep/doc.go +- [ ] T002 Create package structure `pkg/cli/git/` with package doc in pkg/cli/git/doc.go +- [ ] T003 [P] Add new test directories: test/unit/cli/graph/, test/integration/cli/graph/, test/functional/cli/graph/ +- [ ] T004 [P] Define AppGraph types in pkg/corerp/api/v20231001preview/appgraph_static_types.go +- [ ] T005 [P] Define GraphDiff types in pkg/corerp/api/v20231001preview/appgraph_diff_types.go +- [ ] T006 Add JSON schema validation helpers in pkg/cli/output/json.go (deterministic key ordering) + +--- + +## Phase 2: Foundational (Blocking Prerequisites) + +**Purpose**: Core infrastructure required by ALL user stories + +**⚠️ CRITICAL**: No user story work can begin until this phase is complete + +- [ ] T007 Implement Bicep CLI executor in pkg/cli/bicep/executor.go (wraps `bicep build --stdout`) +- [ ] T008 Implement ARM JSON parser interface in pkg/cli/bicep/parser.go (extract resources array) +- [ ] T009 Implement resource extraction from ARM JSON in pkg/cli/bicep/extractor.go +- [ ] T010 Implement connection detection from resource properties in pkg/cli/bicep/connections.go +- [ ] T011 [P] Implement source hash computation (SHA256 of input files) in pkg/cli/bicep/hash.go +- [ ] T012 [P] Add Bicep file detection logic (`.bicep` extension) in pkg/cli/cmd/app/graph/detect.go +- [ ] T013 Unit tests for Bicep executor in test/unit/cli/graph/executor_test.go +- [ ] T014 Unit tests for ARM JSON parser in test/unit/cli/graph/parser_test.go + +**Checkpoint**: Foundation ready - user story implementation can begin + +--- + +## Phase 3: User Story 1 - Generate App Graph from Bicep Files (Priority: P1) 🎯 MVP + +**Goal**: Enable `rad app graph app.bicep` to generate a JSON app graph from Bicep files without deployment + +**Independent Test**: Run CLI against sample Bicep file, verify JSON output contains expected resources and connections + +### Tests for User Story 1 + +- [ ] T015 [P] [US1] Unit test for graph generation with valid Bicep in test/unit/cli/graph/static_test.go +- [ ] T016 [P] [US1] Unit test for error handling with invalid Bicep in test/unit/cli/graph/static_errors_test.go +- [ ] T017 [P] [US1] Unit test for module resolution in test/unit/cli/graph/modules_test.go +- [ ] T018 [US1] Integration test with real Bicep CLI in test/integration/cli/graph/bicep_integration_test.go + +### Implementation for User Story 1 + +- [ ] T019 [US1] Implement static graph generator in pkg/cli/cmd/app/graph/static.go +- [ ] T020 [US1] Add file input detection to existing graph.go entry point in pkg/cli/cmd/app/graph/graph.go +- [ ] T021 [US1] Implement module resolution (transitive Bicep imports) in pkg/cli/bicep/modules.go +- [ ] T022 [US1] Add parameter file support (`--parameters`) in pkg/cli/cmd/app/graph/params.go +- [ ] T023 [US1] Implement required parameter validation (fail if missing) in pkg/cli/bicep/params.go +- [ ] T024 [US1] Add Radius Bicep extension type detection in pkg/cli/bicep/radius_types.go +- [ ] T025 [US1] Implement error handling with line/column info in pkg/cli/bicep/errors.go +- [ ] T026 [US1] Add logging for graph generation operations in pkg/cli/cmd/app/graph/static.go + +**Checkpoint**: `rad app graph app.bicep` generates valid JSON graph from Bicep files + +--- + +## Phase 4: User Story 2 - Export Graph as Diff-Friendly Format (Priority: P1) + +**Goal**: Output deterministic JSON to `.radius/app-graph.json` and optional Markdown with Mermaid diagrams + +**Independent Test**: Generate graph twice from identical input, verify byte-identical output; verify Markdown renders in GitHub + +### Tests for User Story 2 + +- [ ] T027 [P] [US2] Unit test for deterministic JSON output in test/unit/cli/graph/json_determinism_test.go +- [ ] T028 [P] [US2] Unit test for Mermaid diagram generation in test/unit/cli/graph/mermaid_test.go +- [ ] T029 [P] [US2] Unit test for Markdown table formatting in test/unit/cli/graph/markdown_test.go +- [ ] T030 [US2] Integration test for file output paths in test/integration/cli/graph/output_test.go + +### Implementation for User Story 2 + +- [ ] T031 [US2] Implement deterministic JSON serializer in pkg/cli/output/deterministic_json.go +- [ ] T032 [US2] Implement default output path (`.radius/app-graph.json`) in pkg/cli/cmd/app/graph/output.go +- [ ] T033 [US2] Add `--stdout` flag for stdout output in pkg/cli/cmd/app/graph/flags.go +- [ ] T034 [US2] Add `-o` flag for custom output path in pkg/cli/cmd/app/graph/flags.go +- [ ] T035 [US2] Implement Mermaid diagram generator in pkg/cli/output/mermaid.go +- [ ] T036 [US2] Implement Markdown table formatter in pkg/cli/output/markdown.go +- [ ] T037 [US2] Add `--format markdown` flag (generates both JSON + Markdown) in pkg/cli/cmd/app/graph/flags.go +- [ ] T038 [US2] Integrate display.go with new output formatters in pkg/cli/cmd/app/graph/display.go +- [ ] T039 [US2] Add Mermaid shape mapping (containers→rectangles, gateways→diamonds, databases→cylinders) in pkg/cli/output/mermaid.go + +**Checkpoint**: Deterministic JSON output + optional Markdown with Mermaid diagrams working + +--- + +## Phase 5: User Story 3 - Git Metadata Enrichment (Priority: P2) + +**Goal**: Automatically enrich each resource with git commit information (SHA, author, date, message) + +**Independent Test**: Generate graph in git repo, verify each resource has git metadata; verify `--no-git` skips enrichment + +### Tests for User Story 3 + +- [ ] T040 [P] [US3] Unit test for git blame parsing in test/unit/cli/graph/git_blame_test.go +- [ ] T041 [P] [US3] Unit test for git log parsing in test/unit/cli/graph/git_log_test.go +- [ ] T042 [P] [US3] Unit test for uncommitted file detection in test/unit/cli/graph/git_uncommitted_test.go +- [ ] T043 [US3] Integration test with real git repository in test/integration/cli/graph/git_integration_test.go + +### Implementation for User Story 3 + +- [ ] T044 [US3] Implement git repository detection in pkg/cli/git/repo.go +- [ ] T045 [US3] Implement git blame executor in pkg/cli/git/blame.go +- [ ] T046 [US3] Implement git log metadata extraction in pkg/cli/git/log.go +- [ ] T047 [US3] Implement per-resource git info enrichment in pkg/cli/git/metadata.go +- [ ] T048 [US3] Add uncommitted changes detection in pkg/cli/git/status.go +- [ ] T049 [US3] Add `--no-git` flag for faster execution in pkg/cli/cmd/app/graph/flags.go +- [ ] T050 [US3] Handle non-git directories gracefully in pkg/cli/git/metadata.go +- [ ] T051 [US3] Handle shallow clones (mark as "history unavailable") in pkg/cli/git/blame.go +- [ ] T052 [US3] Add linked commit SHA in Markdown output in pkg/cli/output/markdown.go + +**Checkpoint**: Graph resources include git metadata by default; `--no-git` works + +--- + +## Phase 6: User Story 4 - GitHub Action for PR Graph Diff (Priority: P2) + +**Goal**: GitHub Action reads committed JSON from git history and posts diff comments on PRs + +**Independent Test**: Create PR with graph changes, verify Action posts comment with change table and Mermaid diagrams + +### Tests for User Story 4 + +- [ ] T053 [P] [US4] Unit test for JSON-to-JSON diff computation in test/unit/cli/graph/diff_test.go +- [ ] T054 [P] [US4] Unit test for diff summary generation in test/unit/cli/graph/diff_summary_test.go +- [ ] T055 [US4] Unit test for diff Markdown rendering in test/unit/cli/graph/diff_render_test.go + +### Implementation for User Story 4 + +- [ ] T056 [US4] Implement graph diff computation in pkg/cli/cmd/app/graph/diff.go +- [ ] T057 [US4] Implement resource comparison (by ID) in pkg/cli/cmd/app/graph/diff.go +- [ ] T058 [US4] Implement connection comparison (by source+target tuple) in pkg/cli/cmd/app/graph/diff.go +- [ ] T059 [US4] Implement diff summary statistics in pkg/cli/cmd/app/graph/diff.go +- [ ] T060 [US4] Implement diff Markdown renderer (change table + before/after Mermaid) in pkg/cli/output/diff_markdown.go +- [ ] T061 [US4] Create GitHub Action definition in actions/app-graph-diff/action.yml +- [ ] T062 [US4] Implement diff computation shell script in actions/app-graph-diff/diff.sh +- [ ] T063 [US4] Implement Mermaid rendering for Action in actions/app-graph-diff/render.js +- [ ] T064 [US4] Add PR comment create-or-update logic in actions/app-graph-diff/comment.sh +- [ ] T065 [US4] Add monorepo support (glob `**/.radius/app-graph.json`) in actions/app-graph-diff/detect.sh +- [ ] T066 [US4] Add staleness validation (compare committed vs regenerated) in actions/app-graph-diff/validate.sh +- [ ] T067 [US4] Add `push` trigger support for baseline tracking in actions/app-graph-diff/action.yml + +**Checkpoint**: GitHub Action posts diff comments on PRs with graph changes + +--- + +## Phase 7: User Story 5 - Historical Graph Timeline (Priority: P3) + +**Goal**: Enable `rad app graph history` to show graph evolution across commits + +**Independent Test**: Run history command on repo with multiple commits, verify timeline shows graph changes + +### Tests for User Story 5 + +- [ ] T068 [P] [US5] Unit test for timeline generation in test/unit/cli/graph/history_test.go +- [ ] T069 [US5] Integration test with multi-commit git history in test/integration/cli/graph/history_integration_test.go + +### Implementation for User Story 5 + +- [ ] T070 [US5] Implement `rad app graph history` subcommand in pkg/cli/cmd/app/graph/history.go +- [ ] T071 [US5] Add `--commits N` flag in pkg/cli/cmd/app/graph/history.go +- [ ] T072 [US5] Implement `--at ` flag for graph at specific commit in pkg/cli/cmd/app/graph/flags.go +- [ ] T073 [US5] Implement `rad app graph diff --from X --to Y` subcommand in pkg/cli/cmd/app/graph/diff.go +- [ ] T074 [US5] Implement commit range iteration in pkg/cli/git/history.go +- [ ] T075 [US5] Implement change summary per commit in pkg/cli/cmd/app/graph/history.go + +**Checkpoint**: Historical timeline and commit-specific graph generation working + +--- + +## Phase 8: User Story 6 - Environment-Resolved Graph (Priority: P3) + +**Goal**: Enable `rad app graph --environment` to show resolved recipe types instead of abstract Radius types + +**Independent Test**: Generate graph with environment flag, verify abstract types resolve to concrete infrastructure types + +### Tests for User Story 6 + +- [ ] T076 [P] [US6] Unit test for recipe type resolution in test/unit/cli/graph/resolve_test.go +- [ ] T077 [US6] Integration test with Radius environment in test/integration/cli/graph/environment_test.go + +### Implementation for User Story 6 + +- [ ] T078 [US6] Add `--environment` flag in pkg/cli/cmd/app/graph/flags.go +- [ ] T079 [US6] Implement environment connection in pkg/cli/cmd/app/graph/environment.go +- [ ] T080 [US6] Implement recipe lookup from environment in pkg/cli/cmd/app/graph/recipes.go +- [ ] T081 [US6] Implement portable type → concrete type resolution in pkg/cli/cmd/app/graph/resolve.go +- [ ] T082 [US6] Add "no recipe bound" annotation for unbound types in pkg/cli/cmd/app/graph/resolve.go +- [ ] T083 [US6] Integrate resolved types into graph output in pkg/cli/cmd/app/graph/static.go + +**Checkpoint**: Environment-resolved graphs show concrete infrastructure types + +--- + +## Phase 9: Polish & Cross-Cutting Concerns + +**Purpose**: Documentation, validation, and refinements + +- [ ] T084 [P] Update pkg/cli/cmd/app/graph/README.md with new command documentation +- [ ] T085 [P] Add godoc comments to all exported types in pkg/cli/bicep/ +- [ ] T086 [P] Add godoc comments to all exported types in pkg/cli/git/ +- [ ] T087 Run golangci-lint and fix any issues in new code +- [ ] T088 [P] Create functional E2E test in test/functional/cli/graph/e2e_test.go +- [ ] T089 Validate quickstart.md scenarios work end-to-end +- [ ] T090 Update CHANGELOG.md with new feature description +- [ ] T091 [P] Create GitHub Action README in actions/app-graph-diff/README.md + +--- + +## Dependencies & Execution Order + +### Phase Dependencies + +- **Setup (Phase 1)**: No dependencies - can start immediately +- **Foundational (Phase 2)**: Depends on Setup - BLOCKS all user stories +- **US1 (Phase 3)**: Depends on Foundational - First MVP +- **US2 (Phase 4)**: Depends on Foundational - Second MVP capability +- **US3 (Phase 5)**: Depends on US1/US2 working - Enrichment layer +- **US4 (Phase 6)**: Depends on US2 (diff-friendly output) + US3 (git metadata) +- **US5 (Phase 7)**: Depends on US3 (git integration) +- **US6 (Phase 8)**: Can start after US1 - independent branch +- **Polish (Phase 9)**: After all desired user stories complete + +### User Story Dependencies + +``` +Foundational (Phase 2) + │ + ├──────────────┬──────────────┐ + ▼ ▼ ▼ + US1 (P1) US2 (P1) US6 (P3) + │ │ (independent) + └──────┬───────┘ + ▼ + US3 (P2) + │ + ┌──────┴──────┐ + ▼ ▼ + US4 (P2) US5 (P3) +``` + +### Parallel Opportunities + +**Phase 1 (Setup)**: T001, T002 sequential; T003-T006 all parallel +**Phase 2 (Foundational)**: T007-T010 sequential; T011-T012 parallel; T013-T014 parallel +**Each User Story**: All tests marked [P] can run in parallel; implementation tasks mostly sequential within story + +--- + +## Parallel Example: User Story 1 Tests + +```bash +# Launch all US1 tests in parallel: +Task: "T015 [P] [US1] Unit test for graph generation with valid Bicep" +Task: "T016 [P] [US1] Unit test for error handling with invalid Bicep" +Task: "T017 [P] [US1] Unit test for module resolution" + +# Then run integration test: +Task: "T018 [US1] Integration test with real Bicep CLI" +``` + +--- + +## Implementation Strategy + +### MVP First (US1 + US2 = P1 Stories) + +1. Complete Phase 1: Setup +2. Complete Phase 2: Foundational (CRITICAL) +3. Complete Phase 3: User Story 1 (core graph generation) +4. Complete Phase 4: User Story 2 (diff-friendly output) +5. **STOP and VALIDATE**: Run quickstart.md scenarios locally +6. Deploy CLI changes for developer feedback + +### Git Integration (P2 Stories) + +1. Add US3: Git metadata enrichment +2. Add US4: GitHub Action for PR diffs +3. **VALIDATE**: Test in real PR workflow + +### Advanced Features (P3 Stories) + +1. Add US5: Historical timeline (optional) +2. Add US6: Environment resolution (optional) +3. Final polish phase + +### Parallel Team Strategy + +With multiple developers: +- **Developer A**: Phase 1 → Phase 2 → US1 → US3 → US5 +- **Developer B**: Phase 1 (parallel) → US2 → US4 (GitHub Action) +- **Developer C**: US6 (can start after Phase 2) + +--- + +## Notes + +- Radius repository is at `../radius` relative to design-notes +- All Go code must pass `golangci-lint` (Constitution Principle II) +- All exported types need godoc comments (NFR-002) +- JSON output must be deterministic (FR-004, SC-002) +- Existing `rad app graph ` behavior must not change (FR-003) +- GitHub Action is lightweight (reads JSON only, no Bicep tooling)