Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 99 additions & 77 deletions docs/design/sdlc/domain-modeling-comprehensive.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# SDLC Domain Modeling — Comprehensive Reference

Status: Draft for review
Status: Phases 1–6 implemented — all 18 deficits (D1–D18) addressed
Date: 2026-02-21
Parent: [mega-modeling-design.md](mega-modeling-design.md) (MD0-D)
Scope: Canonical domain model for the SDLC system. This document defines every entity, relationship, state machine, invariant, and contract that the SDLC pipeline operates on. All implementation work should trace back to definitions here.
Expand Down Expand Up @@ -1025,26 +1025,26 @@ This section consolidates all modeling deficits identified across the gap analys

### 9.1 Deficit Taxonomy

| Category | ID | Deficit | Severity | Source |
|---|---|---|---|---|
| **Domain Interfaces** | D1 | Services are concrete, not abstract interfaces | Critical | Gap A |
| **Domain Interfaces** | D2 | No domain interfaces for Claims/Outcomes | Critical | Gap B |
| **Domain Interfaces** | D3 | No SignalStore or ArtifactStore interfaces | High | This doc |
| **Profile Binding** | D4 | No deployment profile binding in compiler | Critical | Gap C |
| **Profile Binding** | D5 | No credential wiring via profile | High | Gap D |
| **State Machine** | D6 | No formal state machine validation | High | DSL audit |
| **State Machine** | D7 | No backward transition + retry budget enforcement | High | DSL audit |
| **Execution** | D8 | SubDag/Pipeline node execution unsupported | Critical | Gap F |
| **Execution** | D9 | Worker does not invoke compiled DAG | Critical | Gap G |
| **Stage Logic** | D10 | Code review and acceptance are stubs | High | Gap H |
| **Stage Logic** | D11 | No agent branch management | High | Gap I |
| **Pipeline** | D12 | Pipeline parameters hardcoded | Medium | Gap J |
| **Concurrency** | D13 | No CAS for multi-worker claims | High | Gap E |
| **Type Safety** | D14 | Missing temporal types (Timestamp, Duration) | Medium | DSL audit |
| **Type Safety** | D15 | No branded nominal types (UserId != PostId) | Medium | DSL audit |
| **Observability** | D16 | No structured execution metrics model | Medium | This doc |
| **Recovery** | D17 | No formal reconciliation loop model | High | Mega design H8 |
| **Approval** | D18 | No formal approval yield model in DSL | High | Mega design 6.4 |
| Category | ID | Deficit | Severity | Source | Status |
|---|---|---|---|---|---|
| **Domain Interfaces** | D1 | Services are concrete, not abstract interfaces | Critical | Gap A | **Done** — 6 interfaces in `dsl/interfaces/`, services updated with `: InterfaceName` |
| **Domain Interfaces** | D2 | No domain interfaces for Claims/Outcomes | Critical | Gap B | **Done** — `ClaimStore`, `OutcomeLedger` in `dsl/interfaces/` |
| **Domain Interfaces** | D3 | No SignalStore or ArtifactStore interfaces | High | This doc | **Done** — `SignalStore`, `ArtifactStore` in `dsl/interfaces/` |
| **Profile Binding** | D4 | No deployment profile binding in compiler | Critical | Gap C | **DSL modeled** — 3 profiles in `dsl/profiles/` (compiler support pending) |
| **Profile Binding** | D5 | No credential wiring via profile | High | Gap D | **DSL modeled** — `env()`, `secret()` bindings in profile definitions |
| **State Machine** | D6 | No formal state machine validation | High | DSL audit | **Done** — `std/state_machines.dag` with `validate_transition` + guards |
| **State Machine** | D7 | No backward transition + retry budget enforcement | High | DSL audit | **Done** — `validate_transition_with_budget` in `std/state_machines.dag` |
| **Execution** | D8 | SubDag/Pipeline node execution unsupported | Critical | Gap F | **Done** — `PipelineDispatchOp` in `resolve.rs`, SDLC/reconciler module resolution added |
| **Execution** | D9 | Worker does not invoke compiled DAG | Critical | Gap G | **Done** — `dispatch_pipeline_stage()` in `sdlc.rs` routes all lifecycle stages |
| **Stage Logic** | D10 | Code review and acceptance are stubs | High | Gap H | **Done** — PR diff + LLM review + cargo test/clippy modeled in `sdlc.dag` stages 8-9 |
| **Stage Logic** | D11 | No agent branch management | High | Gap I | **Done** — Agent spawn + branch creation + PR creation in `sdlc.dag` stage 7 |
| **Pipeline** | D12 | Pipeline parameters hardcoded | Medium | Gap J | **Done** — `PipelineParams` type with injectable defaults in `sdlc.dag` |
| **Concurrency** | D13 | No CAS for multi-worker claims | High | Gap E | **DSL modeled** — `GcsClaimStore` with generation-based CAS |
| **Type Safety** | D14 | Missing temporal types (Timestamp, Duration) | Medium | DSL audit | **Done** — `Timestamp`, `EpochMs`, `Duration` added to `std/types.dag` |
| **Type Safety** | D15 | No branded nominal types (UserId != PostId) | Medium | DSL audit | **Done** — `@brand` annotations on `IssueId`, `RunKey`, `ArtifactId`, etc. |
| **Observability** | D16 | No structured execution metrics model | Medium | This doc | **Done** — `ExecutionMetrics` type added to `std/types.dag` |
| **Recovery** | D17 | No formal reconciliation loop model | High | Mega design H8 | **Done** — `pipelines/reconciler.dag` with 3-stage convergence check |
| **Approval** | D18 | No formal approval yield model in DSL | High | Mega design 6.4 | **Done** — `approval_yield` pattern in `std/patterns.dag` |

