Strip objective intake ceremony

This commit is contained in:
Meta Vens 2026-08-24 09:07:42 +02:00
commit 952dcd9f65
4 changed files with 30 additions and 84 deletions

View file

@ -373,7 +373,7 @@ fn run_coordinator(args: &Args) -> Result<Value> {
"threadId": thread_id,
"grantId": claim.grant_id,
"preparationId": preparation_id,
"mindProjectionDigest": intake.mind.projection_digest,
"mindProjectionDigest": intake.mind_projection_digest,
"commitReceiptId": intake.commit_receipt.receipt_id,
"canonicalObjectiveChanged": intake.changed,
}));
@ -387,7 +387,7 @@ fn run_coordinator(args: &Args) -> Result<Value> {
startup_events.push(json!({
"type": "operatorObjectiveIntake",
"threadId": thread_id,
"mindProjectionDigest": intake.mind.projection_digest,
"mindProjectionDigest": intake.mind_projection_digest,
"commitReceiptId": intake.commit_receipt.receipt_id,
"changed": intake.changed,
}));
@ -2183,52 +2183,6 @@ mod tests {
Ok(())
}
#[test]
fn operator_objective_intake_creates_once_and_refuses_replacement() -> Result<()> {
let temp = tempfile::tempdir()?;
let store = temp.path().join("runtime.cc");
epiphany_core::initialize_runtime_spine(
&store,
epiphany_core::RuntimeSpineInitOptions {
runtime_id: "objective-intake-bin".into(),
display_name: "Objective intake bin".into(),
created_at: "2026-08-14T00:00:00Z".into(),
},
)?;
let first = intake_operator_objective(
&store,
"thread-1",
"Map the machine",
"cli://epiphany-mvp-coordinator",
)?;
assert!(first.changed);
assert_eq!(first.mind.objective.as_deref(), Some("Map the machine"));
let repeated = intake_operator_objective(
&store,
"thread-1",
" Map the machine ",
"cli://epiphany-mvp-coordinator",
)?;
assert!(!repeated.changed);
assert_eq!(
repeated.mind.projection_digest,
first.mind.projection_digest
);
assert_eq!(repeated.commit_receipt, first.commit_receipt);
let error = intake_operator_objective(
&store,
"thread-1",
"Replace the machine",
"cli://epiphany-mvp-coordinator",
)
.expect_err("objective replacement must require a typed adoption flow");
assert!(error.to_string().contains("refusing to replace"));
Ok(())
}
#[test]
fn resident_operator_objective_uses_the_authenticated_grant_as_provenance() -> Result<()> {
let temp = tempfile::tempdir()?;
@ -2249,9 +2203,15 @@ mod tests {
"resident-self-grant://grant-1",
)?;
assert!(applied.changed);
assert_eq!(applied.intake.source_ref, "resident-self-grant://grant-1");
let mut cache = epiphany_core::runtime_spine_cache(&store)?;
cache.pull_all_backing_stores()?;
let intakes = cache.get_all::<epiphany_core::UserObjectiveIntake>()?;
assert_eq!(intakes.len(), 1);
assert_eq!(intakes[0].source_ref, "resident-self-grant://grant-1");
assert_eq!(
applied.mind.objective.as_deref(),
epiphany_core::assemble_mind_view(&store)?
.objective
.as_deref(),
Some("Keep the objective in Mind")
);
assert!(

View file

@ -1,16 +1,13 @@
use crate::{
EpiphanyMindCommitAuthority, EpiphanyMindCommitOutcome, EpiphanyMindCommitReceipt,
EpiphanyMindDocumentVersion, EpiphanyMindObjectiveDocument, EpiphanyMindView,
MIND_OBJECTIVE_KEY, assemble_mind_view, commit_operator_mind_mutation, runtime_spine_cache,
EpiphanyMindDocumentVersion, EpiphanyMindObjectiveDocument, MIND_OBJECTIVE_KEY,
assemble_mind_view, commit_operator_mind_mutation, runtime_spine_cache,
};
use anyhow::{Result, anyhow};
use cultcache_rs::DatabaseEntry;
use sha2::{Digest, Sha256};
use std::path::Path;
pub const USER_OBJECTIVE_INTAKE_SCHEMA_VERSION: &str = "gamecult.epiphany.user_objective_intake.v0";
pub const USER_OBJECTIVE_INTAKE_CONTRACT: &str = "The human supplies the initial objective. Self records that assertion and the canonical keyed Mind objective in one CAS. Thread identity is provenance only. Repeated identical intake is read-idempotent; replacement requires a separate reviewed adoption flow.";
#[derive(Debug, Clone)]
pub struct UserObjectiveIntakeInput {
pub thread_id: String,
@ -27,29 +24,20 @@ pub struct UserObjectiveIntakeInput {
)]
pub struct UserObjectiveIntake {
#[cultcache(key = 0)]
pub schema_version: String,
#[cultcache(key = 1)]
pub intake_id: String,
#[cultcache(key = 2)]
pub thread_id: String,
#[cultcache(key = 3)]
#[cultcache(key = 1)]
pub objective: String,
#[cultcache(key = 4)]
pub objective_sha256: String,
#[cultcache(key = 5)]
#[cultcache(key = 2)]
pub source_actor: String,
#[cultcache(key = 6)]
#[cultcache(key = 3)]
pub source_ref: String,
#[cultcache(key = 7)]
#[cultcache(key = 4)]
pub submitted_at: String,
#[cultcache(key = 8)]
pub contract: String,
}
#[derive(Debug, Clone)]
pub struct UserObjectiveIntakeApplied {
pub intake: UserObjectiveIntake,
pub mind: EpiphanyMindView,
pub mind_projection_digest: String,
pub commit_receipt: EpiphanyMindCommitReceipt,
pub changed: bool,
}
@ -70,7 +58,6 @@ pub fn intake_user_objective(
{
return Err(anyhow!("invalid typed user-objective intake"));
}
let objective_sha256 = format!("{:x}", Sha256::digest(objective.as_bytes()));
let intake_id = format!("user-objective-{:x}", Sha256::digest(thread_id.as_bytes()));
let mut cache = runtime_spine_cache(store)?;
@ -81,7 +68,6 @@ pub fn intake_user_objective(
.ok_or_else(|| anyhow!("typed user-objective intake lost its Mind objective"))?;
if existing.thread_id != thread_id
|| existing.objective != objective
|| existing.objective_sha256 != objective_sha256
|| existing.source_actor != source_actor
|| existing.source_ref != source_ref
|| objective_document.objective.trim() != objective
@ -112,8 +98,7 @@ pub fn intake_user_objective(
})
.ok_or_else(|| anyhow!("typed user-objective intake lost its Mind commit receipt"))?;
return Ok(UserObjectiveIntakeApplied {
intake: existing,
mind: assemble_mind_view(store)?,
mind_projection_digest: assemble_mind_view(store)?.projection_digest,
commit_receipt: receipt,
changed: false,
});
@ -127,15 +112,11 @@ pub fn intake_user_objective(
));
}
let intake = UserObjectiveIntake {
schema_version: USER_OBJECTIVE_INTAKE_SCHEMA_VERSION.into(),
intake_id: intake_id.clone(),
thread_id: thread_id.to_string(),
objective: objective.to_string(),
objective_sha256,
source_actor: source_actor.to_string(),
source_ref: source_ref.to_string(),
submitted_at: input.submitted_at,
contract: USER_OBJECTIVE_INTAKE_CONTRACT.into(),
};
let provenance = cache.prepare_entry(&intake_id, &intake)?.0;
let objective_write = crate::mind_documents::prepare_mind_document(
@ -159,8 +140,7 @@ pub fn intake_user_objective(
}
};
Ok(UserObjectiveIntakeApplied {
intake,
mind: assemble_mind_view(store)?,
mind_projection_digest: assemble_mind_view(store)?.projection_digest,
commit_receipt,
changed: true,
})
@ -195,7 +175,10 @@ mod tests {
)?;
let first = intake_user_objective(&store, input("Map the machine"))?;
assert!(first.changed);
assert_eq!(first.mind.objective.as_deref(), Some("Map the machine"));
assert_eq!(
assemble_mind_view(&store)?.objective.as_deref(),
Some("Map the machine")
);
assert_eq!(
first.commit_receipt.invariant_owner,
"Self.user_objective_intake"
@ -208,11 +191,16 @@ mod tests {
.iter()
.all(|envelope| envelope.r#type != "epiphany.thread_state")
);
let after_first = std::fs::read(&store)?;
let repeated = intake_user_objective(&store, input(" Map the machine "))?;
assert!(!repeated.changed);
assert_eq!(repeated.intake, first.intake);
assert_eq!(
repeated.mind_projection_digest,
first.mind_projection_digest
);
assert_eq!(repeated.commit_receipt, first.commit_receipt);
assert_eq!(std::fs::read(&store)?, after_first);
let before = std::fs::read(&store)?;
let error = intake_user_objective(&store, input("Replace the machine"))

View file

@ -74,8 +74,6 @@ pub use agent_launch::epiphany_role_label;
pub use agent_launch::epiphany_role_launch_output_schema;
pub use atlas::*;
pub use causal_work_identity::*;
pub use coordinator_objective_intake::USER_OBJECTIVE_INTAKE_CONTRACT;
pub use coordinator_objective_intake::USER_OBJECTIVE_INTAKE_SCHEMA_VERSION;
pub use coordinator_objective_intake::UserObjectiveIntake;
pub use coordinator_objective_intake::UserObjectiveIntakeApplied;
pub use coordinator_objective_intake::UserObjectiveIntakeInput;

View file

@ -69,7 +69,7 @@ pub const COORDINATOR_RUN_RECEIPT_TYPE: &str = "epiphany.coordinator_run_receipt
pub const RUNTIME_IDENTITY_KEY: &str = "self";
pub const RUNTIME_SWARM_BINDING_KEY: &str = "runtime-swarm-binding";
pub const RUNTIME_SWARM_BINDING_SCHEMA_VERSION: &str = "epiphany.runtime.swarm_binding.v1";
pub const RUNTIME_SPINE_SCHEMA_VERSION: &str = "epiphany.runtime_spine.v31";
pub const RUNTIME_SPINE_SCHEMA_VERSION: &str = "epiphany.runtime_spine.v32";
pub const EPIPHANY_RUNTIME_ROOT_SESSION_ID: &str = "epiphany-main";
pub const RUNTIME_MODEL_EXECUTION_BINDING_SCHEMA_VERSION: &str =
"epiphany.runtime.model_execution_binding.v0";