feat(dynamic-views): add branch-aware compute and hierarchical step IDs#2332
feat(dynamic-views): add branch-aware compute and hierarchical step IDs#2332Jrakru wants to merge 19 commits into
Conversation
There was a problem hiding this comment.
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.
- 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)
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
5d06a5b to
23befb4
Compare
- 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
✅ Copilot Feedback AddressedThanks for the review! I've addressed the valid feedback: Fixed Issues:
Already Fixed (from PR #2333 rebase):
All 686 core tests passing ✅ Commit: |
| readonly parallelId: string | ||
| readonly __parallel: NonEmptyReadonlyArray<DynamicStep<A> | DynamicStepsSeries<A>> | ||
| readonly __parallel?: NonEmptyReadonlyArray<DynamicStep<A> | DynamicStepsSeries<A>> | ||
| readonly isLegacyParallel?: boolean |
There was a problem hiding this comment.
I see assignment of isLegacyParallel, but don't see usage.
Or is it in later PRs?
There was a problem hiding this comment.
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.
|
@Jrakru, I have some questions. In tests you have But what if How do we decide which paths are mutually alternate options inside Another - how to express in For instance: option 2: But it means that, we have to calculate all branches. What do you think? |
- 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
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
There was a problem hiding this comment.
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.
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
d0dfe8e to
363b3a7
Compare
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Jrakru <Jrakru@users.noreply.github.com>
There was a problem hiding this comment.
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.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Jrakru <Jrakru@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Jrakru <Jrakru@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Jrakru <Jrakru@users.noreply.github.com>
There was a problem hiding this comment.
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.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Jrakru <Jrakru@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Jrakru <Jrakru@users.noreply.github.com>
There was a problem hiding this comment.
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)
|
Will reopen a clean PR without all the noise from copilot |
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
|
@Jrakru ok! |
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:
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.tsstepEdgePath()for arbitrary-depth hierarchical IDsstepEdgePath([1])→'step-01'stepEdgePath([3, 2])→'step-03.02'stepEdgePath([4, 1, 2])→'step-04.01.02'stepEdgeId()to usestepEdgePath()internallyComputed View Types
File:
packages/core/src/types/view-computed.tsNew types added:
ComputedBranchTrailEntry: Branch ancestry for each edgebranchId,pathId,pathIndex,indexWithinPath,isDefaultPathComputedBranchCollectionPath: Metadata for each branch pathpathId,pathIndex,edgeIds[],pathName,pathTitleComputedBranchCollection: Complete collection metadatabranchId,kind(parallel/alternate),paths[],defaultPathIdComputedEdge.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.tsBranchCollectionAccumulatorfor metadata assemblybranchTrailfor each edge with full ancestrybranchCollectionsarray when feature flag enabledActor Discovery
File:
packages/core/src/compute-view/dynamic-view/utils.tselementsFromStepsto traverse branch collectionsTests
New Test Files (7 tests total)
packages/core/src/types/__tests__/step-edge-id.spec.ts(5 tests)packages/core/src/compute-view/dynamic-view/__test__/branch-traversal.spec.ts(2 tests)Test Results
Backward Compatibility
Feature flag guarded via
isDynamicBranchCollectionsEnabled():When Flag OFF (default):
'step-01','step-02'branchTrailon edgesbranchCollectionspropertyWhen Flag ON:
branchTrailpresent on all edgesbranchCollectionsarray emittedDependencies
Technical Notes
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.tspackages/core/src/types/__tests__/step-edge-id.spec.tsTotal: +612 insertions, -108 deletions
Quality Gates