Collapse Epiphany CRRC reads into view

This commit is contained in:
Meta Vens 2026-05-12 06:17:12 +01:00
commit 32d6eed2d8
14 changed files with 117 additions and 1169 deletions

View file

@ -356,11 +356,6 @@ client_request_definitions! {
params: v2::ThreadEpiphanyRolesParams,
response: v2::ThreadEpiphanyRolesResponse,
},
#[experimental("thread/epiphany/coordinator")]
ThreadEpiphanyCoordinator => "thread/epiphany/coordinator" {
params: v2::ThreadEpiphanyCoordinatorParams,
response: v2::ThreadEpiphanyCoordinatorResponse,
},
#[experimental("thread/epiphany/roleLaunch")]
ThreadEpiphanyRoleLaunch => "thread/epiphany/roleLaunch" {
params: v2::ThreadEpiphanyRoleLaunchParams,
@ -396,21 +391,6 @@ client_request_definitions! {
params: v2::ThreadEpiphanyGraphQueryParams,
response: v2::ThreadEpiphanyGraphQueryResponse,
},
#[experimental("thread/epiphany/pressure")]
ThreadEpiphanyPressure => "thread/epiphany/pressure" {
params: v2::ThreadEpiphanyPressureParams,
response: v2::ThreadEpiphanyPressureResponse,
},
#[experimental("thread/epiphany/reorient")]
ThreadEpiphanyReorient => "thread/epiphany/reorient" {
params: v2::ThreadEpiphanyReorientParams,
response: v2::ThreadEpiphanyReorientResponse,
},
#[experimental("thread/epiphany/crrc")]
ThreadEpiphanyCrrc => "thread/epiphany/crrc" {
params: v2::ThreadEpiphanyCrrcParams,
response: v2::ThreadEpiphanyCrrcResponse,
},
#[experimental("thread/epiphany/reorientLaunch")]
ThreadEpiphanyReorientLaunch => "thread/epiphany/reorientLaunch" {
params: v2::ThreadEpiphanyReorientLaunchParams,
@ -2104,89 +2084,6 @@ mod tests {
Ok(())
}
#[test]
fn serialize_thread_epiphany_coordinator_response() -> Result<()> {
let response = ClientResponse::ThreadEpiphanyCoordinator {
request_id: RequestId::Integer(8),
response: v2::ThreadEpiphanyCoordinatorResponse {
thread_id: "thr_123".to_string(),
source: v2::ThreadEpiphanyRolesSource::Live,
state_status: v2::ThreadEpiphanyReorientStateStatus::Ready,
state_revision: Some(4),
action: v2::ThreadEpiphanyCoordinatorAction::LaunchModeling,
target_role: Some(v2::ThreadEpiphanyRoleId::Modeling),
recommended_scene_action: Some(v2::ThreadEpiphanySceneAction::RoleLaunch),
requires_review: false,
can_auto_run: true,
reason: "The modeling/checkpoint lane is ready.".to_string(),
source_signals: v2::ThreadEpiphanyCoordinatorSignals {
pressure_level: v2::ThreadEpiphanyPressureLevel::Low,
should_prepare_compaction: false,
reorient_action: v2::ThreadEpiphanyReorientAction::Resume,
crrc_action: v2::ThreadEpiphanyCrrcAction::Continue,
modeling_result_status: v2::ThreadEpiphanyRoleResultStatus::MissingBinding,
verification_result_status: v2::ThreadEpiphanyRoleResultStatus::MissingBinding,
reorient_result_status: v2::ThreadEpiphanyReorientResultStatus::MissingBinding,
},
roles: vec![v2::ThreadEpiphanyRoleLane {
id: v2::ThreadEpiphanyRoleId::Modeling,
title: "Modeling / Checkpoint".to_string(),
owner_role: "epiphany-modeler".to_string(),
status: v2::ThreadEpiphanyRoleStatus::Ready,
note: "Checkpoint ready.".to_string(),
jobs: Vec::new(),
authority_scopes: vec!["thread/epiphany/roleLaunch".to_string()],
recommended_action: Some(v2::ThreadEpiphanySceneAction::RoleLaunch),
}],
note: "Coordinator is read-only.".to_string(),
},
};
assert_eq!(response.id(), &RequestId::Integer(8));
assert_eq!(response.method(), "thread/epiphany/coordinator");
assert_eq!(
json!({
"method": "thread/epiphany/coordinator",
"id": 8,
"response": {
"threadId": "thr_123",
"source": "live",
"stateStatus": "ready",
"stateRevision": 4,
"action": "launchModeling",
"targetRole": "modeling",
"recommendedSceneAction": "roleLaunch",
"requiresReview": false,
"canAutoRun": true,
"reason": "The modeling/checkpoint lane is ready.",
"sourceSignals": {
"pressureLevel": "low",
"shouldPrepareCompaction": false,
"reorientAction": "resume",
"crrcAction": "continue",
"modelingResultStatus": "missingBinding",
"verificationResultStatus": "missingBinding",
"reorientResultStatus": "missingBinding"
},
"roles": [
{
"id": "modeling",
"title": "Modeling / Checkpoint",
"ownerRole": "epiphany-modeler",
"status": "ready",
"note": "Checkpoint ready.",
"authorityScopes": ["thread/epiphany/roleLaunch"],
"recommendedAction": "roleLaunch"
}
],
"note": "Coordinator is read-only."
}
}),
serde_json::to_value(&response)?,
);
Ok(())
}
#[test]
fn serialize_thread_epiphany_role_launch_response() -> Result<()> {
let response = ClientResponse::ThreadEpiphanyRoleLaunch {
@ -2981,235 +2878,6 @@ mod tests {
Ok(())
}
#[test]
fn serialize_thread_epiphany_pressure_response() -> Result<()> {
let response = ClientResponse::ThreadEpiphanyPressure {
request_id: RequestId::Integer(8),
response: v2::ThreadEpiphanyPressureResponse {
thread_id: "thr_123".to_string(),
source: v2::ThreadEpiphanyPressureSource::Live,
pressure: v2::ThreadEpiphanyPressure {
status: v2::ThreadEpiphanyPressureStatus::Ready,
level: v2::ThreadEpiphanyPressureLevel::High,
basis: v2::ThreadEpiphanyPressureBasis::AutoCompactLimit,
used_tokens: Some(92_000),
model_context_window: Some(128_000),
model_auto_compact_token_limit: Some(100_000),
remaining_tokens: Some(8_000),
ratio_per_mille: Some(920),
should_prepare_compaction: true,
note: "Pressure is derived from the model auto-compact token limit."
.to_string(),
},
},
};
assert_eq!(response.id(), &RequestId::Integer(8));
assert_eq!(response.method(), "thread/epiphany/pressure");
assert_eq!(
json!({
"method": "thread/epiphany/pressure",
"id": 8,
"response": {
"threadId": "thr_123",
"source": "live",
"pressure": {
"status": "ready",
"level": "high",
"basis": "autoCompactLimit",
"usedTokens": 92000,
"modelContextWindow": 128000,
"modelAutoCompactTokenLimit": 100000,
"remainingTokens": 8000,
"ratioPerMille": 920,
"shouldPrepareCompaction": true,
"note": "Pressure is derived from the model auto-compact token limit."
}
}
}),
serde_json::to_value(&response)?,
);
Ok(())
}
#[test]
fn serialize_thread_epiphany_reorient_response() -> Result<()> {
let response = ClientResponse::ThreadEpiphanyReorient {
request_id: RequestId::Integer(8),
response: v2::ThreadEpiphanyReorientResponse {
thread_id: "thr_123".to_string(),
source: v2::ThreadEpiphanyReorientSource::Live,
state_status: v2::ThreadEpiphanyReorientStateStatus::Ready,
state_revision: Some(4),
decision: v2::ThreadEpiphanyReorientDecision {
action: v2::ThreadEpiphanyReorientAction::Regather,
checkpoint_status: v2::ThreadEpiphanyReorientCheckpointStatus::ResumeReady,
checkpoint_id: Some("ix-1".to_string()),
pressure_level: v2::ThreadEpiphanyPressureLevel::High,
retrieval_status: v2::ThreadEpiphanyRetrievalFreshnessStatus::Stale,
graph_status: v2::ThreadEpiphanyGraphFreshnessStatus::Ready,
watcher_status: v2::ThreadEpiphanyInvalidationStatus::Changed,
reasons: vec![
v2::ThreadEpiphanyReorientReason::CheckpointPathsChanged,
v2::ThreadEpiphanyReorientReason::FrontierChanged,
],
checkpoint_dirty_paths: vec![PathBuf::from("src/lib.rs")],
checkpoint_changed_paths: vec![PathBuf::from("src/lib.rs")],
active_frontier_node_ids: vec!["state-spine".to_string()],
next_action: "Re-gather source before editing.".to_string(),
note: "Resume-ready checkpoint was invalidated by watcher/frontier drift."
.to_string(),
},
},
};
assert_eq!(response.id(), &RequestId::Integer(8));
assert_eq!(response.method(), "thread/epiphany/reorient");
assert_eq!(
json!({
"method": "thread/epiphany/reorient",
"id": 8,
"response": {
"threadId": "thr_123",
"source": "live",
"stateStatus": "ready",
"stateRevision": 4,
"decision": {
"action": "regather",
"checkpointStatus": "resumeReady",
"checkpointId": "ix-1",
"pressureLevel": "high",
"retrievalStatus": "stale",
"graphStatus": "ready",
"watcherStatus": "changed",
"reasons": [
"checkpointPathsChanged",
"frontierChanged"
],
"checkpointDirtyPaths": ["src/lib.rs"],
"checkpointChangedPaths": ["src/lib.rs"],
"activeFrontierNodeIds": ["state-spine"],
"nextAction": "Re-gather source before editing.",
"note": "Resume-ready checkpoint was invalidated by watcher/frontier drift."
}
}
}),
serde_json::to_value(&response)?,
);
Ok(())
}
#[test]
fn serialize_thread_epiphany_crrc_response() -> Result<()> {
let response = ClientResponse::ThreadEpiphanyCrrc {
request_id: RequestId::Integer(9),
response: v2::ThreadEpiphanyCrrcResponse {
thread_id: "thr_123".to_string(),
source: v2::ThreadEpiphanyReorientSource::Live,
state_status: v2::ThreadEpiphanyReorientStateStatus::Ready,
state_revision: Some(4),
pressure: v2::ThreadEpiphanyPressure {
status: v2::ThreadEpiphanyPressureStatus::Ready,
level: v2::ThreadEpiphanyPressureLevel::High,
basis: v2::ThreadEpiphanyPressureBasis::AutoCompactLimit,
used_tokens: Some(92_000),
model_context_window: Some(128_000),
model_auto_compact_token_limit: Some(100_000),
remaining_tokens: Some(8_000),
ratio_per_mille: Some(920),
should_prepare_compaction: true,
note: "Pressure is derived from the model auto-compact token limit."
.to_string(),
},
decision: v2::ThreadEpiphanyReorientDecision {
action: v2::ThreadEpiphanyReorientAction::Regather,
checkpoint_status: v2::ThreadEpiphanyReorientCheckpointStatus::ResumeReady,
checkpoint_id: Some("ix-1".to_string()),
pressure_level: v2::ThreadEpiphanyPressureLevel::High,
retrieval_status: v2::ThreadEpiphanyRetrievalFreshnessStatus::Stale,
graph_status: v2::ThreadEpiphanyGraphFreshnessStatus::Ready,
watcher_status: v2::ThreadEpiphanyInvalidationStatus::Changed,
reasons: vec![v2::ThreadEpiphanyReorientReason::CheckpointPathsChanged],
checkpoint_dirty_paths: Vec::new(),
checkpoint_changed_paths: vec![PathBuf::from("src/lib.rs")],
active_frontier_node_ids: vec!["state-spine".to_string()],
next_action: "Re-gather source before editing.".to_string(),
note: "Resume-ready checkpoint was invalidated by watcher/frontier drift."
.to_string(),
},
recommendation: v2::ThreadEpiphanyCrrcRecommendation {
action: v2::ThreadEpiphanyCrrcAction::LaunchReorientWorker,
recommended_scene_action: Some(v2::ThreadEpiphanySceneAction::ReorientLaunch),
reason: "The current pressure/reorientation verdict needs a bounded worker before safe continuation."
.to_string(),
},
reorient_binding_id: "reorient-worker".to_string(),
reorient_result_status: v2::ThreadEpiphanyReorientResultStatus::MissingBinding,
reorient_job: None,
reorient_finding: None,
available_actions: vec![
v2::ThreadEpiphanySceneAction::Reorient,
v2::ThreadEpiphanySceneAction::Crrc,
v2::ThreadEpiphanySceneAction::ReorientLaunch,
],
note: "The current pressure/reorientation verdict needs a bounded worker before safe continuation. Result status: MissingBinding. No matching Epiphany reorientation worker binding exists."
.to_string(),
},
};
assert_eq!(response.id(), &RequestId::Integer(9));
assert_eq!(response.method(), "thread/epiphany/crrc");
assert_eq!(
json!({
"method": "thread/epiphany/crrc",
"id": 9,
"response": {
"threadId": "thr_123",
"source": "live",
"stateStatus": "ready",
"stateRevision": 4,
"pressure": {
"status": "ready",
"level": "high",
"basis": "autoCompactLimit",
"usedTokens": 92000,
"modelContextWindow": 128000,
"modelAutoCompactTokenLimit": 100000,
"remainingTokens": 8000,
"ratioPerMille": 920,
"shouldPrepareCompaction": true,
"note": "Pressure is derived from the model auto-compact token limit."
},
"decision": {
"action": "regather",
"checkpointStatus": "resumeReady",
"checkpointId": "ix-1",
"pressureLevel": "high",
"retrievalStatus": "stale",
"graphStatus": "ready",
"watcherStatus": "changed",
"reasons": ["checkpointPathsChanged"],
"checkpointChangedPaths": ["src/lib.rs"],
"activeFrontierNodeIds": ["state-spine"],
"nextAction": "Re-gather source before editing.",
"note": "Resume-ready checkpoint was invalidated by watcher/frontier drift."
},
"recommendation": {
"action": "launchReorientWorker",
"recommendedSceneAction": "reorientLaunch",
"reason": "The current pressure/reorientation verdict needs a bounded worker before safe continuation."
},
"reorientBindingId": "reorient-worker",
"reorientResultStatus": "missingBinding",
"availableActions": ["reorient", "crrc", "reorientLaunch"],
"note": "The current pressure/reorientation verdict needs a bounded worker before safe continuation. Result status: MissingBinding. No matching Epiphany reorientation worker binding exists."
}
}),
serde_json::to_value(&response)?,
);
Ok(())
}
#[test]
fn serialize_thread_epiphany_reorient_launch_response() -> Result<()> {
let response = ClientResponse::ThreadEpiphanyReorientLaunch {
@ -4719,18 +4387,6 @@ mod tests {
assert_eq!(reason, Some("thread/epiphany/roles"));
}
#[test]
fn thread_epiphany_coordinator_is_marked_experimental() {
let request = ClientRequest::ThreadEpiphanyCoordinator {
request_id: RequestId::Integer(1),
params: v2::ThreadEpiphanyCoordinatorParams {
thread_id: "thr_123".to_string(),
},
};
let reason = crate::experimental_api::ExperimentalApi::experimental_reason(&request);
assert_eq!(reason, Some("thread/epiphany/coordinator"));
}
#[test]
fn thread_epiphany_role_launch_is_marked_experimental() {
let request = ClientRequest::ThreadEpiphanyRoleLaunch {
@ -4817,42 +4473,6 @@ mod tests {
assert_eq!(reason, Some("thread/epiphany/planning"));
}
#[test]
fn thread_epiphany_pressure_is_marked_experimental() {
let request = ClientRequest::ThreadEpiphanyPressure {
request_id: RequestId::Integer(1),
params: v2::ThreadEpiphanyPressureParams {
thread_id: "thr_123".to_string(),
},
};
let reason = crate::experimental_api::ExperimentalApi::experimental_reason(&request);
assert_eq!(reason, Some("thread/epiphany/pressure"));
}
#[test]
fn thread_epiphany_reorient_is_marked_experimental() {
let request = ClientRequest::ThreadEpiphanyReorient {
request_id: RequestId::Integer(1),
params: v2::ThreadEpiphanyReorientParams {
thread_id: "thr_123".to_string(),
},
};
let reason = crate::experimental_api::ExperimentalApi::experimental_reason(&request);
assert_eq!(reason, Some("thread/epiphany/reorient"));
}
#[test]
fn thread_epiphany_crrc_is_marked_experimental() {
let request = ClientRequest::ThreadEpiphanyCrrc {
request_id: RequestId::Integer(1),
params: v2::ThreadEpiphanyCrrcParams {
thread_id: "thr_123".to_string(),
},
};
let reason = crate::experimental_api::ExperimentalApi::experimental_reason(&request);
assert_eq!(reason, Some("thread/epiphany/crrc"));
}
#[test]
fn thread_epiphany_reorient_launch_is_marked_experimental() {
let request = ClientRequest::ThreadEpiphanyReorientLaunch {

View file

@ -4364,38 +4364,6 @@ pub enum ThreadEpiphanyRoleResultStatus {
Cancelled,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ThreadEpiphanyCoordinatorParams {
pub thread_id: String,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ThreadEpiphanyCoordinatorResponse {
pub thread_id: String,
pub source: ThreadEpiphanyRolesSource,
pub state_status: ThreadEpiphanyReorientStateStatus,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(optional = nullable)]
pub state_revision: Option<u64>,
pub action: ThreadEpiphanyCoordinatorAction,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(optional = nullable)]
pub target_role: Option<ThreadEpiphanyRoleId>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(optional = nullable)]
pub recommended_scene_action: Option<ThreadEpiphanySceneAction>,
pub requires_review: bool,
pub can_auto_run: bool,
pub reason: String,
pub source_signals: ThreadEpiphanyCoordinatorSignals,
pub roles: Vec<ThreadEpiphanyRoleLane>,
pub note: String,
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
@ -4947,30 +4915,6 @@ pub struct ThreadEpiphanyGraphQueryMissing {
pub edge_ids: Vec<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ThreadEpiphanyPressureParams {
pub thread_id: String,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ThreadEpiphanyPressureResponse {
pub thread_id: String,
pub source: ThreadEpiphanyPressureSource,
pub pressure: ThreadEpiphanyPressure,
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub enum ThreadEpiphanyPressureSource {
Stored,
Live,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
@ -5025,26 +4969,6 @@ pub enum ThreadEpiphanyPressureBasis {
ModelContextWindow,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ThreadEpiphanyReorientParams {
pub thread_id: String,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ThreadEpiphanyReorientResponse {
pub thread_id: String,
pub source: ThreadEpiphanyReorientSource,
pub state_status: ThreadEpiphanyReorientStateStatus,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(optional = nullable)]
pub state_revision: Option<u64>,
pub decision: ThreadEpiphanyReorientDecision,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
@ -5137,39 +5061,6 @@ pub struct ThreadEpiphanyReorientAcceptResponse {
pub finding: ThreadEpiphanyReorientFinding,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ThreadEpiphanyCrrcParams {
pub thread_id: String,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ThreadEpiphanyCrrcResponse {
pub thread_id: String,
pub source: ThreadEpiphanyReorientSource,
pub state_status: ThreadEpiphanyReorientStateStatus,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(optional = nullable)]
pub state_revision: Option<u64>,
pub pressure: ThreadEpiphanyPressure,
pub decision: ThreadEpiphanyReorientDecision,
pub recommendation: ThreadEpiphanyCrrcRecommendation,
pub reorient_binding_id: String,
pub reorient_result_status: ThreadEpiphanyReorientResultStatus,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(optional = nullable)]
pub reorient_job: Option<ThreadEpiphanyJob>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(optional = nullable)]
pub reorient_finding: Option<ThreadEpiphanyReorientFinding>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub available_actions: Vec<ThreadEpiphanySceneAction>,
pub note: String,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]