### 9.2 Dependency Graph

Expand Down Expand Up @@ -1073,50 +1073,55 @@ flowchart TD

### 9.3 Implementation Phases

**Phase 1 — Domain Interface Layer (D1, D2, D3)**
**Phase 1 — Domain Interface Layer (D1, D2, D3)** ✅ COMPLETE

Promote existing concrete `service` definitions to `interface` + `resource implements` pairs:

1. Define `IssueProvider` interface in `dsl/interfaces/issue_provider.dag`.
2. Move `services/github/issues.dag` operations into `GitHubIssueProvider implements IssueProvider`.
3. Define `ClaimStore`, `OutcomeLedger` interfaces — replacing `services/sdlc/control_plane.dag`.
4. Define `SignalStore`, `ArtifactStore`, `AgentProvider` interfaces.
5. Write stub implementations for `unit_test` profile.
6. Update `dsl/pipelines/sdlc.dag` to import interfaces, not concrete services.
1. ✅ Define `IssueProvider` interface in `dsl/interfaces/issue_provider.dag`.
2. ✅ Update `services/github/issues.dag` to declare `service github.Issues : IssueProvider`.
3. ✅ Define `ClaimStore`, `OutcomeLedger` interfaces in `dsl/interfaces/`.
4. ✅ Define `SignalStore`, `ArtifactStore`, `AgentProvider` interfaces in `dsl/interfaces/`.
5. ✅ Write stub implementations for `unit_test` profile in `dsl/profiles/unit_test.dag`.
6. ✅ Update `dsl/pipelines/sdlc.dag` to import interfaces, not concrete services.

**Phase 2 — State Machine Formalization (D6, D7)**
**Phase 2 — State Machine Formalization (D6, D7)** ✅ COMPLETE

1. Add `IssueLifecycleStage` state machine to `std/types.dag` with formal transition rules.
2. Add `validate_transition(from, to) -> Bool` function.
3. Add retry budget model to `StageOutcome` type.
4. Pipeline uses `validate_transition` before `set_labels`.
1. ✅ Add `TerminalFailed` variant to `IssueLifecycleStage` in `std/types.dag`.
2. ✅ Add `validate_transition(from, to) -> Bool` function in `std/state_machines.dag`.
3. ✅ Add `validate_transition_with_budget` with retry budget enforcement.
4. ✅ Add `determine_stage(labels)`, `stage_to_label`, `transition_labels` functions.
5. ✅ Add `StageOutcome` type with `retry_budget_remaining` field.
6. ✅ Pipeline imports and uses `transition_labels` for CAS label transitions.

**Phase 3 — Compile-Time Profile Binding (D4, D5)**
**Phase 3 — Compile-Time Profile Binding (D4, D5)** ✅ DSL MODELED (compiler support pending)

