Grand Diomande Research · Full HTML Reader

Plan IR v1.1 Specification

1. **Policy Hashing**: Replace inline policy configs with pre-computed hash references 2. **Compile-Time Type Checking**: Enforce binding type compatibility during compilation 3. **ForEachAnchor**: Atlas generation via anchor iteration 4. **SelectAnchor**: Single anchor extraction from sets 5. **Evidence Authority Gating**: Prevent lifecycle promotions from simulated evidence 6. **Slice Provenance Chain**: Propagate source_slice_id through downstream bindings

Agents That Account for Themselves proposal experiment writeup candidate score 26 .md

Full Public Reader

Plan IR v1.1 Specification

Version: 1.1.0
Status: Provisional
Effective Date: 2026-01-01
Supersedes: Plan IR v1.0

---

1. Overview

Plan IR v1.1 extends the base Plan Intermediate Representation with six critical enhancements:

1. Policy Hashing: Replace inline policy configs with pre-computed hash references
2. Compile-Time Type Checking: Enforce binding type compatibility during compilation
3. ForEachAnchor: Atlas generation via anchor iteration
4. SelectAnchor: Single anchor extraction from sets
5. Evidence Authority Gating: Prevent lifecycle promotions from simulated evidence
6. Slice Provenance Chain: Propagate source_slice_id through downstream bindings

These changes transform the Plan IR from a narrative description into a compilable, fingerprintable, replayable, auditable execution contract.

---

2. Motivation

2.1 Float Serialization Instability

Problem: Policy configurations contain floating-point values (e.g., `distance_decay: 0.9`). JSON serialization of floats can produce different representations across platforms, causing non-deterministic plan fingerprints.

Solution: Pre-compute policy hashes at registration time. Plans reference policies by `(policy_id, params_hash)` instead of embedding the full config.

2.2 Type Safety Gap

Problem: v1.0 allowed connecting incompatible step outputs to inputs (e.g., feeding Atoms to a step expecting Slice). Errors only surfaced at runtime.

Solution: Introduce `BindingType` enum and compile-time validation of producer-consumer relationships.

2.3 Atlas Generation

Problem: No native way to iterate over anchors and generate per-anchor artifacts (slices, atoms, realizations).

Solution: Add `ForEachAnchor` step that executes a sub-plan for each anchor, bundling results.

2.4 Evidence Authority

Problem: Simulated evidence could accidentally trigger lifecycle promotions (Proto→Provisional→Canonical), corrupting the vocabulary ledger.

Solution: Add `EvidenceAuthority` gating to block promotions unless evidence is `KernelMeasured`.

2.5 Provenance Gaps

Problem: Downstream bindings (Atoms, Proposals, Observations, Realizations) lost connection to their originating slice, making audit trails incomplete.

Solution: Propagate `source_slice_id` through the entire pipeline.

---

3. Binding Type System

3.1 BindingType Enum

rust
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum BindingType {
    Snapshot,      // Graph state capture
    Anchors,       // List of anchor IDs
    Anchor,        // Single anchor ID
    Slice,         // Context slice
    Atoms,         // Extracted atoms
    Proposals,     // Operator sequence proposals
    Observations,  // Evidence observations
    Realizations,  // Realized N'Ko forms
    Bundle,        // Artifact bundle
    Custom,        // Extensible type
}

3.2 Type Compatibility Matrix

Step KindInput Type RequiredOutput Type Produced
SnapshotSnapshot
SelectAnchorsSnapshotAnchors
SelectAnchorAnchorsAnchor
SliceAnchor (or Anchors*)Slice
AtomizeSliceAtoms
ProposeAtomsProposals
ObserveProposalsObservations
RealizeProposalsRealizations
BundleAnyBundle
SubPlanVariesVaries
ForEachAnchorAnchorsBundle

*Slice step accepts Anchors for backward compatibility (uses first anchor).

3.3 Compile-Time Validation

During `Plan::compile()`:

rust
for step in &self.steps {
    for (ref_name, expected_type) in step.kind.input_type_requirements() {
        if let Some(producer_id) = binding_producers.get(ref_name) {
            if let Some(producer) = self.get_step(producer_id) {
                let actual_type = producer.kind.output_type();
                if actual_type != Some(expected_type) {
                    return Err(CompileError::TypeMismatch {
                        step: step.id.clone(),
                        binding: ref_name.to_string(),
                        expected: expected_type,
                        actual: actual_type,
                    });
                }
            }
        }
    }
}

---

4. Policy Reference System

4.1 PolicyRef Structure

