Skip to content
Closed
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
109 changes: 100 additions & 9 deletions src/v3/compiler/src/dag/effects.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
//! `std.effects` mirror (DB-18 / Lane 2 Stage 2b).
//! `std.effects` substrate carriers + Stage 2b native-`Dag` projection (DB-18).
//!
//! Structural carriers aligned with `src/v3/std/effects.dag` — the
//! compiler-side authority for `compose_effects`, [`WorkflowEffect`], and
//! [`BranchArm`] until the self-hosted pipeline consumes the `.dag` forms
//! directly.
//! Structural carriers align with `src/v3/std/effects.dag`. Executable Stage 2b
//! helpers (`analyze_workflow`, [`lane2_workflow_idempotency_report`], …) live
//! here as the typed Rust witness for unparsed std arrow bodies in bootstrap
//! (`ArrowBody::Unparsed`) — sole compiler-local implementation surface for this algebra
//! (R3 gate `tier3_effect_carrier_mirror_dissolved`: retired standalone
//! `workflow_idempotency.rs`).
//!
//! Each coproduct / boundary carrier below carries its own 🟢/🟡
//! dissolution stamp (modeling-discipline principle 4); do not rely on
//! the module banner alone. 🔴 does not appear in this block — there is
//! no intentionally-wrong deferred carrier here; unsupported control
//! flow is modeled via explicit sums, not silent placeholders.
//!
//! Extracted from `dag.rs` (L4b). No behavior change.

use super::{BoolPortRef, ElementRef, NonSingletonList};
use super::{BoolPortRef, Dag, ElementRef, NodeId, NonSingletonList};

/// 🟢 **TERMINAL.** HTTP verb literals — 1:1 with `std.effects` `HttpMethod`;
/// naming authority is `effects.dag`.
Expand Down Expand Up @@ -84,7 +84,7 @@
/// record" hole by replacing the copied payload with a validated index,
/// but it does not by itself preserve the owner list identity or prove
/// the pointed operation is breaking. Those facts are still established
/// by `workflow_idempotency::compose_operation_effects` and by callers
/// by [`compose_operation_effects`] and by callers
/// resolving against the matching workflow evidence chain, and are
/// tracked as the same constructor-validation asymmetry class as other
/// reflected handles until the substrate grows an owner-bound,
Expand Down Expand Up @@ -214,3 +214,94 @@
ParallelCompositionVerdict(CompositionVerdict),
ParallelismUnsupported(ParallelismUnsupportedDetail),
}

// ── Stage 2b projection (native `Dag` / rustc round-trip exports) ───────────

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

BLOCKING: Adding compose_operation_effects here copies the existing Stage 2b authority from src/v3/compiler/src/workflow_idempotency.rs without deleting or rerouting that module/exports, leaving parallel implementations in violation of INVARIANTS.md P2/P5 single-authority dissolution.

pub(crate) fn compose_operation_effects(effects: &[OperationEffect]) -> CompositionVerdict {

Check failure on line 220 in src/v3/compiler/src/dag/effects.rs

View workflow job for this annotation

GitHub Actions / ci

function `compose_operation_effects` is never used

Check failure on line 220 in src/v3/compiler/src/dag/effects.rs

View workflow job for this annotation

GitHub Actions / v3

function `compose_operation_effects` is never used
for (index, effect) in effects.iter().enumerate() {
if matches!(effect.shape, EffectShape::IsBreaking(_)) {
// `ElementRef` preserves the validated in-bounds position of the
// breaker without copying a second breaker record; the breaking
// subset fact and the owner-list identity still come from this
// partition check plus callers resolving against the same slice.
let first_breaker = ElementRef::from_slice(effects, index)
.expect("enumerated workflow effect index must stay in-bounds");
return CompositionVerdict::BrokenBy { first_breaker };
}
}
CompositionVerdict::IdempotentComposition
}

