phase29ai(p3): typed Freeze + candidate-set planner boundary

This commit is contained in:
2025-12-29 07:26:08 +09:00
parent f7a61532ae
commit 3fb5c1a544
4 changed files with 140 additions and 6 deletions

View File

@ -7,6 +7,7 @@ use crate::ast::ASTNode;
use crate::mir::builder::control_flow::plan::facts::try_build_loop_facts;
use crate::mir::builder::control_flow::plan::normalize::{canonicalize_loop_facts, CanonicalLoopFacts};
use super::candidates::CandidateSet;
use super::{Freeze, Plan};
/// Phase 29ai P0: External-ish SSOT entrypoint (skeleton)
@ -20,12 +21,25 @@ pub(in crate::mir::builder) fn build_plan(
return Ok(None);
};
let canonical = canonicalize_loop_facts(facts);
let plan = build_plan_from_facts(canonical)?;
Ok(Some(plan))
build_plan_from_facts(canonical)
}
pub(in crate::mir::builder) fn build_plan_from_facts(
_facts: CanonicalLoopFacts,
) -> Result<Plan, Freeze> {
Err("freeze[phase29ai/p0]: build_plan_from_facts not implemented".to_string())
) -> Result<Option<Plan>, Freeze> {
// Phase 29ai P3: CandidateSet-based boundary (SSOT)
//
// P3 note: Facts are currently `Ok(None)` (P0 skeleton), so this function is
// unreachable in normal execution today. We still implement the SSOT
// boundary here so that future Facts work cannot drift.
let candidates = CandidateSet::new();
// No candidates in P3 (unreachable today); boundary remains stable.
match candidates.finalize()? {
Some(plan) => Ok(Some(plan)),
None => Err(Freeze::unsupported(
"facts were provided but no planner rule produced a candidate (P3 placeholder)",
)),
}
}

View File

@ -0,0 +1,52 @@
//! Phase 29ai P3: CandidateSet — SSOT implementation
//!
//! SSOT: "0 candidates = Ok(None), 1 = Ok(Some), 2+ = Freeze(ambiguous)"
#![allow(dead_code)]
use super::{Freeze, Plan, PlanKind};
#[derive(Debug, Clone)]
pub(in crate::mir::builder) struct PlanCandidate {
pub kind: PlanKind,
pub rule: &'static str,
}
#[derive(Debug, Default)]
pub(in crate::mir::builder) struct CandidateSet {
candidates: Vec<PlanCandidate>,
}
impl CandidateSet {
pub(in crate::mir::builder) fn new() -> Self {
Self {
candidates: Vec::new(),
}
}
pub(in crate::mir::builder) fn push(&mut self, candidate: PlanCandidate) {
self.candidates.push(candidate);
}
pub(in crate::mir::builder) fn finalize(self) -> Result<Option<Plan>, Freeze> {
match self.candidates.len() {
0 => Ok(None),
1 => {
let c = self.candidates.into_iter().next().expect("len == 1");
Ok(Some(Plan { kind: c.kind }))
}
n => {
let rules = self
.candidates
.iter()
.map(|c| c.rule)
.collect::<Vec<_>>()
.join(", ");
Err(Freeze::ambiguous(format!(
"multiple plan candidates (count={}): {}",
n, rules
)))
}
}
}
}

View File

@ -0,0 +1,66 @@
//! Phase 29ai P3: Typed Freeze (Fail-Fast) — SSOT implementation
//!
//! Tag taxonomy SSOT:
//! - docs/development/current/main/design/planfrag-freeze-taxonomy.md
#![allow(dead_code)]
use std::fmt;
#[derive(Debug, Clone)]
pub(in crate::mir::builder) struct Freeze {
pub tag: &'static str,
pub message: String,
pub hint: Option<String>,
}
impl Freeze {
pub(in crate::mir::builder) fn contract(message: impl Into<String>) -> Self {
Self {
tag: "contract",
message: message.into(),
hint: None,
}
}
pub(in crate::mir::builder) fn ambiguous(message: impl Into<String>) -> Self {
Self {
tag: "ambiguous",
message: message.into(),
hint: None,
}
}
pub(in crate::mir::builder) fn unsupported(message: impl Into<String>) -> Self {
Self {
tag: "unsupported",
message: message.into(),
hint: None,
}
}
pub(in crate::mir::builder) fn bug(message: impl Into<String>) -> Self {
Self {
tag: "bug",
message: message.into(),
hint: None,
}
}
pub(in crate::mir::builder) fn with_hint(mut self, hint: impl Into<String>) -> Self {
self.hint = Some(hint.into());
self
}
}
impl fmt::Display for Freeze {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[plan/freeze:{}] {}", self.tag, self.message)?;
if let Some(hint) = &self.hint {
write!(f, "\n hint: {}", hint)?;
}
Ok(())
}
}
impl std::error::Error for Freeze {}

View File

@ -6,8 +6,10 @@
#![allow(dead_code, unused_imports)]
pub(in crate::mir::builder) mod build;
pub(in crate::mir::builder) mod candidates;
pub(in crate::mir::builder) mod freeze;
pub(in crate::mir::builder) type Freeze = String;
pub(in crate::mir::builder) use freeze::Freeze;
#[derive(Debug, Clone)]
pub(in crate::mir::builder) struct Plan {
@ -19,4 +21,4 @@ pub(in crate::mir::builder) enum PlanKind {
Placeholder,
}
pub(in crate::mir::builder) use build::{build_plan, build_plan_from_facts};
pub(in crate::mir::builder) use build::build_plan;