rust
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct PolicyRef {
    /// Policy type identifier (e.g., "slice_policy_v1")
    pub policy_id: String,
    /// xxHash64 of canonical policy JSON
    pub params_hash: String,
}

4.2 Policy Registration

Policies are registered once and referenced by hash:

rust
impl PolicyRef {
    pub fn from_policy<P: Serialize>(policy_id: &str, policy: &P) -> Self {
        Self {
            policy_id: policy_id.to_string(),
            params_hash: canonical_hash_hex(policy),
        }
    }

    pub fn from_slice_policy(policy: &SlicePolicyV1) -> Self {
        Self::from_policy("slice_policy_v1", policy)
    }

    pub fn from_anchor_policy(policy: &AnchorSelectorConfig) -> Self {
        Self::from_policy("anchor_selector_v1", policy)
    }
}

4.3 Step Kind Updates

Steps that use policies include optional `policy_ref`:

rust
StepKind::SelectAnchors {
    snapshot_ref: String,
    policy: AnchorSelectorConfig,
    policy_ref: Option<PolicyRef>,  // v1.1
    output_binding: String,
}

StepKind::Slice {
    anchor_ref: String,
    policy: SlicePolicyV1,
    policy_ref: Option<PolicyRef>,  // v1.1
    output_binding: String,
}

4.4 Determinism Guarantee

When `policy_ref` is present, the plan fingerprint uses the hash instead of serializing the policy, ensuring cross-platform determinism.

---

5. New Step Kinds

5.1 SelectAnchor

Select a single anchor from an anchors set.

