Skip to content

feat(dynamic-views): add branch-aware compute and hierarchical step IDs#2332

Closed
Jrakru wants to merge 19 commits into
likec4:mainfrom
Jrakru:feat/unified-branch-compute
Closed

feat(dynamic-views): add branch-aware compute and hierarchical step IDs#2332
Jrakru wants to merge 19 commits into
likec4:mainfrom
Jrakru:feat/unified-branch-compute

Conversation

@Jrakru

@Jrakru Jrakru commented Oct 24, 2025

Copy link
Copy Markdown
Collaborator

Rationale

With unified branch structures now available in the parser (PR #2331), the compute layer must be updated to traverse branch collections and emit metadata that downstream systems (layout, UI) need to render and interact with branches.

Without this change:

  • Branch collections exist in parsed views but are invisible to computed views
  • Step IDs remain flat, unable to represent nested branch hierarchies
  • UI cannot display branch selection or track user progress through paths
  • Sequence diagrams cannot properly order actors from branch scenarios

This PR adapts the compute layer to be branch-aware while maintaining complete backward compatibility for legacy dynamic views.

What This Changes

Hierarchical Step ID System

File: packages/core/src/types/scalar.ts

  • Add stepEdgePath() for arbitrary-depth hierarchical IDs
  • Support legacy format: stepEdgePath([1])'step-01'
  • Support parallel format: stepEdgePath([3, 2])'step-03.02'
  • Support nested branches: stepEdgePath([4, 1, 2])'step-04.01.02'
  • Refactor stepEdgeId() to use stepEdgePath() internally

Computed View Types

File: packages/core/src/types/view-computed.ts

New types added:

  • ComputedBranchTrailEntry: Branch ancestry for each edge
    • Tracks: branchId, pathId, pathIndex, indexWithinPath, isDefaultPath
  • ComputedBranchCollectionPath: Metadata for each branch path
    • Includes: pathId, pathIndex, edgeIds[], pathName, pathTitle
  • ComputedBranchCollection: Complete collection metadata
    • Includes: branchId, kind (parallel/alternate), paths[], defaultPathId
  • ComputedEdge.branchTrail: Optional branch ancestry (feature flag guarded)
  • ComputedDynamicView.branchCollections: Optional collections array (feature flag guarded)

Branch-Aware Traversal

File: packages/core/src/compute-view/dynamic-view/compute.ts

  • Implement branch stack tracking during traversal
  • Maintain BranchCollectionAccumulator for metadata assembly
  • Build branchTrail for each edge with full ancestry
  • Register edge IDs with appropriate branch paths
  • Emit branchCollections array when feature flag enabled
  • Preserve legacy behavior when feature flag disabled

Actor Discovery

File: packages/core/src/compute-view/dynamic-view/utils.ts

  • Update elementsFromSteps to traverse branch collections
  • Ensure sequence diagram actor ordering works with branches

Tests

New Test Files (7 tests total)

packages/core/src/types/__tests__/step-edge-id.spec.ts (5 tests)

  • ✅ Legacy compatibility verification
  • ✅ Hierarchical ID generation
  • ✅ Alphanumeric suffix support
  • ✅ Error handling for invalid input

packages/core/src/compute-view/dynamic-view/__test__/branch-traversal.spec.ts (2 tests)

  • ✅ Feature flag enabled: hierarchical IDs + metadata emission
  • ✅ Feature flag disabled: legacy IDs + no metadata

Test Results

  • 1,400 tests passing (no regressions)
  • 0 type errors
  • All quality gates passing

Backward Compatibility

Feature flag guarded via isDynamicBranchCollectionsEnabled():

When Flag OFF (default):

  • ✅ Legacy step IDs: 'step-01', 'step-02'
  • ✅ No branchTrail on edges
  • ✅ No branchCollections property
  • ✅ Identical behavior to pre-PR02

When Flag ON:

  • ✅ Hierarchical step IDs for nested branches
  • branchTrail present on all edges
  • branchCollections array emitted
  • ✅ Full branch metadata available

Dependencies

Technical Notes

  • ✅ No UI changes (deferred to PR04/PR05)
  • ✅ No sequence layout changes (deferred to PR03)
  • ✅ Type-safe discriminated unions for branch types
  • ✅ Comprehensive test coverage for both flag states
  • ✅ Zero regressions in existing compute tests

Files Changed

Modified (4 files):

  • packages/core/src/compute-view/dynamic-view/compute.ts (+340, -108)
  • packages/core/src/compute-view/dynamic-view/utils.ts (~20 changes)
  • packages/core/src/types/scalar.ts (+37)
  • packages/core/src/types/view-computed.ts (+46)

New (2 test files):

  • packages/core/src/compute-view/dynamic-view/__test__/branch-traversal.spec.ts
  • packages/core/src/types/__tests__/step-edge-id.spec.ts

Total: +612 insertions, -108 deletions

Quality Gates

  • ✅ All tests pass (1,400 tests)
  • ✅ TypeScript compilation passes
  • ✅ Feature flag defaults to OFF
  • ✅ Backward compatible with existing dynamic views
  • ✅ Comprehensive test coverage

Copilot AI review requested due to automatic review settings October 24, 2025 02:49

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

This PR adds branch-aware computation capabilities to dynamic views, enabling the system to traverse and emit metadata for branch collections (parallel/alternate paths) while maintaining backward compatibility through a feature flag.

Key Changes:

  • Introduced hierarchical step ID system supporting arbitrary nesting depth (e.g., step-04.01.02)
  • Added branch metadata types and computation logic to track branch ancestry and path information
  • Updated actor discovery to traverse branch collections for sequence diagram ordering

Reviewed Changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/core/src/types/scalar.ts Added stepEdgePath() for hierarchical step IDs with legacy compatibility
packages/core/src/types/view-computed.ts Defined computed branch metadata types (ComputedBranchTrailEntry, ComputedBranchCollection, etc.)
packages/core/src/compute-view/dynamic-view/compute.ts Implemented branch-aware traversal with dual-mode processing (legacy vs. hierarchical)
packages/core/src/compute-view/dynamic-view/utils.ts Updated flattenSteps() to handle branch collections for actor discovery
packages/core/src/config/featureFlags.ts Created feature flag system with isDynamicBranchCollectionsEnabled()
packages/core/src/types/view-parsed.dynamic.ts Added branch collection types and type guards
packages/language-server/src/model/parser/ViewsParser.ts Implemented parser for branch collections and paths
packages/language-server/src/like-c4.langium Updated grammar to support parallel/alternate with path blocks
Test files Comprehensive coverage for hierarchical IDs, branch traversal, and parser behavior

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment thread packages/language-server/src/like-c4.langium Outdated
Comment thread packages/core/src/compute-view/dynamic-view/utils.ts Outdated
Comment thread packages/core/src/compute-view/dynamic-view/compute.ts
Comment thread packages/language-server/src/model/parser/ViewsParser.ts Outdated
Jrakru added a commit to Jrakru/likec4 that referenced this pull request Oct 24, 2025
- Remove duplicate label property from DynamicAlternateBranch (Comment #4)
- Remove path keyword from metadata grammar to avoid ambiguity (Comment #1)
- Performance optimization deferred (Comment #2)
- Code duplication addressed in PR likec4#2332 (Comment #3)
Jrakru and others added 5 commits October 24, 2025 11:47
Introduces foundational types and grammar for parallel and alternate branch paths in dynamic views.

New Types:
- DynamicBranchCollection: Union of parallel/alternate branches
- DynamicBranchPath: Named or anonymous execution paths
- DynamicParallelBranch: Concurrent execution paths
- DynamicAlternateBranch: Mutually exclusive paths

Grammar Updates:
- DynamicViewBranchCollection: parallel|par|alternate|alt keywords
- DynamicViewBranchPath: Named paths with optional titles
- Backward compatible via feature flag (defaults OFF)

Changes:
- Add feature flag system (LIKEC4_UNIFIED_BRANCHES)
- Add type guards and helpers (isDynamicBranchCollection, toLegacyParallel)
- Update compute logic to handle branch collections
- Add test coverage for new types

Breaking: None (feature flag defaults to false)
Feature: Enables structured branch syntax for future PRs
- Extract kind mapping to helper function for maintainability
- Simplify nested ternary for __parallel assignment using if/else
- Remove type casts by using proper type narrowing
- Add documentation for feature flag dual env var support
- Add JSDoc for toLegacyParallel function behavior
- Improve isDynamicStep boolean logic clarity
- Better handling of nested branch collections in compute/utils
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Jrakru <Jrakru@users.noreply.github.com>
- Use direct property check ('paths' in step) instead of function call for better performance in isDynamicStep
- Extract parseValidSteps() helper to eliminate code duplication in parser
- Update parseDynamicBranchPath to use new helper function
With unified branch structures now available in the parser (PR01), the compute
layer must be updated to traverse branch collections and emit metadata that
downstream systems (layout, UI) need to render and interact with branches.

Without this change:
- Branch collections exist in parsed views but are invisible to computed views
- Step IDs remain flat, unable to represent nested branch hierarchies
- UI cannot display branch selection or track user progress through paths
- Sequence diagrams cannot properly order actors from branch scenarios

This PR adapts the compute layer to be branch-aware while maintaining complete
backward compatibility for legacy dynamic views.

- Add stepEdgePath() for arbitrary-depth hierarchical IDs
- Support legacy format: stepEdgePath([1]) → 'step-01'
- Support parallel format: stepEdgePath([3, 2]) → 'step-03.02'
- Support nested branches: stepEdgePath([4, 1, 2]) → 'step-04.01.02'
- Refactor stepEdgeId() to use stepEdgePath() internally

- Add ComputedBranchTrailEntry: branch ancestry for each edge
  - Tracks: branchId, pathId, pathIndex, indexWithinPath, isDefaultPath
- Add ComputedBranchCollectionPath: metadata for each branch path
  - Includes: pathId, pathIndex, edgeIds[], pathName, pathTitle
- Add ComputedBranchCollection: complete collection metadata
  - Includes: branchId, kind (parallel/alternate), paths[], defaultPathId
- Add optional branchTrail to ComputedEdge
- Add optional branchCollections to ComputedDynamicView

- Implement branch stack tracking during traversal
- Maintain BranchCollectionAccumulator for metadata assembly
- Build branchTrail for each edge with full ancestry
- Register edge IDs with appropriate branch paths
- Emit branchCollections array when feature flag enabled
- Preserve legacy behavior when feature flag disabled

- Update elementsFromSteps to traverse branch collections
- Ensure sequence diagram actor ordering works with branches

- Add step-edge-id.spec.ts (5 tests)
  - Legacy compatibility verification
  - Hierarchical ID generation
  - Alphanumeric suffix support
  - Error handling for invalid input
- Add branch-traversal.spec.ts (2 tests)
  - Feature flag enabled: hierarchical IDs + metadata
  - Feature flag disabled: legacy IDs + no metadata
- All existing tests pass (1,400 tests)

Feature flag guarded via isDynamicBranchCollectionsEnabled():

**When Flag OFF (default):**
- Legacy step IDs: 'step-01', 'step-02'
- No branchTrail on edges
- No branchCollections property
- Identical behavior to pre-PR02

**When Flag ON:**
- Hierarchical step IDs for nested branches
- branchTrail present on all edges
- branchCollections array emitted
- Full branch metadata available

This enables:
- PR03: Sequence layout updates for branch rendering
- PR04: Walkthrough state machine with branch navigation
- PR05: UI components for branch path selection

- No UI changes (deferred to PR04/PR05)
- No sequence layout changes (deferred to PR03)
- Type-safe discriminated unions for branch types
- Comprehensive test coverage for both flag states
- Zero regressions in existing compute tests
@Jrakru Jrakru force-pushed the feat/unified-branch-compute branch from 5d06a5b to 23befb4 Compare October 24, 2025 16:44
- Remove unnecessary recursion in flattenSteps for series steps
- Fix series step indexing to share root index across series items
- Both issues identified by Copilot code review
@Jrakru

Jrakru commented Oct 24, 2025

Copy link
Copy Markdown
Collaborator Author

✅ Copilot Feedback Addressed

Thanks for the review! I've addressed the valid feedback:

Fixed Issues:

  1. Comment Bump vscode-languageserver from 8.0.2 to 8.1.0 #2 - Removed unnecessary recursion in flattenSteps() for series steps

    • Changed flatMap(s.__series, flattenSteps)[...s.__series]
    • Copilot correctly identified that __series contains DynamicStep<A>[], making recursion redundant
  2. Comment Bump vscode-languageclient from 8.0.2 to 8.1.0 #3 - Fixed series step indexing bug

    • Moved rootIndex++ outside the series loop
    • Series steps now correctly share the same root index (e.g., step-03.01, step-03.02)
    • Previously was incorrectly incrementing for each item, breaking grouping semantics

Already Fixed (from PR #2333 rebase):

  1. Comment Bump @typescript-eslint/eslint-plugin from 5.57.0 to 5.57.1 #1 - Grammar 'path' keyword conflict - Already resolved in PR feat(dynamic-views): unified branch foundations (types & parser) #2333 where 'path' was removed from metadata keys
  2. Comment Bump @types/vscode from 1.76.0 to 1.77.0 #4 - Nested ternary readability - Already simplified to if/else blocks in PR feat(dynamic-views): unified branch foundations (types & parser) #2333

All 686 core tests passing ✅

Commit: 3a625df5d

@Jrakru

Jrakru commented Oct 24, 2025

Copy link
Copy Markdown
Collaborator Author

Update on dependencies: This PR now depends on the updated PR #2333 (unified branch foundations). The original PR #2331 was closed and replaced with a cleaner version that incorporated all Copilot feedback.

@davydkov davydkov left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@Jrakru, this is awesome work!

Comment thread packages/core/src/types/scalar.ts Outdated
Comment thread packages/core/src/types/scalar.ts Outdated
Comment thread packages/core/src/config/featureFlags.ts
readonly parallelId: string
readonly __parallel: NonEmptyReadonlyArray<DynamicStep<A> | DynamicStepsSeries<A>>
readonly __parallel?: NonEmptyReadonlyArray<DynamicStep<A> | DynamicStepsSeries<A>>
readonly isLegacyParallel?: boolean

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I see assignment of isLegacyParallel, but don't see usage.
Or is it in later PRs?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I wanted a unified approach to alternate and parallel branches so that it can be maintained more easily in the future. I added it in case we need to have to maintain backward compatibility.

Comment thread packages/language-server/src/__tests__/views-dynamic.spec.ts Outdated
@davydkov

Copy link
Copy Markdown
Member

@Jrakru, I have some questions.

In tests you have

  dynamic view branchPaths {
    parallel {
      path success "Happy path" {
        A -> B
      }
      path failure {
        B -> C
      }
    }
  }

But what if

  dynamic view branchPaths {
    parallel {
      A1 -> B1
      path success "Happy path" {
        A -> B
      }
      A2 -> B2
      path failure {
        B -> C
      }
      path another {
        B1 -> C1
      }
    }
  }

How do we decide which paths are mutually alternate options inside parallel? Because they are on the same "level"?
Or should we separate parallel and alternate?

Another - how to express in A -> B -> C that B->C fails?

For instance:

A -> B
alternate {
  path success "Happy path" {
    B -> C
  }
  path failure {
    B -> C
  }   
}
C -> D // Does it mean it happens always
       // regardless of alternate outcome?
       // I know it happens if only B -> C succeed
       // Do we need something like "end" or "stop" in failure branch?

option 2:

A -> B
alternate {
  path success "Happy path" {
    B -> C
    C -> D // clearly part of happy path
  }
  path failure {
    B -> C
  }   
}

But it means that, we have to calculate all branches.
The following has three variants, doesn't it?

A -> B
alternate {
  path success "Happy path" {
    B -> C
    alternate {
      path success "Happy path 1" {
        C -> D -> E   // 1
      }
      path failure {
        C -> D        // 2
      }
    }
  }
  path failure {
    B -> C            // 3
  }   
}

What do you think?

- Comment #3: Fix series step indexing bug - move rootIndex++ inside loop
- Comment #5: Replace runtime invariant with NonEmptyArray type enforcement
- Comment #6: Optimize formatIndex by removing redundant number check
- Add experimental.dynamicBranchCollections to project config schema
- Update LikeC4Project type with experimental config section
- Modify DynamicViewCompute to read from project config
- Maintain backward compatibility with environment variables
- This enables per-project feature adoption instead of global 'works on my machine' issues
Jrakru added a commit to Jrakru/likec4 that referenced this pull request Nov 5, 2025
Address PR likec4#2332 reviewer questions by implementing comprehensive
parser-level validation rules for branch collections (parallel/alternate).

Changes:
- Add validation check 'dynamicViewBranchCollection' with 5 rules:
  1. Empty branch collection → Error
  2. Degenerate single-path branch → Warning (LIKEC4-DEGENERATE-BRANCH)
  3. Nested homogeneous parallel (P-in-P) → Error (LIKEC4-NESTED-PARALLEL)
  4. Nested homogeneous alternate (A-in-A) → Hint (LIKEC4-NESTED-ALTERNATE)
  5. Duplicate path names → Error (LIKEC4-DUP-PATH-NAME)

- Fix missing brace bug in compute.ts (branch tracking)
- Add 'hints' support to test helper (DiagnosticSeverity.Hint)
- Add 10 new tests in validation/dynamic-view.spec.ts
- Update existing tests to account for new warnings/errors
- Fix grammar conflict (path keyword vs metadata key)
- Add upstream policy documents for nesting rules

Test results: All 619 tests pass (56 test files)

Addresses reviewer questions:
- Q1 (mixing paths/steps): Anonymous steps converted to paths at parse
- Q2 (P-in-P semantics): Disallowed as associative/undesirable
- Q3 (post-alternate control flow): Unconditional execution confirmed
- Q4 (multiplicative variants): A-in-A treated as hint for flattening
- Q5 (isLegacyParallel): Forward-compatibility marker explained

Documentation: See BRANCH_VALIDATION_IMPLEMENTATION.md
Ready-to-post reply: See REPLY_TO_DAVYDKOV.md
Copilot AI review requested due to automatic review settings November 5, 2025 17:17

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 28 out of 29 changed files in this pull request and generated 8 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/language-server/src/validation/dynamic-view.ts
Comment thread packages/language-server/src/validation/dynamic-view.ts Outdated
Comment thread upstream/APPROACH_UNIFIED_BRANCH_COLLECTIONS_POLICY.md Outdated
Comment thread upstream/APPROACH_PARALLEL_NESTING_POLICY.md Outdated
Comment thread upstream/APPROACH_ALTERNATE_NESTING_POLICY.md Outdated
Comment thread PR2332_REVIEW_SUMMARY.md Outdated
Comment thread BRANCH_VALIDATION_IMPLEMENTATION.md Outdated
Comment thread packages/language-server/src/validation/dynamic-view.ts
Address PR likec4#2332 reviewer questions by implementing comprehensive
parser-level validation rules for branch collections (parallel/alternate).

Changes:
- Add validation check 'dynamicViewBranchCollection' with 5 rules:
  1. Empty branch collection → Error
  2. Degenerate single-path branch → Warning (LIKEC4-DEGENERATE-BRANCH)
  3. Nested homogeneous parallel (P-in-P) → Error (LIKEC4-NESTED-PARALLEL)
  4. Nested homogeneous alternate (A-in-A) → Hint (LIKEC4-NESTED-ALTERNATE)
  5. Duplicate path names → Error (LIKEC4-DUP-PATH-NAME)

- Fix missing brace bug in compute.ts (branch tracking)
- Add 'hints' support to test helper (DiagnosticSeverity.Hint)
- Add 10 new tests in validation/dynamic-view.spec.ts
- Update existing tests to account for new warnings/errors
- Fix grammar conflict (path keyword vs metadata key)

Test results: All 619 tests pass (56 test files)

Addresses reviewer questions:
- Q1 (mixing paths/steps): Anonymous steps converted to paths at parse
- Q2 (P-in-P semantics): Disallowed as associative/undesirable
- Q3 (post-alternate control flow): Unconditional execution confirmed
- Q4 (multiplicative variants): A-in-A treated as hint for flattening
- Q5 (isLegacyParallel): Forward-compatibility marker explained
@Jrakru Jrakru force-pushed the feat/unified-branch-compute branch from d0dfe8e to 363b3a7 Compare November 5, 2025 17:21
Copilot AI review requested due to automatic review settings November 5, 2025 17:22
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Jrakru <Jrakru@users.noreply.github.com>

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 22 out of 24 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/language-server/src/validation/dynamic-view.ts
Comment thread packages/core/src/compute-view/dynamic-view/compute.ts Outdated
Comment thread packages/core/src/types/scalar.ts Outdated
Comment thread packages/core/src/compute-view/dynamic-view/compute.ts Outdated
Comment thread packages/core/src/types/scalar.ts Outdated
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Jrakru <Jrakru@users.noreply.github.com>
Copilot AI review requested due to automatic review settings November 5, 2025 17:26
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Jrakru <Jrakru@users.noreply.github.com>
Jrakru and others added 2 commits November 5, 2025 12:26
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Jrakru <Jrakru@users.noreply.github.com>

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 22 out of 24 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/core/src/types/scalar.ts
Comment thread packages/core/src/config/featureFlags.ts Outdated
Comment thread packages/language-server/src/validation/dynamic-view.ts
Comment thread packages/core/src/compute-view/dynamic-view/compute.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Jrakru <Jrakru@users.noreply.github.com>
Copilot AI review requested due to automatic review settings November 5, 2025 17:29
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Jrakru <Jrakru@users.noreply.github.com>

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 22 out of 24 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

The compute function was only checking project config and environment
variables but not the programmatic feature flag set via
enableDynamicBranchCollections() used in tests.

Now checks flags in order of precedence:
1. Programmatic feature flag (for tests)
2. Project config
3. Environment variable (backward compatibility)

Fixes test: 'emits hierarchical step ids and branch metadata when feature flag enabled'
- Fix missing const declaration for destructuring assignment (syntax error from rebase)
- Remove test for empty array runtime validation (TypeScript type error only)
@Jrakru

Jrakru commented Nov 5, 2025

Copy link
Copy Markdown
Collaborator Author

Will reopen a clean PR without all the noise from copilot

@Jrakru Jrakru closed this Nov 5, 2025
Jrakru added a commit to Jrakru/likec4 that referenced this pull request Nov 5, 2025
This commit implements unified branch collections (alternate and parallel)
for LikeC4 dynamic views, with branch-aware compute and hierarchical step IDs.

## Core Features

### Grammar & Types
- Add `alternate` and `parallel` DSL syntax to Langium grammar
- Define `DynamicStepsAlternate` and `DynamicStepsParallel` types
- Add `DynamicStepsAlternate.path` for named alternate paths
- Support nested branch structures with depth limits

### Compute Layer
- Implement hierarchical step IDs (e.g., "1", "1.1", "1.1.1")
- Add branch trail tracking for step context
- Compute path metadata (selected path, available paths)
- Support compound elements in dynamic view steps
- Add programmatic feature flags with proper precedence

### Parser & Validation
- Parse alternate/parallel blocks with path names
- Format alternate/parallel syntax in LikeC4Formatter
- Validate empty branch collections (error)
- Validate degenerate single-path branches (warning)
- Validate nested homogeneous parallel (error)
- Validate nested homogeneous alternate (hint)
- Validate duplicate path names within branches (error)

## Technical Details

### New Types
- `StepEdgeId`: Hierarchical step identifier with parent/sibling tracking
- `BranchTrail`: Records branch context (type, path, depth)
- `DynamicViewComputed.branches`: Metadata for branch navigation

### Feature Flags
- `enableDynamicBranches`: Master toggle for alternate/parallel support
- Configurable via likec4.config.ts
- Programmatic flag for testing with proper precedence

### Validation Diagnostics
- `LIKEC4-EMPTY-BRANCH`: Empty branch collection
- `LIKEC4-DEGENERATE-BRANCH`: Single path in branch
- `LIKEC4-NESTED-PARALLEL`: Nested parallel-in-parallel
- `LIKEC4-NESTED-ALTERNATE`: Nested alternate-in-alternate
- `LIKEC4-DUP-PATH-NAME`: Duplicate path names

## Tests
- 19+ new tests covering all validation rules
- Branch traversal compute tests
- Step edge ID hierarchical tests
- Parser tests for alternate/parallel syntax
- All existing tests pass (1,409 passed)

## Breaking Changes
None - this is an additive feature behind a feature flag.

## Related
- Addresses PR likec4#2332 review feedback
- Foundation for walkthrough state machine (PR04)
- Enables alternate paths use case from executive summary
@davydkov

davydkov commented Nov 5, 2025

Copy link
Copy Markdown
Member

@Jrakru ok!

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.

3 participants