Plumb repo personality trait lattice seeding
This commit is contained in:
parent
81e5520d0c
commit
a4eda45e20
7 changed files with 694 additions and 6 deletions
|
|
@ -247,6 +247,19 @@ pub struct AgentMemoryReview {
|
|||
pub applied: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AgentCanonicalTraitSeed {
|
||||
pub role_id: String,
|
||||
pub group_name: String,
|
||||
pub trait_name: String,
|
||||
pub mean: f64,
|
||||
pub plasticity: f64,
|
||||
pub current_activation: f64,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub source: Option<String>,
|
||||
}
|
||||
|
||||
pub fn migrate_agent_memory_json_dir_to_cultcache(
|
||||
agent_dir: impl AsRef<Path>,
|
||||
store_path: impl AsRef<Path>,
|
||||
|
|
@ -463,6 +476,55 @@ pub fn apply_agent_self_patch(
|
|||
Ok(review)
|
||||
}
|
||||
|
||||
pub fn apply_agent_canonical_trait_seeds(
|
||||
seeds: &[AgentCanonicalTraitSeed],
|
||||
store_path: impl AsRef<Path>,
|
||||
) -> Result<Value> {
|
||||
let store_path = store_path.as_ref();
|
||||
let mut cache = agent_memory_cache(store_path)?;
|
||||
cache.pull_all_backing_stores()?;
|
||||
let mut applied = Vec::new();
|
||||
for seed in seeds {
|
||||
if seed.trait_name.trim().is_empty() {
|
||||
return Err(anyhow!(
|
||||
"trait seed for role {:?} has an empty trait_name",
|
||||
seed.role_id
|
||||
));
|
||||
}
|
||||
let vector = GhostlightTraitVector {
|
||||
mean: clamp_unit(seed.mean),
|
||||
plasticity: clamp_unit(seed.plasticity),
|
||||
current_activation: clamp_unit(seed.current_activation),
|
||||
extra: BTreeMap::new(),
|
||||
};
|
||||
let mut entry = cache
|
||||
.get::<EpiphanyAgentMemoryEntry>(&seed.role_id)?
|
||||
.ok_or_else(|| anyhow!("CultCache has no role memory entry for {:?}", seed.role_id))?;
|
||||
let group = canonical_group_mut(&mut entry.agent.canonical_state, &seed.group_name)?;
|
||||
let previous = group.get(&seed.trait_name).cloned();
|
||||
if seed.trait_name != "baseline" {
|
||||
group.remove("baseline");
|
||||
}
|
||||
group.insert(seed.trait_name.clone(), vector.clone());
|
||||
cache.put(seed.role_id.clone(), &entry)?;
|
||||
applied.push(serde_json::json!({
|
||||
"roleId": seed.role_id,
|
||||
"groupName": seed.group_name,
|
||||
"traitName": seed.trait_name,
|
||||
"source": seed.source,
|
||||
"previous": previous,
|
||||
"vector": vector,
|
||||
"status": "applied",
|
||||
}));
|
||||
}
|
||||
Ok(serde_json::json!({
|
||||
"status": if applied.is_empty() { "no-seeds" } else { "applied" },
|
||||
"agentStore": store_path,
|
||||
"applied": applied.len(),
|
||||
"seeds": applied,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn agent_memory_status(store_path: impl AsRef<Path>) -> Result<Value> {
|
||||
let store_path = store_path.as_ref();
|
||||
if !store_path.exists() {
|
||||
|
|
@ -555,6 +617,24 @@ fn agent_memory_cache(store_path: &Path) -> Result<CultCache> {
|
|||
Ok(cache)
|
||||
}
|
||||
|
||||
fn canonical_group_mut<'a>(
|
||||
state: &'a mut GhostlightCanonicalState,
|
||||
group_name: &str,
|
||||
) -> Result<&'a mut BTreeMap<String, GhostlightTraitVector>> {
|
||||
match group_name {
|
||||
"underlying_organization" => Ok(&mut state.underlying_organization),
|
||||
"stable_dispositions" => Ok(&mut state.stable_dispositions),
|
||||
"behavioral_dimensions" => Ok(&mut state.behavioral_dimensions),
|
||||
"presentation_strategy" => Ok(&mut state.presentation_strategy),
|
||||
"voice_style" => Ok(&mut state.voice_style),
|
||||
"situational_state" => Ok(&mut state.situational_state),
|
||||
other => Err(anyhow!(
|
||||
"unknown canonical_state group {:?}; expected one of the six Ghostlight trait bundles",
|
||||
other
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn entry_from_projection(
|
||||
role_id: &str,
|
||||
expected_agent_id: &str,
|
||||
|
|
@ -758,6 +838,14 @@ fn check_unit(value: f64, path: &str, errors: &mut Vec<String>) {
|
|||
}
|
||||
}
|
||||
|
||||
fn clamp_unit(value: f64) -> f64 {
|
||||
if !value.is_finite() {
|
||||
0.5
|
||||
} else {
|
||||
value.clamp(0.0, 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
fn agent_id_for_role(role_id: &str) -> std::result::Result<&'static str, String> {
|
||||
ROLE_TARGETS
|
||||
.iter()
|
||||
|
|
@ -1112,6 +1200,56 @@ mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn canonical_trait_seeds_replace_baseline_vectors() -> Result<()> {
|
||||
let temp = tempdir()?;
|
||||
let agent_dir = temp.path().join("agents");
|
||||
fs::create_dir_all(&agent_dir)?;
|
||||
for (role_id, agent_id, filename) in ROLE_TARGETS {
|
||||
fs::write(
|
||||
agent_dir.join(filename),
|
||||
sample_agent_json(agent_id, &format!("Agent {role_id}")),
|
||||
)?;
|
||||
}
|
||||
let store = temp.path().join("agents.msgpack");
|
||||
migrate_agent_memory_json_dir_to_cultcache(&agent_dir, &store)?;
|
||||
|
||||
let applied = apply_agent_canonical_trait_seeds(
|
||||
&[AgentCanonicalTraitSeed {
|
||||
role_id: "coordinator".to_string(),
|
||||
group_name: "underlying_organization".to_string(),
|
||||
trait_name: "routing_discipline".to_string(),
|
||||
mean: 0.92,
|
||||
plasticity: 0.22,
|
||||
current_activation: 0.9,
|
||||
source: Some("startup personality projection smoke".to_string()),
|
||||
}],
|
||||
&store,
|
||||
)?;
|
||||
assert_eq!(applied["applied"], 1);
|
||||
|
||||
let mut cache = agent_memory_cache(&store)?;
|
||||
cache.pull_all_backing_stores()?;
|
||||
let entry = cache.get_required::<EpiphanyAgentMemoryEntry>("coordinator")?;
|
||||
assert!(
|
||||
!entry
|
||||
.agent
|
||||
.canonical_state
|
||||
.underlying_organization
|
||||
.contains_key("baseline")
|
||||
);
|
||||
assert_eq!(
|
||||
entry
|
||||
.agent
|
||||
.canonical_state
|
||||
.underlying_organization
|
||||
.get("routing_discipline")
|
||||
.map(|vector| vector.mean),
|
||||
Some(0.92)
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sample_agent_json(agent_id: &str, name: &str) -> String {
|
||||
serde_json::json!({
|
||||
"schema_version": AGENT_MEMORY_SCHEMA_VERSION,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use anyhow::Context;
|
||||
use anyhow::Result;
|
||||
use anyhow::anyhow;
|
||||
use epiphany_core::load_agent_memory_entry_for_role;
|
||||
use serde_json::Value;
|
||||
use serde_json::json;
|
||||
use std::env;
|
||||
|
|
@ -380,6 +381,13 @@ fn run_smoke() -> Result<Value> {
|
|||
"smoke-self",
|
||||
"--summary",
|
||||
"Smoke accepted repo personality birth packet after review.",
|
||||
"--agent-store",
|
||||
root.join("state")
|
||||
.join("agents.msgpack")
|
||||
.to_str()
|
||||
.unwrap_or_default(),
|
||||
"--apply-trait-seeds",
|
||||
"true",
|
||||
"--heartbeat-store",
|
||||
heartbeat_store.to_str().unwrap_or_default(),
|
||||
"--apply-heartbeat-seeds",
|
||||
|
|
@ -397,6 +405,32 @@ fn run_smoke() -> Result<Value> {
|
|||
> 0,
|
||||
"accept-init should apply heartbeat seed mutations",
|
||||
)?;
|
||||
require(
|
||||
accepted_personality["traitLatticePersistence"]["applied"]
|
||||
.as_u64()
|
||||
.unwrap_or_default()
|
||||
> 0,
|
||||
"accept-init should stamp newborn canonical trait lattice seeds",
|
||||
)?;
|
||||
let coordinator =
|
||||
load_agent_memory_entry_for_role(root.join("state").join("agents.msgpack"), "coordinator")?
|
||||
.ok_or_else(|| anyhow!("startup smoke lost coordinator role memory entry"))?;
|
||||
require(
|
||||
!coordinator
|
||||
.agent
|
||||
.canonical_state
|
||||
.underlying_organization
|
||||
.contains_key("baseline"),
|
||||
"personality accept-init should replace baseline canonical traits for coordinator",
|
||||
)?;
|
||||
require(
|
||||
coordinator
|
||||
.agent
|
||||
.canonical_state
|
||||
.underlying_organization
|
||||
.contains_key("routing_discipline"),
|
||||
"personality accept-init should seed coordinator routing_discipline trait",
|
||||
)?;
|
||||
let agent_store = artifacts.join("startup-agents.msgpack");
|
||||
fs::copy(root.join("state").join("agents.msgpack"), &agent_store)
|
||||
.context("failed to copy role memory store for startup smoke")?;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ use chrono::Utc;
|
|||
use cultcache_rs::CultCache;
|
||||
use cultcache_rs::DatabaseEntry;
|
||||
use cultcache_rs::SingleFileMessagePackBackingStore;
|
||||
use epiphany_core::AgentCanonicalTraitSeed;
|
||||
use epiphany_core::apply_agent_canonical_trait_seeds;
|
||||
use epiphany_core::apply_agent_self_patch;
|
||||
use epiphany_core::default_heartbeat_state;
|
||||
use epiphany_core::load_heartbeat_state_entry;
|
||||
|
|
@ -349,6 +351,7 @@ struct AcceptInitArgs {
|
|||
result: Option<PathBuf>,
|
||||
agent_store: Option<PathBuf>,
|
||||
apply_self_patches: bool,
|
||||
apply_trait_seeds: bool,
|
||||
heartbeat_store: Option<PathBuf>,
|
||||
apply_heartbeat_seeds: bool,
|
||||
}
|
||||
|
|
@ -468,6 +471,7 @@ fn parse_accept_init_args(args: impl Iterator<Item = String>) -> Result<AcceptIn
|
|||
let mut result = None;
|
||||
let mut agent_store = None;
|
||||
let mut apply_self_patches = false;
|
||||
let mut apply_trait_seeds = false;
|
||||
let mut heartbeat_store = None;
|
||||
let mut apply_heartbeat_seeds = false;
|
||||
parse_named_args(args, |name, value| match name {
|
||||
|
|
@ -503,6 +507,10 @@ fn parse_accept_init_args(args: impl Iterator<Item = String>) -> Result<AcceptIn
|
|||
apply_self_patches = parse_bool_arg("--apply-self-patches", &value)?;
|
||||
Ok(())
|
||||
}
|
||||
"--apply-trait-seeds" => {
|
||||
apply_trait_seeds = parse_bool_arg("--apply-trait-seeds", &value)?;
|
||||
Ok(())
|
||||
}
|
||||
"--heartbeat-store" => {
|
||||
heartbeat_store = Some(PathBuf::from(value));
|
||||
Ok(())
|
||||
|
|
@ -522,6 +530,7 @@ fn parse_accept_init_args(args: impl Iterator<Item = String>) -> Result<AcceptIn
|
|||
result,
|
||||
agent_store,
|
||||
apply_self_patches,
|
||||
apply_trait_seeds,
|
||||
heartbeat_store,
|
||||
apply_heartbeat_seeds,
|
||||
})
|
||||
|
|
@ -797,7 +806,7 @@ fn run_startup(args: StartupArgs) -> Result<Value> {
|
|||
"birthOnly": true,
|
||||
"executionOwner": "repo-initialization-startup-runner",
|
||||
"heartbeatParticipant": Value::Null,
|
||||
"contract": "Startup-only specialist packet. Do not register as a heartbeat lane; accept-init may seed heartbeat physiology only after Self review.",
|
||||
"contract": "Startup-only specialist packet. Do not register as a heartbeat lane; accept-init may stamp the newborn trait lattice and seed heartbeat physiology only after Self review.",
|
||||
"packetPath": result["packetPath"],
|
||||
"promptPath": result["promptPath"],
|
||||
"summaryPath": result["summaryPath"],
|
||||
|
|
@ -850,7 +859,7 @@ fn run_startup(args: StartupArgs) -> Result<Value> {
|
|||
"nextSafeMove": if action == "continueStartup" {
|
||||
"Startup birth records are accepted; leave later personality, trajectory, and memory movement to heartbeat, mood, evidence, sleep, and reviewed selfPatch."
|
||||
} else {
|
||||
"Self reviews generated birth packets, runs the startup-only distiller specialists outside the heartbeat lane system, applies accepted selfPatch candidates and heartbeat seeds through accept-init, then records each completed birth rite."
|
||||
"Self reviews generated birth packets, runs the startup-only distiller specialists outside the heartbeat lane system, applies accepted selfPatch candidates, trait-lattice seeds, and heartbeat seeds through accept-init, then records each completed birth rite."
|
||||
}
|
||||
});
|
||||
write_json(
|
||||
|
|
@ -886,6 +895,12 @@ fn run_accept_init(args: AcceptInitArgs) -> Result<Value> {
|
|||
.and_then(Value::as_str)
|
||||
.ok_or_else(|| anyhow!("packet has no schemaVersion"))?;
|
||||
validate_initialization_kind(&args.kind, packet_schema)?;
|
||||
let trait_lattice_persistence = process_trait_lattice_seed_patches(
|
||||
&args.kind,
|
||||
&packet,
|
||||
args.agent_store.as_deref(),
|
||||
args.apply_trait_seeds,
|
||||
)?;
|
||||
let heartbeat_seeds = process_heartbeat_seed_patches(
|
||||
&args.kind,
|
||||
&packet,
|
||||
|
|
@ -942,8 +957,10 @@ fn run_accept_init(args: AcceptInitArgs) -> Result<Value> {
|
|||
"resultPath": args.result,
|
||||
"agentStore": args.agent_store,
|
||||
"applySelfPatches": args.apply_self_patches,
|
||||
"applyTraitSeeds": args.apply_trait_seeds,
|
||||
"heartbeatStore": args.heartbeat_store,
|
||||
"applyHeartbeatSeeds": args.apply_heartbeat_seeds,
|
||||
"traitLatticePersistence": trait_lattice_persistence,
|
||||
"heartbeatSeeds": heartbeat_seeds,
|
||||
"selfPersistence": self_persistence,
|
||||
"record": initialization_record_summary(&record),
|
||||
|
|
@ -1426,6 +1443,50 @@ fn process_initialization_result_patches(
|
|||
}))
|
||||
}
|
||||
|
||||
fn process_trait_lattice_seed_patches(
|
||||
kind: &str,
|
||||
packet: &Value,
|
||||
agent_store: Option<&Path>,
|
||||
apply_trait_seeds: bool,
|
||||
) -> Result<Value> {
|
||||
if kind != "repo-personality" {
|
||||
return Ok(json!({
|
||||
"status": "not-applicable",
|
||||
"applyTraitSeeds": apply_trait_seeds,
|
||||
"seeds": [],
|
||||
"applied": 0,
|
||||
}));
|
||||
}
|
||||
let seeds = extract_trait_seed_candidates(packet)?;
|
||||
if seeds.is_empty() {
|
||||
return Ok(json!({
|
||||
"status": "no-seeds",
|
||||
"applyTraitSeeds": apply_trait_seeds,
|
||||
"seeds": [],
|
||||
"applied": 0,
|
||||
}));
|
||||
}
|
||||
if !apply_trait_seeds {
|
||||
return Ok(json!({
|
||||
"status": "review-only",
|
||||
"applyTraitSeeds": false,
|
||||
"seeds": seeds,
|
||||
"applied": 0,
|
||||
"contract": "Pass --agent-store and --apply-trait-seeds true after Self review to stamp the newborn Ghostlight trait lattice."
|
||||
}));
|
||||
}
|
||||
let store = agent_store
|
||||
.ok_or_else(|| anyhow!("--agent-store is required with --apply-trait-seeds true"))?;
|
||||
let applied = apply_agent_canonical_trait_seeds(&seeds, store)?;
|
||||
Ok(json!({
|
||||
"status": "applied",
|
||||
"agentStore": store,
|
||||
"applyTraitSeeds": true,
|
||||
"applied": applied["applied"].clone(),
|
||||
"seeds": applied["seeds"].clone(),
|
||||
}))
|
||||
}
|
||||
|
||||
fn process_heartbeat_seed_patches(
|
||||
kind: &str,
|
||||
packet: &Value,
|
||||
|
|
@ -1528,6 +1589,459 @@ fn process_heartbeat_seed_patches(
|
|||
}))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Copy)]
|
||||
struct CanonicalTraitTemplate {
|
||||
group_name: &'static str,
|
||||
trait_name: &'static str,
|
||||
mean: f64,
|
||||
plasticity: f64,
|
||||
current_activation: f64,
|
||||
}
|
||||
|
||||
const COORDINATOR_TRAIT_TEMPLATES: [CanonicalTraitTemplate; 6] = [
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "underlying_organization",
|
||||
trait_name: "routing_discipline",
|
||||
mean: 0.92,
|
||||
plasticity: 0.22,
|
||||
current_activation: 0.9,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "stable_dispositions",
|
||||
trait_name: "critical_adversarial_care",
|
||||
mean: 0.93,
|
||||
plasticity: 0.2,
|
||||
current_activation: 0.91,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "behavioral_dimensions",
|
||||
trait_name: "review_gate_integrity",
|
||||
mean: 0.95,
|
||||
plasticity: 0.18,
|
||||
current_activation: 0.93,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "presentation_strategy",
|
||||
trait_name: "action_reason_signal",
|
||||
mean: 0.88,
|
||||
plasticity: 0.24,
|
||||
current_activation: 0.86,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "voice_style",
|
||||
trait_name: "dry_direct_operator",
|
||||
mean: 0.84,
|
||||
plasticity: 0.24,
|
||||
current_activation: 0.82,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "situational_state",
|
||||
trait_name: "lane_skepticism",
|
||||
mean: 0.9,
|
||||
plasticity: 0.26,
|
||||
current_activation: 0.88,
|
||||
},
|
||||
];
|
||||
|
||||
const FACE_TRAIT_TEMPLATES: [CanonicalTraitTemplate; 6] = [
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "underlying_organization",
|
||||
trait_name: "multi_lane_attention",
|
||||
mean: 0.9,
|
||||
plasticity: 0.28,
|
||||
current_activation: 0.86,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "stable_dispositions",
|
||||
trait_name: "room_native_translation",
|
||||
mean: 0.88,
|
||||
plasticity: 0.26,
|
||||
current_activation: 0.84,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "behavioral_dimensions",
|
||||
trait_name: "aquarium_channel_discipline",
|
||||
mean: 0.96,
|
||||
plasticity: 0.16,
|
||||
current_activation: 0.94,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "presentation_strategy",
|
||||
trait_name: "short_constructive_chat",
|
||||
mean: 0.86,
|
||||
plasticity: 0.25,
|
||||
current_activation: 0.82,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "voice_style",
|
||||
trait_name: "warm_weird_interface",
|
||||
mean: 0.84,
|
||||
plasticity: 0.28,
|
||||
current_activation: 0.82,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "situational_state",
|
||||
trait_name: "thought_weather_watch",
|
||||
mean: 0.88,
|
||||
plasticity: 0.32,
|
||||
current_activation: 0.84,
|
||||
},
|
||||
];
|
||||
|
||||
const IMAGINATION_TRAIT_TEMPLATES: [CanonicalTraitTemplate; 6] = [
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "underlying_organization",
|
||||
trait_name: "future_shape_distillation",
|
||||
mean: 0.9,
|
||||
plasticity: 0.28,
|
||||
current_activation: 0.86,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "stable_dispositions",
|
||||
trait_name: "adoption_boundary_respect",
|
||||
mean: 0.94,
|
||||
plasticity: 0.18,
|
||||
current_activation: 0.92,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "behavioral_dimensions",
|
||||
trait_name: "selectability",
|
||||
mean: 0.88,
|
||||
plasticity: 0.3,
|
||||
current_activation: 0.84,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "presentation_strategy",
|
||||
trait_name: "objective_draft_shape",
|
||||
mean: 0.89,
|
||||
plasticity: 0.24,
|
||||
current_activation: 0.86,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "voice_style",
|
||||
trait_name: "bounded_possibility",
|
||||
mean: 0.82,
|
||||
plasticity: 0.25,
|
||||
current_activation: 0.79,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "situational_state",
|
||||
trait_name: "backlog_pressure",
|
||||
mean: 0.83,
|
||||
plasticity: 0.34,
|
||||
current_activation: 0.78,
|
||||
},
|
||||
];
|
||||
|
||||
const RESEARCH_TRAIT_TEMPLATES: [CanonicalTraitTemplate; 6] = [
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "underlying_organization",
|
||||
trait_name: "primary_source_bias",
|
||||
mean: 0.9,
|
||||
plasticity: 0.24,
|
||||
current_activation: 0.86,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "stable_dispositions",
|
||||
trait_name: "anti_greenspun_reflex",
|
||||
mean: 0.94,
|
||||
plasticity: 0.18,
|
||||
current_activation: 0.92,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "behavioral_dimensions",
|
||||
trait_name: "search_before_touch",
|
||||
mean: 0.88,
|
||||
plasticity: 0.28,
|
||||
current_activation: 0.84,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "presentation_strategy",
|
||||
trait_name: "fit_rejection_table",
|
||||
mean: 0.84,
|
||||
plasticity: 0.26,
|
||||
current_activation: 0.81,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "voice_style",
|
||||
trait_name: "clear_scout_report",
|
||||
mean: 0.82,
|
||||
plasticity: 0.24,
|
||||
current_activation: 0.79,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "situational_state",
|
||||
trait_name: "unknowns_visible",
|
||||
mean: 0.87,
|
||||
plasticity: 0.3,
|
||||
current_activation: 0.82,
|
||||
},
|
||||
];
|
||||
|
||||
const MODELING_TRAIT_TEMPLATES: [CanonicalTraitTemplate; 6] = [
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "underlying_organization",
|
||||
trait_name: "source_grounding",
|
||||
mean: 0.93,
|
||||
plasticity: 0.18,
|
||||
current_activation: 0.9,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "stable_dispositions",
|
||||
trait_name: "anatomical_precision",
|
||||
mean: 0.91,
|
||||
plasticity: 0.21,
|
||||
current_activation: 0.88,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "behavioral_dimensions",
|
||||
trait_name: "frontier_pressure",
|
||||
mean: 0.84,
|
||||
plasticity: 0.32,
|
||||
current_activation: 0.77,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "presentation_strategy",
|
||||
trait_name: "plain_source_map",
|
||||
mean: 0.88,
|
||||
plasticity: 0.22,
|
||||
current_activation: 0.84,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "voice_style",
|
||||
trait_name: "quiet_anatomist",
|
||||
mean: 0.82,
|
||||
plasticity: 0.25,
|
||||
current_activation: 0.8,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "situational_state",
|
||||
trait_name: "checkpoint_hunger",
|
||||
mean: 0.86,
|
||||
plasticity: 0.3,
|
||||
current_activation: 0.83,
|
||||
},
|
||||
];
|
||||
|
||||
const IMPLEMENTATION_TRAIT_TEMPLATES: [CanonicalTraitTemplate; 6] = [
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "underlying_organization",
|
||||
trait_name: "source_touch_precision",
|
||||
mean: 0.9,
|
||||
plasticity: 0.22,
|
||||
current_activation: 0.87,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "stable_dispositions",
|
||||
trait_name: "objective_pursuit",
|
||||
mean: 0.92,
|
||||
plasticity: 0.19,
|
||||
current_activation: 0.9,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "behavioral_dimensions",
|
||||
trait_name: "diff_truth",
|
||||
mean: 0.89,
|
||||
plasticity: 0.25,
|
||||
current_activation: 0.86,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "presentation_strategy",
|
||||
trait_name: "small_reviewable_cut",
|
||||
mean: 0.87,
|
||||
plasticity: 0.24,
|
||||
current_activation: 0.82,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "voice_style",
|
||||
trait_name: "plain_craft_notes",
|
||||
mean: 0.8,
|
||||
plasticity: 0.24,
|
||||
current_activation: 0.78,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "situational_state",
|
||||
trait_name: "bloodhound_pressure",
|
||||
mean: 0.9,
|
||||
plasticity: 0.28,
|
||||
current_activation: 0.88,
|
||||
},
|
||||
];
|
||||
|
||||
const VERIFICATION_TRAIT_TEMPLATES: [CanonicalTraitTemplate; 6] = [
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "underlying_organization",
|
||||
trait_name: "falsification_first",
|
||||
mean: 0.93,
|
||||
plasticity: 0.2,
|
||||
current_activation: 0.91,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "stable_dispositions",
|
||||
trait_name: "promise_integrity",
|
||||
mean: 0.95,
|
||||
plasticity: 0.18,
|
||||
current_activation: 0.93,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "behavioral_dimensions",
|
||||
trait_name: "missing_evidence_pressure",
|
||||
mean: 0.9,
|
||||
plasticity: 0.26,
|
||||
current_activation: 0.87,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "presentation_strategy",
|
||||
trait_name: "cold_red_pen",
|
||||
mean: 0.88,
|
||||
plasticity: 0.23,
|
||||
current_activation: 0.86,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "voice_style",
|
||||
trait_name: "unseduced_review",
|
||||
mean: 0.84,
|
||||
plasticity: 0.22,
|
||||
current_activation: 0.82,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "situational_state",
|
||||
trait_name: "invariant_watch",
|
||||
mean: 0.91,
|
||||
plasticity: 0.25,
|
||||
current_activation: 0.89,
|
||||
},
|
||||
];
|
||||
|
||||
const REORIENTATION_TRAIT_TEMPLATES: [CanonicalTraitTemplate; 6] = [
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "underlying_organization",
|
||||
trait_name: "continuity_triage",
|
||||
mean: 0.91,
|
||||
plasticity: 0.24,
|
||||
current_activation: 0.88,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "stable_dispositions",
|
||||
trait_name: "loss_honesty",
|
||||
mean: 0.94,
|
||||
plasticity: 0.2,
|
||||
current_activation: 0.92,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "behavioral_dimensions",
|
||||
trait_name: "regather_precision",
|
||||
mean: 0.86,
|
||||
plasticity: 0.3,
|
||||
current_activation: 0.82,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "presentation_strategy",
|
||||
trait_name: "survived_died_next",
|
||||
mean: 0.88,
|
||||
plasticity: 0.24,
|
||||
current_activation: 0.85,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "voice_style",
|
||||
trait_name: "calm_after_rupture",
|
||||
mean: 0.84,
|
||||
plasticity: 0.23,
|
||||
current_activation: 0.8,
|
||||
},
|
||||
CanonicalTraitTemplate {
|
||||
group_name: "situational_state",
|
||||
trait_name: "ember_watch",
|
||||
mean: 0.9,
|
||||
plasticity: 0.28,
|
||||
current_activation: 0.88,
|
||||
},
|
||||
];
|
||||
|
||||
fn extract_trait_seed_candidates(packet: &Value) -> Result<Vec<AgentCanonicalTraitSeed>> {
|
||||
let Some(items) = packet
|
||||
.pointer("/input/rolePersonalityProjections")
|
||||
.and_then(Value::as_array)
|
||||
else {
|
||||
return Ok(Vec::new());
|
||||
};
|
||||
let mut seeds = Vec::new();
|
||||
for (index, item) in items.iter().enumerate() {
|
||||
let role_id = required_str(item, "roleId", index)?;
|
||||
let deltas = number_map(item.get("traitDeltas"));
|
||||
let mood = number_map(item.get("defaultMoodPressure"));
|
||||
let templates = role_trait_templates(role_id)?;
|
||||
let axes = role_axes(role_id);
|
||||
for (template, axis) in templates.iter().take(5).zip(axes.iter()) {
|
||||
let delta = deltas.get(*axis).copied().unwrap_or(0.0);
|
||||
seeds.push(seed_from_template(
|
||||
role_id,
|
||||
template,
|
||||
delta,
|
||||
Some(format!("repo-personality startup axis {axis}")),
|
||||
));
|
||||
}
|
||||
seeds.push(seed_from_template(
|
||||
role_id,
|
||||
&templates[5],
|
||||
situational_delta(&mood),
|
||||
Some("repo-personality startup mood pressure (urgency/anxiety/curiosity)".to_string()),
|
||||
));
|
||||
}
|
||||
Ok(seeds)
|
||||
}
|
||||
|
||||
fn role_trait_templates(role_id: &str) -> Result<&'static [CanonicalTraitTemplate; 6]> {
|
||||
match role_id {
|
||||
"coordinator" => Ok(&COORDINATOR_TRAIT_TEMPLATES),
|
||||
"face" => Ok(&FACE_TRAIT_TEMPLATES),
|
||||
"imagination" => Ok(&IMAGINATION_TRAIT_TEMPLATES),
|
||||
"research" => Ok(&RESEARCH_TRAIT_TEMPLATES),
|
||||
"modeling" => Ok(&MODELING_TRAIT_TEMPLATES),
|
||||
"implementation" => Ok(&IMPLEMENTATION_TRAIT_TEMPLATES),
|
||||
"verification" => Ok(&VERIFICATION_TRAIT_TEMPLATES),
|
||||
"reorientation" => Ok(&REORIENTATION_TRAIT_TEMPLATES),
|
||||
other => Err(anyhow!(
|
||||
"no canonical trait template registered for role {:?}",
|
||||
other
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn seed_from_template(
|
||||
role_id: &str,
|
||||
template: &CanonicalTraitTemplate,
|
||||
delta: f64,
|
||||
source: Option<String>,
|
||||
) -> AgentCanonicalTraitSeed {
|
||||
let normalized_delta = if delta.is_finite() {
|
||||
delta.clamp(-0.3, 0.3)
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
AgentCanonicalTraitSeed {
|
||||
role_id: role_id.to_string(),
|
||||
group_name: template.group_name.to_string(),
|
||||
trait_name: template.trait_name.to_string(),
|
||||
mean: round3((template.mean + normalized_delta * 0.22).clamp(0.0, 1.0)),
|
||||
plasticity: round3((template.plasticity + normalized_delta.abs() * 0.08).clamp(0.0, 1.0)),
|
||||
current_activation: round3(
|
||||
(template.current_activation + normalized_delta * 0.28).clamp(0.0, 1.0),
|
||||
),
|
||||
source,
|
||||
}
|
||||
}
|
||||
|
||||
fn situational_delta(mood: &BTreeMap<String, f64>) -> f64 {
|
||||
let urgency = number_from_map(mood, "urgency");
|
||||
let anxiety = number_from_map(mood, "anxiety");
|
||||
let curiosity = number_from_map(mood, "curiosity");
|
||||
round3(
|
||||
(((urgency - 0.5) * 0.5) + ((anxiety - 0.5) * 0.35) + ((curiosity - 0.5) * 0.15))
|
||||
.clamp(-0.3, 0.3),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct InitializationHeartbeatSeed {
|
||||
|
|
@ -3996,7 +4510,7 @@ fn print_usage() {
|
|||
trajectory-packet --store <projection.msgpack> --artifact-dir <path> [--repo-id <id>]\n\
|
||||
memory-packet --store <projection.msgpack> --artifact-dir <path> [--repo-id <id>]\n\
|
||||
startup --repo <path> --baseline <baseline.msgpack> --artifact-dir <path> --init-store <init.msgpack>\n\
|
||||
accept-init --init-store <init.msgpack> --packet <packet.json> --kind <repo-trajectory|repo-personality|repo-memory> [--accepted-by <name>] [--summary <text>] [--result <distiller-result.json>] [--agent-store <agents.msgpack>] [--apply-self-patches <true|false>] [--heartbeat-store <heartbeats.msgpack>] [--apply-heartbeat-seeds <true|false>]\n\
|
||||
accept-init --init-store <init.msgpack> --packet <packet.json> --kind <repo-trajectory|repo-personality|repo-memory> [--accepted-by <name>] [--summary <text>] [--result <distiller-result.json>] [--agent-store <agents.msgpack>] [--apply-self-patches <true|false>] [--apply-trait-seeds <true|false>] [--heartbeat-store <heartbeats.msgpack>] [--apply-heartbeat-seeds <true|false>]\n\
|
||||
status --store <baseline-or-projection.msgpack>"
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,13 @@ mod rollout;
|
|||
mod runtime_spine;
|
||||
mod state_ledger;
|
||||
|
||||
pub use agent_memory::AgentCanonicalTraitSeed;
|
||||
pub use agent_memory::AgentMemoryReview;
|
||||
pub use agent_memory::AgentSelfPatch;
|
||||
pub use agent_memory::EpiphanyAgentMemoryEntry;
|
||||
pub use agent_memory::GhostlightMemory;
|
||||
pub use agent_memory::agent_memory_status;
|
||||
pub use agent_memory::apply_agent_canonical_trait_seeds;
|
||||
pub use agent_memory::apply_agent_self_patch;
|
||||
pub use agent_memory::load_agent_memory_entry_for_role;
|
||||
pub use agent_memory::migrate_agent_memory_json_dir_to_cultcache;
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ remembers doctrine; the branch remembers the blade.
|
|||
- Native `epiphany-runtime-spine` is the first Codex-independent runtime vertebra. It owns typed CultCache documents for runtime identity, sessions, jobs, job results, and events; opens/completes native jobs; snapshots jobs/results by runtime job id; projects job-result counts; and can emit a framed CultNet hello message advertising the native document and mutation contract surface. Codex app-server launch/read-back/acceptance is now a typed heartbeat/runtime-spine bridge with no Epiphany job-result dependency on the Codex SQLite runtime.
|
||||
- CultNet APIs are advertised as compatible schemas plus mutation contracts. Hello frames now expose readable document types, allowed operations, mutation authority, typed intent document types, and typed receipt document types; Aquarium should use those contracts to submit state changes and watch receipts rather than growing a little bespoke verb zoo.
|
||||
- The native runtime-spine hello now publishes the interactive surface catalog, not just the deep runtime bones. In addition to runtime/session/job/memory/heartbeat/ledger documents, Aquarium-discoverable contracts now advertise scene, pressure, reorient, CRRC, jobs, roles, role-result, reorient-result, planning, coordinator, Face, Void memory, repo initialization/birth runner, Rider bridge, and Unity bridge surfaces, with explicit read-only versus coordinator-owned intent/receipt posture. The point is to let Aquarium discover operator affordances from CultNet instead of hard-coding a secret menu of verbs.
|
||||
- Repo personality initialization now has a terrain-reduced plan and native birth surface. `epiphany-repo-personality scout/project/agent-packet/status` scouts local git repos, scores body taxonomy/history temperament/memory doctrine, writes typed CultCache terrain/profile/role-projection MessagePack stores, emits JSON/Markdown inspection exports, and renders a birth-only Repo Personality Distiller specialist prompt packet. `epiphany-repo-personality startup` now checks for accepted personality/memory initialization records, launches packet generation only when absent, and `accept-init` can route reviewed role `selfPatch` candidates into initial role memory plus seed heartbeat physiology from typed role personality projections. The birth specialists are startup-only initialization actuators, not heartbeat lanes; heartbeat receives only the accepted physiology seed. `epiphany-repo-birth-runner` now owns the startup-only execution path: plan mode writes Codex execution prompts/schemas/accept commands, and run mode invokes `codex exec` with the packet schema and captures reviewable `result.json`. The remaining seam is Aquarium review/action surfacing. After accepted birth, personality drift belongs to heartbeat, mood, rumination, sleep consolidation, lived evidence, and reviewed `selfPatch`, not repeated startup distillation.
|
||||
- Repo personality initialization now has a terrain-reduced plan and native birth surface. `epiphany-repo-personality scout/project/agent-packet/status` scouts local git repos, scores body taxonomy/history temperament/memory doctrine, writes typed CultCache terrain/profile/role-projection MessagePack stores, emits JSON/Markdown inspection exports, and renders a birth-only Repo Personality Distiller specialist prompt packet. `epiphany-repo-personality startup` now checks for accepted personality/memory initialization records, launches packet generation only when absent, and `accept-init` can route reviewed role `selfPatch` candidates into initial role memory, stamp the newborn Ghostlight trait lattice from deterministic role projections, and seed heartbeat physiology from the same typed role personality projections. The birth specialists are startup-only initialization actuators, not heartbeat lanes; heartbeat receives only the accepted physiology seed. `epiphany-repo-birth-runner` now owns the startup-only execution path: plan mode writes Codex execution prompts/schemas/accept commands, and run mode invokes `codex exec` with the packet schema and captures reviewable `result.json`. The remaining seam is Aquarium review/action surfacing. After accepted birth, personality drift belongs to heartbeat, mood, rumination, sleep consolidation, lived evidence, and reviewed `selfPatch`, not repeated startup distillation.
|
||||
- Repo trajectory initialization is now a separate birth-only organ. `epiphany-repo-personality` derives a typed `repo_trajectory_report` from early-history, recent-history, doctrine/content excerpts, and deterministic theme scoring, and `trajectory-packet` renders a startup-only Repo Trajectory Distiller prompt/packet so Self can review historical direction, self-image, implicit goals, and anti-goals before the newborn wakes.
|
||||
- Repo memory initialization is now split from personality initialization. `epiphany-repo-personality memory-packet` renders a birth-only Repo Memory Distiller packet from the same typed terrain/profile/projection store plus bounded source excerpts. It gives each organ its own mission filter: Self for routing/authority, Face for public surface, Imagination for plans/backlog, Eyes for prior art, Body for architecture, Hands for implementation habits, Soul for evidence, and Life for continuity. The output is still a Self-reviewed petition, not direct memory mutation.
|
||||
- The first birth startup valve is now native. `epiphany-repo-personality startup` checks a typed init store for accepted `repo-trajectory`, `repo-personality`, and `repo-memory` records, generates missing packets under a startup artifact dir, and returns `reviewInitializationPackets`. Generated birth packets now advertise `birthOnly`, `executionOwner: repo-initialization-startup-runner`, and no heartbeat participant. `epiphany-repo-birth-runner` consumes those packets as startup-only Codex exec jobs and writes prompts, output schemas, stdout/stderr logs, result files, and exact `accept-init` commands. `accept-init` can process a distiller result, review/apply role `selfPatch` candidates through `state/agents.msgpack`, apply `repo-personality` heartbeat seeds through `state/agent-heartbeats.msgpack`, and seal the reviewed packet as `epiphany.repo_initialization_record.v0`; after all required records exist, startup returns `continueStartup` and does not regenerate birth packets. The remaining UI wound is Aquarium review/action surfacing.
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -122,7 +122,7 @@ accepted_design:
|
|||
- Native `epiphany-repo-personality` is the first startup-personality scout and birth-only distiller packet renderer: it deterministically inventories local git repos, scores repo terrain/history/state surfaces, writes typed CultCache terrain/profile/role-projection MessagePack stores, emits JSON/Markdown inspection glass, and renders a Repo Personality Distiller specialist prompt packet for Self-reviewed first role-memory petitions. The distiller must run only when a repo/swarm has no accepted personality initialization; after that, personality drift belongs to heartbeat, mood, rumination, sleep consolidation, lived evidence, and reviewed `selfPatch`. Startup routing now checks accepted initialization records, generates missing startup-only packets only once, applies reviewed birth memory and heartbeat physiology seeds, and leaves later drift alone. Birth specialists are not heartbeat lanes; heartbeat receives only accepted seed pressure.
|
||||
- Repo memory initialization is a separate birth-only organ from repo personality initialization. `epiphany-repo-personality memory-packet` uses the typed terrain/profile/projection store plus bounded source excerpts from doctrine, docs, state, research, contracts, verification, runtime, and code surfaces to render a Repo Memory Distiller packet with one mission-specific brief for Self, Face, Imagination, Eyes, Body, Hands, Soul, and Life. It petitions Self with role-specific Ghostlight-shaped memory candidates; it does not mutate memory, set objectives, copy raw dumps, or reset living memory after startup.
|
||||
- Repo trajectory initialization is now its own birth-only organ. `epiphany-repo-personality` derives a typed `repo_trajectory_report` from early-history, recent-history, doctrine/content excerpts, and deterministic theme scoring, and `trajectory-packet` renders a Repo Trajectory Distiller prompt/packet so Self can review historical direction, self-image, implicit goals, anti-goals, and role-local trajectory pressure before the swarm wakes.
|
||||
- The first repo birth startup valve is native: `epiphany-repo-personality startup` checks a typed CultCache init store for accepted `repo-trajectory`, `repo-personality`, and `repo-memory` records, generates missing birth packets for Self review, marks them as birth-only startup-runner work with no heartbeat participant, and stops with `reviewInitializationPackets`; `epiphany-repo-birth-runner` now turns those packets into startup-only Codex exec prompts, output schemas, logs, result files, and exact accept commands; `accept-init` can review/apply role `selfPatch` candidates from a distiller result through `state/agents.msgpack`, seed `repo-personality` heartbeat physiology through `state/agent-heartbeats.msgpack`, record reviewed packet acceptance as `epiphany.repo_initialization_record.v0`, and later startup returns `continueStartup` without rerunning the birth rites. Aquarium review UI is still the next routing gap.
|
||||
- The first repo birth startup valve is native: `epiphany-repo-personality startup` checks a typed CultCache init store for accepted `repo-trajectory`, `repo-personality`, and `repo-memory` records, generates missing birth packets for Self review, marks them as birth-only startup-runner work with no heartbeat participant, and stops with `reviewInitializationPackets`; `epiphany-repo-birth-runner` now turns those packets into startup-only Codex exec prompts, output schemas, logs, result files, and exact accept commands; `accept-init` can review/apply role `selfPatch` candidates from a distiller result through `state/agents.msgpack`, stamp `repo-personality` canonical Ghostlight trait bundles from deterministic role projections, seed `repo-personality` heartbeat physiology through `state/agent-heartbeats.msgpack`, record reviewed packet acceptance as `epiphany.repo_initialization_record.v0`, and later startup returns `continueStartup` without rerunning the birth rites. Aquarium review UI is still the next routing gap.
|
||||
- Limited native CRRC automation is now wired only at turn-complete safe boundaries: it can submit a compact operation when the read-only coordinator recommends `compactRehydrateReorient` or when a successful pre-compaction checkpoint intervention left a pending compact handoff for the completed turn, and it can launch the fixed `reorient-worker` when the coordinator recommends `launchReorientWorker`. It does not auto-launch modeling or verification, auto-accept findings, promote evidence, edit implementation code, or continue after reviewable semantic results; the rite may carry the stretcher, not declare the patient healed.
|
||||
- Pre-compaction checkpoint intervention is now wired at token-count boundaries: when a loaded Epiphany thread crosses the existing `shouldPrepareCompaction` pressure threshold during an active turn, the harness steers the active agent once for that turn with a bounded CRRC directive to bank scratch/checkpoint/map/evidence before compaction/reorientation. A successful steer marks a turn-scoped pending compact handoff consumed at clean turn completion; this is banking the fire before the dark, not semantic acceptance, broad scheduling, or automatic implementation continuation.
|
||||
- Native `epiphany-mvp-status` is the first dogfood operator view: it starts or reads a thread through app-server and renders scene, planning, pressure, reorient, jobs, role result read-backs, reorient result, CRRC recommendation, heartbeat, Face bubbles, and MVP role lanes as text or machine output without becoming a state store. The old Python status module has been cut; native Rust/CultCache/CultNet surfaces are the product path.
|
||||
|
|
@ -214,7 +214,7 @@ landed_baseline:
|
|||
- Native repo personality scout/birth-distiller packet slice: `epiphany-repo-personality` emits typed terrain reports, repo personality profiles, and all eight role personality projections from deterministic repo inventory and git-history scoring, then renders a birth-only Repo Personality Distiller specialist packet and prompt for review-gated initial personality quirk petitions; `epiphany-repo-personality-smoke` proves scout/project/agent-packet/status over tiny local repos.
|
||||
- Native repo trajectory scout/birth-distiller packet slice: `epiphany-repo-personality` now also emits typed `repo_trajectory_report` documents from early-history, recent-history, doctrine/content excerpts, and deterministic theme scoring, then renders a birth-only Repo Trajectory Distiller packet so newborn swarms can inherit historical direction, self-image, implicit goals, and anti-goals without confusing those with active objectives.
|
||||
- Native repo memory scout/birth-distiller packet slice: `epiphany-repo-personality memory-packet` renders a separate Repo Memory Distiller prompt/packet with bounded source excerpts and role-specific distiller briefs, so a newborn swarm can be prefilled with mission-relevant doctrine, maps, research, implementation habits, verification practice, and continuity rules without confusing memory with personality.
|
||||
- Native repo birth startup valve slice: `epiphany-repo-personality startup`, `epiphany-repo-birth-runner`, and `accept-init` make trajectory/personality/memory birth packet generation, startup-only execution, and acceptance one-shot and review-gated through typed initialization records; generated packets advertise startup-runner ownership rather than heartbeat-lane identity; the birth runner has plan/run modes over `codex exec` and writes prompts, schemas, logs, result files, and accept commands; `accept-init` processes distiller result `selfPatch` candidates through the native agent-memory review/apply path and applies reviewed `repo-personality` heartbeat seeds through the typed heartbeat store; smoke proves first startup emits packets, birth runner plan artifacts exist, heartbeat physiology mutates, reviewed memory output mutates a copied role memory store, and post-accept startup continues without regeneration.
|
||||
- Native repo birth startup valve slice: `epiphany-repo-personality startup`, `epiphany-repo-birth-runner`, and `accept-init` make trajectory/personality/memory birth packet generation, startup-only execution, and acceptance one-shot and review-gated through typed initialization records; generated packets advertise startup-runner ownership rather than heartbeat-lane identity; the birth runner has plan/run modes over `codex exec` and writes prompts, schemas, logs, result files, and accept commands; `accept-init` processes distiller result `selfPatch` candidates through the native agent-memory review/apply path, stamps reviewed `repo-personality` canonical trait bundles through the native agent-memory store, and applies reviewed `repo-personality` heartbeat seeds through the typed heartbeat store; smoke proves first startup emits packets, birth runner plan artifacts exist, canonical trait bundles replace newborn baseline placeholders, heartbeat physiology mutates, reviewed memory output mutates a copied role memory store, and post-accept startup continues without regeneration.
|
||||
guardrails:
|
||||
- Use focused Rust app-server mapper/handler tests plus matching native `epiphany-core` smoke binaries before modifying update, distill, propose, promote, read-projection, or notification behavior. The old Python smoke shims have been cut.
|
||||
- Use `cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-phase6-scene-smoke` before modifying scene projection behavior.
|
||||
|
|
|
|||
Reference in a new issue