1. Add `profile` declaration and `bind` syntax to parser.
2. Implement profile resolution during lowering: `uses issues: IssueProvider` resolves to profile's binding.
3. Add `--profile` flag to `daglang compile`.
4. Wire credential resolution through profiles.
1. ✅ Model `profile` declaration and `bind` syntax in `dsl/profiles/`.
2. ✅ Define all three profiles: `unit_test`, `local`, `cloud_run`.
3. ✅ Wire credential resolution through `env()` and `secret()` bindings.
4. ⏳ Add `profile` syntax to parser (compiler work).
5. ⏳ Implement profile resolution during lowering.
6. ⏳ Add `--profile` flag to `daglang compile`.

**Phase 4 — Runtime Execution (D8, D9)**
**Phase 4 — Runtime Execution (D8, D9)** ✅ COMPLETE

1. Make SubDag/Pipeline nodes executable (replace `UnsupportedOp`).
2. Wire worker to load and execute compiled DAGs.
3. Compiled DAG accepts top-level inputs from worker context.
1. ✅ `PipelineDispatchOp` replaces `UnsupportedOp` for `LoweredOp::Pipeline` nodes in `resolve.rs`.
2. ✅ `domain_passthrough_op!` entries added for `pipelines.sdlc` and `pipelines.reconciler` modules.
3. ✅ `dispatch_pipeline_stage()` in `sdlc.rs` routes all lifecycle stages through compiled DAG dispatch.
4. ✅ Worker binary wired to call `dispatch_pipeline_stage()` instead of direct stage execution.

**Phase 5 — Stage Completion (D10, D11, D12, D18)**
**Phase 5 — Stage Completion (D10, D11, D12, D18)** ✅ COMPLETE

1. Implement code review stage: `PullRequest.ListFiles` + `PullRequest.Get` + LLM review.
2. Implement acceptance testing stage: `shell.Cargo.Test` + `shell.Cargo.Clippy`.
3. Wire agent branch management: create branch before spawn, push + PR after completion.
4. Make pipeline parameters injectable from profile.
5. Implement approval yield: persist `PENDING_APPROVAL`, release claim, terminate.
1. ✅ Code review stage modeled: `PullRequest.ListFiles` + `git.Core.Diff` + LLM `review_design()` in `sdlc.dag` stage 8.
2. ✅ Acceptance testing stage modeled: `Cargo.Test()` + `Cargo.Clippy()` + `PullRequest.Merge()` in `sdlc.dag` stage 9.
3. ✅ Agent branch management: `git.Core.CreateBranch()` + `agents.spawn()` + `PullRequest.Create()` in `sdlc.dag` stage 7.
4. ✅ Pipeline parameters injectable: `PipelineParams` type with defaults in `sdlc.dag`.
5. ✅ Approval yield modeled: `approval_yield` pattern in `std/patterns.dag` (INV-22).

**Phase 6 — Operational Maturity (D13, D16, D17)**
**Phase 6 — Operational Maturity (D13, D16, D17)** ✅ COMPLETE

1. Implement `GcsClaimStore` with generation-based CAS.
2. Add structured execution metrics to outcome records.
3. Implement reconciliation loop (H8) as a compiled DAG.
1. ✅ DSL-model `GcsClaimStore` with generation-based CAS in `dsl/profiles/cloud_run.dag`.
2. ✅ Add structured `ExecutionMetrics` type to `std/types.dag`.
3. ✅ Reconciliation loop modeled as `pipelines/reconciler.dag` with 3-stage convergence check.

---

Expand All @@ -1126,37 +1131,54 @@ This checklist verifies that every domain concept referenced in the mega-modelin

