Replies: 2 comments
-
Diamond Dependency Problem: Blocked vs UnblockedGraph StructureDependencies:
Julia Version Resolution RulesRule 1: Pre-release Filtering (Most Important!)By default, pre-releases are completely IGNORED during resolution. # Available versions: C v1, v2-beta.1
# Compat declaration: C = "1"
# Resolution process:
# 1. Filter: Remove all pre-releases → candidates = {v1}
# 2. Resolve: Only v1 is considered
# Result: v1Pre-releases only become candidates if EXPLICITLY allowed: # Available versions: C v1, v2-beta.1
# Compat declaration: C = "1, 2.0.0-" ← Explicit mention of pre-releases
# Resolution process:
# 1. Filter: Keep pre-releases (explicitly allowed) → candidates = {v1, v2-beta.1}
# 2. Resolve: Both are now candidates
# 3. Select: Prefer stable over pre-release → v1
# Result: v1Rule 2: Version OrderingOnce filtered, versions follow: Rule 3: IntersectionThe resolver finds the intersection of all constraints: Rule 4: Stable PreferenceWhen intersection contains both stable and pre-release versions, prefer stable. Rule 5: Maximum SelectionWithin the same stability class, choose the highest version. The Key Insight: Why Betas MatterBetas don't get chosen over stables. Betas create resolution PATHS that didn't exist before. Without beta: With beta: The beta is used ONLY when it's the ONLY way to satisfy all constraints. Scenario: C Breaking Change (v1 → v2)Initial State (All Stable)Available versions: Compat declarations: Compat(A, v1) = {B ↦ {v1}, D ↦ {v1}, C ↦ {v1}}
Compat(B, v1) = {C ↦ {v1}}
Compat(D, v1) = {C ↦ {v1}}
Compat(C, v1) = {}Resolution for A: Problem 1: BLOCKED - Without Beta StrategyStep 1: C v2 Released (Breaking Change)Available versions: Note: v2 is stable, so it's not filtered out. But constraints prevent its use. Step 2: B Updated to Use C v2Create B v2 that requires C v2: Compat: Compat(B, v2) = {C ↦ {v2}} # Breaking: now requires v2Step 3: Try to Test A with New B v2Attempt configuration: Constraints on C: Result: ❌ UNSATISFIABLE - Cannot test A with B v2! Why? A and D require C v1, but B v2 requires C v2. No common version exists. Solution: UNBLOCKED - With Beta StrategyPhase 1: Preventive WideningBEFORE releasing C v2, widen all compat constraints: Compat(A, v1.1) = {B ↦ {v1}, D ↦ {v1}, C ↦ {v1, v2-}} # Accept v1 AND v2 betas
Compat(B, v1.1) = {C ↦ {v1, v2-}} # Accept both
Compat(D, v1.1) = {C ↦ {v1, v2-}} # Accept bothRegister new versions: User installing A: using Pkg
Pkg.add("A")
# Resolution:
# 1. A v1.1 requires: B ∈ {v1}, D ∈ {v1}, C ∈ {v1, v2-}
# 2. B v1.1 requires: C ∈ {v1, v2-}
# 3. D v1.1 requires: C ∈ {v1, v2-}
# 4. Intersection: {v1, v2-} ∩ {v1, v2-} ∩ {v1, v2-} = {v1, v2-}
# 5. Filter pre-releases: v2- candidates don't exist yet (only widened compat)
# 6. Choose: v1 (stable, only concrete option)
Result: A v1.1, B v1.1, D v1.1, C v1 ✅No disruption for users! Phase 2: Release C v2-betaUser installing A: Pkg.add("A")
# Resolution:
# 1. Constraints create intersection: {v1, v2-}
# 2. Candidates after filtering: {v1, v2-beta.1} ← beta now allowed!
# 3. Prefer stable: v1 chosen over v2-beta.1
# Result: A v1.1, B v1.1, D v1.1, C v1 ✅Why? Even though v2-beta.1 is in the intersection, the resolver prefers stable v1. Key point: User still gets v1, but now v2-beta.1 is "ready" as a fallback path. Phase 3: Update B to Use C v2-betaRelease B v2: Compat(B, v2) = {C ↦ {v2-}} # Requires beta explicitlyPhase 4: Test A with B v2 (NOW IT WORKS!)Attempt configuration: Constraints on C: Filtering and selection: Result: ✅ SATISFIABLE Configuration: Now we can test A with the new B! 🎉 Why it works:
Phase 5: Also Update D (Same Process)Test A with both B v2 and D v2: Configuration: Constraints: Result: ✅ Phase 6: Release C v2 StableUser installing A with old dependencies: Pkg.add("A")
# A v1.1 + B v1.1 + D v1.1
# Intersection: {v1, v2-}
# Available: {v1, v2-beta.1, v2}
# Prefer stable: v1 chosen ✅User installing A with new B v2 and D v2: # A v1.1 + B v2 + D v2
# Intersection: {v2-}
# Available matching {v2-}: {v2-beta.1, v2}
# v2 is stable pre-release → Choose v2 ✅Everything works! ✅ Key ComparisonWithout Beta Strategy (BLOCKED)With Beta Strategy (UNBLOCKED)Visual Resolution StepsBlocked Case (No Beta)Unblocked Case (With Beta)Why This Strategy Works: The Complete Picture1. Widening Creates Potential Paths2. Betas Enable New Intersections3. Stable Preference Protects Users4. Gradual MigrationSummaryThe Paradox ResolvedYou asked: "If resolver takes maximum, why don't users get beta?" Answer: The resolver does NOT simply take maximum. It follows this order:
Result:
Why Betas Are EssentialWithout betas:
With betas:
Key insight: Betas are fallback paths used only when necessary, not preferred alternatives. |
Beta Was this translation helpful? Give feedback.
-
|
See new repo https://github.com/control-toolbox/DevelopmentGuide. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Development Workflow Guide for Control Toolbox
Overview
This guide explains how to efficiently develop across multiple Control Toolbox packages using Julia's
Pkg.develop()feature. This workflow is designed for small teams (3-4 developers) working on interdependent packages.Key Principle: Develop all packages locally simultaneously, ignoring version constraints during development. Register versions only when features are complete and tested.
One-Time Setup
1. Clone All Repositories
Create a dedicated folder and clone all repositories side-by-side:
Result:
2. Set Up Development Environment
Navigate to your main working package (typically OptimalControl) and activate development mode for all dependencies:
cd OptimalControl.jl julia --projectIn Julia REPL:
You should see
(dev)markers:What this means: All packages now use your local code, completely ignoring version constraints.
3. Create a Setup Script (Optional but Recommended)
Create
~/dev/control-toolbox/dev-setup.jl:Usage in any project:
Daily Development Workflow
Working on a Single Package
Example: Improving CTBase
Test in isolation:
Test with dependents:
Key advantage: Changes in CTBase are immediately available to all dependent packages. No registration, no waiting.
Working Across Multiple Packages
Example: API change in CTBase affecting CTModels
Everything works? Great! Both changes are compatible.
Tests fail? Fix immediately - you have all the code locally.
Handling Breaking Changes
Simple Process (Recommended for Small Teams)
Step 1: Announce
Post in team chat:
Step 2: Make changes across all affected packages
Step 3: Test everything together
Step 4: When all works, push and create PRs
Step 5: Merge in dependency order
Step 6: Register new versions
Register in the same order:
@JuliaRegistrator registeron CTBase → wait for registrationTimeline: Can complete in a few hours (not weeks!)
Version Management
During Development: Don't Touch Versions
While actively developing:
When Ready to Release
Only register when:
Process:
Project.toml:@JuliaRegistrator registerFrequency: Weekly or monthly releases are fine. Don't release daily!
Common Tasks
Check What's in Development Mode
Look for
(dev)markers to see which packages are using local code.Switch Back to Registry Version
To free all packages:
Reset Everything (When Things Break)
Pull Latest Changes from Team
Since everything is in development mode, all packages automatically use the updated code.
Team Coordination
Communication
Use team chat for:
Example messages:
Branch Strategy
Simple approach:
feature/descriptionmainFor coordinated changes:
epic/v0.17Example: Complete Feature Development
Scenario: Add new solver algorithm requiring changes in CTBase and CTModels
Monday Morning (1 hour)
Monday Afternoon (30 min)
Later (when ready to release)
Total active time: 1.5 hours. Feature is developed, tested, and merged.
Advantages of This Workflow
✅ Fast iteration - No waiting for registrations or CI
✅ Simple - Easy to understand and explain
✅ Flexible - Easy to experiment and refactor
✅ Julia-native - Uses
Pkg.develop()as intended✅ Safe - Test everything together before releasing
✅ Low overhead - Minimal coordination needed
When to Evolve This Workflow
This workflow is ideal for:
Consider more structure when:
But until then: Keep it simple! 🚀
Quick Reference
Initial Setup
Daily Development
Check Status
Release
Getting Help
Happy developing! 🎉
Beta Was this translation helpful? Give feedback.
All reactions