rust
StepKind::SelectAnchor {
    /// Reference to anchors binding
    anchors_ref: String,
    /// How to select the anchor
    selector: AnchorSelector,
    /// Name for the anchor binding
    output_binding: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AnchorSelector {
    Index(usize),        // Select by 0-based index
    First,               // Select first anchor
    Last,                // Select last anchor
    Random { seed: u64 }, // Deterministic pseudo-random
    HighestSalience,     // Query store for salience
}

Type Signature: `Anchors → Anchor`

5.2 ForEachAnchor

Execute a sub-plan for each anchor in a set (atlas generation).

rust
StepKind::ForEachAnchor {
    /// Reference to anchors binding
    anchors_ref: String,
    /// Sub-plan to execute for each anchor
    /// Receives "current_anchor" as Anchor type
    body: Box<Plan>,
    /// Name for the bundle output
    output_binding: String,
}

Type Signature: `Anchors → Bundle`

Execution Model:
1. For each `anchor_id` in anchors:
a. Create isolated context with `current_anchor` binding
b. Execute body plan recursively
c. Collect per-anchor outputs
2. Bundle all outputs with iteration index metadata

Namespace Isolation: Each iteration gets a fresh binding namespace. The body plan cannot see parent bindings except those explicitly passed.

---

6. Evidence Authority Gating

6.1 EvidenceAuthority Enum

rust
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum EvidenceAuthority {
    /// Allow all operations regardless of evidence source.
    /// Use for development, testing, or exploratory runs.
    Permissive,

    /// Allow observations but block lifecycle promotions from simulation.
    /// Realize steps that would cause Proto→Provisional or Provisional→Canonical
    /// transitions will fail unless evidence is KernelMeasured.
    PromotionGated,

    /// Block any lifecycle-affecting operations unless evidence is KernelMeasured.
    /// Most restrictive mode for production runs.
    Strict,
}

6.2 ExecutorConfig Integration

rust
pub struct ExecutorConfig {
    pub batch_id: String,
    pub evidence_mode: EvidenceSource,
    pub continue_on_failure: bool,
    pub evidence_authority: EvidenceAuthority,  // v1.1
}

6.3 Authority Checking

rust
impl EvidenceAuthority {
    pub fn allows_promotion(&self, evidence_source: &EvidenceSource) -> bool {
        match self {
            EvidenceAuthority::Permissive => true,
            EvidenceAuthority::PromotionGated | EvidenceAuthority::Strict => {
                matches!(evidence_source, EvidenceSource::KernelMeasured)
            }
        }
    }

    pub fn allows_observation(&self, evidence_source: &EvidenceSource) -> bool {
        match self {
            EvidenceAuthority::Permissive | EvidenceAuthority::PromotionGated => true,
            EvidenceAuthority::Strict => {
                matches!(evidence_source, EvidenceSource::KernelMeasured)
            }
        }
    }
}

6.4 Gating Points

StepCheck Required
Observe`allows_observation()`
Realize (with promotion mode)`allows_promotion()`

---

7. Slice Provenance Chain

7.1 Updated BindingValue Variants

rust
pub enum BindingValue {
    // ... existing variants ...

    /// Atomization result (v1.1: includes provenance).
    Atoms {
        atom_ids: Vec<String>,
        atom_count: usize,
        source_slice_id: String,  // v1.1
    },

    /// Operator proposals (v1.1: includes provenance).
    Proposals {
        proposal_ids: Vec<String>,
        proposal_count: usize,
        source_slice_id: String,  // v1.1
    },

    /// Observation results (v1.1: includes provenance).
    Observations {
        request_ids: Vec<String>,
        observation_count: usize,
        source_slice_id: String,  // v1.1
    },

    /// Realized forms (v1.1: includes provenance).
    Realizations {
        form_ids: Vec<String>,
        realization_count: usize,
        source_slice_id: String,  // v1.1
    },
}

7.2 Provenance Accessor

rust
impl BindingValue {
    pub fn source_slice_id(&self) -> Option<&str> {
        match self {
            BindingValue::Slice { slice_id, .. } => Some(slice_id),
            BindingValue::Atoms { source_slice_id, .. } => Some(source_slice_id),
            BindingValue::Proposals { source_slice_id, .. } => Some(source_slice_id),
            BindingValue::Observations { source_slice_id, .. } => Some(source_slice_id),
            BindingValue::Realizations { source_slice_id, .. } => Some(source_slice_id),
            _ => None,
        }
    }
}

7.3 Propagation Flow

Slice{slice_id: "abc123"}
    ↓ Atomize
Atoms{source_slice_id: "abc123"}
    ↓ Propose
Proposals{source_slice_id: "abc123"}
    ↓ Observe / Realize
Observations{source_slice_id: "abc123"}
Realizations{source_slice_id: "abc123"}

---

8. Compile Errors

8.1 New Error Variants

rust
#[derive(Debug, Error)]
pub enum CompileError {
    // ... existing variants ...

    /// v1.1: Type mismatch between step input and producer output.
    #[error("Step '{step}' expects binding '{binding}' to be {expected}, got {actual:?}")]
    TypeMismatch {
        step: StepId,
        binding: String,
        expected: BindingType,
        actual: Option<BindingType>,
    },

    /// v1.1: Binding collision in SubPlan namespace.
    #[error("Binding collision in SubPlan: '{binding}' exists in both parent and child")]
    BindingCollision { binding: String },
}

---

9. Migration Guide

9.1 From v1.0 to v1.1

1. Add policy_ref to policy-using steps (optional but recommended):

rust
   // Before
   StepKind::Slice { anchor_ref, policy, output_binding }

   // After
   StepKind::Slice {
       anchor_ref,
       policy,
       policy_ref: Some(PolicyRef::from_slice_policy(&policy)),
       output_binding
   }

2. Update BindingValue consumers to handle new `source_slice_id` field:

rust
   // Before
   BindingValue::Atoms { atom_ids, atom_count }

   // After
   BindingValue::Atoms { atom_ids, atom_count, source_slice_id }

3. Add EvidenceAuthority to ExecutorConfig:

rust
   // Before
   ExecutorConfig::with_batch_id("BATCH-001")

   // After (production)
   ExecutorConfig::production("BATCH-001")
   // or
   ExecutorConfig::with_batch_id("BATCH-001")
       .with_evidence_authority(EvidenceAuthority::PromotionGated)

9.2 Breaking Changes

  • `BindingValue::Atoms`, `Proposals`, `Observations`, `Realizations` require `source_slice_id`
  • Plans using type-incompatible bindings will fail at compile time

9.3 Backward Compatibility

  • Plans without `policy_ref` continue to work (hash computed at execution time)
  • `SelectAnchor` and `ForEachAnchor` are additive (new step kinds)
  • Default `EvidenceAuthority` is `PromotionGated` (safe default)

---

10. Examples

10.1 Atlas Generation Plan

rust
let atlas_plan = Plan::new("atlas", "Generate atlas for all anchors")
    .add_step(Step::new("snapshot", "Capture graph", StepKind::Snapshot {
        output_binding: "graph_snapshot".to_string(),
    }))
    .add_step(Step::new("select", "Select anchors", StepKind::SelectAnchors {
        snapshot_ref: "graph_snapshot".to_string(),
        policy: AnchorSelectorConfig::default(),
        policy_ref: Some(PolicyRef::from_anchor_policy(&AnchorSelectorConfig::default())),
        output_binding: "all_anchors".to_string(),
    }))
    .add_step(Step::new("atlas", "Generate per-anchor slices", StepKind::ForEachAnchor {
        anchors_ref: "all_anchors".to_string(),
        body: Box::new(
            Plan::new("per_anchor", "Per-anchor processing")
                .add_step(Step::new("slice", "Slice context", StepKind::Slice {
                    anchor_ref: "current_anchor".to_string(),
                    policy: SlicePolicyV1::default(),
                    policy_ref: Some(PolicyRef::from_slice_policy(&SlicePolicyV1::default())),
                    output_binding: "context_slice".to_string(),
                }))
                .add_step(Step::new("atomize", "Extract atoms", StepKind::Atomize {
                    slice_ref: "context_slice".to_string(),
                    output_binding: "atoms".to_string(),
                }))
        ),
        output_binding: "atlas_bundle".to_string(),
    }))
    .compile()
    .expect("Should compile");

10.2 Production Execution with Authority Gating

rust
let config = ExecutorConfig::production("PROD-2026-001");
// evidence_mode: KernelMeasured
// evidence_authority: PromotionGated

let mut executor = PlanExecutor::new(store, content_provider, config);
let ctx = executor.execute(&plan)?;
// Realize steps with promotion will succeed because evidence is KernelMeasured

10.3 Type-Safe Plan

rust
let plan = Plan::new("typed", "Type-checked plan")
    .add_step(Step::new("s1", "Snapshot", StepKind::Snapshot {
        output_binding: "snap".to_string(),
    }))
    .add_step(Step::new("s2", "Select", StepKind::SelectAnchors {
        snapshot_ref: "snap".to_string(),  // Expects Snapshot ✓
        policy: AnchorSelectorConfig::default(),
        policy_ref: None,
        output_binding: "anchors".to_string(),
    }))
    .add_step(Step::new("s3", "Pick one", StepKind::SelectAnchor {
        anchors_ref: "anchors".to_string(),  // Expects Anchors ✓
        selector: AnchorSelector::First,
        output_binding: "anchor".to_string(),
    }))
    .add_step(Step::new("s4", "Slice", StepKind::Slice {
        anchor_ref: "anchor".to_string(),  // Expects Anchor ✓
        policy: SlicePolicyV1::default(),
        policy_ref: None,
        output_binding: "slice".to_string(),
    }))
    .compile()
    .expect("Type checking passes");

---

11. Invariants

11.1 Type Safety Invariant

INVARIANT: ∀ step ∈ compiled_plan:
    ∀ (ref, expected_type) ∈ step.input_type_requirements():
        producer(ref).output_type() == Some(expected_type)

11.2 Provenance Invariant

INVARIANT: ∀ binding ∈ {Atoms, Proposals, Observations, Realizations}:
    binding.source_slice_id ≠ ""

11.3 Authority Invariant

INVARIANT: evidence_authority ∈ {PromotionGated, Strict} ∧
           evidence_mode == BridgeSimulation ⟹
           realize_with_promotion() fails

11.4 ForEachAnchor Isolation Invariant

INVARIANT: ∀ iteration ∈ ForEachAnchor:
    iteration.bindings ∩ parent.bindings == ∅
    (except explicitly passed inputs)

---

12. Schema Version

rust
pub const PLAN_SCHEMA_VERSION: &str = "1.1.0";

Plans created with v1.1 will have:

json
{
  "schema_version": "1.1.0",
  ...
}

---

13. Validation Checklist

Before executing a v1.1 plan:

  • [ ] `schema_version == "1.1.0"`
  • [ ] All binding references resolve to valid producers
  • [ ] All input types match producer output types
  • [ ] `policy_ref.params_hash` matches registered policy (if present)
  • [ ] `evidence_authority` is appropriate for the use case
  • [ ] ForEachAnchor body plans have no external binding dependencies

---

14. Document History

VersionDateAuthorChanges
1.1.02026-01-01AgentInitial v1.1 specification

---

15. Related Documents

  • [BRIDGE_CHARTER.md](BRIDGE_CHARTER.md) - Authority boundary specification
  • [SLICE_POLICY_V1_SPEC.md](../../cc-graph-kernel/docs/SLICE_POLICY_V1_SPEC.md) - Slice policy specification
  • [PROJECT_CHARTER.md](../../cc-semantic-language/docs/PROJECT_CHARTER.md) - Semantic kernel charter
  • [INVARIANTS.md](../../cc-semantic-language/docs/INVARIANTS.md) - System invariants

Promotion Decision

Attach run IDs, datasets, metrics, and reproduction commands.

Source Anchor

Comp-Core/core/semantic/cc-cognitivetwin-bridge/docs/PLAN_IR_V1_1_SPEC.md

Detected Structure

Evaluation · References · Architecture