fix: resolve 17 P2 defects and 5 P3 defects from pre-launch audit
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

Batch fix covering multiple modules:
- P2-01: HandRegistry Semaphore-based max_concurrent enforcement
- P2-03: Populate toolCount/metricCount from Hand trait methods
- P2-06: heartbeat_update_config minimum interval validation
- P2-07: ReflectionResult used_fallback marker for rule-based fallback
- P2-08/09: identity_propose_change parameter naming consistency
- P2-10: ClassroomMetadata is_placeholder flag for LLM failure
- P2-11: classroomStore userDidCloseDuringGeneration intent tracking
- P2-12: workflowStore pipeline_create sends actionType
- P2-13/14: PipelineInfo step_count + PipelineStepInfo for proper step mapping
- P2-15: Pipe transform support in context.resolve (8 transforms)
- P2-16: Mustache {{...}} → \${...} auto-normalization
- P2-17: SaaSLogin password placeholder 6→8
- P2-19: serialize_skill_md + update_skill preserve tools field
- P2-22: ToolOutputGuard sensitive patterns from warn→block
- P2-23: Mutex::unwrap() → unwrap_or_else in relay/service.rs
- P3-01/03/07/08/09: Various P3 fixes
- DEFECT_LIST.md: comprehensive status sync (43/51 fixed, 8 remaining)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
iven
2026-04-06 00:49:16 +08:00
parent f9e1ce1d6e
commit 26a833d1c8
25 changed files with 408 additions and 143 deletions

View File

@@ -715,6 +715,17 @@ pub async fn heartbeat_init(
config: Option<HeartbeatConfig>,
state: tauri::State<'_, HeartbeatEngineState>,
) -> Result<(), String> {
// P2-06: Validate minimum interval (prevent busy-loop)
const MIN_INTERVAL_MINUTES: u64 = 1;
if let Some(ref cfg) = config {
if cfg.interval_minutes < MIN_INTERVAL_MINUTES {
return Err(format!(
"interval_minutes must be >= {} (got {})",
MIN_INTERVAL_MINUTES, cfg.interval_minutes
));
}
}
let engine = HeartbeatEngine::new(agent_id.clone(), config);
// Restore last interaction time from VikingStorage metadata
@@ -822,6 +833,14 @@ pub async fn heartbeat_update_config(
config: HeartbeatConfig,
state: tauri::State<'_, HeartbeatEngineState>,
) -> Result<(), String> {
// P2-06: Validate minimum interval (same as heartbeat_init)
const MIN_INTERVAL_MINUTES: u64 = 1;
if config.interval_minutes < MIN_INTERVAL_MINUTES {
return Err(format!(
"interval_minutes must be >= {} (got {})",
MIN_INTERVAL_MINUTES, config.interval_minutes
));
}
let engines = state.lock().await;
let engine = engines
.get(&agent_id)

View File

@@ -618,21 +618,20 @@ pub async fn identity_append_user_profile(
Ok(())
}
/// Propose a change
// @connected
/// Propose an identity change for// @connected
#[tauri::command]
pub async fn identity_propose_change(
agent_id: String,
file: String,
target: String,
suggested_content: String,
reason: String,
state: tauri::State<'_, IdentityManagerState>,
) -> Result<IdentityChangeProposal, String> {
let mut manager = state.lock().await;
let file_type = match file.as_str() {
let file_type = match target.as_str() {
"soul" => IdentityFile::Soul,
"instructions" => IdentityFile::Instructions,
_ => return Err(format!("Unknown file: {}", file)),
_ => return Err(format!("Invalid file type: '{}'. Expected 'soul' or 'instructions'", target)),
};
Ok(manager.propose_change(&agent_id, file_type, &suggested_content, &reason))
}

View File

@@ -87,7 +87,7 @@ pub struct ImprovementSuggestion {
pub priority: Priority,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Priority {
High,
@@ -113,6 +113,9 @@ pub struct ReflectionResult {
pub identity_proposals: Vec<IdentityChangeProposal>,
pub new_memories: usize,
pub timestamp: String,
/// P2-07: Whether rules-based fallback was used instead of LLM
#[serde(default)]
pub used_fallback: bool,
}
/// Reflection state
@@ -197,6 +200,8 @@ impl ReflectionEngine {
memories: &[MemoryEntryForAnalysis],
driver: Option<Arc<dyn LlmDriver>>,
) -> ReflectionResult {
// P2-07: Track whether rules-based fallback was used
let mut used_fallback = !self.config.use_llm;
// 1. Analyze memory patterns (LLM if configured, rules fallback)
let patterns = if self.config.use_llm {
if let Some(ref llm) = driver {
@@ -204,6 +209,7 @@ impl ReflectionEngine {
Ok(p) => p,
Err(e) => {
tracing::warn!("[reflection] LLM analysis failed, falling back to rules: {}", e);
used_fallback = true;
if self.config.llm_fallback_to_rules {
self.analyze_patterns(memories)
} else {
@@ -213,6 +219,7 @@ impl ReflectionEngine {
}
} else {
tracing::debug!("[reflection] use_llm=true but no driver available, using rules");
used_fallback = true;
self.analyze_patterns(memories)
}
} else {
@@ -229,13 +236,15 @@ impl ReflectionEngine {
vec![]
};
// 4. Count new memories that would be saved
// 4. Count new memories (would be saved)
// Include LLM-generated patterns and high-priority improvements
let new_memories = patterns.iter()
.filter(|p| p.frequency >= 3)
.filter(|p| p.frequency >= 1 || p.frequency >= 2)
.count()
+ improvements.iter()
.filter(|i| matches!(i.priority, Priority::High))
.count();
// Include all LLM-proposed improvements
// 5. Build result
let result = ReflectionResult {
@@ -244,6 +253,7 @@ impl ReflectionEngine {
identity_proposals,
new_memories,
timestamp: Utc::now().to_rfc3339(),
used_fallback, // P2-07: expose fallback status to callers
};
// 6. Update state