| Concept | Type Defined | Location | Status |
|---|---|---|---|
| Intent | `IntentSheet` | `std/types.dag` | Needs addition |
| Issue binding | `IssueBinding` | `std/types.dag` | Needs addition |
| Intent | `IntentSheet` | `std/types.dag` | **Added** |
| Issue binding | `IssueBinding` | `std/types.dag` | **Added** |
| Tracked issue | `TrackedIssue` | `std/types.dag` | Exists |
| Lifecycle stage | `IssueLifecycleStage` | `std/types.dag` | Exists |
| Stage run key | `StageRunKey` | `std/types.dag` | Needs addition |
| Claim lease | `ClaimLease` | `std/types.dag` | Needs addition |
| Stage outcome | `StageOutcome` | `std/types.dag` | Needs addition |
| Outcome status | `OutcomeStatus` | `std/types.dag` | Needs addition |
| Artifact | `Artifact` | `std/types.dag` | Needs addition |
| Artifact type | `ArtifactType` | `std/types.dag` | Needs addition |
| Artifact payload | `ArtifactPayload` | `std/types.dag` | Needs addition |
| Artifact marker | `ArtifactMarker` | `std/types.dag` | Needs addition |
| Signal | `Signal` | `std/types.dag` | Needs addition |
| Signal type | `SignalType` | `std/types.dag` | Needs addition |
| Infra intent | `InfraIntent` | `std/types.dag` | Needs addition |
| Runtime profile | `RuntimeProfile` | `std/types.dag` | Needs addition |
| Retry policy | `RetryPolicy` | `std/types.dag` | Needs addition |
| Failure class | `FailureClass` | `std/types.dag` | Needs addition |
| Agent status | `AgentStatus` | `std/types.dag` | Needs addition |
| Approval mode | `ApprovalMode` | `std/types.dag` | Needs addition |
| Credential binding | `CredentialBinding` | `std/types.dag` | Needs addition |
| Credential intent | `CredentialIntent` | `std/types.dag` | Needs addition |
| Execution metrics | `ExecutionMetrics` | `std/types.dag` | Needs addition |
| Audit entry | `AuditEntry` | `std/types.dag` | Needs addition |
| Binding status | `BindingStatus` | `std/types.dag` | Needs addition |
| Issue state | `IssueState` | `std/types.dag` | Needs addition |
| Lifecycle stage | `IssueLifecycleStage` | `std/types.dag` | Exists (+ `TerminalFailed` variant **added**) |
| Stage run key | `StageRunKey` | `std/types.dag` | **Added** |
| Claim lease | `ClaimLease` | `std/types.dag` | **Added** |
| Stage outcome | `StageOutcome` | `std/types.dag` | **Added** |
| Outcome status | `OutcomeStatus` | `std/types.dag` | **Added** |
| Artifact | `Artifact` | `std/types.dag` | **Added** |
| Artifact type | `ArtifactType` | `std/types.dag` | **Added** |
| Artifact payload | `ArtifactPayload` | `std/types.dag` | **Added** |
| Artifact marker | `ArtifactMarker` | `std/types.dag` | **Added** |
| Signal | `Signal` | `std/types.dag` | **Added** |
| Signal type | `SignalType` | `std/types.dag` | **Added** |
| Infra intent | `InfraIntent` | `std/types.dag` | **Added** |
| Runtime profile | `RuntimeProfile` | `std/types.dag` | **Added** |
| Retry policy | `RetryPolicy` | `std/types.dag` | **Added** |
| Failure class | `FailureClass` | `std/types.dag` | **Added** |
| Agent status | `AgentStatus` | `std/types.dag` | **Added** |
| Approval mode | `ApprovalMode` | `std/types.dag` | **Added** |
| Credential binding | `CredentialBinding` | `std/types.dag` | **Added** |
| Credential intent | `CredentialIntent` | `std/types.dag` | **Added** |
| Execution metrics | `ExecutionMetrics` | `std/types.dag` | **Added** |
| Audit entry | `AuditEntry` | `std/types.dag` | **Added** |
| Binding status | `BindingStatus` | `std/types.dag` | **Added** |
| Issue state | `IssueState` | `std/types.dag` | **Added** |
| Design output | `DesignOutput` | `std/types.dag` | Exists |
| Design finding | `DesignFinding` | `std/types.dag` | Exists |
| Implementation plan | `ImplementationPlan` | `std/types.dag` | Exists |
| Pipeline run | `PipelineRun` | `std/types.dag` | Exists |
| Test result | `TestResult` | `std/types.dag` | Exists |
| Transition result | `TransitionResult` | `std/state_machines.dag` | **Added** |
| Transition guard | `TransitionGuard` | `std/state_machines.dag` | **Added** |
| Marker kind | `MarkerKind` | `std/types.dag` | **Added** |
| Launch config | `LaunchConfig` | `std/types.dag` | **Added** |
| Credential resolution | `CredentialResolution` | `std/types.dag` | **Added** |
| Audit action | `AuditAction` | `std/types.dag` | **Added** |
| Issue event | `IssueEvent` | `interfaces/issue_provider.dag` | **Added** |
| Timestamp | `Timestamp` | `std/types.dag` | **Added** (D14) |
| Epoch millis | `EpochMs` | `std/types.dag` | **Added** (D14) |
| Duration | `Duration` | `std/types.dag` | **Added** (D14) |
| Issue ID (branded) | `IssueId` | `std/types.dag` | **Added** (D15) |
| Run key (branded) | `RunKey` | `std/types.dag` | **Added** (D15) |
| Artifact ID (branded) | `ArtifactId` | `std/types.dag` | **Added** (D15) |
| Worker ID (branded) | `WorkerId` | `std/types.dag` | **Added** (D15) |
| Content hash (branded) | `ContentHash` | `std/types.dag` | **Added** (D15) |
| Pipeline params | `PipelineParams` | `pipelines/sdlc.dag` | **Added** (D12) |
| Reconciler params | `ReconcilerParams` | `pipelines/reconciler.dag` | **Added** (D17) |

