Codex CRITICAL + 4 HIGH + 5 MEDIUM/LOW from RULE 0.23 dual-review and
RULE 0.25 multi-critic swarm — all closed.
CRITICAL fix
- Model::slug() ledger compatibility: posterior.rs + select_kernel.rs
query `WHERE model = ?2 OR model = ?3`, binding canonical + legacy
slug pair via new `Model::legacy_slug()`. Production ledger rows
written under "haiku"/"sonnet"/"opus" remain visible to posterior
aggregation. Regression test ledger_legacy_slug_counted.
HIGH fixes
- cmd_select(): no longer early-returns on profile match. Profile's
default_model_ref now becomes DecisionInput.fallback; select() always
runs, posterior/kernel evidence wins if present. RULE 0.20 cost
optimisation restored for all 18 registered agents.
- Registry pricing SSoT: DecisionInput now carries Option<Arc<Registry>>.
estimated_cost() tries registry first; hardcoded match is documented
fallback only. select_posterior.rs no longer duplicates models.toml
constants.
- registry.rs portability: include_str!() embeds the three TOMLs at
compile time. load_embedded() new; disk path tried first via
KEI_REGISTRIES_DIR, embedded as fallback. `cargo install`d binaries
now find registries unconditionally. embedded_registry_matches_disk
test ensures embedded ≡ disk source.
- next_model() ambiguity: replaced Option<&Model> with EscalationResult
enum (Next(&Model) / AtTop / NotFound). Callers can distinguish typo
from ceiling. 5 new tests.
MEDIUM fixes
- posterior.rs u32 overflow: `(n_plus + n_minus) as u32` →
`u32::try_from(n_plus.saturating_add(n_minus)).unwrap_or(u32::MAX)`.
overflow_guard_on_huge_n test with i64::MAX.
- pick() unknown-model: now returns None when default_model_ref's model
is absent from registry. Inverted the deprecation guard.
- HOME unset: disk_registries_dir() returns None on empty HOME and
falls through to embedded registries. open_ledger() logs warning
and returns None instead of opening at malformed path.
- SQLite WAL + busy_timeout: applied to ledger connection in
open_ledger() — concurrent CLI invocations no longer SQLITE_BUSY.
LOW fixes
- impl Model consolidation: next_tier() moved to pricing.rs.
escalate.rs uses current.next_tier() instead of duplicating logic.
- complexity.rs: removed duplicate "ml-implementer" in HEAVY_ROLES.
- dna_class.rs: role("") now returns None instead of Some("").
Verification (orchestrator-side, RULE 0.13 §Verify-before-commit):
- cargo check → clean
- cargo test --release → 63 passed / 0 failed (was 58 → +5 new tests
cover legacy-slug, EscalationResult, overflow, unknown-model, embedded)
- Constructor Pattern → all files ≤ 200 LOC (max registry.rs 196)
- Largest fn from_ledger 28 LOC / limit 30
DNA-INDEX.md regenerated by kei-registry hook (cosmetic).
=== STATUS-TRUTH MARKER ===
shipped: functional
stubs: 0
cargo-check: PASS
behaviour-verified: yes
follow-up-required:
- (none from this commit; next audit pass before merge to main)
138 lines
4.1 KiB
Rust
138 lines
4.1 KiB
Rust
//! Task-class DNA extraction.
|
|
//!
|
|
//! Full DNA format: `<role>::<caps>::<sha8-scope>::<sha8-body>-<nonce8>`.
|
|
//! Examples:
|
|
//! code-implementer-rust::?::e3929e37::041b7526-674c5cf3
|
|
//! edit-local::NG-FW-FD-CP-CG-TG-ND-RF::5435F821::AC73A6A3-b3d36aa6
|
|
//!
|
|
//! Three abstraction levels for posterior aggregation:
|
|
//!
|
|
//! 1. `full_dna` — every spawn unique (random nonce). One observation per row.
|
|
//! 2. `task_class_dna` — strip `-<nonce8>`. Same prompt re-runs cluster.
|
|
//! 3. `agent_class_dna` — strip `::<body8>-<nonce8>`. Same agent at same scope,
|
|
//! different prompts cluster. Highest-level routable identity.
|
|
//!
|
|
//! Constructor Pattern: this cube is purely lexical. No I/O, no SQL.
|
|
|
|
/// Strip trailing `-<nonce8>` from full DNA. Mirrors the SQL VIRTUAL column
|
|
/// in `kei-ledger` schema v9.
|
|
pub fn task_class_dna(full: &str) -> Option<&str> {
|
|
if full.is_empty() {
|
|
return None;
|
|
}
|
|
let bytes = full.as_bytes();
|
|
if bytes.len() < 9 {
|
|
return Some(full);
|
|
}
|
|
if bytes[bytes.len() - 9] == b'-' {
|
|
Some(&full[..bytes.len() - 9])
|
|
} else {
|
|
Some(full)
|
|
}
|
|
}
|
|
|
|
/// Strip `::<body8>-<nonce8>` from full DNA. Yields role+caps+scope identity.
|
|
pub fn agent_class_dna(full: &str) -> Option<&str> {
|
|
let task_class = task_class_dna(full)?;
|
|
let last_sep = task_class.rfind("::")?;
|
|
Some(&task_class[..last_sep])
|
|
}
|
|
|
|
/// First `::` separated component — the substrate role slug.
|
|
/// Returns None for empty input or empty role segment (side fix).
|
|
pub fn role(dna: &str) -> Option<&str> {
|
|
dna.split("::").next().filter(|s| !s.is_empty())
|
|
}
|
|
|
|
/// Second `::` separated component — capability bundle codes.
|
|
pub fn caps(dna: &str) -> Option<&str> {
|
|
dna.split("::").nth(1)
|
|
}
|
|
|
|
/// Third `::` separated component — scope sha-8.
|
|
pub fn scope_sha(dna: &str) -> Option<&str> {
|
|
dna.split("::").nth(2)
|
|
}
|
|
|
|
/// Body sha-8 from a task-class DNA (after agent_class).
|
|
/// Returns None if input is not a task_class_dna (i.e. shorter than 4 fields).
|
|
pub fn body_sha(task_class: &str) -> Option<&str> {
|
|
task_class.split("::").nth(3)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
const SAMPLE: &str = "code-implementer-rust::?::e3929e37::041b7526-674c5cf3";
|
|
|
|
#[test]
|
|
fn strips_nonce_for_task_class() {
|
|
assert_eq!(
|
|
task_class_dna(SAMPLE),
|
|
Some("code-implementer-rust::?::e3929e37::041b7526")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn strips_body_and_nonce_for_agent_class() {
|
|
assert_eq!(
|
|
agent_class_dna(SAMPLE),
|
|
Some("code-implementer-rust::?::e3929e37")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn extracts_role_with_internal_hyphens() {
|
|
assert_eq!(role(SAMPLE), Some("code-implementer-rust"));
|
|
}
|
|
|
|
#[test]
|
|
fn extracts_caps_placeholder() {
|
|
assert_eq!(caps(SAMPLE), Some("?"));
|
|
}
|
|
|
|
#[test]
|
|
fn extracts_scope_sha() {
|
|
assert_eq!(scope_sha(SAMPLE), Some("e3929e37"));
|
|
}
|
|
|
|
#[test]
|
|
fn extracts_body_sha_from_task_class() {
|
|
let tc = task_class_dna(SAMPLE).unwrap();
|
|
assert_eq!(body_sha(tc), Some("041b7526"));
|
|
}
|
|
|
|
#[test]
|
|
fn handles_real_caps_string() {
|
|
let dna = "edit-local::NG-FW-FD-CP-CG-TG-ND-RF::5435F821::AC73A6A3-b3d36aa6";
|
|
assert_eq!(role(dna), Some("edit-local"));
|
|
assert_eq!(caps(dna), Some("NG-FW-FD-CP-CG-TG-ND-RF"));
|
|
assert_eq!(scope_sha(dna), Some("5435F821"));
|
|
assert_eq!(
|
|
agent_class_dna(dna),
|
|
Some("edit-local::NG-FW-FD-CP-CG-TG-ND-RF::5435F821")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn empty_returns_none() {
|
|
assert_eq!(task_class_dna(""), None);
|
|
assert_eq!(agent_class_dna(""), None);
|
|
// Side fix: role("") returns None (not Some("")) — empty role is not useful.
|
|
assert_eq!(role(""), None);
|
|
}
|
|
|
|
#[test]
|
|
fn short_input_passes_through() {
|
|
// Less than 9 chars total: no nonce to strip.
|
|
assert_eq!(task_class_dna("abc"), Some("abc"));
|
|
}
|
|
|
|
#[test]
|
|
fn missing_dash_means_no_nonce_strip() {
|
|
// 9+ chars but no '-' at position len-9.
|
|
let no_nonce = "role::cap::scope12::body";
|
|
assert_eq!(task_class_dna(no_nonce), Some(no_nonce));
|
|
}
|
|
}
|