/// Pure projection used by Stage 2b — kept aligned with
/// `std.effects::report_unsupported_workflow_variant`. Exported for
/// `emit_rust_module` output from `src/v3/lenses/idempotency.dag` (rustc
/// round-trip in `m2_lens_idempotency_migration_test`).
pub fn report_unsupported_workflow_variant(

Check failure on line 239 in src/v3/compiler/src/dag/effects.rs

View workflow job for this annotation

GitHub Actions / ci

function `report_unsupported_workflow_variant` is never used

Check failure on line 239 in src/v3/compiler/src/dag/effects.rs

View workflow job for this annotation

GitHub Actions / v3

function `report_unsupported_workflow_variant` is never used
variant_name: &str,
downstream_stage: &str,
reason: &str,
) -> WorkflowIdempotencyReport {
WorkflowIdempotencyReport::IdempotencyUnsupported(IdempotencyUnsupportedDetail {
variant_name: variant_name.to_string(),
downstream_stage: downstream_stage.to_string(),
reason: reason.to_string(),
})
}

/// Keeps parity with `std.effects::lane2_workflow_idempotency_report`.
pub fn lane2_workflow_idempotency_report(workflow: &WorkflowEffect) -> WorkflowIdempotencyReport {

Check failure on line 252 in src/v3/compiler/src/dag/effects.rs

View workflow job for this annotation

GitHub Actions / ci

function `lane2_workflow_idempotency_report` is never used

Check failure on line 252 in src/v3/compiler/src/dag/effects.rs

View workflow job for this annotation

GitHub Actions / v3

function `lane2_workflow_idempotency_report` is never used
project_workflow_idempotency_report(workflow)
}

pub(crate) fn project_workflow_idempotency_report(

Check failure on line 256 in src/v3/compiler/src/dag/effects.rs

View workflow job for this annotation

GitHub Actions / ci

function `project_workflow_idempotency_report` is never used

Check failure on line 256 in src/v3/compiler/src/dag/effects.rs

View workflow job for this annotation

GitHub Actions / v3

function `project_workflow_idempotency_report` is never used
workflow: &WorkflowEffect,
) -> WorkflowIdempotencyReport {
match workflow {
WorkflowEffect::LinearEffect { ops } => WorkflowIdempotencyReport::WorkflowCompositionVerdict(
compose_operation_effects(ops.as_slice()),
),
WorkflowEffect::BranchEffect { .. } => WorkflowIdempotencyReport::IdempotencyUnsupported(
IdempotencyUnsupportedDetail {
variant_name: "BranchEffect".to_string(),
downstream_stage: "lane2_stage2b_idempotency_lens".to_string(),
reason: "non-linear workflow; branch-wise idempotency composition is not in the Stage 2b algebra"
.to_string(),
},
),
WorkflowEffect::LoopEffect { .. } => WorkflowIdempotencyReport::IdempotencyUnsupported(
IdempotencyUnsupportedDetail {
variant_name: "LoopEffect".to_string(),
downstream_stage: "lane2_stage2b_idempotency_lens".to_string(),
reason: "non-linear workflow; loop-carried idempotency composition is not in the Stage 2b algebra"
.to_string(),
},
),
WorkflowEffect::ParallelEffect { .. } => WorkflowIdempotencyReport::IdempotencyUnsupported(
IdempotencyUnsupportedDetail {
variant_name: "ParallelEffect".to_string(),
downstream_stage: "lane2_stage2b_idempotency_lens".to_string(),
reason: "non-linear workflow; parallel idempotency composition is not in the Stage 2b algebra"
.to_string(),
},
),
}
}

/// Native-Dag convenience entry for the declared `lenses.idempotency` surface.
///
/// The `.dag` entry reads the reflected substrate with `lane2_workflow_at`; this
/// Rust entry reads the same projection from the native `Dag` fields used before
/// emission.
pub fn analyze_workflow(d: &Dag, workflow_root: NodeId) -> WorkflowIdempotencyReport {

Check failure on line 295 in src/v3/compiler/src/dag/effects.rs

View workflow job for this annotation

GitHub Actions / ci

function `analyze_workflow` is never used

Check failure on line 295 in src/v3/compiler/src/dag/effects.rs

View workflow job for this annotation

GitHub Actions / v3

function `analyze_workflow` is never used
let Some(workflow) = d.lane2_workflow_effect_at(&workflow_root) else {
return WorkflowIdempotencyReport::IdempotencyUnsupported(
IdempotencyUnsupportedDetail {
variant_name: "Lane2WorkflowRoot".to_string(),
downstream_stage: "lane2_stage2b_idempotency_lens".to_string(),
reason: "no WorkflowEffect at this substrate root - populate `lane2_workflow` on `Value`/`Bind` via lowering or `try_register_lane2_workflow_effect`"
.to_string(),
},
);
};
project_workflow_idempotency_report(workflow)
}
Loading