use anda_core::Message;
use anda_engine::{rfc3339_datetime, rfc3339_datetime_now};
use anda_kip::{
Command, ElementReference, ErrorObject, Executor, IngestContext, IngestEvidence, Json,
KipError, KipValue, Map, MutationClause, Request, Response, Scalar, TopLevelStatus,
execute_request, transition_state,
};
pub fn request(command: impl Into<String>) -> Request {
Request::single(command)
}
pub fn string_literal(value: &str) -> String {
format!("\"{}\"", value.replace('\\', "\\\\").replace('"', "\\\""))
}
pub fn timestamp(now_ms: u64) -> String {
rfc3339_datetime(now_ms).unwrap_or_else(rfc3339_datetime_now)
}
pub(crate) fn observation_timestamp(value: Option<&str>, received_at: u64) -> String {
value
.and_then(|value| chrono::DateTime::parse_from_rfc3339(value.trim()).ok())
.map(|value| {
value
.to_utc()
.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)
})
.filter(|value| anda_kip::timestamp::parse(value, "timestamp").is_ok())
.unwrap_or_else(|| timestamp(received_at))
}
pub fn request_with(command: impl Into<String>, parameters: Map<String, Json>) -> Request {
Request {
parameters: Some(parameters),
..Request::single(command)
}
}
pub fn param(name: &str, value: impl Into<Json>) -> Map<String, Json> {
Map::from_iter([(name.to_string(), value.into())])
}
pub fn succeeded(response: &Response) -> bool {
response.status == TopLevelStatus::Succeeded
}
pub fn error_of(response: &Response) -> Option<&ErrorObject> {
response
.error
.as_ref()
.or_else(|| response.results.first().and_then(|r| r.error.as_ref()))
}
pub fn ok_result(response: &Response) -> Option<&Json> {
if !succeeded(response) {
return None;
}
response.results.first().and_then(|r| r.result.as_ref())
}
pub fn error_message(response: &Response) -> String {
match error_of(response) {
Some(error) => format!("{}: {}", error.code, error.message),
None => format!("{:?}", response.status),
}
}
pub fn changed(response: &Response, op: &str) -> u64 {
count_changes(response, |change| {
change.get("op").and_then(Json::as_str) == Some(op)
})
}
#[cfg_attr(not(feature = "wiki"), allow(dead_code))]
pub fn transitioned(response: &Response, to: &str) -> u64 {
count_changes(response, |change| {
change.get("op").and_then(Json::as_str) == Some("lifecycle")
&& change
.get("state")
.and_then(|state| state.get("to"))
.and_then(Json::as_str)
== Some(to)
})
}
fn count_changes(response: &Response, matches: impl Fn(&Json) -> bool) -> u64 {
let Some(result) = ok_result(response) else {
return 0;
};
result
.get("changes")
.and_then(Json::as_array)
.map(|changes| changes.iter().filter(|change| matches(change)).count() as u64)
.unwrap_or(0)
}
pub async fn execute_readonly_request(executor: &impl Executor, request: &Request) -> Response {
match request.parse_operations() {
Ok(commands) => {
if commands.iter().any(|command| command.is_mutation()) {
return Response::from(KipError::readonly_violation(
"this endpoint executes KQL and META only; KML mutations must go through the \
state-capable path",
))
.with_request_id(request.request_id.clone());
}
}
Err(err) => return Response::from(err).with_request_id(request.request_id.clone()),
}
execute_request(executor, request).await
}
pub const MAX_GATED_SELECTION: u64 = 20;
pub const MAX_INGESTED_MESSAGES: usize = 16;
fn evidence_class(role: &str) -> &'static str {
match role {
"user" => "user_statement",
"assistant" => "agent_statement",
"tool" => "tool_result",
_ => "message",
}
}
pub fn observation_ingest(
messages: &[Message],
observed_at: &str,
origin: &str,
source_actor: Option<&str>,
) -> Option<IngestContext> {
let start = messages.len().saturating_sub(MAX_INGESTED_MESSAGES);
let recent = &messages[start..];
if recent.is_empty() {
return None;
}
let evidence = recent
.iter()
.enumerate()
.map(|(index, message)| IngestEvidence {
key: format!("msg{}", index + 1),
evidence_class: evidence_class(&message.role).to_string(),
payload: serde_json::to_value(message).ok(),
observed_at: Some(observed_at.to_string()),
client_key: Some(format!("{origin}:{}", start + index + 1)),
source_actor: source_actor
.filter(|_| message.role == "user")
.map(ElementReference::by_id),
..Default::default()
})
.collect();
Some(IngestContext {
evidence,
extensions: None,
})
}
pub fn attach_observation(
request: &mut Request,
observation: &IngestContext,
) -> Result<(), String> {
if request.ingest.is_some() {
return Err("formation ingest is supplied by the host".into());
}
let claimed = |parameters: Option<&Map<String, Json>>| {
parameters.is_some_and(|parameters| {
observation
.evidence
.iter()
.any(|entry| parameters.contains_key(&entry.key))
})
};
if claimed(request.parameters.as_ref())
|| request
.operations
.iter()
.any(|operation| claimed(operation.parameters.as_ref()))
{
return Err("captured observation bindings cannot be replaced".into());
}
if request
.operations
.iter()
.any(|operation| operation.parse().is_ok_and(|command| command.is_mutation()))
{
request.ingest = Some(observation.clone());
}
Ok(())
}
pub async fn execute_cognition_request(executor: &impl Executor, request: &Request) -> Response {
let commands = match request.parse_operations() {
Ok(commands) => commands,
Err(err) => return Response::from(err).with_request_id(request.request_id.clone()),
};
for (index, command) in commands.iter().enumerate() {
let parameters = operation_parameters(request, index);
if let Some(refusal) = unsupported_cognitive_write(command, parameters.as_ref()) {
return Response::from(KipError::unsupported_capability(refusal))
.with_request_id(request.request_id.clone());
}
if let Some(refusal) = cognition_refusal(command, parameters.as_ref()) {
return Response::from(KipError::not_authorized(refusal))
.with_request_id(request.request_id.clone());
}
}
execute_request(executor, request).await
}
fn operation_parameters(request: &Request, index: usize) -> Option<Map<String, Json>> {
let request_parameters = request.parameters.as_ref();
let operation_parameters = request
.operations
.get(index)
.and_then(|operation| operation.parameters.as_ref());
match (request_parameters, operation_parameters) {
(None, None) => None,
(outer, inner) => {
let mut merged = outer.cloned().unwrap_or_default();
merged.extend(inner.cloned().unwrap_or_default());
Some(merged)
}
}
}
fn unsupported_cognitive_write(
command: &Command,
parameters: Option<&Map<String, Json>>,
) -> Option<String> {
use anda_kip::{SymbolRef, UpdateAction};
let Command::Kml(statement) = command else {
return None;
};
let mut facets = Vec::new();
for clause in &statement.clauses {
match clause {
MutationClause::CreateConcept(c) => {
facets.extend(c.set_facets.iter().map(|f| &f.facet))
}
MutationClause::UpsertConcept(c) => {
facets.extend(c.set_facets.iter().map(|f| &f.facet));
facets.extend(c.unset_facets.iter().map(|f| &f.facet));
}
MutationClause::CreateEvidence(c)
| MutationClause::CreateAssertion(c)
| MutationClause::CreateActivity(c) => {
facets.extend(c.set_facets.iter().map(|f| &f.facet))
}
MutationClause::Update(c) => {
for action in &c.actions {
match action {
UpdateAction::SetFacet(f) => facets.push(&f.facet),
UpdateAction::UnsetFacet(f) => facets.push(&f.facet),
_ => {}
}
}
}
_ => {}
}
}
for facet in facets {
let name = match facet {
SymbolRef::Name(name) => Some(name.as_str()),
SymbolRef::Param(name) => parameters.and_then(|p| p.get(name)).and_then(Json::as_str),
};
let Some(name) = name else {
return Some("model facet names must resolve before execution".into());
};
if [
"TrialRecord",
"EvaluationRecord",
"OutcomeRecord",
"AttemptRecord",
"TrialState",
"GradingState",
"WatchState",
"LeaseState",
]
.contains(&name.rsplit('/').next().unwrap_or(name))
{
return Some(format!(
"{name} requires a configured host learning/runtime binding; it cannot be authored by a model plan"
));
}
}
None
}
fn cognition_refusal(command: &Command, parameters: Option<&Map<String, Json>>) -> Option<String> {
let Command::Kml(statement) = command else {
return None;
};
for clause in &statement.clauses {
let verb = match clause {
MutationClause::CreateConcept(_)
| MutationClause::UpsertConcept(_)
| MutationClause::EnsureProposition(_)
| MutationClause::CreateEvidence(_)
| MutationClause::CreateAssertion(_)
| MutationClause::CreateActivity(_) => {
if let Some(refusal) = unbounded_selection(clause, parameters) {
return Some(refusal);
}
continue;
}
MutationClause::Transition(transition) => {
match transition_state_of(transition, parameters) {
Some(state) if COGNITIVE_TRANSITIONS.contains(&state) => {
if let Some(refusal) = unbounded_selection(clause, parameters) {
return Some(refusal);
}
continue;
}
Some(state) => {
return Some(format!(
"formation cannot TRANSITION memory to \"{state}\"; it corrects \
cognition (retracted / superseded / corrected) and runs its own \
Activities. Removing memory belongs to maintenance"
));
}
None => {
return Some(
"formation must write the TRANSITION state as a literal this \
request can be read against; a state bound elsewhere cannot be \
checked before it runs"
.to_string(),
);
}
}
}
MutationClause::Update(_) => "UPDATE",
MutationClause::SetRetention(_) => "SET RETENTION",
MutationClause::Purge(_) => "PURGE",
MutationClause::PurgePayload(_) => "PURGE PAYLOAD",
MutationClause::MergeConcept(_) => "MERGE CONCEPT",
};
return Some(format!(
"formation cannot issue {verb}; it writes cognition (CREATE / UPSERT / ENSURE / \
ASSERT) and corrects it (TRANSITION to retracted / superseded / corrected). \
Administering memory in bulk belongs to maintenance"
));
}
None
}
const COGNITIVE_TRANSITIONS: &[&str] = &[
transition_state::RETRACTED,
transition_state::SUPERSEDED,
transition_state::CORRECTED,
transition_state::RUNNING,
transition_state::COMPLETED,
transition_state::FAILED,
transition_state::CANCELLED,
];
fn transition_state_of<'a>(
transition: &'a anda_kip::Transition,
parameters: Option<&'a Map<String, Json>>,
) -> Option<&'a str> {
match &transition.to {
Scalar::Literal(KipValue::String(state)) => Some(state.as_str()),
Scalar::Param(name) => parameters?.get(name)?.as_str(),
_ => None,
}
}
pub async fn execute_maintenance_request(executor: &impl Executor, request: &Request) -> Response {
let commands = match request.parse_operations() {
Ok(commands) => commands,
Err(err) => return Response::from(err).with_request_id(request.request_id.clone()),
};
for (index, command) in commands.iter().enumerate() {
let parameters = operation_parameters(request, index);
if let Some(refusal) = unsupported_cognitive_write(command, parameters.as_ref()) {
return Response::from(KipError::unsupported_capability(refusal))
.with_request_id(request.request_id.clone());
}
if let Some(refusal) = maintenance_refusal(command, parameters.as_ref()) {
return Response::from(KipError::not_authorized(refusal))
.with_request_id(request.request_id.clone());
}
}
execute_request(executor, request).await
}
fn maintenance_refusal(
command: &Command,
parameters: Option<&Map<String, Json>>,
) -> Option<String> {
let Command::Kml(statement) = command else {
return None;
};
for clause in &statement.clauses {
match clause {
MutationClause::Purge(_) | MutationClause::PurgePayload(_) => {
return Some(
"maintenance cannot issue PURGE or PURGE PAYLOAD; erasure is irreversible \
and this deployment runs it deterministically from a person's forget \
request, never from a maintenance plan. TRANSITION to archived or \
tombstoned is yours"
.to_string(),
);
}
MutationClause::SetRetention(retention)
if retention
.values
.iter()
.any(|(name, _)| name == "legal_hold") =>
{
return Some(
"maintenance cannot place or lift a legal hold; set a retention class and \
an expires_at, and leave the hold to a person"
.to_string(),
);
}
_ => {}
}
if let Some(refusal) = unbounded_selection(clause, parameters) {
return Some(refusal);
}
}
None
}
fn unbounded_selection(
clause: &MutationClause,
parameters: Option<&Map<String, Json>>,
) -> Option<String> {
let (verb, where_clauses, limit) = match clause {
MutationClause::Update(c) => ("UPDATE", &c.where_clauses, &c.limit),
MutationClause::Transition(c) => ("TRANSITION", &c.where_clauses, &c.limit),
MutationClause::SetRetention(c) => ("SET RETENTION", &c.where_clauses, &c.limit),
MutationClause::Purge(c) => ("PURGE", &c.where_clauses, &c.limit),
MutationClause::PurgePayload(c) => ("PURGE PAYLOAD", &c.where_clauses, &c.limit),
_ => return None,
};
if where_clauses
.as_ref()
.is_none_or(|clauses| clauses.is_empty())
{
return None;
}
match selection_limit(limit.as_ref(), parameters) {
Some(limit) if limit <= MAX_GATED_SELECTION => None,
_ => Some(format!(
"a {verb} that selects with WHERE must carry LIMIT {MAX_GATED_SELECTION} or less"
)),
}
}
fn selection_limit(limit: Option<&Scalar>, parameters: Option<&Map<String, Json>>) -> Option<u64> {
match limit? {
Scalar::Literal(KipValue::Number(number)) => number.as_u64(),
Scalar::Param(name) => parameters?.get(name)?.as_u64(),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
use anda_kip::{KipError, OperationResult};
#[test]
fn a_single_command_request_carries_one_operation() {
let req = request("DESCRIBE PRIMER");
assert_eq!(req.kip, "2.0");
assert_eq!(req.operations.len(), 1);
assert_eq!(
req.operations[0].command.as_deref(),
Some("DESCRIBE PRIMER")
);
req.validate().unwrap();
}
#[test]
fn parameters_ride_the_envelope_rather_than_the_command_text() {
let req = request_with("FIND(?x) WHERE { ?x {type: :t} }", param("t", "Person"));
assert_eq!(req.parameters.as_ref().unwrap()["t"], Json::from("Person"));
req.validate().unwrap();
}
#[test]
fn an_operation_level_failure_is_not_read_as_an_empty_success() {
let response = Response::from_results(vec![OperationResult::failed(
KipError::not_found_or_not_visible("nothing here"),
)]);
assert!(response.error.is_none(), "the failure is per-operation");
assert!(!succeeded(&response));
assert_eq!(ok_result(&response), None);
assert!(error_of(&response).is_some());
}
#[test]
fn an_unknown_outcome_does_not_read_as_success() {
let response = Response::outcome_unknown(KipError::outcome_unknown("connection dropped"));
assert!(!succeeded(&response));
assert_eq!(response.status, TopLevelStatus::OutcomeUnknown);
}
fn parsed(command: &str) -> Command {
request(command)
.parse_operations()
.expect("the command parses")
.remove(0)
}
#[test]
fn the_cognition_gate_admits_what_formation_encodes() {
for command in [
r#"FIND(?c.id) WHERE { ?c CONCEPT {type: "Person"} } LIMIT 5"#,
"LIST PREDICATES LIMIT 100",
"DESCRIBE PRIMER",
r#"MUTATE { ASSERT (:alice, "prefers", :dark) { by: :alice, mode: "stated" } }"#,
r#"MUTATE {
CREATE EVIDENCE ?e { SET FIELDS { evidence_class: "user_statement", payload: :p } }
UPSERT CONCEPT ?a { MATCH {type: "Person", key: :k} SET FIELDS {name: :n} }
ENSURE PROPOSITION ?p2 (?a, "prefers", :dark)
CREATE ASSERTION ?as { SET FIELDS { proposition: ?p2, asserted_by: ?a, stance: "support" } }
CREATE ACTIVITY ?act { SET FIELDS { activity_class: "extraction", status: "completed" } }
}"#,
r#"MUTATE { ASSERT (:alice, "prefers", :light) { by: :alice, mode: "stated" } SUPERSEDING :old }"#,
r#"TRANSITION :old TO "corrected" BY :new"#,
r#"TRANSITION :act TO "completed""#,
r#"TRANSITION ?a TO "retracted" WHERE { ?a ASSERTION {asserted_by: :alice} } LIMIT 5"#,
r#"TRANSITION :a TO "retracted""#,
] {
assert_eq!(
cognition_refusal(&parsed(command), None),
None,
"should be admitted: {command}"
);
}
}
#[test]
fn the_cognition_gate_refuses_administering_memory_in_bulk() {
for (command, verb) in [
(
r#"UPDATE ?c SET FACET "MnemonicState" {salience: 0.1} WHERE { ?c CONCEPT {} } LIMIT 5"#,
"UPDATE",
),
(
r#"SET RETENTION ?c { retention_class: "standard" } WHERE { ?c CONCEPT {} } LIMIT 5"#,
"SET RETENTION",
),
(
r#"TRANSITION ?c TO "archived" WHERE { ?c CONCEPT {} } LIMIT 5"#,
"archived",
),
(
r#"TRANSITION ?c TO "tombstoned" WHERE { ?c CONCEPT {} } LIMIT 5"#,
"tombstoned",
),
(
r#"PURGE ?c WHERE { ?c CONCEPT {} } LIMIT 5 CONFIRM "PURGE""#,
"PURGE",
),
(
r#"PURGE PAYLOAD ?e WHERE { ?e EVIDENCE {} } LIMIT 5 CONFIRM "PURGE""#,
"PURGE PAYLOAD",
),
(r#"MERGE CONCEPT :dup INTO :canonical"#, "MERGE CONCEPT"),
] {
let refusal = cognition_refusal(&parsed(command), None)
.unwrap_or_else(|| panic!("should be refused: {command}"));
assert!(refusal.contains(verb), "{refusal}");
}
}
#[test]
fn a_selecting_retraction_must_say_how_much_it_may_withdraw() {
let unbounded = r#"TRANSITION ?a TO "retracted" WHERE { ?a ASSERTION {} }"#;
assert!(cognition_refusal(&parsed(unbounded), None).is_some());
let over_budget = r#"TRANSITION ?a TO "retracted" WHERE { ?a ASSERTION {} } LIMIT 500"#;
assert!(cognition_refusal(&parsed(over_budget), None).is_some());
let bound = r#"TRANSITION ?a TO "retracted" WHERE { ?a ASSERTION {} } LIMIT :n"#;
assert_eq!(
cognition_refusal(&parsed(bound), Some(¶m("n", 5))),
None
);
assert!(cognition_refusal(&parsed(bound), Some(¶m("n", 5000))).is_some());
assert!(cognition_refusal(&parsed(bound), None).is_some());
}
#[test]
fn a_transition_state_the_gate_cannot_read_is_refused() {
let parameterised = r#"TRANSITION :a TO :state"#;
assert_eq!(
cognition_refusal(&parsed(parameterised), Some(¶m("state", "retracted"))),
None,
"a bound cognitive state resolves and passes"
);
let refusal =
cognition_refusal(&parsed(parameterised), Some(¶m("state", "tombstoned")))
.expect("a bound removal state is refused on the state it names");
assert!(refusal.contains("tombstoned"), "{refusal}");
for parameters in [
None,
Some(param("other", "retracted")),
Some(param("state", 7)),
] {
let refusal = cognition_refusal(&parsed(parameterised), parameters.as_ref())
.expect("an unreadable state is refused");
assert!(refusal.contains("literal"), "{refusal}");
}
}
#[test]
fn the_cognition_gate_reads_the_command_not_the_label() {
let smuggled = r#"MUTATE {
CREATE ACTIVITY ?a { SET FIELDS { activity_class: "extraction", status: "completed" } }
PURGE :victim CONFIRM "PURGE"
}"#;
let refusal = cognition_refusal(&parsed(smuggled), None).expect("refused");
assert!(refusal.contains("PURGE"), "{refusal}");
}
#[test]
fn the_maintenance_gate_admits_the_custodial_verbs() {
for command in [
r#"FIND(?c.id) WHERE { ?c CONCEPT {} } LIMIT 20"#,
"LIST PREDICATES LIMIT 500",
r#"UPDATE ?c SET FACET "MnemonicState" {salience: 0.9} WHERE { ?c CONCEPT {} } LIMIT 20"#,
r#"TRANSITION ?c TO "archived" WHERE { ?c CONCEPT {} } LIMIT 20"#,
r#"TRANSITION ?c TO "tombstoned" WHERE { ?c CONCEPT {} } LIMIT 20"#,
r#"TRANSITION ?a TO "archived" WHERE { STRUCTURAL (?a, "evidence", :e) } LIMIT 20"#,
r#"SET RETENTION ?e { retention_class: "standard", expires_at: "2027-01-01T00:00:00.000Z" } WHERE { ?e EVIDENCE {} } LIMIT 20"#,
r#"TRANSITION "C-7" TO "archived""#,
r#"MERGE CONCEPT ?dup INTO ?canonical WHERE { ?dup CONCEPT {key: "alice-2"} ?canonical CONCEPT {key: "alice"} }"#,
] {
assert_eq!(
maintenance_refusal(&parsed(command), None),
None,
"should be admitted: {command}"
);
}
}
#[test]
fn the_maintenance_gate_refuses_erasure_and_holds() {
for (command, expected) in [
(
r#"PURGE ?c WHERE { ?c CONCEPT {} } LIMIT 5 CONFIRM "PURGE""#,
"PURGE",
),
(r#"PURGE :victim CONFIRM "PURGE""#, "PURGE"),
(r#"PURGE PAYLOAD :e CONFIRM "PURGE""#, "PURGE PAYLOAD"),
(
r#"SET RETENTION :e { retention_class: "standard", legal_hold: true }"#,
"legal hold",
),
(
r#"SET RETENTION :e { retention_class: "standard", legal_hold: false }"#,
"legal hold",
),
(
r#"SET RETENTION :e { legal_hold: :whatever }"#,
"legal hold",
),
(
r#"TRANSITION ?c TO "archived" WHERE { ?c CONCEPT {} }"#,
"LIMIT 20 or less",
),
(
r#"UPDATE ?c SET FACET "MnemonicState" {salience: 0.9} WHERE { ?c CONCEPT {} } LIMIT 500"#,
"LIMIT 20 or less",
),
] {
let refusal = maintenance_refusal(&parsed(command), None)
.unwrap_or_else(|| panic!("should be refused: {command}"));
assert!(refusal.contains(expected), "{command}: {refusal}");
}
}
#[test]
fn nothing_formation_may_write_is_something_maintenance_may_not() {
for command in [
r#"MUTATE { ASSERT (:alice, "prefers", :dark) { by: :alice, mode: "stated" } }"#,
r#"TRANSITION :old TO "corrected" BY :new"#,
r#"TRANSITION ?a TO "retracted" WHERE { ?a ASSERTION {asserted_by: :alice} } LIMIT 5"#,
] {
let command = parsed(command);
assert_eq!(cognition_refusal(&command, None), None);
assert_eq!(maintenance_refusal(&command, None), None);
}
}
fn said(role: &str, text: &str) -> Message {
Message {
role: role.to_string(),
content: vec![text.to_string().into()],
..Default::default()
}
}
#[test]
fn each_message_is_its_own_observation() {
let messages = [
said("user", "I always prefer dark mode."),
said("assistant", "Noted."),
];
let ingest = observation_ingest(
&messages,
"2026-08-20T00:00:00.000Z",
"formation:chat-42",
None,
)
.expect("two messages produce two entries");
let keys: Vec<_> = ingest.evidence.iter().map(|e| e.key.as_str()).collect();
assert_eq!(keys, ["msg1", "msg2"]);
let classes: Vec<_> = ingest
.evidence
.iter()
.map(|e| e.evidence_class.as_str())
.collect();
assert_eq!(classes, ["user_statement", "agent_statement"]);
assert_eq!(
ingest.evidence[0].payload,
Some(serde_json::to_value(&messages[0]).unwrap())
);
let keys: Vec<_> = ingest
.evidence
.iter()
.map(|e| e.client_key.as_deref().unwrap())
.collect();
assert_eq!(keys, ["formation:chat-42:1", "formation:chat-42:2"]);
assert!(observation_ingest(&[], "2026-08-20T00:00:00.000Z", "x", None).is_none());
}
#[test]
fn only_the_newest_messages_are_minted() {
let messages: Vec<_> = (0..MAX_INGESTED_MESSAGES + 4)
.map(|n| said("user", &format!("turn {n}")))
.collect();
let ingest = observation_ingest(&messages, "2026-08-20T00:00:00.000Z", "o", None).unwrap();
assert_eq!(ingest.evidence.len(), MAX_INGESTED_MESSAGES);
assert_eq!(ingest.evidence[0].key, "msg1");
assert_eq!(
ingest.evidence[0].payload,
Some(serde_json::to_value(said("user", "turn 4")).unwrap())
);
}
#[test]
fn a_source_is_named_only_for_what_the_counterparty_said() {
let messages = [said("user", "hi"), said("assistant", "hello")];
let ingest =
observation_ingest(&messages, "2026-08-20T00:00:00.000Z", "o", Some("C-7")).unwrap();
assert_eq!(
ingest.evidence[0].source_actor,
Some(ElementReference::by_id("C-7"))
);
assert_eq!(ingest.evidence[1].source_actor, None);
}
#[test]
fn a_model_cannot_shadow_captured_source_handles() {
let observation =
observation_ingest(&[said("user", "hi")], "2026-08-20T00:00:00.000Z", "o", None)
.unwrap();
let mut plain = request("MUTATE { CREATE ACTIVITY ?a { SET FIELDS {} } }");
attach_observation(&mut plain, &observation).unwrap();
assert!(plain.ingest.is_some(), "the ordinary case attaches");
let mut claimed = request_with("MUTATE { CREATE ACTIVITY ?a { SET FIELDS {} } }", {
param("msg1", "mine")
});
assert!(attach_observation(&mut claimed, &observation).is_err());
assert!(claimed.ingest.is_none());
let mut per_operation = request("MUTATE { CREATE ACTIVITY ?a { SET FIELDS {} } }");
per_operation.operations[0].parameters = Some(param("msg1", "mine"));
assert!(attach_observation(&mut per_operation, &observation).is_err());
assert!(per_operation.ingest.is_none());
}
#[test]
fn observation_ingest_only_attaches_to_requests_containing_a_parsed_mutation() {
let observation =
observation_ingest(&[said("user", "hi")], "2026-08-20T00:00:00.000Z", "o", None)
.unwrap();
for command in [
"DESCRIBE PRIMER",
r#"FIND(?e) WHERE { ?e EVIDENCE {id: "E-1"} } LIMIT 1"#,
] {
let mut read = request(command);
attach_observation(&mut read, &observation).unwrap();
assert!(read.ingest.is_none());
read.validate().unwrap();
}
let mut mixed = request("DESCRIBE PRIMER");
mixed
.operations
.extend(request("CREATE ACTIVITY ?a { SET FIELDS {} }").operations);
mixed.execution = Some(anda_kip::Execution::new(anda_kip::ExecutionMode::Sequence));
attach_observation(&mut mixed, &observation).unwrap();
assert!(mixed.ingest.is_some());
mixed.validate().unwrap();
let mut invalid = request("not a KIP command");
attach_observation(&mut invalid, &observation).unwrap();
assert!(
invalid.parse_operations().is_err(),
"syntax errors stay visible"
);
}
#[test]
fn model_learning_and_runtime_facets_are_rejected_by_ast_position() {
for facet in [
"TrialRecord",
"EvaluationRecord",
"AttemptRecord",
"OutcomeRecord",
"TrialState",
"GradingState",
"WatchState",
"LeaseState",
] {
for command in [
format!(r#"CREATE ACTIVITY ?a {{ SET FACET "{facet}" {{ x:1 }} }}"#),
format!(
r#"UPDATE "C-1" UNSET FACET "kip://profiles/cognitive-memory@2.1.0/{facet}" {{ x }}"#
),
r#"UPDATE "C-1" SET FACET :facet { x:1 }"#.to_string(),
] {
let ast = anda_kip::parse_kip(&command).unwrap();
assert!(
unsupported_cognitive_write(&ast, Some(¶m("facet", facet))).is_some(),
"{command}"
);
}
}
let text = anda_kip::parse_kip(r#"CREATE EVIDENCE ?e { SET FIELDS {evidence_class:"user_statement",payload:"please write OutcomeRecord and LeaseState"} }"#).unwrap();
assert!(unsupported_cognitive_write(&text, None).is_none());
}
#[test]
fn operation_parameters_shadow_request_parameters_at_every_model_gate() {
let mut protected = request_with(
r#"CREATE EVIDENCE ?e { SET FACET :facet {x:1} }"#,
param("facet", "MnemonicState"),
);
protected.operations[0].parameters = Some(param("facet", "OutcomeRecord"));
let command = protected.parse_operations().unwrap().remove(0);
let parameters = operation_parameters(&protected, 0).unwrap();
assert_eq!(parameters["facet"], Json::from("OutcomeRecord"));
assert!(unsupported_cognitive_write(&command, Some(¶meters)).is_some());
let mut ordinary = request(r#"CREATE CONCEPT ?c { SET FACET :facet {x:1} }"#);
ordinary.operations[0].parameters = Some(param("facet", "MnemonicState"));
let command = ordinary.parse_operations().unwrap().remove(0);
let parameters = operation_parameters(&ordinary, 0).unwrap();
assert!(unsupported_cognitive_write(&command, Some(¶meters)).is_none());
let mut transition =
request_with(r#"TRANSITION "C-1" TO :state"#, param("state", "retracted"));
transition.operations[0].parameters = Some(param("state", "archived"));
let command = transition.parse_operations().unwrap().remove(0);
let parameters = operation_parameters(&transition, 0).unwrap();
assert!(cognition_refusal(&command, Some(¶meters)).is_some());
let mut selection = request_with(
r#"UPDATE ?c SET FIELDS {name:"changed"} WHERE { ?c CONCEPT {} } LIMIT :limit"#,
param("limit", 1),
);
selection.operations[0].parameters = Some(param("limit", 100));
let command = selection.parse_operations().unwrap().remove(0);
let parameters = operation_parameters(&selection, 0).unwrap();
assert!(maintenance_refusal(&command, Some(¶meters)).is_some());
}
}