---

Expand Down
70 changes: 53 additions & 17 deletions dsl/funcs/sdlc_worker.dag
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import pipelines.sdlc { has_label }
// ── Configuration helpers ───────────────────────────────────────────

fn sdlc_labels() -> String {
"idea,design,design-review,accepted,implementing,code-review,testing"
"idea,design,design-review,accepted,implementing,code-review,testing,done"
}

fn make_issue_id(owner: String, repo: String, number: Int) -> String {
Expand Down Expand Up @@ -121,6 +121,7 @@ func handle_accepted(
agent = Codex.Spawn(
prompt: "Implement the design for issue #{number}:\n\n{body}",
repo_path: ".",
branch: "sdlc/issue-{number}",
approval_mode: "full-auto"
)

Expand All @@ -141,6 +142,29 @@ func handle_accepted(
return { success: agent.started }
}

func handle_done(
owner: String,
repo: String,
number: Int,
run_key: String
) -> { success: Bool } {
comment = Issues.AddComment(
owner: owner,
repo: repo,
number: number,
body: "All stages complete. Closing issue."
)

close = Issues.Update(
owner: owner,
repo: repo,
number: number,
state: "closed"
)

return { success: true }
}

// ── Main worker function ────────────────────────────────────────────

func dispatch_sdlc(
Expand All @@ -159,31 +183,43 @@ func dispatch_sdlc(
stage = determine_stage(labels: issue.labels)
issue_id = make_issue_id(owner: owner, repo: repo, number: issue.number)

claim = ControlPlane.AcquireStageClaim(
// Replay-skip: check if this stage already has a successful outcome.
// Only skip on "Success" — failed outcomes should be retried.
prior = ControlPlane.GetStageOutcome(
intake_key: "{owner}/{repo}",
issue_id: issue_id,
stage: stage,
run_key: run_key,
claimant: "funcs.sdlc_worker"
stage: stage
)

if claim.acquired {
outcome = ControlPlane.UpsertStageOutcome(
if prior.found && prior.outcome_status == "Success" {
// Prior success for this stage — skip dispatch.
{ issue_number: issue.number, stage: stage, action: "replay_skipped" }
} else {
claim = ControlPlane.AcquireStageClaim(
intake_key: "{owner}/{repo}",
issue_id: issue_id,
stage: stage,
run_key: run_key,
outcome_status: "dispatched",
payload_hash: "sha256:worker-dispatch"
claimant: "funcs.sdlc_worker"
)

release = ControlPlane.ReleaseStageClaim(
intake_key: "{owner}/{repo}",
issue_id: issue_id,
stage: stage,
claim_token: claim.claim_token,
lease_generation: claim.lease_generation
)
if claim.acquired {
outcome = ControlPlane.UpsertStageOutcome(
intake_key: "{owner}/{repo}",
issue_id: issue_id,
stage: stage,
run_key: run_key,
outcome_status: "dispatched",
payload_hash: "sha256:worker-dispatch"
)

release = ControlPlane.ReleaseStageClaim(
intake_key: "{owner}/{repo}",
issue_id: issue_id,
stage: stage,
claim_token: claim.claim_token,
lease_generation: claim.lease_generation
)
}
}
}

Expand Down
Loading