Compare commits

5 Commits

186 changed files with 106667 additions and 130 deletions

7
.gitignore vendored
View File

@@ -11,3 +11,10 @@ sgclaw_config.json
nul
target-test/
target-zhihu-nav/
dist/
.codex/
node_modules/
tmp_*
vibe_images/
sgclaw_config_zhihu_probe.json
examples/

1
Cargo.lock generated
View File

@@ -2384,6 +2384,7 @@ dependencies = [
"serde",
"serde_json",
"sha2",
"tempfile",
"thiserror 1.0.69",
"tokio",
"toml 0.8.23",

View File

@@ -22,3 +22,6 @@ tungstenite = "0.29"
uuid = { version = "1", features = ["v4"] }
zip = { version = "0.6.6", default-features = false, features = ["deflate"] }
zeroclaw = { package = "zeroclawlabs", path = "third_party/zeroclaw", default-features = false }
[dev-dependencies]
tempfile = "3"

View File

@@ -1,10 +1,565 @@
use std::any::Any;
use std::fs::{self, OpenOptions};
use std::io::Write;
use std::panic::{self, AssertUnwindSafe};
use std::path::{Path, PathBuf};
use std::process::ExitCode;
use sgclaw::config::SgClawSettings;
use sgclaw::generated_scene::scheduled_monitoring_runtime::{
run_scheduled_monitoring_command_adapter, run_scheduled_monitoring_skill_command_adapter,
run_scheduled_monitoring_skill_command_adapter_many,
ScheduledMonitoringCommandAdapterRequest, ScheduledMonitoringSkillCommandAdapterRequest,
ScheduledMonitoringSkillCommandAdapterManyRequest,
};
use serde_json::json;
fn main() -> ExitCode {
if let Err(err) = sgclaw::service::run() {
eprintln!("sg_claw failed: {err}");
return ExitCode::FAILURE;
let args: Vec<String> = std::env::args().skip(1).collect();
let args_for_log = args.clone();
let working_dir = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
let exit_code =
execute_with_top_level_logging(&working_dir, &args_for_log, || run_main(args));
ExitCode::from(exit_code as u8)
}
fn run_main(args: Vec<String>) -> i32 {
match parse_scheduled_monitoring_cli(args) {
Ok(Some(config)) => {
let result = if let Some(skills_dir) = config.skills_dir.as_ref() {
if config.trigger_paths.len() == 1 {
run_scheduled_monitoring_skill_command_adapter(
ScheduledMonitoringSkillCommandAdapterRequest {
trigger_path: &config.trigger_paths[0],
skills_dir,
config_path: config.config_path.as_deref(),
output_path: &config.output_path,
watch: config.watch,
max_runs: config.max_runs,
},
)
} else {
run_scheduled_monitoring_skill_command_adapter_many(
ScheduledMonitoringSkillCommandAdapterManyRequest {
trigger_paths: &config.trigger_paths,
skills_dir,
config_path: config.config_path.as_deref(),
output_path: &config.output_path,
watch: config.watch,
max_runs: config.max_runs,
},
)
}
} else {
if config.trigger_paths.len() != 1 {
eprintln!(
"scheduled monitoring trigger failed: multiple --scheduled-monitoring-trigger values require --skills-dir"
);
return 1;
}
run_scheduled_monitoring_command_adapter(ScheduledMonitoringCommandAdapterRequest {
trigger_path: &config.trigger_paths[0],
contract_path: &config.contract_path,
preview_fixtures_path: &config.fixtures_path,
output_path: &config.output_path,
})
};
match result {
Ok(_) => return 0,
Err(err) => {
eprintln!("scheduled monitoring trigger failed: {err}");
return 1;
}
}
}
Ok(None) => {}
Err(err) => {
eprintln!("sg_claw argument error: {err}");
return 1;
}
}
ExitCode::SUCCESS
if let Err(err) = sgclaw::service::run() {
eprintln!("sg_claw failed: {err}");
return 1;
}
0
}
fn execute_with_top_level_logging<F>(working_dir: &Path, args: &[String], runner: F) -> i32
where
F: FnOnce() -> i32,
{
let started_at = chrono::Local::now().to_rfc3339();
let outcome = panic::catch_unwind(AssertUnwindSafe(runner));
match outcome {
Ok(exit_code) => {
append_watch_exit_log(
working_dir,
&started_at,
args,
"process_exit",
if exit_code == 0 { "success" } else { "failure" },
exit_code,
None,
);
exit_code
}
Err(payload) => {
let panic_message = extract_panic_message(payload.as_ref());
append_watch_exit_log(
working_dir,
&started_at,
args,
"process_panic",
"panic",
1,
Some(&panic_message),
);
eprintln!("sg_claw panicked: {panic_message}");
1
}
}
}
fn extract_panic_message(payload: &(dyn Any + Send)) -> String {
if let Some(message) = payload.downcast_ref::<String>() {
return message.clone();
}
if let Some(message) = payload.downcast_ref::<&str>() {
return (*message).to_string();
}
"unknown panic payload".to_string()
}
fn append_watch_exit_log(
working_dir: &Path,
started_at: &str,
args: &[String],
event: &str,
outcome: &str,
exit_code: i32,
message: Option<&str>,
) {
let log_path = working_dir.join("results").join("sgclaw-watch-fatal.log");
if let Some(parent) = log_path.parent() {
let _ = fs::create_dir_all(parent);
}
let payload = json!({
"ts": chrono::Local::now().to_rfc3339(),
"event": event,
"outcome": outcome,
"exitCode": exit_code,
"startedAt": started_at,
"cwd": working_dir.display().to_string(),
"watch": args.iter().any(|arg| arg == "--watch"),
"args": args,
"message": message,
});
if let Ok(mut file) = OpenOptions::new().create(true).append(true).open(&log_path) {
let _ = writeln!(file, "{payload}");
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct ScheduledMonitoringCliConfig {
trigger_paths: Vec<PathBuf>,
output_path: PathBuf,
skills_dir: Option<PathBuf>,
config_path: Option<PathBuf>,
contract_path: PathBuf,
fixtures_path: PathBuf,
watch: bool,
max_runs: Option<usize>,
}
fn parse_scheduled_monitoring_cli(
args: Vec<String>,
) -> Result<Option<ScheduledMonitoringCliConfig>, String> {
let mut trigger_paths = Vec::new();
let mut output_path = None;
let mut skills_dir = None;
let mut config_path = None;
let mut contract_path = None;
let mut fixtures_path = None;
let mut watch = false;
let mut max_runs = None;
let mut iter = args.into_iter();
while let Some(arg) = iter.next() {
match arg.as_str() {
"--scheduled-monitoring-trigger" => {
trigger_paths.push(PathBuf::from(next_arg(
&mut iter,
"--scheduled-monitoring-trigger",
)?));
}
"--output" => {
output_path = Some(PathBuf::from(next_arg(&mut iter, "--output")?));
}
"--skills-dir" => {
skills_dir = Some(PathBuf::from(next_arg(&mut iter, "--skills-dir")?));
}
"--config-path" => {
config_path = Some(resolve_process_path(PathBuf::from(next_arg(
&mut iter,
"--config-path",
)?)));
}
"--scheduled-monitoring-contract" => {
contract_path = Some(PathBuf::from(next_arg(
&mut iter,
"--scheduled-monitoring-contract",
)?));
}
"--scheduled-monitoring-fixtures" => {
fixtures_path = Some(PathBuf::from(next_arg(
&mut iter,
"--scheduled-monitoring-fixtures",
)?));
}
"--watch" => {
watch = true;
}
"--max-runs" => {
max_runs = Some(parse_usize_arg(&mut iter, "--max-runs")?);
}
_ => {
if let Some(value) = arg.strip_prefix("--scheduled-monitoring-trigger=") {
trigger_paths.push(PathBuf::from(value));
} else if let Some(value) = arg.strip_prefix("--output=") {
output_path = Some(PathBuf::from(value));
} else if let Some(value) = arg.strip_prefix("--skills-dir=") {
skills_dir = Some(PathBuf::from(value));
} else if let Some(value) = arg.strip_prefix("--config-path=") {
config_path = Some(resolve_process_path(PathBuf::from(value)));
} else if let Some(value) = arg.strip_prefix("--scheduled-monitoring-contract=") {
contract_path = Some(PathBuf::from(value));
} else if let Some(value) = arg.strip_prefix("--scheduled-monitoring-fixtures=") {
fixtures_path = Some(PathBuf::from(value));
} else if let Some(value) = arg.strip_prefix("--max-runs=") {
max_runs = Some(
value
.parse::<usize>()
.map_err(|_| format!("invalid value for --max-runs: {value}"))?,
);
}
}
}
}
if trigger_paths.is_empty() {
if watch {
if let Some(config_path) = config_path.as_deref() {
if let Some(settings) =
SgClawSettings::load(Some(config_path)).map_err(|err| err.to_string())?
{
trigger_paths = settings
.scheduled_monitoring_watch_tasks
.into_iter()
.map(PathBuf::from)
.collect();
}
}
}
if trigger_paths.is_empty() {
return Ok(None);
}
}
let output_path = output_path.ok_or_else(|| {
"missing required --output for --scheduled-monitoring-trigger".to_string()
})?;
Ok(Some(ScheduledMonitoringCliConfig {
trigger_paths,
output_path,
skills_dir,
config_path,
contract_path: contract_path.unwrap_or_else(|| {
PathBuf::from(
"tests/fixtures/generated_scene/scheduled_monitoring_action_trigger_runtime_contract_2026-04-22.json",
)
}),
fixtures_path: fixtures_path.unwrap_or_else(|| {
PathBuf::from(
"tests/fixtures/generated_scene/monitoring_action_mock_validation_fixtures_2026-04-22.json",
)
}),
watch,
max_runs,
}))
}
fn next_arg(iter: &mut impl Iterator<Item = String>, flag: &str) -> Result<String, String> {
iter.next()
.ok_or_else(|| format!("missing value for {flag}"))
}
fn parse_usize_arg(iter: &mut impl Iterator<Item = String>, flag: &str) -> Result<usize, String> {
let value = next_arg(iter, flag)?;
value
.parse::<usize>()
.map_err(|_| format!("invalid value for {flag}: {value}"))
}
fn resolve_process_path(path: PathBuf) -> PathBuf {
if path.is_absolute() {
path
} else {
std::env::current_dir()
.unwrap_or_else(|_| PathBuf::from("."))
.join(path)
}
}
#[cfg(test)]
mod tests {
use super::{execute_with_top_level_logging, parse_scheduled_monitoring_cli};
use serde_json::Value;
use std::fs;
use std::path::{Path, PathBuf};
use std::time::{SystemTime, UNIX_EPOCH};
fn temp_json_file(prefix: &str, body: &str) -> PathBuf {
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos();
let path = std::env::temp_dir().join(format!("{prefix}-{nanos}.json"));
fs::write(&path, body).unwrap();
path
}
fn temp_workspace(prefix: &str) -> PathBuf {
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos();
let path = std::env::temp_dir().join(format!("{prefix}-{nanos}"));
fs::create_dir_all(path.join("results")).unwrap();
path
}
fn read_exit_log_line(workspace: &Path) -> Value {
let raw = fs::read_to_string(workspace.join("results").join("sgclaw-watch-fatal.log"))
.unwrap();
serde_json::from_str(raw.lines().last().unwrap()).unwrap()
}
#[test]
fn scheduled_monitoring_cli_is_absent_by_default() {
assert!(parse_scheduled_monitoring_cli(vec![
"--config-path".to_string(),
"sgclaw_config.json".to_string(),
])
.unwrap()
.is_none());
}
#[test]
fn scheduled_monitoring_cli_requires_output() {
let error = parse_scheduled_monitoring_cli(vec![
"--scheduled-monitoring-trigger".to_string(),
"trigger.json".to_string(),
])
.unwrap_err();
assert!(error.contains("missing required --output"));
}
#[test]
fn scheduled_monitoring_cli_parses_trigger_output_and_defaults() {
let config = parse_scheduled_monitoring_cli(vec![
"--scheduled-monitoring-trigger".to_string(),
"trigger.json".to_string(),
"--output".to_string(),
"run-record.json".to_string(),
])
.unwrap()
.unwrap();
assert_eq!(config.trigger_paths, vec![PathBuf::from("trigger.json")]);
assert_eq!(config.output_path, PathBuf::from("run-record.json"));
assert_eq!(config.skills_dir, None);
assert!(config
.contract_path
.ends_with("scheduled_monitoring_action_trigger_runtime_contract_2026-04-22.json"));
assert!(config
.fixtures_path
.ends_with("monitoring_action_mock_validation_fixtures_2026-04-22.json"));
}
#[test]
fn scheduled_monitoring_cli_parses_optional_skills_dir() {
let config = parse_scheduled_monitoring_cli(vec![
"--scheduled-monitoring-trigger".to_string(),
"trigger.json".to_string(),
"--output".to_string(),
"run-record.json".to_string(),
"--skills-dir".to_string(),
"skills".to_string(),
"--config-path".to_string(),
"sgclaw_config.json".to_string(),
])
.unwrap()
.unwrap();
assert_eq!(config.skills_dir, Some(PathBuf::from("skills")));
assert!(
config
.config_path
.as_ref()
.is_some_and(|path| path.ends_with("sgclaw_config.json"))
);
}
#[test]
fn scheduled_monitoring_cli_parses_watch_and_max_runs() {
let config = parse_scheduled_monitoring_cli(vec![
"--scheduled-monitoring-trigger".to_string(),
"trigger.json".to_string(),
"--output".to_string(),
"run-record.json".to_string(),
"--watch".to_string(),
"--max-runs".to_string(),
"2".to_string(),
])
.unwrap()
.unwrap();
assert!(config.watch);
assert_eq!(config.max_runs, Some(2));
}
#[test]
fn scheduled_monitoring_cli_parses_multiple_triggers() {
let config = parse_scheduled_monitoring_cli(vec![
"--scheduled-monitoring-trigger".to_string(),
"fee.json".to_string(),
"--scheduled-monitoring-trigger".to_string(),
"archive.json".to_string(),
"--output".to_string(),
"watch-run-record.json".to_string(),
"--skills-dir".to_string(),
"skills".to_string(),
"--watch".to_string(),
])
.unwrap()
.unwrap();
assert_eq!(
config.trigger_paths,
vec![PathBuf::from("fee.json"), PathBuf::from("archive.json")]
);
assert_eq!(config.output_path, PathBuf::from("watch-run-record.json"));
assert_eq!(config.skills_dir, Some(PathBuf::from("skills")));
assert!(config.watch);
}
#[test]
fn scheduled_monitoring_cli_loads_watch_tasks_from_config_when_watch_has_no_trigger() {
let config_path = temp_json_file(
"sgclaw-watch-config",
r#"{
"apiKey": "sk-test",
"baseUrl": "https://api.deepseek.com",
"model": "deepseek-chat",
"scheduledMonitoring": {
"watchTasks": [
"handoff/trigger.read_only.template.json",
"handoff/trigger.archive_workorder_grid_push.template.json"
]
}
}"#,
);
let config = parse_scheduled_monitoring_cli(vec![
"--config-path".to_string(),
config_path.to_string_lossy().into_owned(),
"--skills-dir".to_string(),
"skills".to_string(),
"--output".to_string(),
"watch-run-record.json".to_string(),
"--watch".to_string(),
])
.unwrap()
.unwrap();
assert_eq!(
config.trigger_paths,
vec![
PathBuf::from("handoff/trigger.read_only.template.json"),
PathBuf::from("handoff/trigger.archive_workorder_grid_push.template.json")
]
);
}
#[test]
fn scheduled_monitoring_cli_explicit_trigger_overrides_config_watch_tasks() {
let config_path = temp_json_file(
"sgclaw-watch-config-override",
r#"{
"apiKey": "sk-test",
"baseUrl": "https://api.deepseek.com",
"model": "deepseek-chat",
"scheduledMonitoring": {
"watchTasks": [
"handoff/trigger.read_only.template.json",
"handoff/trigger.archive_workorder_grid_push.template.json"
]
}
}"#,
);
let config = parse_scheduled_monitoring_cli(vec![
"--config-path".to_string(),
config_path.to_string_lossy().into_owned(),
"--scheduled-monitoring-trigger".to_string(),
"only-this.json".to_string(),
"--output".to_string(),
"watch-run-record.json".to_string(),
"--watch".to_string(),
])
.unwrap()
.unwrap();
assert_eq!(config.trigger_paths, vec![PathBuf::from("only-this.json")]);
}
#[test]
fn top_level_logging_records_non_zero_exit() {
let workspace = temp_workspace("sgclaw-exit-log");
let args = vec!["--watch".to_string(), "--output".to_string(), "watch-run-record.json".to_string()];
let exit_code = execute_with_top_level_logging(&workspace, &args, || 1);
assert_eq!(exit_code, 1);
let payload = read_exit_log_line(&workspace);
assert_eq!(payload["event"], "process_exit");
assert_eq!(payload["outcome"], "failure");
assert_eq!(payload["exitCode"], 1);
assert_eq!(payload["watch"], true);
assert_eq!(payload["args"][0], "--watch");
}
#[test]
fn top_level_logging_records_panic_as_failure() {
let workspace = temp_workspace("sgclaw-panic-log");
let args = vec!["--watch".to_string()];
let exit_code = execute_with_top_level_logging(&workspace, &args, || {
panic!("boom");
});
assert_eq!(exit_code, 1);
let payload = read_exit_log_line(&workspace);
assert_eq!(payload["event"], "process_panic");
assert_eq!(payload["outcome"], "panic");
assert_eq!(payload["exitCode"], 1);
assert_eq!(payload["message"], "boom");
}
}

View File

@@ -442,21 +442,69 @@ fn build_get_text_js(source_url: &str, selector: &str) -> String {
fn build_eval_js(source_url: &str, script: &str) -> String {
let escaped_source_url = escape_js_single_quoted(source_url);
let escaped_script = escape_js_single_quoted(script);
let callback = EVAL_CALLBACK_NAME;
let events_url = escape_js_single_quoted(&events_endpoint_url(source_url));
let script_len = script.len();
let eval_sentinel = format!("sgclaw-eval-wrapper-{script_len}");
eprintln!(
"[callback_backend] build_eval_js source_url={} script_len={} sentinel={}",
source_url,
script_len,
eval_sentinel
);
format!(
"(function(){{try{{\
var v=(function(){{return {script}}})();\
function _s(v){{\
var t=(typeof v==='string')?v:JSON.stringify(v);\
var __sgclawEvalSentinel='{eval_sentinel}';\
function _j(v){{\
if(typeof v==='string')return v;\
try{{return JSON.stringify(v);}}catch(_){{return String(v);}}\
}}\
function _e(err){{\
if(!err)return{{message:'unknown error'}};\
if(typeof err==='string')return{{message:err}};\
return {{\
name: err.name||'Error',\
message: err.message||String(err),\
stack: err.stack||'',\
code: err.code||'',\
stage: err.stage||'',\
url: err.url||'',\
timeoutMs: err.timeoutMs||0,\
trace: err.trace||null\
}};\
}}\
function _emit(payload){{\
var t=_j(payload);\
try{{callBackJsToCpp('{escaped_source_url}@_@'+window.location.href+'@_@{callback}@_@sgBrowserExcuteJsCodeByDomain@_@'+(t??''))}}catch(_){{}}\
var j=JSON.stringify({{type:'callback',callback:'{callback}',request_url:'{escaped_source_url}',payload:{{value:(t??'')}}}});\
var j=JSON.stringify({{type:'callback',callback:'{callback}',request_url:'{escaped_source_url}',payload:payload}});\
try{{var r=new XMLHttpRequest();r.open('POST','{events_url}',true);r.setRequestHeader('Content-Type','application/json');r.send(j)}}catch(_){{}}\
try{{navigator.sendBeacon('{events_url}',new Blob([j],{{type:'application/json'}}))}}catch(_){{}}\
}}\
if(v&&typeof v.then==='function'){{v.then(_s).catch(function(){{}});}}else{{_s(v);}}\
}}catch(e){{}}}})()"
var _compiled;\
try{{\
_compiled = new Function('return ({escaped_script});');\
}}catch(compileErr){{\
_emit({{value:null,error:_e(compileErr),phase:'eval_compile_failed'}});\
return;\
}}\
var v;\
try{{\
v = _compiled();\
}}catch(runErr){{\
_emit({{value:null,error:_e(runErr),phase:'eval_runtime_failed'}});\
return;\
}}\
function _s(v){{_emit({{value:v??null,error:null}});}}\
function _f(err){{_emit({{value:null,error:_e(err)}});}}\
if(v&&typeof v.then==='function'){{v.then(_s).catch(_f);}}else{{_s(v);}}\
}}catch(e){{\
var payload={{value:null,error:{{name:e&&e.name||'Error',message:e&&e.message||String(e),stack:e&&e.stack||''}}}};\
try{{callBackJsToCpp('{escaped_source_url}@_@'+window.location.href+'@_@{callback}@_@sgBrowserExcuteJsCodeByDomain@_@'+JSON.stringify(payload))}}catch(_){{}}\
try{{var j=JSON.stringify({{type:'callback',callback:'{callback}',request_url:'{escaped_source_url}',payload:payload}});var r=new XMLHttpRequest();r.open('POST','{events_url}',true);r.setRequestHeader('Content-Type','application/json');r.send(j)}}catch(_){{}}\
try{{navigator.sendBeacon('{events_url}',new Blob([JSON.stringify({{type:'callback',callback:'{callback}',request_url:'{escaped_source_url}',payload:payload}})],{{type:'application/json'}}))}}catch(_){{}}\
}}}})()"
)
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,297 @@
use chrono::Local;
use serde::Serialize;
use std::fs::{self, File, OpenOptions};
use std::io::{BufWriter, Write};
use std::path::PathBuf;
use std::sync::Mutex;
#[derive(Debug)]
pub(crate) struct CallbackHostLifecycleLogger {
path: PathBuf,
writer: Mutex<Option<BufWriter<File>>>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct SharedLifecycleFields {
pub ts: String,
pub event: String,
pub host_instance_id: String,
pub run_id: String,
pub skill_id: String,
pub helper_url: String,
pub listener_port: u16,
pub thread: String,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct HostCreateEvent {
#[serde(flatten)]
pub shared: SharedLifecycleFields,
pub browser_ws_url: String,
pub use_hidden_domain: bool,
pub request_url: String,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct ReadyStateTransitionEvent {
#[serde(flatten)]
pub shared: SharedLifecycleFields,
pub helper_loaded: bool,
pub ready: bool,
pub source: String,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct CommandIssueEvent {
#[serde(flatten)]
pub shared: SharedLifecycleFields,
pub seq: u64,
pub action: String,
pub script_len: usize,
pub expected_domain: String,
pub request_url: String,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct PollErrorEvent {
#[serde(flatten)]
pub shared: SharedLifecycleFields,
pub seq: Option<u64>,
pub message: String,
pub elapsed_ms: Option<u128>,
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct HostDropEvent {
#[serde(flatten)]
pub shared: SharedLifecycleFields,
pub uptime_ms: u128,
pub matched_callback_count: u64,
pub unmatched_callback_count: u64,
pub poll_error_count: u64,
pub helper_loaded: bool,
pub ready: bool,
pub drop_join_ok: bool,
}
impl CallbackHostLifecycleLogger {
pub(crate) fn new(path: PathBuf) -> Self {
Self {
path,
writer: Mutex::new(None),
}
}
pub(crate) fn now_local_rfc3339() -> String {
Local::now().to_rfc3339()
}
pub(crate) fn write_host_create(&self, event: HostCreateEvent) -> std::io::Result<()> {
self.write_line(&event)
}
pub(crate) fn write_ready_state_transition(
&self,
event: ReadyStateTransitionEvent,
) -> std::io::Result<()> {
self.write_line(&event)
}
pub(crate) fn write_command_issue(&self, event: CommandIssueEvent) -> std::io::Result<()> {
self.write_line(&event)
}
pub(crate) fn write_poll_error(&self, event: PollErrorEvent) -> std::io::Result<()> {
self.write_line(&event)
}
pub(crate) fn write_host_drop(&self, event: HostDropEvent) -> std::io::Result<()> {
self.write_line(&event)
}
fn ensure_writer(&self) -> std::io::Result<()> {
let mut guard = self.writer.lock().unwrap();
if guard.is_none() {
if let Some(parent) = self.path.parent() {
fs::create_dir_all(parent)?;
}
let file = OpenOptions::new()
.create(true)
.append(true)
.open(&self.path)?;
*guard = Some(BufWriter::new(file));
}
Ok(())
}
fn write_line<T: Serialize>(&self, value: &T) -> std::io::Result<()> {
self.ensure_writer()?;
let mut guard = self.writer.lock().unwrap();
let writer = guard.as_mut().expect("writer initialized");
serde_json::to_writer(&mut *writer, value)?;
writer.write_all(b"\n")?;
writer.flush()?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::{
CallbackHostLifecycleLogger, CommandIssueEvent, HostCreateEvent, HostDropEvent,
PollErrorEvent, ReadyStateTransitionEvent,
SharedLifecycleFields,
};
#[test]
fn lifecycle_log_writes_host_create_event_with_shared_fields() {
let dir = tempfile::tempdir().unwrap();
let log_path = dir.path().join("callback-host-lifecycle.ndjson");
let logger = CallbackHostLifecycleLogger::new(log_path.clone());
logger
.write_host_create(HostCreateEvent {
shared: SharedLifecycleFields {
ts: "2026-04-29T21:15:32.123+08:00".to_string(),
event: "host_create".to_string(),
host_instance_id: "cbh-000123".to_string(),
run_id: "run-001".to_string(),
skill_id: "command-center-fee-control-monitor".to_string(),
helper_url: "http://127.0.0.1:60882/sgclaw/browser-helper.html".to_string(),
listener_port: 60882,
thread: "callback-host".to_string(),
},
browser_ws_url: "ws://127.0.0.1:12345".to_string(),
use_hidden_domain: true,
request_url: "http://yx.gs.sgcc.com.cn/".to_string(),
})
.unwrap();
let text = std::fs::read_to_string(log_path).unwrap();
assert!(text.contains("\"event\":\"host_create\""));
assert!(text.contains("\"hostInstanceId\":\"cbh-000123\""));
assert!(text.contains("\"listenerPort\":60882"));
assert!(text.contains("\"browserWsUrl\":\"ws://127.0.0.1:12345\""));
}
#[test]
fn lifecycle_log_writes_ready_state_transition_event() {
let dir = tempfile::tempdir().unwrap();
let log_path = dir.path().join("callback-host-lifecycle.ndjson");
let logger = CallbackHostLifecycleLogger::new(log_path.clone());
logger
.write_ready_state_transition(ReadyStateTransitionEvent {
shared: SharedLifecycleFields {
ts: "2026-04-29T21:15:32.441+08:00".to_string(),
event: "ready_state_transition".to_string(),
host_instance_id: "cbh-000123".to_string(),
run_id: "run-001".to_string(),
skill_id: "command-center-fee-control-monitor".to_string(),
helper_url: "http://127.0.0.1:60882/sgclaw/browser-helper.html".to_string(),
listener_port: 60882,
thread: "callback-host".to_string(),
},
helper_loaded: true,
ready: true,
source: "ready_endpoint_hit".to_string(),
})
.unwrap();
let text = std::fs::read_to_string(log_path).unwrap();
assert!(text.contains("\"event\":\"ready_state_transition\""));
assert!(text.contains("\"helperLoaded\":true"));
assert!(text.contains("\"ready\":true"));
assert!(text.contains("\"source\":\"ready_endpoint_hit\""));
}
#[test]
fn lifecycle_log_writes_command_issue_and_poll_error_events() {
let dir = tempfile::tempdir().unwrap();
let log_path = dir.path().join("callback-host-lifecycle.ndjson");
let logger = CallbackHostLifecycleLogger::new(log_path.clone());
logger
.write_command_issue(CommandIssueEvent {
shared: SharedLifecycleFields {
ts: "2026-04-29T21:15:33.018+08:00".to_string(),
event: "command_issue".to_string(),
host_instance_id: "cbh-000123".to_string(),
run_id: "run-001".to_string(),
skill_id: "command-center-fee-control-monitor".to_string(),
helper_url: "http://127.0.0.1:60882/sgclaw/browser-helper.html".to_string(),
listener_port: 60882,
thread: "callback-host".to_string(),
},
seq: 2,
action: "eval".to_string(),
script_len: 29470,
expected_domain: "yx.gs.sgcc.com.cn".to_string(),
request_url: "http://127.0.0.1:60882/sgclaw/browser-helper.html".to_string(),
})
.unwrap();
logger
.write_poll_error(PollErrorEvent {
shared: SharedLifecycleFields {
ts: "2026-04-29T21:15:36.566+08:00".to_string(),
event: "poll_error".to_string(),
host_instance_id: "cbh-000123".to_string(),
run_id: "run-001".to_string(),
skill_id: "command-center-fee-control-monitor".to_string(),
helper_url: "http://127.0.0.1:60882/sgclaw/browser-helper.html".to_string(),
listener_port: 60882,
thread: "callback-host".to_string(),
},
seq: Some(2),
message: "Failed to fetch".to_string(),
elapsed_ms: Some(3548),
})
.unwrap();
let text = std::fs::read_to_string(log_path).unwrap();
assert!(text.contains("\"event\":\"command_issue\""));
assert!(text.contains("\"scriptLen\":29470"));
assert!(text.contains("\"event\":\"poll_error\""));
assert!(text.contains("\"message\":\"Failed to fetch\""));
}
#[test]
fn lifecycle_log_writes_host_drop_event() {
let dir = tempfile::tempdir().unwrap();
let log_path = dir.path().join("callback-host-lifecycle.ndjson");
let logger = CallbackHostLifecycleLogger::new(log_path.clone());
logger
.write_host_drop(HostDropEvent {
shared: SharedLifecycleFields {
ts: "2026-04-29T21:15:58.020+08:00".to_string(),
event: "host_drop".to_string(),
host_instance_id: "cbh-000123".to_string(),
run_id: "run-001".to_string(),
skill_id: "command-center-fee-control-monitor".to_string(),
helper_url: "http://127.0.0.1:60882/sgclaw/browser-helper.html".to_string(),
listener_port: 60882,
thread: "callback-host".to_string(),
},
uptime_ms: 23340,
matched_callback_count: 2,
unmatched_callback_count: 14,
poll_error_count: 11,
helper_loaded: true,
ready: true,
drop_join_ok: true,
})
.unwrap();
let text = std::fs::read_to_string(log_path).unwrap();
assert!(text.contains("\"event\":\"host_drop\""));
assert!(text.contains("\"uptimeMs\":23340"));
assert!(text.contains("\"dropJoinOk\":true"));
}
}

View File

@@ -4,6 +4,7 @@ pub mod bridge_contract;
pub mod bridge_transport;
pub mod callback_backend;
pub(crate) mod callback_host;
pub(crate) mod callback_host_lifecycle_log;
mod pipe_backend;
pub mod ws_backend;
pub mod ws_probe;

View File

@@ -1,3 +1,4 @@
use std::fs;
use std::net::TcpStream;
use std::time::Duration;
@@ -83,24 +84,23 @@ pub fn parse_probe_args(args: &[String]) -> Result<ProbeCliConfig, ProbeError> {
let value = args
.get(index)
.ok_or_else(|| ProbeError::Args("missing value for --step".to_string()))?;
let (label, payload) = value.split_once("::").ok_or_else(|| {
ProbeError::Args(format!(
"invalid --step value (expected <label>::<payload>): {value}"
))
steps.push(parse_step_value(value, "--step")?);
}
"--step-file" => {
index += 1;
let value = args.get(index).ok_or_else(|| {
ProbeError::Args("missing value for --step-file".to_string())
})?;
if label.is_empty() {
return Err(ProbeError::Args("step label must not be empty".to_string()));
let contents = fs::read_to_string(value).map_err(|err| {
ProbeError::Args(format!("failed to read --step-file {value}: {err}"))
})?;
let normalized = contents.trim();
if normalized.is_empty() {
return Err(ProbeError::Args(format!(
"--step-file must not be empty: {value}"
)));
}
if payload.is_empty() {
return Err(ProbeError::Args(
"step payload must not be empty".to_string(),
));
}
steps.push(ProbeStep {
label: label.to_string(),
payload: payload.to_string(),
expect_reply: true,
});
steps.push(parse_step_value(normalized, "--step-file")?);
}
flag => {
return Err(ProbeError::Args(format!("unknown argument: {flag}")));
@@ -127,6 +127,27 @@ pub fn parse_probe_args(args: &[String]) -> Result<ProbeCliConfig, ProbeError> {
})
}
fn parse_step_value(value: &str, source: &str) -> Result<ProbeStep, ProbeError> {
let (label, payload) = value.split_once("::").ok_or_else(|| {
ProbeError::Args(format!(
"invalid {source} value (expected <label>::<payload>): {value}"
))
})?;
if label.is_empty() {
return Err(ProbeError::Args("step label must not be empty".to_string()));
}
if payload.is_empty() {
return Err(ProbeError::Args(
"step payload must not be empty".to_string(),
));
}
Ok(ProbeStep {
label: label.to_string(),
payload: payload.to_string(),
expect_reply: true,
})
}
fn validate_ws_url(ws_url: &str) -> Result<(), ProbeError> {
if ws_url.starts_with("ws://") {
return Ok(());

View File

@@ -12,6 +12,18 @@ use zeroclaw::tools::{Tool, ToolResult};
use crate::browser::BrowserBackend;
use crate::pipe::Action;
fn preview_utf8(text: &str, max_chars: usize) -> &str {
if text.chars().count() <= max_chars {
return text;
}
let mut end = 0usize;
for (idx, ch) in text.char_indices().take(max_chars) {
end = idx + ch.len_utf8();
}
&text[..end]
}
pub struct BrowserScriptSkillTool {
tool_name: String,
tool_description: String,
@@ -269,11 +281,7 @@ fn execute_browser_script_impl(
);
eprintln!(
"[execute_browser_script_impl] 包装后脚本前500字符: {}",
if wrapped_script.len() > 500 {
&wrapped_script[..500]
} else {
&wrapped_script
}
preview_utf8(&wrapped_script, 500)
);
eprintln!("[execute_browser_script_impl] 调用 browser_tool.invoke(Action::Eval)...");

View File

@@ -165,13 +165,23 @@ fn build_scene_execution_plan(
instruction: &str,
mut args: Map<String, Value>,
) -> SceneExecutionPlan {
let bootstrap = entry
.manifest
.bootstrap
.as_ref()
.expect("report scene registry should only contain manifests with bootstrap");
let artifact = entry
.manifest
.artifact
.as_ref()
.expect("report scene registry should only contain manifests with artifact");
args.insert(
"expected_domain".to_string(),
Value::String(entry.manifest.bootstrap.expected_domain.clone()),
Value::String(bootstrap.expected_domain.clone()),
);
args.insert(
"target_url".to_string(),
Value::String(entry.manifest.bootstrap.target_url.clone()),
Value::String(bootstrap.target_url.clone()),
);
SceneExecutionPlan {
@@ -181,11 +191,11 @@ fn build_scene_execution_plan(
"{}.{}",
entry.manifest.scene.skill, entry.manifest.scene.tool
),
expected_domain: entry.manifest.bootstrap.expected_domain.clone(),
target_url: entry.manifest.bootstrap.target_url.clone(),
expected_domain: bootstrap.expected_domain.clone(),
target_url: bootstrap.target_url.clone(),
args,
success_statuses: entry.manifest.artifact.success_status.clone(),
failure_statuses: entry.manifest.artifact.failure_status.clone(),
success_statuses: artifact.success_status.clone(),
failure_statuses: artifact.failure_status.clone(),
postprocess: entry.manifest.postprocess.clone(),
}
}
@@ -252,7 +262,8 @@ fn score_scene(
page_url: Option<&str>,
page_title: Option<&str>,
) -> Option<usize> {
let deterministic = &entry.manifest.deterministic;
let deterministic = entry.manifest.deterministic.as_ref()?;
let bootstrap = entry.manifest.bootstrap.as_ref()?;
if deterministic.suffix != DETERMINISTIC_SUFFIX {
return None;
}
@@ -279,11 +290,7 @@ fn score_scene(
let normalized_url = page_url.unwrap_or_default().to_ascii_lowercase();
if !normalized_url.is_empty() {
if normalized_url.contains(
&entry
.manifest
.bootstrap
.expected_domain
.to_ascii_lowercase(),
&bootstrap.expected_domain.to_ascii_lowercase(),
) {
score += 100;
} else if normalized_url.contains(&entry.manifest.scene.id.to_ascii_lowercase()) {
@@ -296,6 +303,7 @@ fn score_scene(
&& entry
.manifest
.bootstrap
.as_ref()?
.page_title_keywords
.iter()
.any(|keyword| !keyword.trim().is_empty() && title.contains(keyword.as_str()))
@@ -324,8 +332,18 @@ fn log_registry_diag(registry: &[SceneRegistryEntry]) {
registry.len(),
DIAGNOSTIC_SCENE_ID,
entry.skill_root.display(),
entry.manifest.deterministic.suffix == DETERMINISTIC_SUFFIX,
entry.manifest.deterministic.include_keywords
entry
.manifest
.deterministic
.as_ref()
.map(|deterministic| deterministic.suffix == DETERMINISTIC_SUFFIX)
.unwrap_or(false),
entry
.manifest
.deterministic
.as_ref()
.map(|deterministic| deterministic.include_keywords.clone())
.unwrap_or_default()
)),
None => log_deterministic_diag(format!(
"registry loaded count={} diagnostic_scene={} registered=false",
@@ -336,7 +354,13 @@ fn log_registry_diag(registry: &[SceneRegistryEntry]) {
}
fn log_scene_match_diag(entry: &SceneRegistryEntry, instruction: &str) {
let deterministic = &entry.manifest.deterministic;
let Some(deterministic) = entry.manifest.deterministic.as_ref() else {
log_deterministic_diag(format!(
"diagnostic_scene={} deterministic=false",
entry.manifest.scene.id
));
return;
};
let include_hits = deterministic
.include_keywords
.iter()

View File

@@ -1,3 +1,4 @@
pub mod dispatch;
pub mod registry;
pub mod resolvers;
pub mod scheduled_registry;

View File

@@ -0,0 +1,293 @@
use std::collections::HashMap;
use std::fs;
use std::path::{Path, PathBuf};
use thiserror::Error;
use zeroclaw::skills::{load_skills_from_directory, Skill};
use crate::scene_contract::manifest::{
SceneManifest, SCENE_MANIFEST_FILE_NAME, SUPPORTED_SCHEMA_VERSION_V1,
SUPPORTED_SCHEDULED_MONITORING_CATEGORY_V1, SUPPORTED_SCHEDULED_MONITORING_KIND_V1,
};
#[derive(Debug, Clone)]
pub struct ScheduledMonitoringRegistryEntry {
pub manifest: SceneManifest,
pub skill_root: PathBuf,
pub workflow_id: String,
}
#[derive(Debug, Error)]
pub enum ScheduledMonitoringRegistryError {
#[error("failed to read skills directory {path}: {source}")]
ReadSkillsDir {
path: PathBuf,
#[source]
source: std::io::Error,
},
#[error("failed to read scene manifest {path}: {source}")]
ReadManifest {
path: PathBuf,
#[source]
source: std::io::Error,
},
#[error("failed to parse scene manifest {path}: {source}")]
ParseManifest {
path: PathBuf,
#[source]
source: toml::de::Error,
},
#[error("scheduled scene manifest {path} declares unsupported schema_version {version}; only {supported} is supported in v1")]
UnsupportedSchemaVersion {
path: PathBuf,
version: String,
supported: &'static str,
},
#[error("scheduled scene manifest {path} declares unsupported kind {kind}; only {supported} is supported")]
UnsupportedSceneKind {
path: PathBuf,
kind: String,
supported: &'static str,
},
#[error("scheduled scene manifest {path} declares unsupported category {category}; only {supported} is supported")]
UnsupportedSceneCategory {
path: PathBuf,
category: String,
supported: &'static str,
},
#[error("scheduled scene manifest {path} points to missing skill package {skill}")]
MissingSkill { path: PathBuf, skill: String },
#[error("scheduled scene manifest {path} declares skill {manifest_skill}, but containing skill package is {package_skill}")]
SkillPackageMismatch {
path: PathBuf,
manifest_skill: String,
package_skill: String,
},
#[error("scheduled scene manifest {path} is missing trigger section")]
MissingTriggerSection { path: PathBuf },
#[error("scheduled scene manifest {path} is missing modes section")]
MissingModesSection { path: PathBuf },
#[error("scheduled scene manifest {path} is missing runtime_context section")]
MissingRuntimeContextSection { path: PathBuf },
#[error("scheduled scene manifest {path} is missing safety section")]
MissingSafetySection { path: PathBuf },
#[error("scheduled scene manifest {path} is missing tools section")]
MissingToolsSection { path: PathBuf },
#[error("scheduled scene manifest {path} is missing references section")]
MissingReferencesSection { path: PathBuf },
#[error("scheduled scene manifest {path} is missing workflow_id")]
MissingWorkflowId { path: PathBuf },
#[error("scheduled scene manifest {path} has unsafe active or queue_process enablement")]
UnsafeModesEnabled { path: PathBuf },
#[error("scheduled scene manifest {path} incorrectly exposes natural-language primary trigger")]
NaturalLanguagePrimaryEnabled { path: PathBuf },
#[error("scheduled workflow id {workflow_id} is declared twice: {first_path} and {second_path}")]
DuplicateWorkflowId {
workflow_id: String,
first_path: PathBuf,
second_path: PathBuf,
},
}
pub fn load_scheduled_monitoring_registry(
skills_dir: &Path,
) -> Result<Vec<ScheduledMonitoringRegistryEntry>, ScheduledMonitoringRegistryError> {
if !skills_dir.exists() {
return Ok(Vec::new());
}
let mut skill_roots = Vec::new();
for entry in fs::read_dir(skills_dir).map_err(|source| {
ScheduledMonitoringRegistryError::ReadSkillsDir {
path: skills_dir.to_path_buf(),
source,
}
})? {
let entry = entry.map_err(|source| ScheduledMonitoringRegistryError::ReadSkillsDir {
path: skills_dir.to_path_buf(),
source,
})?;
let path = entry.path();
if path.is_dir() {
skill_roots.push(path);
}
}
skill_roots.sort();
let skills_by_root = index_skills_by_root(skills_dir);
let mut workflow_ids = HashMap::new();
let mut registry = Vec::new();
for skill_root in skill_roots {
let manifest_path = skill_root.join(SCENE_MANIFEST_FILE_NAME);
if !manifest_path.exists() {
continue;
}
let manifest = load_manifest(&manifest_path)?;
if manifest.scene.kind != SUPPORTED_SCHEDULED_MONITORING_KIND_V1 {
continue;
}
let workflow_id = validate_manifest(&manifest, &manifest_path, &skill_root, &skills_by_root)?;
if let Some(first_path) = workflow_ids.insert(workflow_id.clone(), manifest_path.clone()) {
return Err(ScheduledMonitoringRegistryError::DuplicateWorkflowId {
workflow_id,
first_path,
second_path: manifest_path,
});
}
registry.push(ScheduledMonitoringRegistryEntry {
manifest,
skill_root,
workflow_id,
});
}
Ok(registry)
}
fn index_skills_by_root(skills_dir: &Path) -> HashMap<PathBuf, Skill> {
load_skills_from_directory(skills_dir, true)
.into_iter()
.filter_map(|skill| {
let skill_root = skill
.location
.as_deref()
.and_then(Path::parent)
.map(Path::to_path_buf)?;
Some((skill_root, skill))
})
.collect()
}
fn load_manifest(path: &Path) -> Result<SceneManifest, ScheduledMonitoringRegistryError> {
let content =
fs::read_to_string(path).map_err(|source| ScheduledMonitoringRegistryError::ReadManifest {
path: path.to_path_buf(),
source,
})?;
toml::from_str(&content).map_err(|source| ScheduledMonitoringRegistryError::ParseManifest {
path: path.to_path_buf(),
source,
})
}
fn validate_manifest(
manifest: &SceneManifest,
manifest_path: &Path,
skill_root: &Path,
skills_by_root: &HashMap<PathBuf, Skill>,
) -> Result<String, ScheduledMonitoringRegistryError> {
if manifest.manifest.schema_version != SUPPORTED_SCHEMA_VERSION_V1 {
return Err(ScheduledMonitoringRegistryError::UnsupportedSchemaVersion {
path: manifest_path.to_path_buf(),
version: manifest.manifest.schema_version.clone(),
supported: SUPPORTED_SCHEMA_VERSION_V1,
});
}
if manifest.scene.kind != SUPPORTED_SCHEDULED_MONITORING_KIND_V1 {
return Err(ScheduledMonitoringRegistryError::UnsupportedSceneKind {
path: manifest_path.to_path_buf(),
kind: manifest.scene.kind.clone(),
supported: SUPPORTED_SCHEDULED_MONITORING_KIND_V1,
});
}
if manifest.scene.category != SUPPORTED_SCHEDULED_MONITORING_CATEGORY_V1 {
return Err(ScheduledMonitoringRegistryError::UnsupportedSceneCategory {
path: manifest_path.to_path_buf(),
category: manifest.scene.category.clone(),
supported: SUPPORTED_SCHEDULED_MONITORING_CATEGORY_V1,
});
}
let trigger = manifest
.trigger
.as_ref()
.ok_or_else(|| ScheduledMonitoringRegistryError::MissingTriggerSection {
path: manifest_path.to_path_buf(),
})?;
let modes = manifest
.modes
.as_ref()
.ok_or_else(|| ScheduledMonitoringRegistryError::MissingModesSection {
path: manifest_path.to_path_buf(),
})?;
let _runtime_context = manifest.runtime_context.as_ref().ok_or_else(|| {
ScheduledMonitoringRegistryError::MissingRuntimeContextSection {
path: manifest_path.to_path_buf(),
}
})?;
let safety = manifest
.safety
.as_ref()
.ok_or_else(|| ScheduledMonitoringRegistryError::MissingSafetySection {
path: manifest_path.to_path_buf(),
})?;
let tools = manifest
.tools
.as_ref()
.ok_or_else(|| ScheduledMonitoringRegistryError::MissingToolsSection {
path: manifest_path.to_path_buf(),
})?;
let _references = manifest.references.as_ref().ok_or_else(|| {
ScheduledMonitoringRegistryError::MissingReferencesSection {
path: manifest_path.to_path_buf(),
}
})?;
let workflow_id = manifest
.scene
.workflow_id
.clone()
.filter(|value| !value.trim().is_empty())
.ok_or_else(|| ScheduledMonitoringRegistryError::MissingWorkflowId {
path: manifest_path.to_path_buf(),
})?;
if safety.active_enabled || safety.queue_process_enabled {
return Err(ScheduledMonitoringRegistryError::UnsafeModesEnabled {
path: manifest_path.to_path_buf(),
});
}
if trigger.natural_language_primary {
return Err(ScheduledMonitoringRegistryError::NaturalLanguagePrimaryEnabled {
path: manifest_path.to_path_buf(),
});
}
if !modes.enabled.iter().any(|mode| mode == "dry_run" || mode == "monitor_only") {
return Err(ScheduledMonitoringRegistryError::UnsafeModesEnabled {
path: manifest_path.to_path_buf(),
});
}
let Some(skill) = skills_by_root.get(skill_root) else {
return Err(ScheduledMonitoringRegistryError::MissingSkill {
path: manifest_path.to_path_buf(),
skill: manifest.scene.skill.clone(),
});
};
if skill.name != manifest.scene.skill {
return Err(ScheduledMonitoringRegistryError::SkillPackageMismatch {
path: manifest_path.to_path_buf(),
manifest_skill: manifest.scene.skill.clone(),
package_skill: skill.name.clone(),
});
}
for expected_tool in [&tools.detect, &tools.decide, &tools.action_plan] {
if expected_tool.trim().is_empty() {
return Err(ScheduledMonitoringRegistryError::MissingToolsSection {
path: manifest_path.to_path_buf(),
});
}
}
Ok(workflow_id)
}

View File

@@ -152,6 +152,8 @@ pub struct SgClawSettings {
pub office_backend: OfficeBackend,
pub browser_ws_url: Option<String>,
pub service_ws_listen_addr: Option<String>,
pub scheduled_monitoring_platform_service_base_url: Option<String>,
pub scheduled_monitoring_watch_tasks: Vec<String>,
}
impl SgClawSettings {
@@ -190,6 +192,8 @@ impl SgClawSettings {
None,
None,
None,
None,
Vec::new(),
)
}
@@ -237,6 +241,16 @@ impl SgClawSettings {
}),
browser_ws_url: self.browser_ws_url.clone(),
service_ws_listen_addr: self.service_ws_listen_addr.clone(),
scheduled_monitoring_platform_service_base_url: self
.scheduled_monitoring_platform_service_base_url
.clone(),
scheduled_monitoring: if self.scheduled_monitoring_watch_tasks.is_empty() {
None
} else {
Some(SerializableScheduledMonitoringSettings {
watch_tasks: self.scheduled_monitoring_watch_tasks.clone(),
})
},
providers: self
.providers
.iter()
@@ -290,6 +304,8 @@ impl SgClawSettings {
None,
None,
None,
None,
Vec::new(),
)?))
}
@@ -376,6 +392,11 @@ impl SgClawSettings {
office_backend,
config.browser_ws_url,
config.service_ws_listen_addr,
config.scheduled_monitoring_platform_service_base_url,
config
.scheduled_monitoring
.map(|value| value.watch_tasks)
.unwrap_or_default(),
)
.map_err(|err| err.with_path(path))
}
@@ -395,6 +416,8 @@ impl SgClawSettings {
office_backend: Option<OfficeBackend>,
browser_ws_url: Option<String>,
service_ws_listen_addr: Option<String>,
scheduled_monitoring_platform_service_base_url: Option<String>,
scheduled_monitoring_watch_tasks: Vec<String>,
) -> Result<Self, ConfigError> {
let direct_submit_skill = normalize_direct_submit_skill(direct_submit_skill)?;
let providers = if providers.is_empty() {
@@ -438,6 +461,10 @@ impl SgClawSettings {
office_backend: office_backend.unwrap_or(OfficeBackend::OpenXml),
browser_ws_url: normalize_optional_value(browser_ws_url),
service_ws_listen_addr: normalize_optional_value(service_ws_listen_addr),
scheduled_monitoring_platform_service_base_url: normalize_optional_value(
scheduled_monitoring_platform_service_base_url,
),
scheduled_monitoring_watch_tasks,
})
}
}
@@ -627,10 +654,26 @@ struct SerializableRawSgClawSettings {
skip_serializing_if = "Option::is_none"
)]
service_ws_listen_addr: Option<String>,
#[serde(
rename = "scheduledMonitoringPlatformServiceBaseUrl",
skip_serializing_if = "Option::is_none"
)]
scheduled_monitoring_platform_service_base_url: Option<String>,
#[serde(
rename = "scheduledMonitoring",
skip_serializing_if = "Option::is_none"
)]
scheduled_monitoring: Option<SerializableScheduledMonitoringSettings>,
#[serde(default)]
providers: Vec<SerializableProviderSettings>,
}
#[derive(Debug, Serialize)]
struct SerializableScheduledMonitoringSettings {
#[serde(rename = "watchTasks")]
watch_tasks: Vec<String>,
}
#[derive(Debug, Serialize)]
struct SerializableProviderSettings {
id: String,
@@ -680,10 +723,24 @@ struct RawSgClawSettings {
default
)]
service_ws_listen_addr: Option<String>,
#[serde(
rename = "scheduledMonitoringPlatformServiceBaseUrl",
alias = "scheduled_monitoring_platform_service_base_url",
default
)]
scheduled_monitoring_platform_service_base_url: Option<String>,
#[serde(rename = "scheduledMonitoring", default)]
scheduled_monitoring: Option<RawScheduledMonitoringSettings>,
#[serde(default)]
providers: Vec<RawProviderSettings>,
}
#[derive(Debug, Deserialize)]
struct RawScheduledMonitoringSettings {
#[serde(rename = "watchTasks", alias = "watch_tasks", default)]
watch_tasks: Vec<String>,
}
#[derive(Debug, Deserialize)]
struct RawProviderSettings {
#[serde(default)]

File diff suppressed because it is too large Load Diff

View File

@@ -21,6 +21,8 @@ pub enum WorkflowArchetype {
LocalDocPipeline,
#[serde(rename = "page_state_eval")]
PageStateEval,
#[serde(rename = "monitoring_action_workflow")]
MonitoringActionWorkflow,
}
impl WorkflowArchetype {
@@ -34,6 +36,7 @@ impl WorkflowArchetype {
Self::MultiEndpointInventory => "multi_endpoint_inventory",
Self::LocalDocPipeline => "local_doc_pipeline",
Self::PageStateEval => "page_state_eval",
Self::MonitoringActionWorkflow => "monitoring_action_workflow",
}
}
@@ -47,6 +50,7 @@ impl WorkflowArchetype {
"multi_endpoint_inventory" => Some(Self::MultiEndpointInventory),
"local_doc_pipeline" => Some(Self::LocalDocPipeline),
"page_state_eval" => Some(Self::PageStateEval),
"monitoring_action_workflow" => Some(Self::MonitoringActionWorkflow),
_ => None,
}
}
@@ -252,6 +256,259 @@ pub struct RuntimeDependencyIr {
pub subordinate_to_business_chain: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct MonitoringRuntimeContextIr {
#[serde(rename = "runtimeContextUrl", default)]
pub runtime_context_url: String,
#[serde(rename = "expectedDomain", default)]
pub expected_domain: String,
#[serde(rename = "gatewayDomain", default)]
pub gateway_domain: String,
#[serde(rename = "localhostServiceBase", default)]
pub localhost_service_base: String,
#[serde(rename = "browserAttachedRequired", default)]
pub browser_attached_required: bool,
#[serde(rename = "hostBridgeRequired", default)]
pub host_bridge_required: bool,
#[serde(
rename = "executionContextMode",
default = "default_execution_context_mode"
)]
pub execution_context_mode: String,
#[serde(
rename = "requestClientMode",
default = "default_request_client_mode"
)]
pub request_client_mode: String,
#[serde(rename = "encryptionMode", default = "default_encryption_mode")]
pub encryption_mode: String,
#[serde(
rename = "attachedPageBrowserActionPolicy",
default = "default_attached_page_browser_action_policy"
)]
pub attached_page_browser_action_policy: String,
#[serde(
rename = "platformWritePolicy",
default = "default_platform_write_policy"
)]
pub platform_write_policy: String,
#[serde(rename = "storageReads", default)]
pub storage_reads: Vec<MonitoringStorageReadIr>,
#[serde(rename = "readSlices", default)]
pub read_slices: Vec<MonitoringReadSliceIr>,
#[serde(rename = "encryptionResolution", default)]
pub encryption_resolution: MonitoringEncryptionResolutionIr,
#[serde(rename = "timeoutContract", default)]
pub timeout_contract: MonitoringTimeoutContractIr,
#[serde(rename = "outputContract", default)]
pub output_contract: MonitoringOutputContractIr,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct MonitoringStorageReadIr {
#[serde(default)]
pub key: String,
#[serde(default)]
pub source: String,
#[serde(rename = "fallbackOrder", default)]
pub fallback_order: Vec<String>,
#[serde(default)]
pub required: bool,
#[serde(rename = "parseMode", default)]
pub parse_mode: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct MonitoringReadSliceIr {
#[serde(default)]
pub name: String,
#[serde(rename = "endpointBinding", default)]
pub endpoint_binding: String,
#[serde(rename = "requestTemplateOverride", default)]
pub request_template_override: Value,
#[serde(rename = "responsePath", default)]
pub response_path: String,
#[serde(rename = "timeoutMs", default)]
pub timeout_ms: u64,
#[serde(rename = "mergeRole", default)]
pub merge_role: String,
#[serde(default)]
pub required: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct MonitoringEncryptionResolutionIr {
#[serde(rename = "primaryMethod", default)]
pub primary_method: String,
#[serde(rename = "fallbackMethods", default)]
pub fallback_methods: Vec<String>,
#[serde(rename = "requiredContext", default)]
pub required_context: Vec<String>,
#[serde(rename = "hardFail", default)]
pub hard_fail: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct MonitoringTimeoutContractIr {
#[serde(rename = "perStepTimeoutMs", default)]
pub per_step_timeout_ms: u64,
#[serde(rename = "overallDetectTimeoutMs", default)]
pub overall_detect_timeout_ms: u64,
#[serde(rename = "statusOnTimeout", default)]
pub status_on_timeout: String,
#[serde(rename = "statusOnPartial", default)]
pub status_on_partial: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct MonitoringSidecarOutputIr {
#[serde(default)]
pub name: String,
#[serde(rename = "relativePath", default)]
pub relative_path: String,
#[serde(rename = "payloadSchema", default)]
pub payload_schema: Value,
#[serde(rename = "sourceField", default)]
pub source_field: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MonitoringOutputContractIr {
#[serde(rename = "runRecordMode", default = "default_run_record_mode")]
pub run_record_mode: String,
#[serde(rename = "businessLogEnabled", default = "default_true")]
pub business_log_enabled: bool,
#[serde(rename = "sidecarOutputs", default)]
pub sidecar_outputs: Vec<MonitoringSidecarOutputIr>,
#[serde(rename = "deltaState", default)]
pub delta_state: Option<MonitoringDeltaStateIr>,
}
impl Default for MonitoringOutputContractIr {
fn default() -> Self {
Self {
run_record_mode: default_run_record_mode(),
business_log_enabled: true,
sidecar_outputs: Vec::new(),
delta_state: None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct MonitoringDeltaStateIr {
#[serde(rename = "identityFields", default)]
pub identity_fields: Vec<String>,
#[serde(rename = "stateSidecarPath", default)]
pub state_sidecar_path: String,
#[serde(rename = "comparisonMode", default)]
pub comparison_mode: String,
#[serde(rename = "emitPolicy", default)]
pub emit_policy: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct MonitoringDependencyIr {
#[serde(default)]
pub name: String,
#[serde(default)]
pub url: String,
#[serde(default)]
pub classification: String,
#[serde(rename = "sideEffect", default)]
pub side_effect: bool,
#[serde(rename = "blockedByDefault", default)]
pub blocked_by_default: bool,
}
impl MonitoringDependencyIr {
pub fn normalized_classification(&self) -> String {
let url = self.url.trim().to_ascii_lowercase();
if url.starts_with("http://localhost:13313/")
|| url.starts_with("https://localhost:13313/")
{
return "host_runtime_local_service".to_string();
}
if url.contains("/monitorservices/")
|| url.contains("/marketingservices/")
|| url.contains("/configservices/")
|| url.contains("/reportservices/")
|| url.contains("/surfaceservices/")
|| url.contains("/msgoffilecenter/")
{
return "remote_platform_service".to_string();
}
let classification = self.classification.trim();
if classification.is_empty() {
String::new()
} else {
classification.to_string()
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct MonitoringSideEffectIr {
#[serde(default)]
pub action: String,
#[serde(default)]
pub signals: Vec<String>,
#[serde(rename = "blockedByDefault", default)]
pub blocked_by_default: bool,
#[serde(rename = "requiredFutureGate", default)]
pub required_future_gate: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct MonitoringSideEffectPolicyIr {
#[serde(rename = "dryRunDefault", default)]
pub dry_run_default: bool,
#[serde(rename = "requiresExplicitConfirmation", default)]
pub requires_explicit_confirmation: bool,
#[serde(rename = "previewBeforeAction", default)]
pub preview_before_action: bool,
#[serde(rename = "maxItemsRequiredForActionModes", default)]
pub max_items_required_for_action_modes: bool,
#[serde(rename = "auditRecordRequired", default)]
pub audit_record_required: bool,
#[serde(rename = "blockedCallSignatures", default)]
pub blocked_call_signatures: Vec<String>,
#[serde(rename = "blockedActions", default)]
pub blocked_actions: Vec<MonitoringSideEffectIr>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct MonitoringActionWorkflowIr {
#[serde(rename = "workflowId", default)]
pub workflow_id: String,
#[serde(rename = "displayName", default)]
pub display_name: String,
#[serde(rename = "defaultMode", default)]
pub default_mode: String,
#[serde(rename = "workflowStages", default)]
pub workflow_stages: Vec<String>,
#[serde(rename = "mvpAllowedStages", default)]
pub mvp_allowed_stages: Vec<String>,
#[serde(rename = "blockedByDefaultStages", default)]
pub blocked_by_default_stages: Vec<String>,
#[serde(rename = "runtimeContext", default)]
pub runtime_context: MonitoringRuntimeContextIr,
#[serde(rename = "localStorageReads", default)]
pub local_storage_reads: Vec<String>,
#[serde(rename = "sessionStorageReads", default)]
pub session_storage_reads: Vec<String>,
#[serde(rename = "localServiceDependencies", default)]
pub local_service_dependencies: Vec<MonitoringDependencyIr>,
#[serde(rename = "businessApiDependencies", default)]
pub business_api_dependencies: Vec<MonitoringDependencyIr>,
#[serde(rename = "previewSchema", default)]
pub preview_schema: Vec<String>,
#[serde(rename = "sideEffectPolicy", default)]
pub side_effect_policy: MonitoringSideEffectPolicyIr,
#[serde(rename = "archetype", default = "default_monitoring_archetype")]
pub archetype: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct MergeFieldMappingIr {
#[serde(rename = "outputField", default)]
@@ -296,6 +553,38 @@ impl Default for ArtifactContractIr {
}
}
fn default_execution_context_mode() -> String {
"attached_page_direct".to_string()
}
fn default_request_client_mode() -> String {
"isolated_xhr".to_string()
}
fn default_encryption_mode() -> String {
"emsslib_data_encrypt_pub".to_string()
}
fn default_attached_page_browser_action_policy() -> String {
"forbid_secondary_jump".to_string()
}
fn default_platform_write_policy() -> String {
"skip_when_zero".to_string()
}
fn default_run_record_mode() -> String {
"per_scene_file".to_string()
}
fn default_true() -> bool {
true
}
fn default_monitoring_archetype() -> String {
"marketing_gateway_monitor".to_string()
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ValidationHintsIr {
#[serde(
@@ -447,6 +736,8 @@ pub struct SceneIr {
pub confidence: f64,
#[serde(default)]
pub uncertainties: Vec<String>,
#[serde(rename = "monitoringActionWorkflow", default)]
pub monitoring_action_workflow: Option<MonitoringActionWorkflowIr>,
}
impl SceneIr {
@@ -620,6 +911,7 @@ impl From<LegacySceneInfoJson> for SceneIr {
column_defs: value.column_defs,
confidence: 0.0,
uncertainties: Vec::new(),
monitoring_action_workflow: None,
}
}
}

View File

@@ -2,3 +2,4 @@ pub mod analyzer;
pub mod generator;
pub mod ir;
pub mod lessons;
pub mod scheduled_monitoring_runtime;

File diff suppressed because it is too large Load Diff

View File

@@ -5,28 +5,50 @@ pub const SCENE_MANIFEST_FILE_NAME: &str = "scene.toml";
pub const SUPPORTED_SCHEMA_VERSION_V1: &str = "1";
pub const SUPPORTED_SCENE_KIND_V1: &str = "browser_script";
pub const SUPPORTED_SCENE_CATEGORY_V1: &str = "report_collection";
pub const SUPPORTED_SCHEDULED_MONITORING_KIND_V1: &str = "scheduled_monitoring_action_workflow";
pub const SUPPORTED_SCHEDULED_MONITORING_CATEGORY_V1: &str = "monitoring";
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SceneManifest {
pub scene: SceneSection,
pub manifest: ManifestSection,
pub bootstrap: BootstrapSection,
pub deterministic: DeterministicSection,
#[serde(default)]
pub bootstrap: Option<BootstrapSection>,
#[serde(default)]
pub deterministic: Option<DeterministicSection>,
#[serde(default)]
pub params: Vec<SceneParam>,
pub artifact: ArtifactSection,
#[serde(default)]
pub artifact: Option<ArtifactSection>,
#[serde(default)]
pub postprocess: Option<PostprocessSection>,
#[serde(default)]
pub trigger: Option<TriggerSection>,
#[serde(default)]
pub modes: Option<ModesSection>,
#[serde(default)]
pub runtime_context: Option<RuntimeContextSection>,
#[serde(default)]
pub safety: Option<SafetySection>,
#[serde(default)]
pub tools: Option<ScheduledToolsSection>,
#[serde(default)]
pub references: Option<ScheduledReferencesSection>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SceneSection {
pub id: String,
pub skill: String,
#[serde(default)]
pub tool: String,
pub kind: String,
pub version: String,
pub category: String,
#[serde(default)]
pub workflow_id: Option<String>,
#[serde(default)]
pub archetype: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -34,7 +56,7 @@ pub struct ManifestSection {
pub schema_version: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct BootstrapSection {
pub expected_domain: String,
pub target_url: String,
@@ -43,7 +65,7 @@ pub struct BootstrapSection {
pub requires_target_page: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct DeterministicSection {
pub suffix: String,
#[serde(default)]
@@ -63,7 +85,7 @@ pub struct SceneParam {
pub resolver_config: Table,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ArtifactSection {
#[serde(rename = "type")]
pub artifact_type: String,
@@ -79,3 +101,201 @@ pub struct PostprocessSection {
#[serde(default)]
pub auto_open: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct TriggerSection {
#[serde(default)]
pub primary: Vec<String>,
#[serde(default)]
pub validation: Vec<String>,
#[serde(default)]
pub allowed: Vec<String>,
#[serde(default)]
pub natural_language_primary: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ModesSection {
#[serde(default)]
pub enabled: Vec<String>,
#[serde(default)]
pub disabled: Vec<String>,
#[serde(default)]
pub default: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct RuntimeContextSection {
#[serde(default)]
pub runtime_context_url: String,
#[serde(default)]
pub expected_domain: String,
#[serde(default)]
pub gateway_domain: String,
#[serde(default)]
pub localhost_service_base: String,
#[serde(default)]
pub browser_attached_required: bool,
#[serde(default)]
pub host_bridge_required: bool,
#[serde(default)]
pub execution_context_mode: String,
#[serde(default)]
pub request_client_mode: String,
#[serde(default)]
pub encryption_mode: String,
#[serde(default)]
pub attached_page_browser_action_policy: String,
#[serde(default)]
pub platform_write_policy: String,
#[serde(default)]
pub storage_reads: Vec<StorageReadSection>,
#[serde(default)]
pub read_slices: Vec<ReadSliceSection>,
#[serde(default)]
pub encryption_resolution: EncryptionResolutionSection,
#[serde(default)]
pub timeout_contract: TimeoutContractSection,
#[serde(default)]
pub output_contract: OutputContractSection,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct StorageReadSection {
#[serde(default)]
pub key: String,
#[serde(default)]
pub source: String,
#[serde(default)]
pub fallback_order: Vec<String>,
#[serde(default)]
pub required: bool,
#[serde(default)]
pub parse_mode: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ReadSliceSection {
#[serde(default)]
pub name: String,
#[serde(default)]
pub endpoint_binding: String,
#[serde(default)]
pub request_template_override: Option<serde_json::Value>,
#[serde(default)]
pub response_path: String,
#[serde(default)]
pub timeout_ms: u64,
#[serde(default)]
pub merge_role: String,
#[serde(default)]
pub required: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct EncryptionResolutionSection {
#[serde(default)]
pub primary_method: String,
#[serde(default)]
pub fallback_methods: Vec<String>,
#[serde(default)]
pub required_context: Vec<String>,
#[serde(default)]
pub hard_fail: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct TimeoutContractSection {
#[serde(default)]
pub per_step_timeout_ms: u64,
#[serde(default)]
pub overall_detect_timeout_ms: u64,
#[serde(default)]
pub status_on_timeout: String,
#[serde(default)]
pub status_on_partial: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct OutputContractSection {
#[serde(default)]
pub run_record_mode: String,
#[serde(default)]
pub business_log_enabled: bool,
#[serde(default)]
pub sidecar_outputs: Vec<SidecarOutputSection>,
#[serde(default)]
pub delta_state: Option<DeltaStateSection>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SidecarOutputSection {
#[serde(default)]
pub name: String,
#[serde(default)]
pub relative_path: String,
#[serde(default)]
pub source_field: String,
#[serde(default)]
pub payload_schema: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct DeltaStateSection {
#[serde(default)]
pub identity_fields: Vec<String>,
#[serde(default)]
pub state_sidecar_path: String,
#[serde(default)]
pub comparison_mode: String,
#[serde(default)]
pub emit_policy: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SafetySection {
#[serde(default)]
pub dry_run_default: bool,
#[serde(default)]
pub active_enabled: bool,
#[serde(default)]
pub queue_process_enabled: bool,
#[serde(default)]
pub side_effects_default: String,
#[serde(default)]
pub audit_required_before_active: bool,
#[serde(default)]
pub idempotency_required_before_active: bool,
#[serde(default)]
pub blocked_call_signatures: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ScheduledToolsSection {
#[serde(default)]
pub detect: String,
#[serde(default)]
pub decide: String,
#[serde(default)]
pub action_plan: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ScheduledReferencesSection {
#[serde(default)]
pub source_evidence: String,
#[serde(default)]
pub workflow_ir: String,
#[serde(default)]
pub trigger_contract: String,
#[serde(default)]
pub platform_dependencies: String,
#[serde(default)]
pub side_effect_policy: String,
#[serde(default)]
pub audit_policy: String,
#[serde(default)]
pub idempotency_policy: String,
#[serde(default)]
pub generation_report: String,
}

View File

@@ -1,7 +1,10 @@
pub mod manifest;
pub use manifest::{
ArtifactSection, BootstrapSection, DeterministicSection, ManifestSection, PostprocessSection,
SceneManifest, SceneParam, SceneSection, SCENE_MANIFEST_FILE_NAME, SUPPORTED_SCENE_CATEGORY_V1,
SUPPORTED_SCENE_KIND_V1, SUPPORTED_SCHEMA_VERSION_V1,
ArtifactSection, BootstrapSection, DeterministicSection, ManifestSection, ModesSection,
PostprocessSection, RuntimeContextSection, SafetySection, ScheduledReferencesSection,
ScheduledToolsSection, SceneManifest, SceneParam, SceneSection, TriggerSection,
SCENE_MANIFEST_FILE_NAME, SUPPORTED_SCENE_CATEGORY_V1, SUPPORTED_SCENE_KIND_V1,
SUPPORTED_SCHEMA_VERSION_V1, SUPPORTED_SCHEDULED_MONITORING_CATEGORY_V1,
SUPPORTED_SCHEDULED_MONITORING_KIND_V1,
};

View File

@@ -364,6 +364,7 @@ pub(crate) fn serve_client(
Duration::from_secs(15),
BROWSER_RESPONSE_TIMEOUT,
true, // use_hidden_domain: hidden domain for invisible helper
None,
) {
Ok(host) => {
send_info_log(sink.as_ref(), "callback-host startup ready")?;

View File

@@ -2,12 +2,14 @@ mod common;
use std::collections::HashMap;
use std::fs;
use std::panic::AssertUnwindSafe;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
use std::time::{SystemTime, UNIX_EPOCH};
use common::MockTransport;
use futures_util::FutureExt;
use serde_json::json;
use sgclaw::browser::{BrowserBackend, PipeBrowserBackend};
use sgclaw::compat::browser_script_skill_tool::{
@@ -201,6 +203,77 @@ async fn execute_browser_script_tool_rejects_missing_expected_domain() {
assert!(transport.sent_messages().is_empty());
}
#[tokio::test]
async fn execute_browser_script_tool_handles_multibyte_wrapped_script_preview_without_panicking() {
let skill_dir = unique_temp_dir("sgclaw-browser-script-helper-utf8-preview");
let scripts_dir = skill_dir.join("scripts");
fs::create_dir_all(&scripts_dir).unwrap();
let args_json = json!({
"expected_domain": "www.zhihu.com"
});
let prefix_len = format!("(function() {{\nconst args = {};\n", args_json)
.len();
let comment_prefix = "//";
let ascii_padding = (0..3)
.find(|pad| (500usize - (prefix_len + comment_prefix.len() + *pad)) % 3 != 0)
.expect("should find a padding value that forces byte 500 off a char boundary");
let script_body = format!(
"{}{}{}\nreturn {{ ok: true }};\n",
comment_prefix,
"a".repeat(ascii_padding),
"".repeat(220)
);
fs::write(scripts_dir.join("utf8_preview.js"), script_body).unwrap();
let transport = Arc::new(MockTransport::new(vec![BrowserMessage::Response {
seq: 1,
success: true,
data: json!({
"text": {
"ok": true
}
}),
aom_snapshot: vec![],
timing: Timing {
queue_ms: 1,
exec_ms: 5,
},
}]));
let browser_tool = BrowserPipeTool::new(
transport.clone(),
test_policy(),
vec![1, 2, 3, 4, 5, 6, 7, 8],
)
.with_response_timeout(Duration::from_secs(1));
let skill_tool = SkillTool {
name: "utf8_preview".to_string(),
description: "Regression for UTF-8 safe wrapped script preview logging".to_string(),
kind: "browser_script".to_string(),
command: "scripts/utf8_preview.js".to_string(),
args: HashMap::new(),
};
let result = AssertUnwindSafe(execute_browser_script_tool(
&skill_tool,
&skill_dir,
&PipeBrowserBackend::from_inner(browser_tool),
json!({
"expected_domain": "www.zhihu.com"
}),
))
.catch_unwind()
.await;
assert!(
result.is_ok(),
"wrapped script preview should not panic on multibyte UTF-8 content"
);
let tool_result = result.unwrap().unwrap();
assert!(tool_result.success);
}
#[tokio::test]
async fn browser_script_skill_tool_executes_packaged_script_via_eval() {
let skill_dir = unique_temp_dir("sgclaw-browser-script-skill");

View File

@@ -1,4 +1,5 @@
use std::net::TcpListener;
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
@@ -208,6 +209,84 @@ fn parse_probe_args_defaults_timeout_when_flag_is_omitted() {
);
}
fn temp_step_file(name: &str, contents: &str) -> PathBuf {
let mut path = std::env::temp_dir();
let nanos = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos();
path.push(format!("sgclaw-ws-probe-{name}-{nanos}.txt"));
std::fs::write(&path, contents).unwrap();
path
}
#[test]
fn parse_probe_args_accepts_step_file() {
let step_file = temp_step_file(
"single",
"open-agent::[\"about:blank\",\"sgOpenAgent\"]\n",
);
let args = vec![
"--ws-url".to_string(),
"ws://127.0.0.1:12345".to_string(),
"--step-file".to_string(),
step_file.display().to_string(),
];
let parsed = parse_probe_args(&args).unwrap();
assert_eq!(parsed.ws_url, "ws://127.0.0.1:12345");
assert_eq!(parsed.timeout_ms, 1500);
assert_eq!(
parsed.steps,
vec![ProbeStep {
label: "open-agent".to_string(),
payload: "[\"about:blank\",\"sgOpenAgent\"]".to_string(),
expect_reply: true,
}]
);
let _ = std::fs::remove_file(step_file);
}
#[test]
fn parse_probe_args_preserves_step_and_step_file_order() {
let step_file = temp_step_file(
"ordered",
"open-hot::[\"about:blank\",\"sgBrowerserOpenPage\",\"https://www.zhihu.com/hot\"]\n",
);
let args = vec![
"--ws-url".to_string(),
"ws://127.0.0.1:12345".to_string(),
"--step".to_string(),
"open-agent::[\"about:blank\",\"sgOpenAgent\"]".to_string(),
"--step-file".to_string(),
step_file.display().to_string(),
];
let parsed = parse_probe_args(&args).unwrap();
assert_eq!(
parsed.steps,
vec![
ProbeStep {
label: "open-agent".to_string(),
payload: "[\"about:blank\",\"sgOpenAgent\"]".to_string(),
expect_reply: true,
},
ProbeStep {
label: "open-hot".to_string(),
payload:
"[\"about:blank\",\"sgBrowerserOpenPage\",\"https://www.zhihu.com/hot\"]"
.to_string(),
expect_reply: true,
},
]
);
let _ = std::fs::remove_file(step_file);
}
#[test]
fn probe_records_welcome_then_silence_transcript() {
let steps = vec![

View File

@@ -321,6 +321,35 @@ fn sgclaw_settings_load_service_ws_listen_addr_from_browser_config() {
);
}
#[test]
fn sgclaw_settings_load_scheduled_monitoring_platform_service_base_from_browser_config() {
let root = std::env::temp_dir().join(format!("sgclaw-monitoring-platform-config-{}", Uuid::new_v4()));
fs::create_dir_all(&root).unwrap();
let config_path = root.join("sgclaw_config.json");
fs::write(
&config_path,
r#"{
"apiKey": "sk-runtime",
"baseUrl": "https://api.deepseek.com",
"model": "deepseek-chat",
"scheduledMonitoringPlatformServiceBaseUrl": "http://25.215.213.128:18080"
}"#,
)
.unwrap();
let settings = SgClawSettings::load(Some(config_path.as_path()))
.unwrap()
.expect("expected sgclaw settings from config file");
assert_eq!(
settings
.scheduled_monitoring_platform_service_base_url
.as_deref(),
Some("http://25.215.213.128:18080")
);
}
#[test]
fn browser_attached_config_uses_low_temperature_for_deterministic_execution() {
let settings = SgClawSettings::from_legacy_deepseek_fields(

View File

@@ -0,0 +1,29 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Bootstrap Localhost Pollution Fixture</title>
</head>
<body>
<script src="http://cdn.example.com/app.js"></script>
<script>
const sourceUrl = "http://yx.gs.sgcc.com.cn";
const requestUrl = "http://localhost:13313/browser-helper.html";
async function getUserList() {
return $.ajax({
url: "http://yxgateway.gs.sgcc.com.cn/marketing/userList",
type: "POST",
contentType: "application/json"
});
}
function exportExcel() {
return $.ajax({
url: "http://localhost:13313/SurfaceServices/personalBread/export/faultDetailsExportXLSX",
type: "POST"
});
}
</script>
</body>
</html>

View File

@@ -0,0 +1,52 @@
{
"runDate": "2026-04-19",
"plan": "2026-04-19-bootstrap-target-normalization-roadmap-plan.md",
"parentFramework": "2026-04-19-scene-skill-102-full-coverage-framework-plan.md",
"parentSequence": "2026-04-19-final-2-residual-child-plan-sequence-plan.md",
"fixedInputBucket": [
"sweep-091-scene"
],
"officialBoardUpdated": false,
"implementationSlice": {
"type": "none",
"summary": "The fixed scene closed under the current deterministic bootstrap target recovery path; no analyzer/generator change was required in this plan."
},
"summary": {
"totalScenes": 1,
"autoPass": 1,
"failClosedKnown": 0,
"sourceUnreadable": 0,
"unknown": 0
},
"scenes": [
{
"sceneId": "sweep-091-scene",
"sceneName": "配网异常设备监控统计",
"previousFrameworkStatus": "framework-structured-fail-closed",
"previousWorkflowArchetype": "page_state_eval",
"rawStatus": "auto-pass",
"workflowArchetype": "single_request_enrichment",
"readinessLevel": "A",
"bootstrap": {
"expectedDomain": "21.77.244.194:18890",
"targetUrl": "http://21.77.244.194:18890/mainSystem",
"source": "deterministic"
},
"missingPieces": [],
"risks": [],
"passedGates": [
"bootstrap_resolved",
"workflow_contract_complete",
"runtime_contract_compatible",
"g1e_scope_compatible"
],
"skillDir": "examples/bootstrap_target_normalization_followup_2026-04-19/skills/sweep-091-scene",
"reportPath": "examples/bootstrap_target_normalization_followup_2026-04-19/skills/sweep-091-scene/references/generation-report.json"
}
],
"notes": [
"This follow-up uses the fixed official-board source scene for sweep-091-scene: 配网异常设备监控统计.",
"Earlier residual reports included a scene-name drift for the same sweep id; this plan does not edit historical assets.",
"Official board update is intentionally deferred to final-2 board reconciliation refresh."
]
}

View File

@@ -0,0 +1,29 @@
{
"runDate": "2026-04-19",
"plan": "2026-04-19-bootstrap-target-normalization-roadmap-plan.md",
"policySource": "tests/fixtures/generated_scene/promotion_board_reconciliation_policy_2026-04-19.json",
"followupSource": "tests/fixtures/generated_scene/bootstrap_target_normalization_followup_2026-04-19.json",
"totalScenes": 1,
"summary": {
"framework-auto-pass-candidate": 1,
"framework-structured-fail-closed": 0,
"source-unreadable": 0,
"unresolved-followup-status": 0
},
"officialBoardUpdated": false,
"canAutoUpdateBoard": false,
"scenes": [
{
"sceneId": "sweep-091-scene",
"sceneName": "配网异常设备监控统计",
"rawStatus": "auto-pass",
"reconciliationCandidateStatus": "framework-auto-pass-candidate",
"workflowArchetype": "single_request_enrichment",
"readinessLevel": "A",
"decisionOverlay": null,
"nextAction": null,
"canAutoUpdateBoard": false,
"policyReason": "Route 6 policy requires a dedicated board reconciliation plan; bootstrap target normalization only publishes candidates."
}
]
}

View File

@@ -0,0 +1,35 @@
{
"runDate": "2026-04-19",
"parentPlan": "docs/superpowers/plans/2026-04-19-bootstrap-target-residual-isolation-plan.md",
"source": "tests/fixtures/generated_scene/full_coverage_reconciliation_candidates_2026-04-19.json",
"scope": {
"isolationOnly": true,
"forbiddenImplementation": [
"src/generated_scene/analyzer.rs",
"src/generated_scene/generator.rs",
"login/runtime implementation files",
"tests/fixtures/generated_scene/scene_execution_board_2026-04-18.json"
]
},
"summary": {
"total": 1,
"isolatedBootstrapTargetResidual": 1,
"loginRecoveryStarted": false,
"runtimeNavigationImplementationStarted": false
},
"decisions": [
{
"index": 91,
"sceneId": "sweep-091-scene",
"sceneName": "用户停电频次分析监测",
"workflowArchetype": "page_state_eval",
"rawSweepStatus": "fail-closed-known",
"reconciliationCandidateStatus": "framework-structured-fail-closed",
"readinessLevel": "C",
"decision": "isolate-bootstrap-target-residual",
"reason": "Page-state/bootstrap-target residual requires navigation/login target normalization and must not be mixed with contract recovery work.",
"nextAction": "future-bootstrap-target-normalization-roadmap-input"
}
],
"stopStatement": "Route D is isolation-complete. Do not begin login recovery or runtime navigation implementation under this plan."
}

View File

@@ -0,0 +1,56 @@
{
"runDate": "2026-04-19",
"parentFramework": "2026-04-19-scene-skill-102-full-coverage-framework-plan",
"parentRoute": "Route 5 / boundary-family fail-closed",
"plan": "2026-04-19-boundary-fail-closed-decision-plan.md",
"scope": {
"decisionOnly": true,
"fixedInputBuckets": {
"local_doc_pipeline": 5,
"host_bridge_workflow": 1,
"page_state_eval_bootstrap_target": 1
},
"forbiddenChanges": [
"src/generated_scene/analyzer.rs",
"src/generated_scene/generator.rs",
"tests/fixtures/generated_scene/scene_execution_board_2026-04-18.json",
"boundary implementation"
]
},
"summary": {
"totalBoundaryBuckets": 3,
"totalBoundaryRecords": 7,
"openImplementationSlices": 0,
"heldOrDeferredRecords": 7,
"unresolvedBoundaryAmbiguity": 0
},
"decisions": [
{
"bucket": "local_doc_pipeline",
"count": 5,
"decision": "hold-as-boundary-fail-closed",
"reason": "G8 local document pipeline requires local document runtime and attachment handling beyond current full-coverage framework implementation routes.",
"nextAction": "defer until a dedicated local-doc runtime roadmap is authorized"
},
{
"bucket": "host_bridge_workflow",
"count": 1,
"decision": "hold-as-boundary-fail-closed",
"reason": "The remaining G6-style boundary record depends on host bridge execution semantics beyond the current decision-only Route 5 scope.",
"nextAction": "defer until a dedicated host-bridge implementation roadmap is authorized"
},
{
"bucket": "page_state_eval/bootstrap_target",
"count": 1,
"decision": "isolate-bootstrap-target",
"reason": "Bootstrap target resolution is a separate navigation/login target problem and must not be mixed with contract recovery work.",
"nextAction": "keep isolated for a future bootstrap-target roadmap"
}
],
"completionCriteria": {
"everyRoute5SubgroupHasNamedDecision": true,
"followUpBoundedPlanIsOptional": true,
"boundaryImplementationStarted": false
},
"stopStatement": "Route 5 is decision-complete. Do not begin boundary implementation under this plan."
}

View File

@@ -0,0 +1,63 @@
{
"decisionDate": "2026-04-19",
"scope": "boundary-family-real-sample-entry-roadmap",
"startingState": {
"mainlineClosed": [
"G1-E",
"G2",
"G3"
],
"boundaryHeld": [
"G6",
"G7",
"G8"
],
"deferredOutOfScope": [
"G4",
"G5"
]
},
"comparisonMatrix": [
{
"group": "G6",
"representativeScene": "电能表现场检验完成率指标报表",
"entryCondition": "A real sample requires host bridge execution semantics beyond current repo-local validation.",
"smallestNewCapability": "host bridge real-sample execution semantics",
"entryCost": "high",
"decision": "hold",
"reason": "Requires host-side execution semantics before a real-sample slice can be bounded safely."
},
{
"group": "G7",
"representativeScene": "计量资产库存统计",
"entryCondition": "A real sample requires multi-endpoint aggregation verification beyond fixture-level coverage.",
"smallestNewCapability": "real multi-endpoint aggregation verification",
"entryCost": "medium",
"decision": "selected",
"reason": "Already has a minimal runnable runtime contract and needs the smallest new capability among boundary families."
},
{
"group": "G8",
"representativeScene": "95598供电服务月报",
"entryCondition": "A real sample requires local document pipeline runtime and attachment handling beyond current repo-local coverage.",
"smallestNewCapability": "local document pipeline runtime and attachment handling",
"entryCost": "high",
"decision": "hold",
"reason": "Still depends on local pipeline and attachment behavior that exceeds the bounded next-step budget."
}
],
"selectedCandidate": {
"group": "G7",
"representativeScene": "计量资产库存统计",
"nextDesign": "docs/superpowers/specs/2026-04-19-g7-real-sample-entry-design.md",
"nextPlan": "docs/superpowers/plans/2026-04-19-g7-real-sample-entry-plan.md"
},
"holdReasons": [
"G6 remains held because host bridge execution semantics are still a stronger prerequisite than a bounded real-sample slice allows.",
"G8 remains held because local document pipeline runtime and attachment handling are still outside the next bounded slice."
],
"notes": [
"Only one boundary family is admitted as the next candidate.",
"This decision does not execute a real sample yet; it only selects the next bounded direction."
]
}

View File

@@ -0,0 +1,90 @@
{
"runDate": "2026-04-19",
"parentPlan": "docs/superpowers/plans/2026-04-19-boundary-residual-hold-decision-plan.md",
"source": "tests/fixtures/generated_scene/full_coverage_reconciliation_candidates_2026-04-19.json",
"scope": {
"decisionOnly": true,
"forbiddenImplementation": [
"src/generated_scene/analyzer.rs",
"src/generated_scene/generator.rs",
"tests/fixtures/generated_scene/scene_execution_board_2026-04-18.json"
]
},
"summary": {
"total": 6,
"localDocPipeline": 5,
"hostBridgeWorkflow": 1,
"heldOrDeferred": 6,
"implementationStarted": false,
"unresolvedBoundaryAmbiguity": 0
},
"decisions": [
{
"index": 33,
"sceneId": "sweep-033-scene",
"sceneName": "供电可靠率指标统计表",
"workflowArchetype": "local_doc_pipeline",
"rawSweepStatus": "fail-closed-known",
"readinessLevel": "C",
"decision": "hold-for-local-doc-runtime-roadmap",
"reason": "Local document pipeline residual requires local document runtime and attachment/document handling that is outside residual Route C implementation scope.",
"nextAction": "future-local-doc-runtime-roadmap-input"
},
{
"index": 34,
"sceneId": "sweep-034-scene",
"sceneName": "供电可靠性数据质量自查报告月报",
"workflowArchetype": "local_doc_pipeline",
"rawSweepStatus": "fail-closed-known",
"readinessLevel": "C",
"decision": "hold-for-local-doc-runtime-roadmap",
"reason": "Local document pipeline residual requires local document runtime and attachment/document handling that is outside residual Route C implementation scope.",
"nextAction": "future-local-doc-runtime-roadmap-input"
},
{
"index": 42,
"sceneId": "sweep-042-scene",
"sceneName": "国网金昌供电公司营商环境周例会报告",
"workflowArchetype": "local_doc_pipeline",
"rawSweepStatus": "fail-closed-known",
"readinessLevel": "C",
"decision": "hold-for-local-doc-runtime-roadmap",
"reason": "Local document pipeline residual requires local document runtime and attachment/document handling that is outside residual Route C implementation scope.",
"nextAction": "future-local-doc-runtime-roadmap-input"
},
{
"index": 51,
"sceneId": "sweep-051-scene",
"sceneName": "嘉峪关可靠性分析报告",
"workflowArchetype": "local_doc_pipeline",
"rawSweepStatus": "fail-closed-known",
"readinessLevel": "C",
"decision": "hold-for-local-doc-runtime-roadmap",
"reason": "Local document pipeline residual requires local document runtime and attachment/document handling that is outside residual Route C implementation scope.",
"nextAction": "future-local-doc-runtime-roadmap-input"
},
{
"index": 74,
"sceneId": "sweep-074-scene",
"sceneName": "同兴智能安全督查日报",
"workflowArchetype": "local_doc_pipeline",
"rawSweepStatus": "fail-closed-known",
"readinessLevel": "C",
"decision": "hold-for-local-doc-runtime-roadmap",
"reason": "Local document pipeline residual requires local document runtime and attachment/document handling that is outside residual Route C implementation scope.",
"nextAction": "future-local-doc-runtime-roadmap-input"
},
{
"index": 85,
"sceneId": "sweep-085-scene",
"sceneName": "业扩报装管理制度",
"workflowArchetype": "host_bridge_workflow",
"rawSweepStatus": "fail-closed-known",
"readinessLevel": "C",
"decision": "hold-for-host-bridge-runtime-roadmap",
"reason": "Host bridge workflow residual requires host bridge execution semantics beyond this decision-only route.",
"nextAction": "future-host-bridge-runtime-roadmap-input"
}
],
"stopStatement": "Route C is decision-complete. Do not begin boundary implementation under this plan."
}

View File

@@ -0,0 +1,97 @@
{
"assetDate": "2026-04-19",
"scope": "post-roadmap-boundary-and-runtime-entry-rules",
"boundaryReadiness": [
{
"group": "G6",
"status": "boundary-family-established",
"readiness": "executed-pass",
"nextEntryCondition": "The fixed G6 real sample has now executed as host_bridge_workflow; keep further host-bridge work bounded to a new roadmap."
},
{
"group": "G7",
"status": "boundary-family-established",
"readiness": "executed-pass",
"nextEntryCondition": "The first fixed G7 real sample has now executed as multi_endpoint_inventory; keep further boundary-family work bounded to a new roadmap."
},
{
"group": "G8",
"status": "boundary-family-established",
"readiness": "hold-as-boundary",
"nextEntryCondition": "A real sample requires local document pipeline runtime and attachment handling beyond current repo-local coverage."
}
],
"deferredFamilyEntryCriteria": [
{
"group": "G4",
"currentStatus": "deferred",
"entryCriteria": [
"at least one stable candidate cluster in the 102-scene execution board",
"a family-level contract that is distinct from existing G1/G2/G3/G6/G7/G8 contracts",
"a prioritization reason written into the next roadmap"
]
},
{
"group": "G5",
"currentStatus": "degraded",
"entryCriteria": [
"a clear reason why degraded handling is insufficient",
"a bounded implementation slice that does not reopen the completed roadmap",
"runtime gaps needed by the family are explicitly classified first"
]
}
],
"runtimeGapMatrix": [
{
"gap": "login-recovery",
"category": "runtime-platform-gap",
"status": "planned-not-implemented",
"blocks": [
"real-world end-to-end execution outside repo-local fixture scope"
]
},
{
"gap": "host-runtime-integration",
"category": "runtime-platform-gap",
"status": "partially-covered-by-boundary-families",
"blocks": [
"future host-bridge rollout beyond the bounded G6 real-sample entry"
]
},
{
"gap": "transport-runtime",
"category": "runtime-platform-gap",
"status": "planned-not-implemented",
"blocks": [
"direct post-roadmap runtime rollout"
]
},
{
"gap": "local-doc-and-attachment-workflows",
"category": "runtime-platform-gap",
"status": "partially-covered-by-G8-fixture-only",
"blocks": [
"G8 real-sample execution"
]
},
{
"gap": "g3-real-sample-output-contract-verification",
"category": "mainline-contract-gap",
"status": "closed-in-mainline",
"blocks": []
},
{
"gap": "g2-real-sample-contract-correction",
"category": "mainline-contract-gap",
"status": "closed-in-mainline",
"blocks": []
}
],
"prioritization": [
"Both G3 and G2 mainline real-sample contract gaps are now closed in the validation layer.",
"G7 is now the first boundary family with an executed-pass real-sample record.",
"G6 is now the second boundary family with an executed-pass real-sample record.",
"Do not open G4 or G5 without a new bounded roadmap that identifies the next mainline pressure explicitly.",
"Keep G8 as a boundary family until a new roadmap promotes it into real-sample execution scope."
]
}

View File

@@ -0,0 +1,50 @@
{
"decisionDate": "2026-04-19",
"scope": "boundary-runtime-prerequisites-roadmap",
"startingState": {
"boundaryClosed": [
"G7"
],
"boundaryHeld": [
"G6",
"G8"
],
"mainlineClosed": [
"G1-E",
"G2",
"G3"
],
"deferredOutOfScope": [
"G4",
"G5"
]
},
"comparisonMatrix": [
{
"direction": "G6-host-bridge-prerequisites",
"blockedCapability": "host bridge real-sample execution semantics",
"isolationCost": "medium",
"decision": "selected",
"reason": "It concentrates on one prerequisite line and is narrower than the combined local-doc plus attachment burden."
},
{
"direction": "G8-local-doc-prerequisites",
"blockedCapability": "local document runtime and attachment handling",
"isolationCost": "high",
"decision": "hold",
"reason": "It still combines local pipeline runtime and attachment handling, which is broader than the next bounded slice should absorb."
}
],
"selectedDirection": {
"direction": "G6-host-bridge-prerequisites",
"nextDesign": "docs/superpowers/specs/2026-04-19-g6-host-bridge-prerequisites-design.md",
"nextPlan": "docs/superpowers/plans/2026-04-19-g6-host-bridge-prerequisites-plan.md"
},
"holdReasons": [
"G8 remains held because local document runtime and attachment handling still form a heavier prerequisite bundle than G6 host-bridge semantics."
],
"notes": [
"The roadmap selects one prerequisite direction only.",
"No boundary family execution is opened under this roadmap."
]
}

View File

@@ -0,0 +1,132 @@
{
"runDate": "2026-04-20",
"plan": "2026-04-20-deterministic-keyword-scoring-refinement-plan.md",
"summary": {
"totalCompletePackages": 101,
"beforeReady": 92,
"beforeAmbiguous": 9,
"afterReady": 101,
"afterAmbiguous": 0,
"afterNoMatch": 0,
"afterOther": 0,
"fixedGapCount": 9,
"fixedGapResolved": 9
},
"decisions": [
{
"sceneId": "sweep-026-scene",
"sceneName": "县区公司故障明细",
"newKeywords": [
"县区公司故障明细"
],
"excludeKeywords": [],
"decision": "full-scene-name-only-with-pair-specific-excludes"
},
{
"sceneId": "sweep-034-scene",
"sceneName": "售电收入日统计排程预测",
"newKeywords": [
"售电收入日统计排程预测"
],
"excludeKeywords": [],
"decision": "full-scene-name-only-with-pair-specific-excludes"
},
{
"sceneId": "sweep-037-scene",
"sceneName": "嘉峪关可靠性分析报告",
"newKeywords": [
"嘉峪关可靠性分析报告"
],
"excludeKeywords": [],
"decision": "full-scene-name-only-with-pair-specific-excludes"
},
{
"sceneId": "sweep-038-scene",
"sceneName": "嘉峪关周报",
"newKeywords": [
"嘉峪关周报"
],
"excludeKeywords": [],
"decision": "full-scene-name-only-with-pair-specific-excludes"
},
{
"sceneId": "sweep-039-scene",
"sceneName": "嘉峪关故障明细",
"newKeywords": [
"嘉峪关故障明细"
],
"excludeKeywords": [],
"decision": "full-scene-name-only-with-pair-specific-excludes"
},
{
"sceneId": "sweep-040-scene",
"sceneName": "嘉峪关日报",
"newKeywords": [
"嘉峪关日报"
],
"excludeKeywords": [],
"decision": "full-scene-name-only-with-pair-specific-excludes"
},
{
"sceneId": "sweep-041-scene",
"sceneName": "嘉峪关月报",
"newKeywords": [
"嘉峪关月报"
],
"excludeKeywords": [],
"decision": "full-scene-name-only-with-pair-specific-excludes"
},
{
"sceneId": "sweep-044-scene",
"sceneName": "国网金昌供电公司指挥中心生产例会报告",
"newKeywords": [
"国网金昌供电公司指挥中心生产例会报告"
],
"excludeKeywords": [],
"decision": "full-scene-name-only-with-pair-specific-excludes"
},
{
"sceneId": "sweep-045-scene",
"sceneName": "国网金昌供电公司营商环境周例会报告",
"newKeywords": [
"国网金昌供电公司营商环境周例会报告"
],
"excludeKeywords": [],
"decision": "full-scene-name-only-with-pair-specific-excludes"
},
{
"sceneId": "sweep-097-scene",
"sceneName": "重要服务事项报备统计",
"newKeywords": [
"重要服务事项报备统计"
],
"excludeKeywords": [
"95598"
],
"decision": "full-scene-name-only-with-pair-specific-excludes"
},
{
"sceneId": "sweep-059-scene",
"sceneName": "故障明细",
"newKeywords": [
"故障明细"
],
"excludeKeywords": [
"县区公司",
"嘉峪关"
],
"decision": "full-scene-name-only-with-pair-specific-excludes"
},
{
"sceneId": "sweep-033-scene",
"sceneName": "售电收入日统计",
"newKeywords": [
"售电收入日统计"
],
"excludeKeywords": [
"排程预测"
],
"decision": "full-scene-name-only-with-pair-specific-excludes"
}
]
}

View File

@@ -2,10 +2,20 @@
<html>
<head>
<meta charset="UTF-8" />
<title>测试外部脚本提取</title>
<title>External Script Bootstrap Fixture</title>
<script src="http://25.215.213.128:18080/a_js/YPTAPI.js"></script>
</head>
<body>
<div id="app">测试页面</div>
<div id="app">Fixture</div>
<script>
const sourceUrl = "http://yx.gs.sgcc.com.cn";
function queryData() {
return $.ajax({
url: "http://yx.gs.sgcc.com.cn/report/query",
type: "POST",
contentType: "application/json"
});
}
</script>
</body>
</html>

View File

@@ -0,0 +1,80 @@
{
"policyVersion": "2026-04-18",
"scope": "roadmap-plan-track-e",
"mainlineGroups": [
{
"group": "G1",
"policy": "mainline",
"executionRule": "build reusable single-request template and validate representative migrations first",
"acceptanceFocus": [
"request/response/normalize restored",
"single_request_table compile path stable",
"family-level reuse confirmed"
]
},
{
"group": "G2",
"policy": "mainline",
"executionRule": "deepen multi-mode semantic recovery before broad expansion",
"acceptanceFocus": [
"mode matrix restored",
"mode-specific request/response contract restored",
"bootstrap business context stable"
]
},
{
"group": "G3",
"policy": "mainline",
"executionRule": "prioritize fail-closed and host-runtime separation before expansion",
"acceptanceFocus": [
"pagination chain restored",
"secondary request chain restored",
"localhost host-runtime evidence separated from business bootstrap"
]
}
],
"boundaryGroups": [
{
"group": "G6",
"policy": "boundary-runtime",
"executionRule": "treat as independent family with explicit host-bridge runtime contract; do not fold back into G1/G1-E/G3",
"acceptanceFocus": [
"host bridge action evidence restored",
"callback request chain present",
"incomplete manual scene IR stays fail-closed"
]
},
{
"group": "G7",
"policy": "boundary-runtime",
"executionRule": "treat as independent family with multi-endpoint aggregation contract; do not fold back into G1/G1-E",
"acceptanceFocus": [
"inventory endpoint set restored",
"inventory aggregate step present",
"incomplete manual scene IR stays fail-closed"
]
},
{
"group": "G8",
"policy": "boundary-runtime",
"executionRule": "treat as independent family with local pipeline contract; do not collapse into G6 host bridge workflow",
"acceptanceFocus": [
"localhost pipeline dependencies restored",
"sql/doc export steps present",
"incomplete manual scene IR stays fail-closed"
]
}
],
"deferredGroups": [
{
"group": "G4",
"policy": "deferred",
"executionRule": "keep extension entry only; do not consume current mainline capacity"
},
{
"group": "G5",
"policy": "degraded",
"executionRule": "default fail-closed or analysis-only; do not pollute mainline archetypes"
}
]
}

View File

@@ -0,0 +1,79 @@
{
"runDate": "2026-04-19",
"plan": "2026-04-19-final-2-official-board-reconciliation-refresh-plan.md",
"inputCandidates": [
"tests/fixtures/generated_scene/bootstrap_target_normalization_reconciliation_candidates_2026-04-19.json",
"tests/fixtures/generated_scene/host_bridge_runtime_reconciliation_candidates_2026-04-19.json"
],
"officialBoard": "tests/fixtures/generated_scene/scene_execution_board_2026-04-18.json",
"officialBoardUpdated": true,
"updatedSceneCount": 2,
"summary": {
"totalScenes": 102,
"frameworkStatusCounts": {
"framework-auto-pass": 102,
"framework-structured-fail-closed": 0,
"framework-valid-host-bridge": 0,
"source-unreadable": 0,
"missing-source": 0,
"unsupported-family": 0,
"misclassified-unresolved": 0,
"unresolved-followup-status": 0
},
"frameworkAutoPassCount": 102,
"frameworkStructuredFailClosedCount": 0,
"frameworkUnresolvedCount": 0
},
"updatedScenes": [
{
"source": "tests/fixtures/generated_scene/bootstrap_target_normalization_reconciliation_candidates_2026-04-19.json",
"sceneId": "sweep-091-scene",
"officialBoardSceneName": "配网异常设备监控统计",
"candidateSceneName": "配网异常设备监控统计",
"before": {
"currentFrameworkStatus": "framework-auto-pass",
"currentFrameworkCandidateStatus": "framework-auto-pass-candidate",
"currentFrameworkArchetype": "single_request_enrichment",
"currentFrameworkReadiness": "A",
"currentFrameworkDecisionOverlay": null,
"currentFrameworkNextAction": null
},
"after": {
"currentFrameworkStatus": "framework-auto-pass",
"currentFrameworkCandidateStatus": "framework-auto-pass-candidate",
"currentFrameworkArchetype": "single_request_enrichment",
"currentFrameworkReadiness": "A",
"currentFrameworkDecisionOverlay": null,
"currentFrameworkNextAction": null
}
},
{
"source": "tests/fixtures/generated_scene/host_bridge_runtime_reconciliation_candidates_2026-04-19.json",
"sceneId": "sweep-085-scene",
"officialBoardSceneName": "计量资产库存统计",
"candidateSceneName": "计量资产库存统计",
"before": {
"currentFrameworkStatus": "framework-structured-fail-closed",
"currentFrameworkCandidateStatus": "framework-structured-fail-closed",
"currentFrameworkArchetype": "host_bridge_workflow",
"currentFrameworkReadiness": "C",
"currentFrameworkDecisionOverlay": "hold-for-host-bridge-runtime-roadmap",
"currentFrameworkNextAction": "future-host-bridge-runtime-roadmap-input"
},
"after": {
"currentFrameworkStatus": "framework-auto-pass",
"currentFrameworkCandidateStatus": "framework-auto-pass-candidate",
"currentFrameworkArchetype": "multi_endpoint_inventory",
"currentFrameworkReadiness": "A",
"currentFrameworkDecisionOverlay": null,
"currentFrameworkNextAction": null
}
}
],
"remainingStructuredFailClosed": [],
"notes": [
"Both final-2 candidate assets were consumed when present.",
"Only framework-layer fields were updated.",
"No analyzer/generator implementation was modified by this refresh."
]
}

View File

@@ -0,0 +1,51 @@
{
"runDate": "2026-04-19",
"plan": "2026-04-19-final-2-residual-roadmap-prioritization-plan.md",
"parentFramework": "2026-04-19-scene-skill-102-full-coverage-framework-plan.md",
"parentSequence": "2026-04-19-final-2-residual-child-plan-sequence-plan.md",
"inputBoard": "tests/fixtures/generated_scene/scene_execution_board_2026-04-18.json",
"totalResiduals": 2,
"selectedRoadmap": "bootstrap target normalization roadmap",
"selectedPlan": "2026-04-19-bootstrap-target-normalization-roadmap-plan.md",
"candidates": [
{
"roadmap": "bootstrap target normalization roadmap",
"plan": "2026-04-19-bootstrap-target-normalization-roadmap-plan.md",
"sceneId": "sweep-091-scene",
"sceneName": "配网异常设备监控统计",
"currentFrameworkArchetype": "page_state_eval",
"currentFrameworkReadiness": "C",
"nextAction": "future-bootstrap-target-normalization-roadmap-input",
"residualCount": 1,
"scopeClarity": 4,
"implementationRisk": 2,
"regressionRisk": 2,
"autoPassProbability": 3,
"score": 13,
"selected": true,
"rationale": "Single-scene bootstrap target normalization is narrower than host-bridge runtime and does not require host transport semantics."
},
{
"roadmap": "host-bridge runtime roadmap",
"plan": "2026-04-19-host-bridge-runtime-roadmap-plan.md",
"sceneId": "sweep-085-scene",
"sceneName": "计量资产库存统计",
"currentFrameworkArchetype": "host_bridge_workflow",
"currentFrameworkReadiness": "C",
"nextAction": "future-host-bridge-runtime-roadmap-input",
"residualCount": 1,
"scopeClarity": 3,
"implementationRisk": 4,
"regressionRisk": 4,
"autoPassProbability": 3,
"score": 7,
"selected": false,
"deferReason": "Host-bridge runtime can affect already passing host-bridge paths and should remain queued until the narrower bootstrap residual is handled."
}
],
"coverageDelta": {
"expectedNow": 0,
"reason": "Decision-only plan"
},
"officialBoardUpdated": false
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,75 @@
{
"batchId": "g1e-light-enrichment-candidates-2026-04-18",
"family": "G1-E",
"source": "docs/superpowers/reports/2026-04-18-g1-e-second-sample-reuse-report.md",
"supportingSources": [
"docs/superpowers/reports/2026-04-18-g1-e-p0-validation-report.md",
"tests/fixtures/generated_scene/scene_ledger_status_2026-04-18.json"
],
"ledgerClusterLabel": "g1e-light-enrichment-candidate",
"selectionRule": "roadmap Track B and Track D G1-E light enrichment samples promoted into reusable family baselines",
"candidateCount": 3,
"representativeBaseline": "tests/fixtures/generated_scene/g1e_light_enrichment",
"promotedBatchExpansionBaselines": [
{
"fixtureDir": "tests/fixtures/generated_scene/g1e_light_enrichment_expansion",
"sceneId": "p1-g1e-light-enrichment-expansion-report",
"sceneName": "P1 G1-E light enrichment expansion report",
"assertions": {
"requiredMainRequest": "getWkorderAll",
"requiredEnrichmentRequest": "queryMeterInfo",
"requiredMergeJoinKey": "wkOrderNo",
"requiredMergeAggregateRule": "group_by:countyCodeName",
"requiredOutputColumn": "meterCapacityThisMonth"
}
},
{
"fixtureDir": "tests/fixtures/generated_scene/g1e_light_enrichment_additional",
"sceneId": "p1-g1e-light-enrichment-additional-report",
"sceneName": "P1 G1-E light enrichment additional report",
"assertions": {
"requiredMainRequest": "getWkorderAll",
"requiredEnrichmentRequest": "queryBusAcpt",
"requiredMergeJoinKey": "wkOrderNo",
"requiredMergeAggregateRule": "group_by:countyCodeName",
"requiredOutputColumn": "batchCapacityThisMonth"
}
}
],
"expectedSharedContract": {
"archetype": "single_request_enrichment",
"requiredGateNames": [
"bootstrap_resolved",
"request_contract_complete",
"response_contract_complete",
"workflow_contract_complete",
"runtime_contract_compatible",
"main_request_resolved",
"enrichment_requests_resolved",
"merge_plan_resolved",
"g1e_scope_compatible"
]
},
"candidates": [
{
"sceneKey": "high_low_voltage_new_capacity_monthly",
"batchRole": "p0-anchor",
"status": "promoted-baseline"
},
{
"sceneKey": "light_enrichment_second_sample",
"batchRole": "first-expansion-anchor",
"status": "promoted-expansion"
},
{
"sceneKey": "light_enrichment_additional_real_sample",
"batchRole": "second-expansion-anchor",
"status": "promoted-expansion"
}
],
"notes": [
"This batch records the current G1-E representative and promoted expansion baselines.",
"The additional sample is now promoted through the same light-enrichment family contract.",
"This keeps G1-E within the roadmap Track B and Track D boundary without forcing a new family scope."
]
}

View File

@@ -0,0 +1,136 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="sgclaw-scene-kind" content="report_collection" />
<meta name="sgclaw-target-url" content="http://yx.gs.sgcc.com.cn/" />
<meta name="sgclaw-expected-domain" content="yx.gs.sgcc.com.cn" />
<title>高低压新增报装容量月度统计表</title>
</head>
<body>
<script>
const workUrl =
"http://yxgateway.gs.sgcc.com.cn/emss-cmnf-common-front/member/workOrderQuery/getWkorderAll";
const headers = { "Content-Type": "application/json" };
async function report() {
const mode = "month";
const month = "04";
const reportType = "capacity";
const groupedData = {};
const requests = [];
requests.push(
axios.post(
workUrl,
window.encrypt_old({
wkOrderNo: "",
pageNo: 1,
pageSize: 1000
}),
{ headers }
)
);
const queryElectCustInfoApi = async (data) => {
const url =
"http://yxgateway.gs.sgcc.com.cn/emss-busexpengaccsf-busexpaccssrv-front/member/workorder/queryElectCustInfo";
const response = await axios.post(
url,
window.encrypt_old({
appNo: data.wkOrderNo
}),
{ headers }
);
return response.data;
};
const queryBusAcptApi = async (data) => {
const url =
"http://yxgateway.gs.sgcc.com.cn/emss-busexpengaccsf-busexpaccssrvacc-front/member/commonBusAcpt97/queryBusAcpt";
const response = await axios.post(
url,
window.encrypt_old({
appNo: data.wkOrderNo
}),
{ headers }
);
return response.data;
};
const getBatchPerCust97Api = async (data) => {
const url =
"http://yxgateway.gs.sgcc.com.cn/emss-busexpengaccsf-busexpaccssrvacc-front/member/lvbatchnewinstBusAcpt97/getBatchPerCust97";
const response = await axios.post(
url,
window.encrypt_old({
pageNo: 1,
pageSize: 20,
baseNewFlag: "01",
appNo: data.wkOrderNo
}),
{ headers }
);
return response.data;
};
for (const item of combinedData) {
const { countyCodeName } = item;
if (!groupedData[countyCodeName]) {
groupedData[countyCodeName] = {
countyCodeName,
hightPressureTotalThisMonth: 0,
hightPressureTotalOtherMonth: 0,
hightVolTotalThisMonth: 0,
hightVolTotalOtherMonth: 0,
lowPressureTotalThisMonth: 0,
lowPressureTotalOtherMonth: 0,
lowVolTotalThisMonth: 0,
lowVolTotalOtherMonth: 0
};
}
}
for (const item of Object.values(groupedData)) {
const {
countyCodeName,
hightAppListThisMonth,
lowAppListThisMonth,
batchAppListThisMonth
} = item;
const hightThis = await this.asyncPool(20, hightAppListThisMonth, queryElectCustInfoApi);
const lowThis = await this.asyncPool(20, lowAppListThisMonth[1], queryElectCustInfoApi);
const volBatchThis = await this.asyncPool(20, lowAppListThisMonth[0], queryBusAcptApi);
const preBatchThis = await this.asyncPool(20, batchAppListThisMonth, getBatchPerCust97Api);
if (hightThis && hightThis.status === 200 && mode === "month" && reportType) {
groupedData[countyCodeName].month = month;
}
await com(hightThis, countyCodeName, "hightVolTotalThisMonth", "hightPressureTotalThisMonth");
await com(lowThis, countyCodeName, "lowVolTotalThisMonth", "lowPressureTotalThisMonth");
await batchCom(volBatchThis, preBatchThis, countyCodeName, "lowVolTotalThisMonth", "lowPressureTotalThisMonth");
}
const titleList = [
["index", "序号", ""],
["countyCodeName", "单位", ""],
["hightPressureTotalOtherMonth", "月前累计新增接入", "高压户数"],
["hightVolTotalOtherMonth", "月前累计新增接入", "高压容量"],
["lowPressureTotalOtherMonth", "月前累计新增接入", "低压户数"],
["lowVolTotalOtherMonth", "月前累计新增接入", "低压容量"],
["otherMonthShare", "月前累计新增接入", "容量占比"],
["hightPressureTotalThisMonth", "本月新增接入", "高压户数"],
["hightVolTotalThisMonth", "本月新增接入", "高压容量"],
["lowPressureTotalThisMonth", "本月新增接入", "低压户数"],
["lowVolTotalThisMonth", "本月新增接入", "低压容量"],
["thisMonthShare", "本月新增接入", "容量占比"],
["yearHightPressureTotal", "年累计新增接入", "高压户数"],
["yearHightVolTotal", "年累计新增接入", "高压容量"],
["yearLowPressureTotal", "年累计新增接入", "低压户数"],
["yearLowVolTotal", "年累计新增接入", "低压容量"],
["yearShare", "年累计新增接入", "容量占比"]
];
return { groupedData, titleList };
}
</script>
</body>
</html>

View File

@@ -0,0 +1,100 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="sgclaw-scene-kind" content="report_collection" />
<meta name="sgclaw-target-url" content="http://yx.gs.sgcc.com.cn/" />
<meta name="sgclaw-expected-domain" content="yx.gs.sgcc.com.cn" />
<title>G1-E Additional Light Enrichment Fixture</title>
</head>
<body>
<script>
const sourceUrl = "http://yx.gs.sgcc.com.cn/report";
const headers = { "Content-Type": "application/json" };
const workUrl =
"http://yx.gs.sgcc.com.cn/report/customerApply/getWkorderAll";
async function reportAdditional() {
const mode = "month";
const month = "04";
const reportType = "capacity";
const groupedData = {};
const mainResponse = await axios.post(
workUrl,
window.encrypt_old({
wkOrderNo: "",
countyCodeName: "",
pageNo: 1,
pageSize: 500
}),
{ headers }
);
const queryBusAcptApi = async (data) => {
const url =
"http://yx.gs.sgcc.com.cn/report/customerApply/queryBusAcpt";
const response = await axios.post(
url,
window.encrypt_old({
appNo: data.wkOrderNo,
countyCodeName: data.countyCodeName
}),
{ headers }
);
return response.data;
};
const queryCapacityInfoApi = async (data) => {
const url =
"http://yx.gs.sgcc.com.cn/report/customerApply/queryCapacityInfo";
const response = await axios.post(
url,
window.encrypt_old({
appNo: data.wkOrderNo
}),
{ headers }
);
return response.data;
};
const rows = mainResponse.data || [];
for (const item of rows) {
const { countyCodeName } = item;
if (!groupedData[countyCodeName]) {
groupedData[countyCodeName] = {
countyCodeName,
batchTotalThisMonth: 0,
batchCapacityThisMonth: 0,
customerTotalThisMonth: 0,
customerCapacityThisMonth: 0,
thisMonthShare: 0
};
}
}
for (const item of rows) {
const busAcpt = await queryBusAcptApi(item);
const capacityInfo = await queryCapacityInfoApi(item);
if (busAcpt && busAcpt.status === 200 && mode === "month" && reportType) {
groupedData[item.countyCodeName].month = month;
}
await com(busAcpt, item.countyCodeName, "batchCapacityThisMonth", "batchTotalThisMonth");
await com(capacityInfo, item.countyCodeName, "customerCapacityThisMonth", "customerTotalThisMonth");
}
const titleList = [
["index", "Index", ""],
["countyCodeName", "Org", ""],
["batchTotalThisMonth", "This Month", "Batch Count"],
["batchCapacityThisMonth", "This Month", "Batch Capacity"],
["customerTotalThisMonth", "This Month", "Customer Count"],
["customerCapacityThisMonth", "This Month", "Customer Capacity"],
["thisMonthShare", "This Month", "Capacity Share"]
];
return { groupedData, titleList };
}
</script>
</body>
</html>

View File

@@ -0,0 +1,100 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="sgclaw-scene-kind" content="report_collection" />
<meta name="sgclaw-target-url" content="http://yx.gs.sgcc.com.cn/" />
<meta name="sgclaw-expected-domain" content="yx.gs.sgcc.com.cn" />
<title>Light Enrichment Expansion Fixture</title>
</head>
<body>
<script>
const sourceUrl = "http://yx.gs.sgcc.com.cn/report";
const headers = { "Content-Type": "application/json" };
const workUrl =
"http://yx.gs.sgcc.com.cn/report/customerApply/getWkorderAll";
async function reportExpansion() {
const mode = "month";
const month = "04";
const reportType = "asset";
const groupedData = {};
const mainResponse = await axios.post(
workUrl,
window.encrypt_old({
wkOrderNo: "",
countyCodeName: "",
pageNo: 1,
pageSize: 500
}),
{ headers }
);
const queryMeterInfoApi = async (data) => {
const url =
"http://yx.gscc.com.cn/report/customerApply/queryMeterInfo";
const response = await axios.post(
url,
window.encrypt_old({
appNo: data.wkOrderNo,
countyCodeName: data.countyCodeName
}),
{ headers }
);
return response.data;
};
const queryTransformerInfoApi = async (item) => {
const url =
"http://yx.gscc.com.cn/report/customerApply/queryTransformerInfo";
const response = await axios.post(
url,
window.encrypt_old({
appNo: item.wkOrderNo
}),
{ headers }
);
return response.data;
};
const rows = mainResponse.data || [];
for (const item of rows) {
const { countyCodeName } = item;
if (!groupedData[countyCodeName]) {
groupedData[countyCodeName] = {
countyCodeName,
meterTotalThisMonth: 0,
meterCapacityThisMonth: 0,
transformerTotalThisMonth: 0,
transformerCapacityThisMonth: 0,
thisMonthShare: 0
};
}
}
for (const item of rows) {
const meterInfo = await queryMeterInfoApi(item);
const transformerInfo = await queryTransformerInfoApi(item);
if (meterInfo && meterInfo.status === 200 && mode === "month" && reportType) {
groupedData[item.countyCodeName].month = month;
}
await com(meterInfo, item.countyCodeName, "meterCapacityThisMonth", "meterTotalThisMonth");
await com(transformerInfo, item.countyCodeName, "transformerCapacityThisMonth", "transformerTotalThisMonth");
}
const titleList = [
["index", "Index", ""],
["countyCodeName", "Org", ""],
["meterTotalThisMonth", "This Month", "Meter Count"],
["meterCapacityThisMonth", "This Month", "Meter Capacity"],
["transformerTotalThisMonth", "This Month", "Transformer Count"],
["transformerCapacityThisMonth", "This Month", "Transformer Capacity"],
["thisMonthShare", "This Month", "Capacity Share"]
];
return { groupedData, titleList };
}
</script>
</body>
</html>

View File

@@ -0,0 +1,53 @@
{
"runDate": "2026-04-19",
"parentFramework": "2026-04-19-scene-skill-102-full-coverage-framework-plan",
"parentRoute": "Route 4 / G1-E single_request_enrichment closure",
"plan": "2026-04-19-g1e-remaining-fail-closed-closure-plan.md",
"scope": {
"fixedInputBucket": "single_request_enrichment structured fail-closed",
"baselineCount": 2,
"allowedChange": "recover G1-E output column mappings from cols.push and wide titleList declarations",
"forbiddenChanges": [
"execution board update",
"new family",
"Route 2/3 asset changes",
"Route 5+ work"
]
},
"summary": {
"beforeFailClosed": 2,
"resolvedToAutoPass": 2,
"remainingFailClosed": 0,
"coverageDelta": 2
},
"scenes": [
{
"sceneId": "sweep-013-scene",
"sceneName": "业扩报装质量评价体系",
"baselineStatus": "fail-closed-known",
"baselineReadiness": "B",
"baselineBlockers": [
"output_columns"
],
"followupStatus": "auto-pass",
"followupReadiness": "A",
"archetype": "single_request_enrichment",
"resolvedBy": "g1e_output_columns_from_cols_push"
},
{
"sceneId": "sweep-068-scene",
"sceneName": "用电报装信息统计列表",
"baselineStatus": "fail-closed-known",
"baselineReadiness": "B",
"baselineBlockers": [
"output_columns"
],
"followupStatus": "auto-pass",
"followupReadiness": "A",
"archetype": "single_request_enrichment",
"resolvedBy": "g1e_output_columns_from_wide_title_list"
}
],
"outputRoot": "examples/g1e_remaining_fail_closed_closure_followup_2026-04-19",
"stopStatement": "Route 4 is closed after measuring the fixed G1-E bucket delta. Do not begin Route 5 in this plan."
}

View File

@@ -0,0 +1,110 @@
{
"batchId": "g2-lineloss-family-candidates-2026-04-18",
"family": "G2",
"source": "docs/superpowers/reports/2026-04-18-g2-family-expansion-third-round-report.md",
"supportingSources": [
"docs/superpowers/reports/2026-04-18-lineloss-family-variant-expansion-report.md",
"tests/fixtures/generated_scene/scene_ledger_status_2026-04-18.json"
],
"ledgerClusterLabel": "lineloss-family-candidate",
"selectionRule": "roadmap Track A and Track D line-loss family variants promoted into reusable multi-mode baselines",
"candidateCount": 6,
"representativeBaseline": "tests/fixtures/generated_scene/multi_mode",
"promotedBatchExpansionBaselines": [
{
"fixtureDir": "tests/fixtures/generated_scene/g2_weekly_single_mode",
"sceneId": "p1-g2-weekly-single-mode-report",
"sceneName": "P1 G2 weekly single mode report",
"assertions": {
"requiredDefaultMode": "week"
}
},
{
"fixtureDir": "tests/fixtures/generated_scene/g2_mixed_linked_workflow",
"sceneId": "p1-g2-mixed-linked-workflow-report",
"sceneName": "P1 G2 mixed linked workflow report",
"assertions": {
"requiredDefaultMode": "primary"
}
},
{
"fixtureDir": "tests/fixtures/generated_scene/g2_comparison_crosscheck",
"sceneId": "p1-g2-comparison-crosscheck-report",
"sceneName": "P1 G2 comparison crosscheck report",
"assertions": {
"requiredDefaultMode": "comparison"
}
},
{
"fixtureDir": "tests/fixtures/generated_scene/g2_diagnosis_drilldown",
"sceneId": "p1-g2-diagnosis-drilldown-report",
"sceneName": "P1 G2 diagnosis drilldown report",
"assertions": {
"requiredDefaultMode": "diagnosis"
}
},
{
"fixtureDir": "tests/fixtures/generated_scene/g2_prediction_compute",
"sceneId": "p1-g2-prediction-compute-report",
"sceneName": "P1 G2 prediction compute report",
"assertions": {
"requiredDefaultMode": "prediction"
}
}
],
"expectedSharedContract": {
"archetype": "multi_mode_request",
"requiredGateNames": [
"bootstrap_resolved",
"request_contract_complete",
"response_contract_complete",
"workflow_contract_complete",
"runtime_contract_compatible"
],
"requiredVariantPatterns": [
"g2_a_dual_mode_baseline",
"g2_b_weekly_single_mode",
"g2_c_mixed_linked_workflow",
"g2_d_prediction_compute",
"g2_e_comparison_crosscheck",
"g2_f_diagnosis_drilldown"
]
},
"candidates": [
{
"sceneKey": "tq_lineloss_report",
"batchRole": "p0-anchor",
"status": "promoted-baseline"
},
{
"sceneKey": "baiyin_lineloss_weekly",
"batchRole": "first-expansion-anchor",
"status": "promoted-expansion"
},
{
"sceneKey": "lineloss_period_diff",
"batchRole": "second-expansion-anchor",
"status": "promoted-expansion"
},
{
"sceneKey": "zero_consumer_crosscheck",
"batchRole": "third-expansion-anchor",
"status": "promoted-expansion"
},
{
"sceneKey": "steal_analysis",
"batchRole": "fourth-expansion-anchor",
"status": "promoted-expansion"
},
{
"sceneKey": "predicted_compute_variant",
"batchRole": "fifth-expansion-anchor",
"status": "promoted-expansion"
}
],
"notes": [
"This batch records the current code-backed G2 representative and promoted expansion baselines.",
"G2-D prediction compute is now promoted as a repo-local reusable expansion baseline within the current lineloss family contract.",
"The next Track D round should continue from the queued downstream family candidates instead of rebuilding G2-A through G2-F state from markdown reports."
]
}

View File

@@ -0,0 +1,34 @@
<html>
<head>
<meta charset="utf-8">
<title>G2 Comparison Crosscheck Fixture</title>
</head>
<body>
<script>
const sourceUrl = "http://20.76.57.61:18080/gsllys";
const reportType = "zeroConsumerCrosscheck";
async function queryMainRank(orgno, fdate) {
return $.ajax({
url: "http://20.76.57.61:18080/gsllys/tqLinelossStatis/getTqLinelossInfoListRank",
type: "POST",
contentType: "application/x-www-form-urlencoded",
data: JSON.stringify({ orgno, fdate, page: 1, rows: 40 })
});
}
async function queryUserElectric(orgno, consno, fdate) {
return $.ajax({
url: "http://20.76.57.61:18080/gsllys/tqLinelossStatis/getUserElectricList",
type: "POST",
contentType: "application/x-www-form-urlencoded",
data: JSON.stringify({ orgno, consno, fdate, page: 1, rows: 20 })
});
}
function mergeRow(TG_NO, TG_NAME, consno, userNmae, thisMonth, beforeMonth1) {
return { TG_NO, TG_NAME, consno, userNmae, thisMonth, beforeMonth1 };
}
</script>
</body>
</html>

View File

@@ -0,0 +1,52 @@
<html>
<head>
<meta charset="utf-8">
<title>G2 Diagnosis Drilldown Fixture</title>
</head>
<body>
<script>
const sourceUrl = "http://20.76.57.61:18080/gsllys";
const reportType = "stealAnalysis";
async function queryMainRank(orgno, fdate) {
return $.ajax({
url: "http://20.76.57.61:18080/gsllys/tqLinelossStatis/getTqLinelossInfoListRank",
type: "POST",
contentType: "application/x-www-form-urlencoded",
data: JSON.stringify({ orgno, fdate, page: 1, rows: 100 })
});
}
async function queryDiagnose(orgno, tgNo, fdate) {
return $.ajax({
url: "http://20.76.57.61:18080/gsllys/tqLinelossStatis/tqAutoDiagnoseAnalyse/search",
type: "POST",
contentType: "application/x-www-form-urlencoded",
data: JSON.stringify({ orgno, tgNo, fdate })
});
}
async function queryDetail(orgno, tgNo, fdate) {
return $.ajax({
url: "http://20.76.57.61:18080/gsllys/stealElecAnalyse/getFlqdyhDetailList",
type: "POST",
contentType: "application/x-www-form-urlencoded",
data: JSON.stringify({ orgno, tgNo, fdate, page: 1, rows: 20 })
});
}
async function queryRemark(orgno, tgNo, fdate) {
return $.ajax({
url: "http://20.76.57.61:18080/gsllys/stealElecAnalyse/userVoltsAndElecflowMoniter/search",
type: "POST",
contentType: "application/x-www-form-urlencoded",
data: JSON.stringify({ orgno, tgNo, fdate, page: 1, rows: 20 })
});
}
function exportRow(TG_NO, LL_TYPE_NAME, LOSS_PQ, LINELOSS_RATE, remark) {
return { TG_NO, LL_TYPE_NAME, LOSS_PQ, LINELOSS_RATE, remark };
}
</script>
</body>
</html>

View File

@@ -0,0 +1,50 @@
<html>
<head>
<meta charset="utf-8">
<title>G2 Mixed Linked Workflow Fixture</title>
</head>
<body>
<script>
const sourceUrl = "http://20.76.57.61:18080/gsllys";
async function queryMainRank(formDate) {
return $.ajax({
url: "http://20.76.57.61:18080/gsllys/tqLinelossStatis/getTqLinelossInfoListRank",
type: "POST",
contentType: "application/x-www-form-urlencoded",
data: JSON.stringify(formDate)
});
}
async function queryUserElectric(query) {
return $.ajax({
url: "http://20.76.57.61:18080/gsllys/tqLinelossStatis/getUserElectricList",
type: "POST",
contentType: "application/x-www-form-urlencoded",
data: JSON.stringify(query)
});
}
async function queryPeerSystemToken(dlMesage) {
return $.ajax({
url: "http://10.4.39.180/xsgl/syncLineLoss/rest/syncLineLossService/workbench",
type: "POST",
contentType: "application/json;charset=UTF-8",
data: JSON.stringify({
userName: dlMesage.userName,
loginName: dlMesage.loginName,
urlType: "WORKBENCH",
url: "/loginInfo/getToken"
})
});
}
function bootScene() {
return sgBrowserExcuteJsCode(
"http://20.76.57.61:18080/gsllys/tqLinelossStatis/tqQualifyRateMonitor",
"run"
);
}
</script>
</body>
</html>

View File

@@ -0,0 +1,112 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>G2 Noisy Multi Mode Fixture</title>
</head>
<body>
<script src="/a_js/jquery.js"></script>
<script>
const loginPath = "http://20.77.115.36:31051";
const mainPath = "http://20.77.115.36:31051";
const sourceUrl = "http://20.76.57.61:18080/gsllys";
const reportType = "lineloss";
async function queryLineloss(period_mode, orgno, weekSfdate, weekEfdate) {
if (period_mode === "month") {
const datas = {
orgno,
yn_flag: 0,
rows: 20,
page: 1,
sidx: "TO_NUMBER(ORG_NO)",
sord: "asc",
fdate: moment().subtract(1, "months").format("YYYY-MM"),
tjzq: "month"
};
return $.ajax({
url: "http://20.76.57.61:18080/gsllys/fourVerEightHor/fourVerEightHorLinelossRateList",
type: "POST",
contentType: "application/x-www-form-urlencoded",
data: JSON.stringify(datas)
});
}
if (period_mode === "week") {
const datas = {
orgno,
tjzq: "week",
rows: 20,
page: 1,
sord: "asc",
weekSfdate,
weekEfdate
};
return $.ajax({
url: "http://20.76.57.61:18080/gsllys/tqLinelossStatis/getYearMonWeekLinelossAnalysisList",
type: "POST",
contentType: "application/x-www-form-urlencoded",
data: JSON.stringify(datas)
});
}
return [];
}
const cols1 = [
["ORG_NAME", "供电单位"],
["LINE_LOSS_RATE", "综合线损率(%)"],
["PPQ", "供电量(Kwh)"],
["UPQ", "售电量(Kwh)"],
["LOSS_PQ", "损失电量(Kwh)"]
]
const cols2 = [
["ORG_NAME", "供电单位"],
["YGDL", "累计供电量"],
["YYDL", "累计售电量"],
["YXSL", "线损完成率(%)"],
["RAT_SCOPE", "线损率累计目标值"],
["BLANK3", "目标完成率"],
["BLANK2", "排名"]
];
async function getUserInfo(custNo) {
return $.ajax({
url: "http://yxgateway.gs.sgcc.com.cn/emss-custmgtf-custview-front/member/cust360ViewInfo/getCustElecInfoByCustIdUnion",
type: "POST",
contentType: "application/json",
data: JSON.stringify({ custNo })
});
}
async function executeTask(period_mode, orgno) {
const pageSize = 20;
let page = 1;
const rows = [];
while (page < 5) {
const response = await queryLineloss(period_mode, orgno, "2026-03-01", "2026-03-07");
const list = response.content || [];
if (!list.length) break;
for (const item of list) {
if (item.statusName !== "回退营销" && item.loss !== null) {
rows.push(item);
}
}
page += 1;
}
return rows;
}
function exportExcel(rows) {
return $.ajax({
url: "http://localhost:13313/SurfaceServices/personalBread/export/faultDetailsExportXLSX",
type: "POST",
data: rows
});
}
const docs1 = "https://github.com/nodeca/pako/";
const docs2 = "https://developer.mozilla.org/En/XMLHttpRequest/Using_XMLHttpRequest#Receiving_binary_data_in_older_browsers";
const docs3 = "https://stackoverflow.com/q/3277182/1008999";
</script>
</body>
</html>

View File

@@ -0,0 +1,39 @@
<html>
<head>
<meta charset="utf-8">
<title>G2 Prediction Compute Fixture</title>
</head>
<body>
<script>
const sourceUrl = "http://20.76.57.61:18080/gsllys";
const reportType = "predictionCompute";
const period_mode = "prediction";
async function queryHighLossForecast(orgno, fdate) {
const params = {
orgno,
fdate,
tjzq: "month",
mode: "prediction",
page: 1,
rows: 60,
reportType: "predictionCompute"
};
return $.ajax({
url: "http://20.76.57.61:18080/gsllys/tqLinelossStatis/highLineLossForecast",
type: "POST",
contentType: "application/x-www-form-urlencoded",
data: JSON.stringify(params)
});
}
function runPredictionMode() {
return queryHighLossForecast("6201001", "2026-04");
}
function normalizePredictionRow(lineId, lineName, lineLossType, lineLossRate, powerLoss) {
return { lineId, lineName, lineLossType, lineLossRate, powerLoss };
}
</script>
</body>
</html>

View File

@@ -0,0 +1,83 @@
{
"runDate": "2026-04-19",
"parentFramework": "2026-04-19-scene-skill-102-full-coverage-framework-plan",
"parentRoute": "Route 3 / G2 multi_mode_request closure",
"plan": "2026-04-19-g2-remaining-fail-closed-closure-plan.md",
"scope": {
"fixedInputBucket": "multi_mode_request structured fail-closed",
"baselineCount": 4,
"allowedChange": "fill empty G2 mode requestTemplate from bounded mode-specific fallback",
"forbiddenChanges": [
"execution board update",
"new family",
"Route 2 asset changes",
"Route 4+ work"
]
},
"summary": {
"beforeFailClosed": 4,
"resolvedToAutoPass": 4,
"remainingFailClosed": 0,
"coverageDelta": 4
},
"scenes": [
{
"sceneId": "sweep-020-scene",
"sceneName": "供电所线路电量统计",
"baselineStatus": "fail-closed-known",
"baselineReadiness": "C",
"baselineBlockers": [
"g2_request_contract",
"request_mode_contract"
],
"followupStatus": "auto-pass",
"followupReadiness": "A",
"archetype": "multi_mode_request",
"resolvedBy": "g2_mode_request_template_fallback"
},
{
"sceneId": "sweep-023-scene",
"sceneName": "供电质量看板-武威",
"baselineStatus": "fail-closed-known",
"baselineReadiness": "C",
"baselineBlockers": [
"g2_request_contract",
"request_mode_contract"
],
"followupStatus": "auto-pass",
"followupReadiness": "A",
"archetype": "multi_mode_request",
"resolvedBy": "g2_mode_request_template_fallback"
},
{
"sceneId": "sweep-070-scene",
"sceneName": "电量、站损自动采集上报",
"baselineStatus": "fail-closed-known",
"baselineReadiness": "C",
"baselineBlockers": [
"g2_request_contract",
"request_mode_contract"
],
"followupStatus": "auto-pass",
"followupReadiness": "A",
"archetype": "multi_mode_request",
"resolvedBy": "g2_mode_request_template_fallback"
},
{
"sceneId": "sweep-083-scene",
"sceneName": "营销业务管控监测日报表",
"baselineStatus": "fail-closed-known",
"baselineReadiness": "C",
"baselineBlockers": [
"g2_request_contract",
"request_mode_contract"
],
"followupStatus": "auto-pass",
"followupReadiness": "A",
"archetype": "multi_mode_request",
"resolvedBy": "g2_mode_request_template_fallback"
}
],
"outputRoot": "examples/g2_remaining_fail_closed_closure_followup_2026-04-19",
"stopStatement": "Route 3 is closed after measuring the fixed G2 bucket delta. Do not begin Route 4 in this plan."
}

View File

@@ -0,0 +1,49 @@
{
"runDate": "2026-04-19",
"parentPlan": "docs/superpowers/plans/2026-04-19-g2-residual-2-readiness-closure-plan.md",
"outputRoot": "D:\\data\\ideaSpace\\rust\\sgClaw\\claw-new\\examples\\g2_residual_2_readiness_closure_2026-04-19",
"summary": {
"total": 2,
"pass": 2,
"failClosed": 0,
"sourceUnreadable": 0,
"unknown": 0
},
"scenes": [
{
"sceneId": "sweep-018-scene",
"sceneName": "白银线损周报",
"exitCode": 0,
"durationSeconds": 46.4,
"workflowArchetype": "multi_mode_request",
"readinessLevel": "A",
"generationStatus": "",
"routeStatus": "pass",
"modeNames": [
"diagnosis"
],
"g2ModesPresentPassed": true,
"g2RequestContractCompletePassed": true,
"g2ResponseContractCompletePassed": true,
"reportPath": "D:\\data\\ideaSpace\\rust\\sgClaw\\claw-new\\examples\\g2_residual_2_readiness_closure_2026-04-19\\skills\\sweep-018-scene\\references\\generation-report.json"
},
{
"sceneId": "sweep-071-scene",
"sceneName": "台区线损大数据-月_周累计线损率统计分析",
"exitCode": 0,
"durationSeconds": 31.28,
"workflowArchetype": "multi_mode_request",
"readinessLevel": "A",
"generationStatus": "",
"routeStatus": "pass",
"modeNames": [
"month",
"week"
],
"g2ModesPresentPassed": true,
"g2RequestContractCompletePassed": true,
"g2ResponseContractCompletePassed": true,
"reportPath": "D:\\data\\ideaSpace\\rust\\sgClaw\\claw-new\\examples\\g2_residual_2_readiness_closure_2026-04-19\\skills\\sweep-071-scene\\references\\generation-report.json"
}
]
}

View File

@@ -0,0 +1,42 @@
<html>
<head>
<meta charset="utf-8">
<title>G2 Weekly Single Mode Fixture</title>
</head>
<body>
<script>
const sourceUrl = "http://20.76.57.61:18080/gsllys";
async function queryWeeklyLineloss(orgno, weekSfdate, weekEfdate) {
const params = {
orgno,
tjzq: "week",
level: "02",
rows: 20,
page: 1,
weekSfdate,
weekEfdate
};
return $.ajax({
url: "http://20.76.57.61:18080/gsllys/tqLinelossStatis/getYearMonWeekLinelossAnalysisList",
type: "POST",
contentType: "application/x-www-form-urlencoded",
data: JSON.stringify(params)
});
}
async function queryWeeklyRank(orgno) {
return $.ajax({
url: "http://20.76.57.61:18080/gsllys/tqLinelossStatis/getTqLinelossInfoListRank",
type: "POST",
contentType: "application/x-www-form-urlencoded",
data: JSON.stringify({ orgno, page: 1, rows: 20 })
});
}
function runWeeklyReport() {
return queryWeeklyLineloss("6201001", "2026-04-01", "2026-04-07");
}
</script>
</body>
</html>

View File

@@ -0,0 +1,203 @@
{
"batchId": "g3-95598-ticket-family-candidates-2026-04-18",
"family": "G3",
"source": "tests/fixtures/generated_scene/scene_ledger_snapshot_2026-04-18.json",
"ledgerClusterLabel": "95598-ticket-family-candidate",
"selectionRule": "ledger grouping result == 95598-ticket-family-candidate",
"candidateCount": 11,
"representativeBaseline": "tests/fixtures/generated_scene/paginated_enrichment",
"firstExpansionBaseline": "tests/fixtures/generated_scene/paginated_enrichment_expansion",
"promotedBatchExpansionBaselines": [
{
"fixtureDir": "tests/fixtures/generated_scene/paginated_enrichment_expansion_workorder",
"sceneId": "p1-g3-paginated-expansion-workorder-report",
"sceneName": "P1 G3 paginated expansion workorder report",
"assertions": {
"expectedPaginationField": "pageNo",
"requiredJoinKey": "workOrderNo",
"requiredAggregateRule": "aggregate:sourceType"
}
},
{
"fixtureDir": "tests/fixtures/generated_scene/paginated_enrichment_expansion_orderno",
"sceneId": "p1-g3-paginated-expansion-orderno-report",
"sceneName": "P1 G3 paginated expansion orderno report",
"assertions": {
"expectedPaginationField": "page",
"requiredJoinKey": "orderNo",
"requiredAggregateRule": "aggregate:sourceType"
}
},
{
"fixtureDir": "tests/fixtures/generated_scene/paginated_enrichment_expansion_source_distribution",
"sceneId": "p1-g3-paginated-expansion-source-distribution-report",
"sceneName": "P1 G3 paginated expansion source distribution report",
"assertions": {
"expectedPaginationField": "pageNum",
"requiredJoinKey": "ticketNo",
"requiredAggregateRule": "aggregate:sourceType"
}
},
{
"fixtureDir": "tests/fixtures/generated_scene/paginated_enrichment_expansion_service_risk",
"sceneId": "p1-g3-paginated-expansion-service-risk-report",
"sceneName": "P1 G3 paginated expansion service risk report",
"assertions": {
"expectedPaginationField": "pageNo",
"requiredJoinKey": "ticketNo",
"requiredAggregateRule": "aggregate:riskLevel"
}
},
{
"fixtureDir": "tests/fixtures/generated_scene/paginated_enrichment_expansion_timeout_warning",
"sceneId": "p1-g3-paginated-expansion-timeout-warning-report",
"sceneName": "P1 G3 paginated expansion timeout warning report",
"assertions": {
"expectedPaginationField": "pageNum",
"requiredJoinKey": "ticketNo",
"requiredAggregateRule": "aggregate:riskLevel"
}
},
{
"fixtureDir": "tests/fixtures/generated_scene/paginated_enrichment_expansion_device_monitor_weekly",
"sceneId": "p1-g3-paginated-expansion-device-monitor-weekly-report",
"sceneName": "P1 G3 paginated expansion device monitor weekly report",
"assertions": {
"expectedPaginationField": "pageNo",
"requiredJoinKey": "ticketNo",
"requiredAggregateRule": "aggregate:sourceType"
}
},
{
"fixtureDir": "tests/fixtures/generated_scene/paginated_enrichment_expansion_customer_satisfaction",
"sceneId": "p1-g3-paginated-expansion-customer-satisfaction-report",
"sceneName": "P1 G3 paginated expansion customer satisfaction report",
"assertions": {
"expectedPaginationField": "page",
"requiredJoinKey": "ticketNo",
"requiredAggregateRule": "aggregate:sourceType"
}
},
{
"fixtureDir": "tests/fixtures/generated_scene/paginated_enrichment_expansion_repair_return",
"sceneId": "p1-g3-paginated-expansion-repair-return-report",
"sceneName": "P1 G3 paginated expansion repair return report",
"assertions": {
"expectedPaginationField": "pageNum",
"requiredJoinKey": "ticketNo",
"requiredAggregateRule": "aggregate:riskLevel"
}
},
{
"fixtureDir": "tests/fixtures/generated_scene/paginated_enrichment_expansion_repair_daily_control",
"sceneId": "p1-g3-paginated-expansion-repair-daily-control-report",
"sceneName": "P1 G3 paginated expansion repair daily control report",
"assertions": {
"expectedPaginationField": "pageNo",
"requiredJoinKey": "ticketNo",
"requiredAggregateRule": "aggregate:riskLevel"
}
},
{
"fixtureDir": "tests/fixtures/generated_scene/paginated_enrichment_expansion_business_stats",
"sceneId": "p1-g3-paginated-expansion-business-stats-report",
"sceneName": "P1 G3 paginated expansion business stats report",
"assertions": {
"expectedPaginationField": "page",
"requiredJoinKey": "ticketNo",
"requiredAggregateRule": "aggregate:sourceType"
}
}
],
"expectedSharedContract": {
"archetype": "paginated_enrichment",
"requiredPaginationFields": [
"page",
"pageNum",
"pageSize",
"pageNo"
],
"requiredJoinKeyPatterns": [
"ticketNo",
"workOrderNo",
"orderNo"
],
"requiredAggregateRulePatterns": [
"aggregate:riskLevel",
"aggregate:sourceType"
]
},
"candidates": [
{
"sceneKey": "95598_ticket_12398_process_timeout_detail",
"ledgerGroupingResult": "95598-ticket-family-candidate",
"ledgerFamilyJudgement": "pending-regroup",
"batchRole": "first-expansion-anchor"
},
{
"sceneKey": "95598_ticket_12398_device_monitor_weekly",
"ledgerGroupingResult": "95598-ticket-family-candidate",
"ledgerFamilyJudgement": "pending-regroup",
"batchRole": "seventh-expansion-anchor"
},
{
"sceneKey": "95598_ticket_customer_satisfaction_daily",
"ledgerGroupingResult": "95598-ticket-family-candidate",
"ledgerFamilyJudgement": "pending-regroup",
"batchRole": "eighth-expansion-anchor"
},
{
"sceneKey": "95598_ticket_detail",
"ledgerGroupingResult": "95598-ticket-family-candidate",
"ledgerFamilyJudgement": "pending-regroup",
"batchRole": "p0-anchor"
},
{
"sceneKey": "95598_ticket_repair_return_analysis",
"ledgerGroupingResult": "95598-ticket-family-candidate",
"ledgerFamilyJudgement": "pending-regroup",
"batchRole": "ninth-expansion-anchor"
},
{
"sceneKey": "95598_ticket_repair_daily_control",
"ledgerGroupingResult": "95598-ticket-family-candidate",
"ledgerFamilyJudgement": "pending-regroup",
"batchRole": "tenth-expansion-anchor"
},
{
"sceneKey": "power_supply_service_ticket_business_stats",
"ledgerGroupingResult": "95598-ticket-family-candidate",
"ledgerFamilyJudgement": "pending-regroup",
"batchRole": "eleventh-expansion-anchor"
},
{
"sceneKey": "process_timeout_risk_ticket_detail",
"ledgerGroupingResult": "95598-ticket-family-candidate",
"ledgerFamilyJudgement": "pending-regroup",
"batchRole": "fifth-expansion-anchor"
},
{
"sceneKey": "ticket_timeout_warning_detail",
"ledgerGroupingResult": "95598-ticket-family-candidate",
"ledgerFamilyJudgement": "pending-regroup",
"batchRole": "sixth-expansion-anchor"
},
{
"sceneKey": "ticket_source_distribution_analysis",
"ledgerGroupingResult": "95598-ticket-family-candidate",
"ledgerFamilyJudgement": "pending-regroup",
"batchRole": "fourth-expansion-anchor"
},
{
"sceneKey": "service_risk_ticket_detail",
"ledgerGroupingResult": "95598-ticket-family-candidate",
"ledgerFamilyJudgement": "pending-regroup",
"batchRole": "third-expansion-anchor"
}
],
"notes": [
"This batch does not claim that all 11 candidates are already runnable or contract-complete.",
"It records that the full current roadmap-selected G3 representative and promoted expansion baselines are the correct family anchor for this ledger cluster.",
"The next execution round should continue from these promoted baselines instead of re-selecting the same candidates from the ledger snapshot."
]
}

View File

@@ -0,0 +1,75 @@
{
"date": "2026-04-19",
"parentRoute": "Route 2: G3 / paginated_enrichment",
"parentPlan": "docs/superpowers/plans/2026-04-19-g3-enrichment-request-closure-plan.md",
"fixedInputBucket": "paginated_enrichment + g3_enrichment_contract + secondary_request",
"beforeCount": 3,
"afterResolvedCount": 2,
"afterResidualCount": 1,
"scenes": [
{
"sceneId": "sweep-001-95598-12398",
"before": {
"generationStatus": "fail-closed",
"readinessLevel": "C",
"enrichmentCount": 0,
"primaryBlockers": [
"g3_enrichment_contract",
"secondary_request"
]
},
"after": {
"generationStatus": "pass",
"readinessLevel": "A",
"enrichmentCount": 2,
"residualBlockers": []
},
"delta": "resolved-to-pass"
},
{
"sceneId": "sweep-008-95598",
"before": {
"generationStatus": "fail-closed",
"readinessLevel": "C",
"enrichmentCount": 0,
"primaryBlockers": [
"g3_enrichment_contract",
"secondary_request",
"g3_runtime_scope"
]
},
"after": {
"generationStatus": "pass",
"readinessLevel": "A",
"enrichmentCount": 3,
"residualBlockers": []
},
"delta": "resolved-to-pass"
},
{
"sceneId": "sweep-002-95598-12398",
"before": {
"generationStatus": "fail-closed",
"readinessLevel": "C",
"enrichmentCount": 0,
"primaryBlockers": [
"g3_enrichment_contract",
"secondary_request",
"g3_export_plan",
"export_plan"
]
},
"after": {
"generationStatus": "fail-closed",
"readinessLevel": "C",
"enrichmentCount": 0,
"residualBlockers": [
"g3_export_plan",
"export_plan"
]
},
"delta": "handed-off-to-export-plan-closure"
}
],
"expectedNextChildPlan": "docs/superpowers/plans/2026-04-19-g3-export-plan-closure-plan.md"
}

View File

@@ -0,0 +1,32 @@
{
"date": "2026-04-19",
"parentRoute": "Route 2: G3 / paginated_enrichment",
"parentPlan": "docs/superpowers/plans/2026-04-19-g3-export-plan-closure-plan.md",
"fixedInputBucket": "paginated_enrichment + g3_export_plan + export_plan",
"beforeCount": 1,
"afterResolvedCount": 1,
"afterResidualCount": 0,
"scenes": [
{
"sceneId": "sweep-002-95598-12398",
"before": {
"generationStatus": "fail-closed",
"readinessLevel": "C",
"exportEntry": null,
"primaryBlockers": [
"g3_export_plan",
"export_plan"
]
},
"after": {
"generationStatus": "pass",
"readinessLevel": "A",
"exportEntry": "exportWord",
"residualBlockers": []
},
"delta": "resolved-to-pass"
}
],
"residualRoute2CountAfterThisPlan": 0,
"expectedNextChildPlan": "docs/superpowers/plans/2026-04-19-g3-residual-contract-closure-plan.md"
}

View File

@@ -0,0 +1,66 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>G3 G8 Mixed Boundary</title>
</head>
<body>
<script>
const pagesDetail = {
loginPath: "http://south.95598.sgcc.com.cn/bs/bsp/jsp/login.jsp",
mainPath: "http://south.95598.sgcc.com.cn/bs/bsp/jsp/main1.jsp"
}
async function getDataCallBack1(targeturl, actionurl, responseText) {
let data = { TabTi: { rows: [{ cols: [] }, { cols: [] }] }, ColumnNames: ["appNo", "custNo"] }
data.TabTi.rows.shift()
let this_rows = data.TabTi.rows.map((e) => e["cols"])
return this_rows
}
function getDataCallBack2(targeturl, actionurl, responseText) {
return responseText
}
async function getTicketDetail(appNo) {
return axios.post("http://south.95598.sgcc.com.cn/bs/businessaccept/queryTicketDetail/query.so", {
appNo: appNo
})
}
function exportExcel(config) {
return docExport(config)
}
function runScene(mac, startHandleTime, endHandleTime) {
let path = moment(endHandleTime).diff(moment(), 'days') < -90
? '/bs/businessaccept/queryHisS95598WkstGrid/query.so'
: '/bs/businessaccept/newQueryS95598WkstGrid/query.so'
BrowserAction(
'sgBrowerserJsAjax2',
pagesDetail.mainPath,
`${path}?appNo=&custNo=&org.sotower.web.taglib.util.PAGEPOLITPAGESIZE_grid=15&org.sotower.web.taglib.util.PAGEPOLITCURRENTPAGEINDEX_grid=${mac.page1}&org.sotower.web.taglib.util.RESETPAGEINDEX_grid=false`,
"getDataCallBack1"
)
axios.post("http://localhost:13313/configServices/selectData", JSON.stringify({
tableName: "work_order_detail_for95598",
query: "WHERE appNo >= '20260101'"
}), {
headers: {
"Content-Type": "application/json"
}
})
let exportConfig = {
url: "http://localhost:13313/SurfaceServices/personalBread/export/faultYoYExportXLSX"
}
if (mac.page1 === mac.total1) {
exportExcel(exportConfig)
}
}
</script>
</body>
</html>

View File

@@ -0,0 +1,82 @@
{
"runDate": "2026-04-19",
"parentPlan": "docs/superpowers/plans/2026-04-19-g3-residual-4-workflow-evidence-closure-plan.md",
"outputRoot": "D:\\data\\ideaSpace\\rust\\sgClaw\\claw-new\\examples\\g3_residual_4_workflow_evidence_closure_2026-04-19",
"summary": {
"total": 4,
"pass": 4,
"failClosed": 0,
"sourceUnreadable": 0,
"unknown": 0
},
"scenes": [
{
"sceneId": "sweep-007-scene",
"sceneName": "95598供电服务月报",
"exitCode": 0,
"durationSeconds": 10.13,
"workflowArchetype": "paginated_enrichment",
"readinessLevel": "A",
"generationStatus": "",
"routeStatus": "pass",
"missingPieces": [
],
"risks": [
],
"reportPath": "D:\\data\\ideaSpace\\rust\\sgClaw\\claw-new\\examples\\g3_residual_4_workflow_evidence_closure_2026-04-19\\skills\\sweep-007-scene\\references\\generation-report.json"
},
{
"sceneId": "sweep-039-scene",
"sceneName": "故障报修工单信息统计表",
"exitCode": 0,
"durationSeconds": 5.11,
"workflowArchetype": "paginated_enrichment",
"readinessLevel": "A",
"generationStatus": "",
"routeStatus": "pass",
"missingPieces": [
],
"risks": [
],
"reportPath": "D:\\data\\ideaSpace\\rust\\sgClaw\\claw-new\\examples\\g3_residual_4_workflow_evidence_closure_2026-04-19\\skills\\sweep-039-scene\\references\\generation-report.json"
},
{
"sceneId": "sweep-068-scene",
"sceneName": "输变电设备运行分析报告",
"exitCode": 0,
"durationSeconds": 10.15,
"workflowArchetype": "paginated_enrichment",
"readinessLevel": "A",
"generationStatus": "",
"routeStatus": "pass",
"missingPieces": [
],
"risks": [
],
"reportPath": "D:\\data\\ideaSpace\\rust\\sgClaw\\claw-new\\examples\\g3_residual_4_workflow_evidence_closure_2026-04-19\\skills\\sweep-068-scene\\references\\generation-report.json"
},
{
"sceneId": "sweep-084-scene",
"sceneName": "巡视计划完成情况自动检索",
"exitCode": 0,
"durationSeconds": 5.09,
"workflowArchetype": "paginated_enrichment",
"readinessLevel": "A",
"generationStatus": "",
"routeStatus": "pass",
"missingPieces": [
],
"risks": [
],
"reportPath": "D:\\data\\ideaSpace\\rust\\sgClaw\\claw-new\\examples\\g3_residual_4_workflow_evidence_closure_2026-04-19\\skills\\sweep-084-scene\\references\\generation-report.json"
}
]
}

View File

@@ -0,0 +1,18 @@
{
"date": "2026-04-19",
"parentRoute": "Route 2: G3 / paginated_enrichment",
"parentPlan": "docs/superpowers/plans/2026-04-19-g3-residual-contract-closure-plan.md",
"inputSources": [
"tests/fixtures/generated_scene/g3_enrichment_request_closure_followup_2026-04-19.json",
"tests/fixtures/generated_scene/g3_export_plan_closure_followup_2026-04-19.json"
],
"residualBeforeThisPlan": 0,
"implementedCorrectionSlice": false,
"residualAfterThisPlan": 0,
"residualGroups": [],
"route2Status": "completed",
"handoff": {
"nextRoute": "Route 3: G2 / multi_mode_request",
"nextPlan": "docs/superpowers/plans/2026-04-19-g2-remaining-fail-closed-closure-plan.md"
}
}

View File

@@ -0,0 +1,56 @@
{
"decisionDate": "2026-04-19",
"scope": "g6-host-bridge-callback-semantics",
"startingState": {
"targetGroup": "G6",
"realExecutionOutOfScope": true,
"implementationOutOfScope": true,
"heldGroups": [
"G8"
]
},
"completionStates": [
{
"state": "ok",
"definition": "All callback_request endpoints return successful callback results and no blockedReason or fatalError is raised."
},
{
"state": "partial",
"definition": "At least one callback_request endpoint returns a non-ok callback result while the overall flow is not blocked and no fatalError is raised."
},
{
"state": "blocked",
"definition": "The flow is stopped by page-context validation or host-bridge unavailability before callback completion can be accepted."
},
{
"state": "error",
"definition": "A fatal execution error is raised outside the bounded blocked-state path."
}
],
"semanticRules": [
{
"rule": "blocked_has_priority",
"summary": "blocked overrides all callback result states"
},
{
"rule": "fatal_error_maps_to_error",
"summary": "fatalError maps directly to error when blocked is absent"
},
{
"rule": "non_ok_callback_maps_to_partial",
"summary": "any non-ok callback result maps to partial when blocked and fatalError are absent"
},
{
"rule": "all_ok_maps_to_ok",
"summary": "all callback results ok maps to ok when blocked and fatalError are absent"
}
],
"selectedFollowup": {
"design": "docs/superpowers/specs/2026-04-19-g6-host-bridge-callback-state-verification-design.md",
"plan": "docs/superpowers/plans/2026-04-19-g6-host-bridge-callback-state-verification-plan.md"
},
"notes": [
"This slice publishes only the bounded completion-state semantics.",
"No G6 real-sample execution or host-runtime implementation is opened here."
]
}

View File

@@ -0,0 +1,44 @@
{
"decisionDate": "2026-04-19",
"scope": "g6-host-bridge-callback-state-verification",
"startingState": {
"targetGroup": "G6",
"realExecutionOutOfScope": true,
"implementationOutOfScope": true,
"heldGroups": [
"G8"
]
},
"verificationTargets": [
{
"state": "ok",
"evidenceRequirement": "all callback_request results are ok and neither blockedReason nor fatalError is present"
},
{
"state": "partial",
"evidenceRequirement": "at least one callback_request result is non-ok while blockedReason and fatalError are both absent"
},
{
"state": "blocked",
"evidenceRequirement": "pageValidation fails or host bridge returns a blocked result before callback success can be accepted"
},
{
"state": "error",
"evidenceRequirement": "fatalError is present while blockedReason is absent"
}
],
"verificationPriority": [
"blocked",
"error",
"partial",
"ok"
],
"selectedFollowup": {
"design": "docs/superpowers/specs/2026-04-19-g6-host-bridge-entry-readiness-design.md",
"plan": "docs/superpowers/plans/2026-04-19-g6-host-bridge-entry-readiness-plan.md"
},
"notes": [
"This slice publishes only bounded verification targets for callback states.",
"No G6 real-sample execution or host-runtime implementation is opened here."
]
}

View File

@@ -0,0 +1,52 @@
{
"decisionDate": "2026-04-19",
"scope": "g6-host-bridge-entry-gate",
"startingState": {
"targetGroup": "G6",
"realExecutionOutOfScope": true,
"implementationOutOfScope": true,
"heldGroups": [
"G8"
]
},
"hardGateConditions": [
{
"name": "host-bridge-action-invocation-defined",
"status": "required",
"failureReason": "g6_bridge_invocation_semantics_missing"
},
{
"name": "callback-request-completion-defined",
"status": "required",
"failureReason": "g6_callback_completion_semantics_missing"
},
{
"name": "callback-state-verification-targets-defined",
"status": "required",
"failureReason": "g6_callback_state_targets_missing"
}
],
"softConditions": [
{
"name": "host-runtime-transport-implementation",
"status": "optional-later"
},
{
"name": "real-sample-execution-proof",
"status": "optional-later"
}
],
"failCloseReasons": [
"g6_bridge_invocation_semantics_missing",
"g6_callback_completion_semantics_missing",
"g6_callback_state_targets_missing"
],
"selectedFollowup": {
"design": "docs/superpowers/specs/2026-04-19-g6-host-bridge-entry-gate-verification-design.md",
"plan": "docs/superpowers/plans/2026-04-19-g6-host-bridge-entry-gate-verification-plan.md"
},
"notes": [
"This slice publishes only bounded future entry-gate conditions.",
"No G6 real-sample execution or host-runtime implementation is opened here."
]
}

View File

@@ -0,0 +1,53 @@
{
"decisionDate": "2026-04-19",
"scope": "g6-host-bridge-entry-readiness",
"startingState": {
"targetGroup": "G6",
"realExecutionOutOfScope": true,
"implementationOutOfScope": true,
"heldGroups": [
"G8"
]
},
"requiredCriteria": [
{
"name": "host-bridge-action-invocation-defined",
"status": "required",
"reason": "A future G6 entry cannot open without an explicit bridge-action invocation semantic."
},
{
"name": "callback-request-completion-defined",
"status": "required",
"reason": "A future G6 entry cannot open without an explicit callback completion semantic."
},
{
"name": "callback-state-verification-targets-defined",
"status": "required",
"reason": "A future G6 entry cannot open without bounded verification targets for ok/partial/blocked/error."
}
],
"optionalCriteria": [
{
"name": "host-runtime-transport-implementation",
"status": "optional-later",
"reason": "Must remain outside this readiness slice."
},
{
"name": "real-sample-execution-proof",
"status": "optional-later",
"reason": "Belongs to a later execution slice, not to readiness modeling."
}
],
"minimalReadinessThreshold": {
"level": "semantic-ready",
"definition": "G6 may be considered ready for a later bounded entry slice only after all required semantic criteria are explicit while direct runtime implementation remains out of scope."
},
"selectedFollowup": {
"design": "docs/superpowers/specs/2026-04-19-g6-host-bridge-entry-gate-design.md",
"plan": "docs/superpowers/plans/2026-04-19-g6-host-bridge-entry-gate-plan.md"
},
"notes": [
"This slice publishes only bounded entry-readiness criteria.",
"No G6 real-sample execution or host-runtime implementation is opened here."
]
}

View File

@@ -0,0 +1,47 @@
{
"decisionDate": "2026-04-19",
"scope": "g6-host-bridge-execution-semantics",
"startingState": {
"targetGroup": "G6",
"realExecutionOutOfScope": true,
"implementationOutOfScope": true,
"heldGroups": [
"G8"
]
},
"semanticModel": {
"bridgeInvocation": {
"name": "host-bridge-action-invocation",
"summary": "A bounded semantic must define how a host bridge action is identified, invoked, and interpreted before any real G6 sample may be executed."
},
"callbackCompletion": {
"name": "callback-request-completion",
"summary": "A bounded semantic must define when callback_request steps count as complete, partial, blocked, or error during later real execution."
}
},
"semanticBoundaries": [
{
"slice": "bridge_action_invocation",
"status": "selected",
"reason": "Directly matches the existing invokeHostBridge semantic seam in the generated G6 runtime shape."
},
{
"slice": "callback_completion_semantics",
"status": "selected",
"reason": "Directly matches the existing callbackEndpoints and callback result accumulation seam in the generated G6 runtime shape."
},
{
"slice": "host_runtime_transport_rebuild",
"status": "out-of-scope",
"reason": "Must remain outside this bounded semantic slice."
}
],
"selectedFollowup": {
"design": "docs/superpowers/specs/2026-04-19-g6-host-bridge-callback-semantics-design.md",
"plan": "docs/superpowers/plans/2026-04-19-g6-host-bridge-callback-semantics-plan.md"
},
"notes": [
"This slice publishes only the minimum semantic boundary.",
"No G6 real-sample execution or host-runtime implementation is opened here."
]
}

View File

@@ -0,0 +1,42 @@
{
"decisionDate": "2026-04-19",
"scope": "g6-host-bridge-prerequisites",
"startingState": {
"targetGroup": "G6",
"executionOutOfScope": true,
"reopenedGroups": [],
"heldGroups": [
"G8"
]
},
"blockedCapability": {
"name": "host-bridge-real-execution-semantics",
"summary": "The generator already models host_bridge_workflow, but the next real-sample step is blocked by the lack of a bounded semantic contract for how host bridge calls are issued, awaited, and validated during real execution.",
"boundedInsteadOfBroadRuntime": true
},
"capabilityBreakdown": [
{
"slice": "bridge_action_invocation",
"status": "needed",
"reason": "A real sample needs a bounded semantic description of how sgBrowserExcuteJsCode-style actions are invoked."
},
{
"slice": "callback_completion_semantics",
"status": "needed",
"reason": "A real sample needs a bounded semantic description of how callback_request steps are recognized as complete or failed."
},
{
"slice": "host_runtime_platform_rebuild",
"status": "out-of-scope",
"reason": "The prerequisite slice must stay narrower than broad host-runtime implementation."
}
],
"selectedFollowup": {
"design": "docs/superpowers/specs/2026-04-19-g6-host-bridge-execution-semantics-design.md",
"plan": "docs/superpowers/plans/2026-04-19-g6-host-bridge-execution-semantics-plan.md"
},
"notes": [
"This slice isolates the minimum blocked capability instead of broadening into host-runtime implementation.",
"No G6 real-sample execution is opened under this plan."
]
}

View File

@@ -0,0 +1,59 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="sgclaw-scene-kind" content="report_collection" />
<meta name="sgclaw-target-url" content="http://yx.gs.sgcc.com.cn/" />
<meta name="sgclaw-expected-domain" content="yx.gscc.com.cn" />
<title>Host Bridge Workflow Fixture</title>
</head>
<body>
<script>
const sourceUrl = "http://yx.gs.sgcc.com.cn/meter";
async function runInspectionRateReport() {
const todo = await BrowserAction("sgBrowerserJsAjax2", {
url: "http://localhost:13313/browser/action/callback",
callback: "loadTodo"
});
const todoRows = await getWorkOrderToDoList(todo.batchNo);
for (const item of todoRows.rows || []) {
await sgBrowserExcuteJsCode("openPlanForm", item.wkOrderNo);
const plan = await queryMeterPlanFormulateApp(item.wkOrderNo);
const details = await queryMeterPlanDtlForAddMeter(plan.planNo);
if (details.rows && details.rows.length > 0) {
item.finishRate = details.rows.filter(row => row.finished).length / details.rows.length;
}
}
return todoRows;
}
async function getWorkOrderToDoList(batchNo) {
return $.ajax({
url: "http://yx.gscc.com.cn/meter/getWorkOrderToDoList",
type: "POST",
contentType: "application/json",
data: JSON.stringify({ batchNo })
});
}
async function queryMeterPlanFormulateApp(wkOrderNo) {
return $.ajax({
url: "http://yx.gscc.com.cn/meter/queryMeterPlanFormulateApp",
type: "POST",
contentType: "application/json",
data: JSON.stringify({ wkOrderNo })
});
}
async function queryMeterPlanDtlForAddMeter(planNo) {
return $.ajax({
url: "http://yx.gscc.com.cn/meter/queryMeterPlanDtlForAddMeter",
type: "POST",
contentType: "application/json",
data: JSON.stringify({ planNo })
});
}
</script>
</body>
</html>

View File

@@ -0,0 +1,73 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="sgclaw-scene-kind" content="report_collection" />
<meta name="sgclaw-target-url" content="http://yx.gscc.com.cn/" />
<meta name="sgclaw-expected-domain" content="yx.gscc.com.cn" />
<title>Multi Endpoint Inventory Fixture</title>
</head>
<body>
<script>
const sourceUrl = "http://yx.gscc.com.cn/asset";
async function runAssetInventory() {
const meter = await assetStatsQueryMeter("04");
const it = await assetStatsQueryIt("04");
const terminal = await assetStatsQueryAcqTrml("04");
const common = await assetStatsQueryMeterCommonModule("04");
const module = await assetStatsQueryJlGnModule("04");
return aggregateInventory([meter, it, terminal, common, module]);
}
async function assetStatsQueryMeter(month) {
return $.ajax({
url: "http://yx.gscc.com.cn/asset/assetStatsQueryMeter",
type: "POST",
contentType: "application/json",
data: JSON.stringify({ month, assetType: "meter" })
});
}
async function assetStatsQueryIt(month) {
return $.ajax({
url: "http://yx.gscc.com.cn/asset/assetStatsQueryIt",
type: "POST",
contentType: "application/json",
data: JSON.stringify({ month, assetType: "it" })
});
}
async function assetStatsQueryAcqTrml(month) {
return $.ajax({
url: "http://yx.gscc.com.cn/asset/assetStatsQueryAcqTrml",
type: "POST",
contentType: "application/json",
data: JSON.stringify({ month, assetType: "terminal" })
});
}
async function assetStatsQueryMeterCommonModule(month) {
return $.ajax({
url: "http://yx.gscc.com.cn/asset/assetStatsQueryMeterCommonModule",
type: "POST",
contentType: "application/json",
data: JSON.stringify({ month, assetType: "common_module" })
});
}
async function assetStatsQueryJlGnModule(month) {
return $.ajax({
url: "http://yx.gscc.com.cn/asset/assetStatsQueryJlGnModule",
type: "POST",
contentType: "application/json",
data: JSON.stringify({ month, assetType: "function_module" })
});
}
function aggregateInventory(parts) {
return parts.flatMap(part => part.rows || []);
}
</script>
</body>
</html>

View File

@@ -0,0 +1,48 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="sgclaw-scene-kind" content="report_collection" />
<meta name="sgclaw-target-url" content="http://south.95598.sgcc.com.cn/" />
<meta name="sgclaw-expected-domain" content="south.95598.sgcc.com.cn" />
<title>Local Document Pipeline Fixture</title>
</head>
<body>
<script>
const sourceUrl = "http://south.95598.sgcc.com.cn/report";
async function runServiceMonthlyReport() {
const sourceRows = await BrowserAction("sgBrowerserJsAjax2", {
url: "http://localhost:13313/configServices/selectData",
callback: "selectData"
});
await $.ajax({
url: "http://localhost:13313/configServices/selectData",
type: "POST",
contentType: "application/json",
data: JSON.stringify({ tableName: "service_monthly_raw", rows: sourceRows })
});
const summary = await definedSqlQuery(
"select city, count(*) as total from service_monthly_raw group by city"
);
return docExport({
template: "95598-service-monthly.docx",
data: summary
});
}
async function definedSqlQuery(sql) {
return $.ajax({
url: "http://localhost:13313/configServices/definedSqlQuery",
type: "POST",
contentType: "application/json",
data: JSON.stringify({ sql })
});
}
function docExport(payload) {
return BrowserAction("docExport", payload);
}
</script>
</body>
</html>

View File

@@ -0,0 +1,33 @@
{
"route": "embedded_dictionary_extraction_hardening",
"date": "2026-04-21",
"status": "completed",
"bucket": {
"focus_archetype": "multi_mode_request",
"anchor_scene": "sweep-030-scene",
"source_driven_dictionary_slice": true
},
"changes": {
"source_side_extraction_added": true,
"generated_org_dictionary_from_source": true,
"runtime_resolver_changed": false,
"materialized_skills_changed": false
},
"verified": {
"real_source_dictionary_codes": [
"62401",
"62408"
],
"fixture_dictionary_remains_empty_without_source_evidence": true,
"tests": [
"cargo test --test scene_generator_test analyzer_extracts_embedded_org_dictionary_from_sweep_030_source -- --nocapture",
"cargo test --test scene_generator_test generator_writes_real_sweep_030_org_dictionary_from_embedded_source -- --nocapture",
"cargo test --test scene_generator_test generator_writes_multi_mode_package_from_deterministic_analysis -- --nocapture"
]
},
"residuals": [
"dictionary extraction currently anchors on source evidence files such as city.js/dict.js/enum.js",
"full tree preservation is not implemented in this slice",
"route does not rematerialize 102 skills"
]
}

View File

@@ -0,0 +1,50 @@
{
"route": "alias_generation_hardening",
"plan": "docs/superpowers/plans/2026-04-20-generated-scene-invocation-alias-generation-hardening-plan.md",
"date": "2026-04-21",
"status": "completed",
"scope": {
"slice": "first reusable deterministic include keyword expansion",
"bucket": "high-risk multi-mode request wording divergence, anchored by sweep-030-scene",
"not_in_scope": [
"runtime dispatch scoring",
"service console behavior",
"manual edits to final materialized scene.toml",
"full 84-scene alias closure",
"rematerialization refresh",
"validation refresh"
]
},
"implementation": {
"changed_files": [
"src/generated_scene/generator.rs",
"tests/scene_generator_test.rs"
],
"summary": [
"Generated deterministic include_keywords now preserve canonical scene names and page title keywords.",
"Generated deterministic include_keywords now add normalized punctuation-stripped aliases.",
"Month/week combined names can produce month-specific and week-specific invocation aliases.",
"Line-loss style names can produce compact aliases such as taiqu-lineloss and lineloss-big-data."
]
},
"anchor_scene": {
"scene_id": "sweep-030-scene",
"expected_generated_aliases": [
"line-loss big data monthly line-loss statistics analysis",
"line-loss big data weekly line-loss statistics analysis",
"taiqu line-loss"
],
"reason": "These aliases match the real operator wording found during the intranet sweep-030 debugging process."
},
"verification": {
"passed": [
"cargo test --test scene_generator_test generator_writes_real_sweep_030_org_dictionary_from_embedded_source -- --nocapture",
"cargo test --test scene_generator_modes_test -- --nocapture"
],
"warnings": [
"Existing dead_code warnings in callback/openxml/generated_scene code remain.",
"Existing unreachable_code warning in scene_generator_test.rs remains."
]
},
"next_route": "generated_scene_runtime_semantics_rematerialization_refresh"
}

View File

@@ -0,0 +1,109 @@
{
"summary": {
"runDate": "2026-04-21",
"plan": "docs/superpowers/plans/2026-04-21-generated-scene-local-doc-pipeline-residual-closure-plan.md",
"scope": "bounded local_doc_pipeline residual closure",
"totalResidualScenes": 6,
"analyzerEvidenceRecovered": 6,
"generatorPackageRecoveryValidated": 6,
"rematerializationRerun": false,
"validationRefreshRerun": false
},
"residualScenes": [
{
"sceneId": "sweep-025-scene",
"sceneName": "local-doc residual sweep-025",
"recoveredEvidence": [
"reportLogQuery",
"reportLogSet",
"reportFileOpen",
"docExport"
],
"closureBasis": "fault details XLSX export plus report log/local file evidence"
},
{
"sceneId": "sweep-047-scene",
"sceneName": "local-doc residual sweep-047",
"recoveredEvidence": [
"reportLogQuery",
"reportLogSet",
"reportLogDelete",
"docTemplateTransform",
"docExport"
],
"closureBasis": "docx template transform and exportImageDocs/local report log evidence"
},
{
"sceneId": "sweep-050-scene",
"sceneName": "local-doc residual sweep-050",
"recoveredEvidence": [
"reportLogQuery",
"reportLogSet",
"reportLogDelete",
"docExport"
],
"closureBasis": "webpack-bundled uploadWord/setWord/aSaveFile document export evidence plus report log"
},
{
"sceneId": "sweep-052-scene",
"sceneName": "local-doc residual sweep-052",
"recoveredEvidence": [
"reportLogQuery",
"reportLogSet",
"reportLogDelete",
"docTemplateTransform",
"docExport"
],
"closureBasis": "docx template path, exportWord/exportImageDocs, and report log evidence"
},
{
"sceneId": "sweep-062-scene",
"sceneName": "local-doc residual sweep-062",
"recoveredEvidence": [
"reportLogQuery",
"reportLogSet",
"reportLogDelete",
"docTemplateTransform",
"docExport"
],
"closureBasis": "docx template path, exportWord/exportImageDocs, and report log evidence"
},
{
"sceneId": "sweep-087-scene",
"sceneName": "local-doc residual sweep-087",
"recoveredEvidence": [
"reportLogQuery",
"reportLogSet",
"reportLogDelete",
"docExport"
],
"closureBasis": "api/genword plus aSaveFile/report log document generation evidence"
}
],
"implementedReusableEvidenceTokens": [
"exportImageDocs",
"exportWordFile",
"uploadWord",
"setWord",
"aSaveFile",
"mammoth.convertToHtml",
"faultDetailsExportXLSX",
"api/genword",
"/docxs/",
"ReportServices/Api/readeFile"
],
"validation": {
"passed": [
"cargo test --test scene_generator_test analyzer_recovers_local_doc_residual_export_workflow_evidence -- --nocapture",
"cargo test --test scene_generator_test generator_recovers_local_doc_residual_packages_from_source_evidence -- --nocapture",
"cargo test --test scene_generator_test generator_writes_g8_local_doc_pipeline_package -- --nocapture",
"cargo test --test scene_generator_test generator_blocks_incomplete_g8_local_doc_pipeline_contract -- --nocapture",
"cargo test --test scene_generator_test generator_accepts_g8_local_doc_select_data_contract -- --nocapture"
],
"knownWarnings": [
"existing dead_code warnings in callback_host/openxml/generator",
"existing unreachable_code warning in scene_generator_test"
]
},
"stopStatement": "No rematerialization or validation refresh was rerun inside this bounded closure plan."
}

View File

@@ -0,0 +1,29 @@
{
"route": "parameter_default_semantics_hardening",
"date": "2026-04-21",
"status": "completed",
"bucket": {
"focus_archetype": "multi_mode_request",
"anchor_scene": "sweep-030-scene",
"source_driven_default_strategy_slice": true
},
"changes": {
"source_side_default_strategy_recovered": true,
"generated_param_resolver_config_updated": true,
"runtime_resolver_logic_changed": false,
"materialized_skills_changed": false
},
"verified": {
"default_strategy": "lineloss_page_semantics",
"tests": [
"cargo test --test scene_generator_test analyzer_recovers_lineloss_period_default_strategy_from_source -- --nocapture",
"cargo test --test scene_generator_test generator_writes_real_sweep_030_org_dictionary_from_embedded_source -- --nocapture",
"cargo test --test scene_generator_modes_test -- --nocapture"
]
},
"residuals": [
"route only preserves first reusable default strategy slice for lineloss-style month/week pages",
"no rematerialization or validation refresh executed in this route",
"other period/date semantics remain for later expansion"
]
}

View File

@@ -0,0 +1,67 @@
{
"route": "resolver_request_mapping_hardening",
"date": "2026-04-20",
"status": "completed",
"implementedSlice": {
"family": "multi_mode_request",
"scope": [
"explicit org resolver output to request-field mapping",
"explicit period payload expansion to request-field mapping",
"scene.toml request-mapping metadata emission",
"generated browser-script request-body construction via mapping metadata"
],
"bucketReason": "highest-signal reusable parameterized request bucket"
},
"changedFiles": [
"src/generated_scene/ir.rs",
"src/generated_scene/generator.rs",
"tests/scene_generator_test.rs",
"tests/scene_generator_modes_test.rs"
],
"emittedMetadata": {
"irField": "ModeIr.requestFieldMappings",
"sceneTomlSection": "[[request_mappings]]",
"mappingExamples": [
{
"sourceField": "org_code",
"targetField": "orgno",
"mode": "month"
},
{
"sourceField": "period_payload.fdate",
"targetField": "fdate",
"mode": "month"
},
{
"sourceField": "period_payload.weekSfdate",
"targetField": "weekSfdate",
"mode": "week"
},
{
"sourceField": "period_payload.weekEfdate",
"targetField": "weekEfdate",
"mode": "week"
}
]
},
"scriptBehaviorDelta": {
"before": "multi_mode_request merged all raw args into requestBody",
"after": "multi_mode_request resolves template values, normalizes period_payload, applies explicit request mappings, and does not blindly merge resolver args"
},
"verification": {
"testsPassed": [
"cargo test --test scene_generator_test generator_derives_reusable_request_field_mappings_for_real_g2_fixture -- --nocapture",
"cargo test --test scene_generator_test generator_writes_multi_mode_package_with_generation_report -- --nocapture",
"cargo test --test scene_generator_modes_test -- --nocapture",
"cargo test --test scene_generator_test generator_writes_multi_mode_package_from_deterministic_analysis -- --nocapture",
"cargo test --test scene_generator_test generator_blocks_incomplete_multi_mode_contract -- --nocapture"
],
"testCount": 9
},
"residuals": [
"single_request_enrichment and other non-G2 request builders still rely on pre-route request construction semantics",
"no 102-scene rematerialization or validation refresh was run in this route",
"runtime_url/dictionary/alias/default-semantics routes remain pending"
],
"nextRoute": "runtime_url_classification_hardening"
}

View File

@@ -0,0 +1,253 @@
{
"runDate": "2026-04-20",
"sourceLedger": "tests/fixtures/generated_scene/generated_scene_source_first_runtime_semantics_ledger_2026-04-20.json",
"routeOrder": [
"resolver_request_mapping_hardening",
"runtime_url_classification_hardening",
"embedded_dictionary_extraction_hardening",
"parameter_default_semantics_recovery_hardening",
"alias_generation_hardening"
],
"routeClusters": [
{
"route": "resolver_request_mapping_hardening",
"count": 102,
"highRiskCount": 76,
"mediumRiskCount": 26,
"archetypeCounts": [
{
"archetype": "paginated_enrichment",
"count": 51
},
{
"archetype": "host_bridge_workflow",
"count": 26
},
{
"archetype": "multi_mode_request",
"count": 10
},
{
"archetype": "local_doc_pipeline",
"count": 6
},
{
"archetype": "single_request_enrichment",
"count": 5
},
{
"archetype": "multi_endpoint_inventory",
"count": 2
},
{
"archetype": "page_state_eval",
"count": 2
}
],
"anchorScenes": [
"sweep-002-scene",
"sweep-003-scene",
"sweep-004-scene",
"sweep-005-scene",
"sweep-006-scene",
"sweep-007-scene",
"sweep-008-scene",
"sweep-009-scene",
"sweep-010-scene",
"sweep-011-scene"
]
},
{
"route": "runtime_url_classification_hardening",
"count": 102,
"highRiskCount": 76,
"mediumRiskCount": 26,
"archetypeCounts": [
{
"archetype": "paginated_enrichment",
"count": 51
},
{
"archetype": "host_bridge_workflow",
"count": 26
},
{
"archetype": "multi_mode_request",
"count": 10
},
{
"archetype": "local_doc_pipeline",
"count": 6
},
{
"archetype": "single_request_enrichment",
"count": 5
},
{
"archetype": "multi_endpoint_inventory",
"count": 2
},
{
"archetype": "page_state_eval",
"count": 2
}
],
"anchorScenes": [
"sweep-002-scene",
"sweep-003-scene",
"sweep-004-scene",
"sweep-005-scene",
"sweep-006-scene",
"sweep-007-scene",
"sweep-008-scene",
"sweep-009-scene",
"sweep-010-scene",
"sweep-011-scene"
]
},
{
"route": "embedded_dictionary_extraction_hardening",
"count": 102,
"highRiskCount": 76,
"mediumRiskCount": 26,
"archetypeCounts": [
{
"archetype": "paginated_enrichment",
"count": 51
},
{
"archetype": "host_bridge_workflow",
"count": 26
},
{
"archetype": "multi_mode_request",
"count": 10
},
{
"archetype": "local_doc_pipeline",
"count": 6
},
{
"archetype": "single_request_enrichment",
"count": 5
},
{
"archetype": "multi_endpoint_inventory",
"count": 2
},
{
"archetype": "page_state_eval",
"count": 2
}
],
"anchorScenes": [
"sweep-002-scene",
"sweep-003-scene",
"sweep-004-scene",
"sweep-005-scene",
"sweep-006-scene",
"sweep-007-scene",
"sweep-008-scene",
"sweep-009-scene",
"sweep-010-scene",
"sweep-011-scene"
]
},
{
"route": "parameter_default_semantics_recovery_hardening",
"count": 89,
"highRiskCount": 75,
"mediumRiskCount": 14,
"archetypeCounts": [
{
"archetype": "paginated_enrichment",
"count": 45
},
{
"archetype": "host_bridge_workflow",
"count": 22
},
{
"archetype": "multi_mode_request",
"count": 9
},
{
"archetype": "local_doc_pipeline",
"count": 6
},
{
"archetype": "single_request_enrichment",
"count": 5
},
{
"archetype": "page_state_eval",
"count": 1
},
{
"archetype": "multi_endpoint_inventory",
"count": 1
}
],
"anchorScenes": [
"sweep-002-scene",
"sweep-003-scene",
"sweep-004-scene",
"sweep-005-scene",
"sweep-006-scene",
"sweep-007-scene",
"sweep-008-scene",
"sweep-009-scene",
"sweep-010-scene",
"sweep-011-scene"
]
},
{
"route": "alias_generation_hardening",
"count": 84,
"highRiskCount": 73,
"mediumRiskCount": 11,
"archetypeCounts": [
{
"archetype": "paginated_enrichment",
"count": 40
},
{
"archetype": "host_bridge_workflow",
"count": 24
},
{
"archetype": "multi_mode_request",
"count": 7
},
{
"archetype": "local_doc_pipeline",
"count": 6
},
{
"archetype": "single_request_enrichment",
"count": 4
},
{
"archetype": "multi_endpoint_inventory",
"count": 2
},
{
"archetype": "page_state_eval",
"count": 1
}
],
"anchorScenes": [
"sweep-002-scene",
"sweep-003-scene",
"sweep-004-scene",
"sweep-005-scene",
"sweep-006-scene",
"sweep-007-scene",
"sweep-008-scene",
"sweep-009-scene",
"sweep-010-scene",
"sweep-011-scene"
]
}
]
}

View File

@@ -0,0 +1,39 @@
{
"runDate": "2026-04-21",
"plan": "docs/superpowers/plans/2026-04-21-generated-scene-runtime-semantics-post-refresh-residual-closure-plan.md",
"scope": "post-refresh-residual-closure-only",
"changedFiles": [
"src/generated_scene/generator.rs",
"tests/scene_generator_test.rs"
],
"residuals": [
{
"id": "deterministic_suffix_regression",
"before": "rematerialized scene.toml emitted scene-name deterministic suffixes",
"after": "render_scene_toml emits suffix = U+3002 x3",
"validation": "generator_writes_real_sweep_030_org_dictionary_from_embedded_source"
},
{
"id": "sweep_078_toml_corruption",
"before": "unescaped newline/control content could be written into TOML string scalars",
"after": "escape_toml escapes newline, carriage return, tab, quotes, backslashes, and control characters",
"validation": "generator_escapes_request_mapping_fields_for_valid_toml"
}
],
"tests": [
{
"command": "cargo test --test scene_generator_test generator_writes_real_sweep_030_org_dictionary_from_embedded_source -- --nocapture",
"status": "passed"
},
{
"command": "cargo test --test scene_generator_test generator_escapes_request_mapping_fields_for_valid_toml -- --nocapture",
"status": "passed"
}
],
"notExecuted": [
"rematerialization refresh",
"validation refresh",
"pseudo-production execution",
"official board update"
]
}

View File

@@ -0,0 +1,15 @@
{
"summary": {
"runDate": "2026-04-21",
"plan": "docs/superpowers/plans/2026-04-21-generated-scene-runtime-semantics-rematerialization-execution-plan.md",
"rerunReason": "local-doc pipeline residual closure verification",
"outputRoot": "D:\\data\\ideaSpace\\rust\\sgClaw\\claw-new\\examples\\scene_skill_102_runtime_semantics_rematerialization_2026-04-21",
"totalScenes": 102,
"attempted": 102,
"skillDirectories": 102,
"materialized": 102,
"failed": 0,
"durationSeconds": 2170.2
},
"failures": []
}

View File

@@ -0,0 +1,70 @@
{
"route": "runtime_url_classification_hardening",
"date": "2026-04-21",
"status": "completed",
"fixed_input_bucket": [
"scenes_with_strong_source_evidence_for_multiple_url_roles",
"scenes_with_target_url_only_generated_manifest",
"high_signal_browser_script_scenes_with_runtime_context_module_route_divergence"
],
"implemented_slice": {
"generator_metadata_fields": [
"bootstrap.appEntryUrl",
"bootstrap.moduleRouteUrl",
"bootstrap.targetUrlKind"
],
"scene_toml_fields": [
"bootstrap.app_entry_url",
"bootstrap.module_route_url",
"bootstrap.target_url_kind"
],
"structured_evidence_fields": [
"appEntryUrl",
"moduleRouteUrl",
"targetUrlKind"
],
"generation_report_fields": [
"App entry URL",
"Module route URL",
"Target URL kind"
]
},
"bucketed_examples": [
{
"scene": "report_collection fixture",
"runtime_context_url": "http://20.76.57.61:18080/gsllys",
"module_route_url": "http://20.76.57.61:18080/gsllys/tqLinelossStatis/tqQualifyRateMonitor",
"target_url_kind": "runtime_context"
},
{
"scene": "multi_mode package fixture",
"runtime_context_url": "http://20.76.57.61:18080/gsllys",
"module_route_url": "http://20.76.57.61:18080/gsllys/monthReport",
"target_url_kind": "runtime_context"
}
],
"tests": [
{
"command": "cargo test --test scene_generator_test analyzer_classifies_supported_report_collection_source -- --nocapture",
"status": "passed"
},
{
"command": "cargo test --test scene_generator_test generator_writes_multi_mode_package_with_generation_report -- --nocapture",
"status": "passed"
},
{
"command": "cargo test --test scene_generator_test generator_writes_multi_mode_package_from_deterministic_analysis -- --nocapture",
"status": "passed"
},
{
"command": "cargo test --test scene_generator_modes_test -- --nocapture",
"status": "passed"
}
],
"not_done_in_route": [
"no_full_102_rematerialization",
"no_validation_refresh",
"no_runtime_or_callback_host_changes",
"no_direct_generated_skill_edits"
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,52 @@
{
"runDate": "2026-04-19",
"plan": "2026-04-19-host-bridge-runtime-roadmap-plan.md",
"parentFramework": "2026-04-19-scene-skill-102-full-coverage-framework-plan.md",
"parentSequence": "2026-04-19-final-2-residual-child-plan-sequence-plan.md",
"fixedInputBucket": [
"sweep-085-scene"
],
"officialBoardUpdated": false,
"implementationSlice": {
"type": "none",
"summary": "The fixed scene closed under the current G7 multi_endpoint_inventory path; no host-bridge runtime implementation was required in this plan."
},
"summary": {
"totalScenes": 1,
"autoPass": 1,
"failClosedKnown": 0,
"sourceUnreadable": 0,
"unknown": 0
},
"scenes": [
{
"sceneId": "sweep-085-scene",
"sceneName": "计量资产库存统计",
"previousFrameworkStatus": "framework-structured-fail-closed",
"previousWorkflowArchetype": "host_bridge_workflow",
"rawStatus": "auto-pass",
"workflowArchetype": "multi_endpoint_inventory",
"readinessLevel": "A",
"bootstrap": {
"expectedDomain": "yxgateway.gs.sgcc.com.cn",
"targetUrl": "http://yxgateway.gs.sgcc.com.cn/emss-asf-assetsubjquery-front",
"source": "deterministic"
},
"missingPieces": [],
"risks": [],
"passedGates": [
"workflow_contract_complete",
"runtime_contract_compatible",
"g7_inventory_endpoints_detected",
"g7_fail_closed"
],
"skillDir": "examples/host_bridge_runtime_followup_2026-04-19/skills/sweep-085-scene",
"reportPath": "examples/host_bridge_runtime_followup_2026-04-19/skills/sweep-085-scene/references/generation-report.json"
}
],
"notes": [
"The official board already marks this scene as G7 / boundary-family / executed-pass at the real-sample layer.",
"The framework residual was a stale host_bridge_workflow view from earlier residual follow-up assets.",
"Official board update is deferred to final-2 board reconciliation refresh."
]
}

View File

@@ -0,0 +1,29 @@
{
"runDate": "2026-04-19",
"plan": "2026-04-19-host-bridge-runtime-roadmap-plan.md",
"policySource": "tests/fixtures/generated_scene/promotion_board_reconciliation_policy_2026-04-19.json",
"followupSource": "tests/fixtures/generated_scene/host_bridge_runtime_followup_2026-04-19.json",
"totalScenes": 1,
"summary": {
"framework-auto-pass-candidate": 1,
"framework-structured-fail-closed": 0,
"source-unreadable": 0,
"unresolved-followup-status": 0
},
"officialBoardUpdated": false,
"canAutoUpdateBoard": false,
"scenes": [
{
"sceneId": "sweep-085-scene",
"sceneName": "计量资产库存统计",
"rawStatus": "auto-pass",
"reconciliationCandidateStatus": "framework-auto-pass-candidate",
"workflowArchetype": "multi_endpoint_inventory",
"readinessLevel": "A",
"decisionOverlay": null,
"nextAction": null,
"canAutoUpdateBoard": false,
"policyReason": "Route 6 policy requires a dedicated board reconciliation plan; host-bridge runtime roadmap only publishes candidates."
}
]
}

View File

@@ -0,0 +1,54 @@
{
"diagnosticDate": "2026-04-19",
"scope": "known-family-timeout-diagnostic",
"results": [
{
"sceneId": "sweep-030-scene",
"sceneName": "台区线损大数据-月_周累计线损率统计分析",
"elapsedSeconds": 21.69,
"timedOut": false,
"exitCode": 0,
"workflowArchetype": "multi_mode_request",
"readinessLevel": "A",
"generationStatus": "generated",
"diagnosticLabel": "known-family-rerun-pass",
"stderrTail": ""
},
{
"sceneId": "sweep-076-scene",
"sceneName": "白银线损周报",
"elapsedSeconds": 34.31,
"timedOut": false,
"exitCode": 0,
"workflowArchetype": "multi_mode_request",
"readinessLevel": "A",
"generationStatus": "generated",
"diagnosticLabel": "known-family-rerun-pass",
"stderrTail": ""
},
{
"sceneId": "sweep-078-scene",
"sceneName": "线损同期差异报表",
"elapsedSeconds": 23.36,
"timedOut": false,
"exitCode": 0,
"workflowArchetype": "multi_mode_request",
"readinessLevel": "A",
"generationStatus": "generated",
"diagnosticLabel": "known-family-rerun-pass",
"stderrTail": ""
},
{
"sceneId": "sweep-079-scene",
"sceneName": "线损大数据-窃电分析",
"elapsedSeconds": 29.15,
"timedOut": false,
"exitCode": 0,
"workflowArchetype": "multi_mode_request",
"readinessLevel": "A",
"generationStatus": "generated",
"diagnosticLabel": "known-family-rerun-pass",
"stderrTail": ""
}
]
}

View File

@@ -0,0 +1,156 @@
{
"runDate": "2026-04-19",
"plan": "2026-04-19-local-doc-official-board-reconciliation-refresh-plan.md",
"inputCandidates": "tests/fixtures/generated_scene/local_doc_runtime_reconciliation_candidates_2026-04-19.json",
"officialBoard": "tests/fixtures/generated_scene/scene_execution_board_2026-04-18.json",
"officialBoardUpdated": true,
"updatedSceneCount": 5,
"summary": {
"totalScenes": 102,
"frameworkStatusCounts": {
"framework-auto-pass": 100,
"framework-structured-fail-closed": 2,
"framework-valid-host-bridge": 0,
"source-unreadable": 0,
"missing-source": 0,
"unsupported-family": 0,
"misclassified-unresolved": 0,
"unresolved-followup-status": 0
},
"frameworkAutoPassCount": 100,
"frameworkStructuredFailClosedCount": 2,
"frameworkUnresolvedCount": 0
},
"updatedScenes": [
{
"sceneId": "sweep-033-scene",
"officialBoardSceneName": "售电收入日统计",
"candidateSceneName": "供电可靠率指标统计表",
"before": {
"currentFrameworkStatus": "framework-structured-fail-closed",
"currentFrameworkCandidateStatus": "framework-structured-fail-closed",
"currentFrameworkArchetype": "local_doc_pipeline",
"currentFrameworkReadiness": "C",
"currentFrameworkDecisionOverlay": "hold-for-local-doc-runtime-roadmap",
"currentFrameworkNextAction": "future-local-doc-runtime-roadmap-input"
},
"after": {
"currentFrameworkStatus": "framework-auto-pass",
"currentFrameworkCandidateStatus": "framework-auto-pass-candidate",
"currentFrameworkArchetype": "local_doc_pipeline",
"currentFrameworkReadiness": "A",
"currentFrameworkDecisionOverlay": null,
"currentFrameworkNextAction": null
}
},
{
"sceneId": "sweep-034-scene",
"officialBoardSceneName": "售电收入日统计排程预测",
"candidateSceneName": "供电可靠性数据质量自查报告月报",
"before": {
"currentFrameworkStatus": "framework-structured-fail-closed",
"currentFrameworkCandidateStatus": "framework-structured-fail-closed",
"currentFrameworkArchetype": "local_doc_pipeline",
"currentFrameworkReadiness": "C",
"currentFrameworkDecisionOverlay": "hold-for-local-doc-runtime-roadmap",
"currentFrameworkNextAction": "future-local-doc-runtime-roadmap-input"
},
"after": {
"currentFrameworkStatus": "framework-auto-pass",
"currentFrameworkCandidateStatus": "framework-auto-pass-candidate",
"currentFrameworkArchetype": "local_doc_pipeline",
"currentFrameworkReadiness": "A",
"currentFrameworkDecisionOverlay": null,
"currentFrameworkNextAction": null
}
},
{
"sceneId": "sweep-042-scene",
"officialBoardSceneName": "四类主动工单统计",
"candidateSceneName": "国网金昌供电公司营商环境周例会报告",
"before": {
"currentFrameworkStatus": "framework-structured-fail-closed",
"currentFrameworkCandidateStatus": "framework-structured-fail-closed",
"currentFrameworkArchetype": "local_doc_pipeline",
"currentFrameworkReadiness": "C",
"currentFrameworkDecisionOverlay": "hold-for-local-doc-runtime-roadmap",
"currentFrameworkNextAction": "future-local-doc-runtime-roadmap-input"
},
"after": {
"currentFrameworkStatus": "framework-auto-pass",
"currentFrameworkCandidateStatus": "framework-auto-pass-candidate",
"currentFrameworkArchetype": "local_doc_pipeline",
"currentFrameworkReadiness": "A",
"currentFrameworkDecisionOverlay": null,
"currentFrameworkNextAction": null
}
},
{
"sceneId": "sweep-051-scene",
"officialBoardSceneName": "安全管控月度工作通报",
"candidateSceneName": "嘉峪关可靠性分析报告",
"before": {
"currentFrameworkStatus": "framework-structured-fail-closed",
"currentFrameworkCandidateStatus": "framework-structured-fail-closed",
"currentFrameworkArchetype": "local_doc_pipeline",
"currentFrameworkReadiness": "C",
"currentFrameworkDecisionOverlay": "hold-for-local-doc-runtime-roadmap",
"currentFrameworkNextAction": "future-local-doc-runtime-roadmap-input"
},
"after": {
"currentFrameworkStatus": "framework-auto-pass",
"currentFrameworkCandidateStatus": "framework-auto-pass-candidate",
"currentFrameworkArchetype": "local_doc_pipeline",
"currentFrameworkReadiness": "A",
"currentFrameworkDecisionOverlay": null,
"currentFrameworkNextAction": null
}
},
{
"sceneId": "sweep-074-scene",
"officialBoardSceneName": "白银公司指挥中心供电服务业务日报",
"candidateSceneName": "同兴智能安全督查日报",
"before": {
"currentFrameworkStatus": "framework-structured-fail-closed",
"currentFrameworkCandidateStatus": "framework-structured-fail-closed",
"currentFrameworkArchetype": "local_doc_pipeline",
"currentFrameworkReadiness": "C",
"currentFrameworkDecisionOverlay": "hold-for-local-doc-runtime-roadmap",
"currentFrameworkNextAction": "future-local-doc-runtime-roadmap-input"
},
"after": {
"currentFrameworkStatus": "framework-auto-pass",
"currentFrameworkCandidateStatus": "framework-auto-pass-candidate",
"currentFrameworkArchetype": "local_doc_pipeline",
"currentFrameworkReadiness": "A",
"currentFrameworkDecisionOverlay": null,
"currentFrameworkNextAction": null
}
}
],
"remainingStructuredFailClosed": [
{
"sceneId": "sweep-085-scene",
"sceneName": "计量资产库存统计",
"currentFrameworkStatus": "framework-structured-fail-closed",
"currentFrameworkArchetype": "host_bridge_workflow",
"currentFrameworkReadiness": "C",
"currentFrameworkDecisionOverlay": "hold-for-host-bridge-runtime-roadmap",
"currentFrameworkNextAction": "future-host-bridge-runtime-roadmap-input"
},
{
"sceneId": "sweep-091-scene",
"sceneName": "配网异常设备监控统计",
"currentFrameworkStatus": "framework-structured-fail-closed",
"currentFrameworkArchetype": "page_state_eval",
"currentFrameworkReadiness": "C",
"currentFrameworkDecisionOverlay": "isolate-bootstrap-target-residual",
"currentFrameworkNextAction": "future-bootstrap-target-normalization-roadmap-input"
}
],
"notes": [
"Only framework-layer fields were updated for the five fixed local-doc scenes.",
"Workbook snapshot fields, official scene names, currentGroup/currentStatus, and real-sample fields were preserved.",
"Official-board names for these sweep ids still differ from local-doc candidate source names; this refresh intentionally does not rename board scenes."
]
}

View File

@@ -0,0 +1,77 @@
{
"runDate": "2026-04-19",
"plan": "2026-04-19-local-doc-runtime-roadmap-plan.md",
"policySource": "tests/fixtures/generated_scene/promotion_board_reconciliation_policy_2026-04-19.json",
"followupSource": "tests/fixtures/generated_scene/local_doc_runtime_roadmap_followup_2026-04-19.json",
"totalScenes": 5,
"summary": {
"framework-auto-pass-candidate": 5,
"framework-structured-fail-closed": 0,
"source-unreadable": 0,
"unresolved-followup-status": 0
},
"officialBoardUpdated": false,
"canAutoUpdateBoard": false,
"scenes": [
{
"sceneId": "sweep-033-scene",
"sceneName": "供电可靠率指标统计表",
"rawStatus": "auto-pass",
"reconciliationCandidateStatus": "framework-auto-pass-candidate",
"workflowArchetype": "local_doc_pipeline",
"readinessLevel": "A",
"decisionOverlay": null,
"nextAction": null,
"canAutoUpdateBoard": false,
"policyReason": "Route 6 policy requires a dedicated board reconciliation plan; local-doc roadmap only publishes candidates."
},
{
"sceneId": "sweep-034-scene",
"sceneName": "供电可靠性数据质量自查报告月报",
"rawStatus": "auto-pass",
"reconciliationCandidateStatus": "framework-auto-pass-candidate",
"workflowArchetype": "local_doc_pipeline",
"readinessLevel": "A",
"decisionOverlay": null,
"nextAction": null,
"canAutoUpdateBoard": false,
"policyReason": "Route 6 policy requires a dedicated board reconciliation plan; local-doc roadmap only publishes candidates."
},
{
"sceneId": "sweep-042-scene",
"sceneName": "国网金昌供电公司营商环境周例会报告",
"rawStatus": "auto-pass",
"reconciliationCandidateStatus": "framework-auto-pass-candidate",
"workflowArchetype": "local_doc_pipeline",
"readinessLevel": "A",
"decisionOverlay": null,
"nextAction": null,
"canAutoUpdateBoard": false,
"policyReason": "Route 6 policy requires a dedicated board reconciliation plan; local-doc roadmap only publishes candidates."
},
{
"sceneId": "sweep-051-scene",
"sceneName": "嘉峪关可靠性分析报告",
"rawStatus": "auto-pass",
"reconciliationCandidateStatus": "framework-auto-pass-candidate",
"workflowArchetype": "local_doc_pipeline",
"readinessLevel": "A",
"decisionOverlay": null,
"nextAction": null,
"canAutoUpdateBoard": false,
"policyReason": "Route 6 policy requires a dedicated board reconciliation plan; local-doc roadmap only publishes candidates."
},
{
"sceneId": "sweep-074-scene",
"sceneName": "同兴智能安全督查日报",
"rawStatus": "auto-pass",
"reconciliationCandidateStatus": "framework-auto-pass-candidate",
"workflowArchetype": "local_doc_pipeline",
"readinessLevel": "A",
"decisionOverlay": null,
"nextAction": null,
"canAutoUpdateBoard": false,
"policyReason": "Route 6 policy requires a dedicated board reconciliation plan; local-doc roadmap only publishes candidates."
}
]
}

View File

@@ -0,0 +1,161 @@
{
"runDate": "2026-04-19",
"plan": "2026-04-19-local-doc-runtime-roadmap-plan.md",
"parentDecision": "2026-04-19-residual-runtime-roadmap-prioritization-plan.md",
"parentFramework": "2026-04-19-scene-skill-102-full-coverage-framework-plan.md",
"fixedInputBucket": [
"sweep-033-scene",
"sweep-034-scene",
"sweep-042-scene",
"sweep-051-scene",
"sweep-074-scene"
],
"officialBoardUpdated": false,
"implementationSlice": {
"type": "bounded-local-doc-contract-widening",
"changedFiles": [
"src/generated_scene/generator.rs",
"tests/scene_generator_test.rs"
],
"summary": "Accept local_doc_pipeline selectData/configServices selectData steps as the query leg of the minimal G8 contract while still requiring doc_export and localhost runtime evidence."
},
"summary": {
"totalScenes": 5,
"autoPass": 5,
"failClosedKnown": 0,
"sourceUnreadable": 0,
"unknown": 0
},
"scenes": [
{
"sceneId": "sweep-033-scene",
"sceneName": "供电可靠率指标统计表",
"workflowArchetype": "local_doc_pipeline",
"readinessLevel": "A",
"missingPieces": [],
"riskCount": 0,
"gates": [
{
"name": "workflow_contract_complete",
"passed": true
},
{
"name": "g8_local_doc_pipeline_detected",
"passed": true
},
{
"name": "g8_fail_closed",
"passed": true
}
],
"rawStatus": "auto-pass",
"skillDir": "examples/local_doc_runtime_roadmap_followup_2026-04-19/skills/sweep-033-scene",
"reportPath": "examples/local_doc_runtime_roadmap_followup_2026-04-19/skills/sweep-033-scene/references/generation-report.json"
},
{
"sceneId": "sweep-034-scene",
"sceneName": "供电可靠性数据质量自查报告月报",
"workflowArchetype": "local_doc_pipeline",
"readinessLevel": "A",
"missingPieces": [],
"riskCount": 0,
"gates": [
{
"name": "workflow_contract_complete",
"passed": true
},
{
"name": "g8_local_doc_pipeline_detected",
"passed": true
},
{
"name": "g8_fail_closed",
"passed": true
}
],
"rawStatus": "auto-pass",
"skillDir": "examples/local_doc_runtime_roadmap_followup_2026-04-19/skills/sweep-034-scene",
"reportPath": "examples/local_doc_runtime_roadmap_followup_2026-04-19/skills/sweep-034-scene/references/generation-report.json"
},
{
"sceneId": "sweep-042-scene",
"sceneName": "国网金昌供电公司营商环境周例会报告",
"workflowArchetype": "local_doc_pipeline",
"readinessLevel": "A",
"missingPieces": [],
"riskCount": 0,
"gates": [
{
"name": "workflow_contract_complete",
"passed": true
},
{
"name": "g8_local_doc_pipeline_detected",
"passed": true
},
{
"name": "g8_fail_closed",
"passed": true
}
],
"rawStatus": "auto-pass",
"skillDir": "examples/local_doc_runtime_roadmap_followup_2026-04-19/skills/sweep-042-scene",
"reportPath": "examples/local_doc_runtime_roadmap_followup_2026-04-19/skills/sweep-042-scene/references/generation-report.json"
},
{
"sceneId": "sweep-051-scene",
"sceneName": "嘉峪关可靠性分析报告",
"workflowArchetype": "local_doc_pipeline",
"readinessLevel": "A",
"missingPieces": [],
"riskCount": 0,
"gates": [
{
"name": "workflow_contract_complete",
"passed": true
},
{
"name": "g8_local_doc_pipeline_detected",
"passed": true
},
{
"name": "g8_fail_closed",
"passed": true
}
],
"rawStatus": "auto-pass",
"skillDir": "examples/local_doc_runtime_roadmap_followup_2026-04-19/skills/sweep-051-scene",
"reportPath": "examples/local_doc_runtime_roadmap_followup_2026-04-19/skills/sweep-051-scene/references/generation-report.json"
},
{
"sceneId": "sweep-074-scene",
"sceneName": "同兴智能安全督查日报",
"workflowArchetype": "local_doc_pipeline",
"readinessLevel": "A",
"missingPieces": [],
"riskCount": 0,
"gates": [
{
"name": "workflow_contract_complete",
"passed": true
},
{
"name": "g8_local_doc_pipeline_detected",
"passed": true
},
{
"name": "g8_fail_closed",
"passed": true
}
],
"rawStatus": "auto-pass",
"skillDir": "examples/local_doc_runtime_roadmap_followup_2026-04-19/skills/sweep-074-scene",
"reportPath": "examples/local_doc_runtime_roadmap_followup_2026-04-19/skills/sweep-074-scene/references/generation-report.json"
}
],
"notes": [
"This asset records only the fixed five local-doc roadmap scenes.",
"The official execution board is intentionally not updated in this plan.",
"Official-board scene names for the same sweep ids differ from the plan-target source names; this plan keeps fixed scene ids and does not correct board naming."
]
}

View File

@@ -0,0 +1,32 @@
{
"route": "monitoring-action-detect-preview-generator-implementation",
"date": "2026-04-21",
"status": "implemented-preview-only",
"samplePackage": "examples/monitoring_action_detect_preview_anchor_2026-04-21/skills/command-center-fee-control-monitor",
"family": "monitoring_action_workflow",
"mode": "detect_preview",
"sideEffectsExecutable": false,
"blockedSignalsPresentAsData": [
"repetCtrlSend",
"mac.sendMessages",
"mac.callOutLogin",
"mac.audioPlay",
"_this.autoTask",
"_this.processQueue",
"mac.exeTQueue"
],
"scriptSafetyScan": {
"containsExecutableRepetCtrlSend": false,
"containsExecutableSendMessages": false,
"containsExecutableCallOutLogin": false,
"containsExecutableAudioPlay": false,
"containsExecutableExeTQueue": false
},
"tests": [
"cargo test --test scene_generator_test generator_emits_monitoring_action_detect_preview_anchor_package -- --nocapture",
"cargo test --test scene_generator_test generator_emits_monitoring_template -- --nocapture",
"cargo test --test scene_generator_modes_test -- --nocapture",
"node examples/monitoring_action_detect_preview_anchor_2026-04-21/skills/command-center-fee-control-monitor/scripts/detect_preview.test.js"
],
"nextRecommendedRoute": "monitoring-action-mock-validation-plan"
}

View File

@@ -0,0 +1,386 @@
{
"family": "monitoring_action_workflow",
"date": "2026-04-21",
"status": "contract-defined",
"workflowId": "command_center_fee_control_monitoring_action",
"displayName": "???????????????",
"anchorEvidence": "tests/fixtures/generated_scene/monitoring_action_source_evidence_extraction_2026-04-21.json",
"defaultMode": "detect_preview",
"workflowStages": [
"detect",
"decide",
"preview",
"act",
"notify",
"log",
"queue_next"
],
"mvpAllowedStages": [
"detect",
"decide",
"preview"
],
"blockedByDefaultStages": [
"act",
"notify",
"log.write",
"queue_next"
],
"runtimeContext": {
"runtime_context_url": "http://yx.gs.sgcc.com.cn/",
"expected_domain": "yx.gs.sgcc.com.cn",
"gateway_domain": "yxgateway.gs.sgcc.com.cn",
"localhost_service_base": "http://localhost:13313",
"browserAttachedRequired": true,
"hostBridgeRequired": true
},
"modes": [
{
"name": "detect_preview",
"enabledInMvp": true,
"allowedStages": [
"detect",
"decide",
"preview"
],
"forbiddenStages": [
"act",
"notify",
"log.write",
"queue_next"
],
"description": "Read source data and local state, compute pending/notify candidates, and output preview without executing side effects."
},
{
"name": "action_plan",
"enabledInMvp": false,
"requiresFutureGate": "preview_approval",
"description": "Prepare but do not execute dispatch/notify actions."
},
{
"name": "execute_dispatch_confirmed",
"enabledInMvp": false,
"requiresFutureGate": "explicit_confirm_dispatch",
"description": "Future mode only. Dispatch fee-control exception orders after explicit confirmation and max item limit."
},
{
"name": "execute_notify_confirmed",
"enabledInMvp": false,
"requiresFutureGate": "explicit_confirm_notify",
"description": "Future mode only. Send SMS/call/audio notifications after explicit confirmation and max item limit."
}
],
"localStorageReads": [
{
"key": "loginUserInfo",
"usage": "current user org and login context"
},
{
"key": "markToken",
"usage": "business gateway Authorization token"
},
{
"key": "yxClassList",
"usage": "cached organization tree/list"
},
{
"key": "zhzxFkycSendTime",
"usage": "last fee-control send/monitor time"
}
],
"localServiceDependencies": [
{
"url": "http://localhost:13313/MonitorServices/getMonitorLog",
"classification": "read_state"
},
{
"url": "http://localhost:13313/MonitorServices/setMonitorData",
"classification": "write_monitor_state",
"sideEffect": true
},
{
"url": "http://localhost:13313/MonitorServices/setMonitorLog",
"classification": "write_monitor_log",
"sideEffect": true
},
{
"url": "http://localhost:13313/MonitorServices/setDisposeLog",
"classification": "write_dispose_log",
"sideEffect": true
},
{
"url": "http://localhost:13313/MonitorServices/setAudioPlayLog",
"classification": "write_notification_log",
"sideEffect": true
},
{
"url": "http://localhost:13313/MonitorServices/setSendMessageLog",
"classification": "write_notification_log",
"sideEffect": true
},
{
"url": "http://localhost:13313/marketingServices/getOtherIphones",
"classification": "configuration_read"
},
{
"url": "http://localhost:13313/marketingServices/messageLogInfo",
"classification": "write_notification_log",
"sideEffect": true
},
{
"url": "http://localhost:13313/marketingServices/iphonesLogInfo",
"classification": "write_notification_log",
"sideEffect": true
}
],
"businessApiDependencies": [
{
"url": "http://yxgateway.gs.sgcc.com.cn/emss-cmc-authdata-subdomain/member/mgtOrg/getAllSubMgtOrgTreeByOrgCode",
"classification": "read_org_tree"
},
{
"url": "http://yxgateway.gs.sgcc.com.cn/emss-chargacctgf-paysrv-front/member/acctabnor/queryAbnorList",
"classification": "read_exception_orders"
},
{
"url": "http://yxgateway.gs.sgcc.com.cn/emss-custmgtf-custview-front//member/electrivity/queryHistoryEnergyCharge",
"classification": "read_charge_history"
},
{
"url": "http://yxgateway.gs.sgcc.com.cn/emss-chargacctgf-paysrv-front/member/acctabnor/repetCtrlSend",
"classification": "dispatch_exception_order",
"sideEffect": true,
"blockedByDefault": true
}
],
"stateDependencies": [
{
"name": "previous_monitor_log",
"source": "MonitorServices/getMonitorLog"
},
{
"name": "current_user_org",
"source": "localStorage.loginUserInfo"
},
{
"name": "gateway_token",
"source": "localStorage.markToken"
},
{
"name": "cached_org_tree",
"source": "localStorage.yxClassList"
},
{
"name": "last_fee_control_send_time",
"source": "localStorage.zhzxFkycSendTime"
},
{
"name": "phone_and_holiday_configuration",
"source": "marketingServices/getOtherIphones"
}
],
"queueDependencies": [
{
"name": "pendingList",
"source": "queueObj.pendingList / obj.pendingList"
},
{
"name": "autoTask",
"source": "_this.autoTask",
"blockedByDefault": true
},
{
"name": "processQueue",
"source": "_this.processQueue",
"blockedByDefault": true
},
{
"name": "exeTQueue",
"source": "mac.exeTQueue",
"blockedByDefault": true
}
],
"dependencyClassification": {
"detectPreviewAllowed": [
"read_state",
"configuration_read",
"read_org_tree",
"read_exception_orders",
"read_charge_history"
],
"blockedByDefault": [
"write_monitor_state",
"write_monitor_log",
"write_dispose_log",
"write_notification_log",
"dispatch_exception_order",
"business_dispatch",
"host_notify",
"queue_continue"
]
},
"decisionRules": {
"source": "anchor scripts",
"recoveredAsOpaqueRules": true,
"knownInputs": [
"previous_monitor_log",
"current exception orders",
"charge history",
"phone/holiday configuration",
"last fee-control send time"
],
"knownOutputs": [
"pendingList",
"notifyCandidates",
"noActionList",
"summary"
]
},
"previewSchema": {
"summary": "object",
"pendingList": "array",
"notifyCandidates": "array",
"actionPlan": "array",
"blockedSideEffects": "array",
"evidence": "object",
"warnings": "array"
},
"actionPlanSchema": {
"itemId": "string",
"customerNo": "string?",
"orgNo": "string?",
"actionType": "dispatch|sms|call|audio|log|queue_next",
"targetEndpointOrHostCall": "string",
"requiresConfirmation": "boolean",
"blockedByDefault": "boolean",
"reason": "string"
},
"sideEffectPolicy": {
"dryRunDefault": true,
"requiresExplicitConfirmation": true,
"previewBeforeAction": true,
"maxItemsRequiredForActionModes": true,
"auditRecordRequired": true,
"blockedCallSignatures": [
"repetCtrlSend",
"mac.sendMessages",
"mac.callOutLogin",
"mac.audioPlay",
"_this.autoTask",
"_this.processQueue",
"mac.exeTQueue",
"setDisposeLog",
"setMonitorData",
"setMonitorLog",
"setSendMessageLog",
"setAudioPlayLog"
],
"blockedActions": [
{
"action": "dispatch_fee_control_exception_order",
"signals": [
"repetCtrlSend"
],
"blockedByDefault": true,
"requiredFutureGate": "explicit_confirm_dispatch"
},
{
"action": "send_sms",
"signals": [
"mac.sendMessages"
],
"blockedByDefault": true,
"requiredFutureGate": "explicit_confirm_notify"
},
{
"action": "call_phone",
"signals": [
"mac.callOutLogin"
],
"blockedByDefault": true,
"requiredFutureGate": "explicit_confirm_notify"
},
{
"action": "play_audio",
"signals": [
"mac.audioPlay or audio log path"
],
"blockedByDefault": true,
"requiredFutureGate": "explicit_confirm_notify"
},
{
"action": "write_monitor_state",
"signals": [
"setMonitorData",
"setMonitorLog"
],
"blockedByDefault": true,
"requiredFutureGate": "dry_run_or_explicit_monitor_write"
},
{
"action": "write_dispose_log",
"signals": [
"setDisposeLog"
],
"blockedByDefault": true,
"requiredFutureGate": "explicit_confirm_dispatch"
},
{
"action": "continue_queue",
"signals": [
"_this.autoTask",
"_this.processQueue",
"mac.exeTQueue"
],
"blockedByDefault": true,
"requiredFutureGate": "explicit_confirm_queue_next"
}
]
},
"gateRequirements": [
{
"gate": "explicit_confirm_dispatch",
"requiredFor": [
"repetCtrlSend",
"setDisposeLog"
],
"mvpEnabled": false
},
{
"gate": "explicit_confirm_notify",
"requiredFor": [
"mac.sendMessages",
"mac.callOutLogin",
"mac.audioPlay",
"notification logs"
],
"mvpEnabled": false
},
{
"gate": "explicit_confirm_queue_next",
"requiredFor": [
"_this.autoTask",
"_this.processQueue",
"mac.exeTQueue"
],
"mvpEnabled": false
},
{
"gate": "dry_run_or_explicit_monitor_write",
"requiredFor": [
"setMonitorData",
"setMonitorLog"
],
"mvpEnabled": false
}
],
"auditRequirements": {
"recordResolvedMode": true,
"recordInputFilters": true,
"recordReadDependencies": true,
"recordBlockedSideEffects": true,
"recordPreviewBeforeAnyAction": true,
"recordConfirmationForFutureActionModes": true
},
"nextRecommendedRoute": "monitoring-action-detect-preview-generator-design"
}

View File

@@ -0,0 +1,62 @@
{
"queryAbnorList": [
{
"id": "MOCK-ORDER-001",
"consNo": "MOCK-CONS-001",
"custNo": "MOCK-CUST-001",
"orgNo": "MOCK-ORG-001",
"abnorType": "fee_control_exception",
"createdAt": "2026-04-22T09:00:00+08:00"
},
{
"id": "MOCK-ORDER-002",
"consNo": "MOCK-CONS-002",
"custNo": "MOCK-CUST-002",
"orgNo": "MOCK-ORG-001",
"abnorType": "fee_control_exception",
"createdAt": "2026-04-22T09:10:00+08:00"
}
],
"queryHistoryEnergyCharge": [
{
"consNo": "MOCK-CONS-001",
"arrears": "120.00",
"chargeStatus": "pending"
},
{
"consNo": "MOCK-CONS-002",
"arrears": "0.00",
"chargeStatus": "cleared"
}
],
"getMonitorLog": {
"lastRunAt": "2026-04-22T08:00:00+08:00",
"processedOrderIds": [
"MOCK-ORDER-000"
]
},
"getOtherIphones": {
"phones": [
"13800000000",
"13900000000"
],
"holidayMode": false
},
"pendingList": [
{
"id": "MOCK-ORDER-001",
"consNo": "MOCK-CONS-001",
"custNo": "MOCK-CUST-001",
"orgNo": "MOCK-ORG-001",
"reason": "mock fee-control exception"
}
],
"notifyCandidates": [
{
"id": "MOCK-ORDER-001",
"channel": "sms",
"phone": "13800000000",
"reason": "mock notification candidate"
}
]
}

View File

@@ -0,0 +1,34 @@
{
"status": "mock-validation-pass",
"family": "monitoring_action_workflow",
"mode": "detect_preview",
"artifactStatus": "preview-ok",
"pendingCount": 1,
"notifyCount": 1,
"actionPlanCount": 1,
"blockedCallSignatures": [
"repetCtrlSend",
"mac.sendMessages",
"mac.callOutLogin",
"mac.audioPlay",
"_this.autoTask",
"_this.processQueue",
"mac.exeTQueue",
"setDisposeLog",
"setMonitorData",
"setMonitorLog",
"setSendMessageLog",
"setAudioPlayLog"
],
"sideEffectCounters": {
"repetCtrlSend": 0,
"sendMessages": 0,
"callOutLogin": 0,
"audioPlay": 0,
"exeTQueue": 0,
"productionLogWrite": 0
},
"nonPreviewModeBlocked": true,
"fixtures": "tests/fixtures/generated_scene/monitoring_action_mock_validation_fixtures_2026-04-22.json",
"skillRoot": "examples/monitoring_action_detect_preview_anchor_2026-04-21/skills/command-center-fee-control-monitor"
}

View File

@@ -0,0 +1,335 @@
{
"family": "monitoring_action_workflow",
"date": "2026-04-21",
"status": "evidence-extracted",
"anchorSources": [
"D:/desk/?????/??????????.txt",
"D:/desk/?????/?????????????.txt"
],
"scripts": [
{
"role": "detection_business_script",
"path": "D:/desk/?????/??????????.txt",
"observedStages": [
"detect",
"decide",
"preview",
"log",
"notify",
"queue_next"
],
"description": "Collects fee-control exception orders, enriches charge history, compares monitor state, prepares pending/notification candidates, writes monitor logs, and may enqueue follow-up actions."
},
{
"role": "automation_action_script",
"path": "D:/desk/?????/?????????????.txt",
"observedStages": [
"act",
"log",
"notify",
"queue_next"
],
"description": "Consumes pendingList, dispatches exception orders through repetCtrlSend, writes dispose logs, and continues an external queue."
}
],
"runtimeContext": {
"runtime_context_url": "http://yx.gs.sgcc.com.cn/",
"expected_domain": "yx.gs.sgcc.com.cn",
"gateway_domain": "yxgateway.gs.sgcc.com.cn",
"localhost_service_base": "http://localhost:13313",
"browserAttachedRequired": true,
"hostBridgeRequired": true
},
"stageEvidence": [
{
"stage": "detect",
"evidence": [
"queryAbnorList",
"queryHistoryEnergyCharge",
"getAllSubMgtOrgTreeByOrgCode",
"MonitorServices/getMonitorLog",
"marketingServices/getOtherIphones"
]
},
{
"stage": "decide",
"evidence": [
"setData pending list computation",
"previous monitor state comparison",
"holiday/time/phone configuration checks"
]
},
{
"stage": "preview",
"evidence": [
"queueObj.pendingList",
"computed call/message/audio candidate lists"
],
"mvpAllowed": true
},
{
"stage": "act",
"evidence": [
"repetCtrlSend"
],
"blockedByDefault": true
},
{
"stage": "notify",
"evidence": [
"mac.sendMessages",
"mac.callOutLogin",
"setSendMessageLog",
"setAudioPlayLog"
],
"blockedByDefault": true
},
{
"stage": "log",
"evidence": [
"setMonitorData",
"setMonitorLog",
"setDisposeLog",
"messageLogInfo",
"iphonesLogInfo"
]
},
{
"stage": "queue_next",
"evidence": [
"_this.autoTask",
"_this.processQueue",
"mac.exeTQueue"
],
"blockedByDefault": true
}
],
"localStorageReads": [
{
"key": "loginUserInfo",
"usage": "current user org and login context"
},
{
"key": "markToken",
"usage": "business gateway Authorization token"
},
{
"key": "yxClassList",
"usage": "cached organization tree/list"
},
{
"key": "zhzxFkycSendTime",
"usage": "last fee-control send/monitor time"
}
],
"localServiceDependencies": [
{
"url": "http://localhost:13313/MonitorServices/getMonitorLog",
"classification": "read_state"
},
{
"url": "http://localhost:13313/MonitorServices/setMonitorData",
"classification": "write_monitor_state",
"sideEffect": true
},
{
"url": "http://localhost:13313/MonitorServices/setMonitorLog",
"classification": "write_monitor_log",
"sideEffect": true
},
{
"url": "http://localhost:13313/MonitorServices/setDisposeLog",
"classification": "write_dispose_log",
"sideEffect": true
},
{
"url": "http://localhost:13313/MonitorServices/setAudioPlayLog",
"classification": "write_notification_log",
"sideEffect": true
},
{
"url": "http://localhost:13313/MonitorServices/setSendMessageLog",
"classification": "write_notification_log",
"sideEffect": true
},
{
"url": "http://localhost:13313/marketingServices/getOtherIphones",
"classification": "configuration_read"
},
{
"url": "http://localhost:13313/marketingServices/messageLogInfo",
"classification": "write_notification_log",
"sideEffect": true
},
{
"url": "http://localhost:13313/marketingServices/iphonesLogInfo",
"classification": "write_notification_log",
"sideEffect": true
}
],
"businessApiDependencies": [
{
"url": "http://yxgateway.gs.sgcc.com.cn/emss-cmc-authdata-subdomain/member/mgtOrg/getAllSubMgtOrgTreeByOrgCode",
"classification": "read_org_tree"
},
{
"url": "http://yxgateway.gs.sgcc.com.cn/emss-chargacctgf-paysrv-front/member/acctabnor/queryAbnorList",
"classification": "read_exception_orders"
},
{
"url": "http://yxgateway.gs.sgcc.com.cn/emss-custmgtf-custview-front//member/electrivity/queryHistoryEnergyCharge",
"classification": "read_charge_history"
},
{
"url": "http://yxgateway.gs.sgcc.com.cn/emss-chargacctgf-paysrv-front/member/acctabnor/repetCtrlSend",
"classification": "dispatch_exception_order",
"sideEffect": true,
"blockedByDefault": true
}
],
"sideEffectEvidence": [
{
"action": "dispatch_fee_control_exception_order",
"signals": [
"repetCtrlSend"
],
"blockedByDefault": true,
"requiredFutureGate": "explicit_confirm_dispatch"
},
{
"action": "send_sms",
"signals": [
"mac.sendMessages"
],
"blockedByDefault": true,
"requiredFutureGate": "explicit_confirm_notify"
},
{
"action": "call_phone",
"signals": [
"mac.callOutLogin"
],
"blockedByDefault": true,
"requiredFutureGate": "explicit_confirm_notify"
},
{
"action": "play_audio",
"signals": [
"mac.audioPlay or audio log path"
],
"blockedByDefault": true,
"requiredFutureGate": "explicit_confirm_notify"
},
{
"action": "write_monitor_state",
"signals": [
"setMonitorData",
"setMonitorLog"
],
"blockedByDefault": true,
"requiredFutureGate": "dry_run_or_explicit_monitor_write"
},
{
"action": "write_dispose_log",
"signals": [
"setDisposeLog"
],
"blockedByDefault": true,
"requiredFutureGate": "explicit_confirm_dispatch"
},
{
"action": "continue_queue",
"signals": [
"_this.autoTask",
"_this.processQueue",
"mac.exeTQueue"
],
"blockedByDefault": true,
"requiredFutureGate": "explicit_confirm_queue_next"
}
],
"stateDependencies": [
{
"name": "previous_monitor_log",
"source": "MonitorServices/getMonitorLog"
},
{
"name": "current_user_org",
"source": "localStorage.loginUserInfo"
},
{
"name": "gateway_token",
"source": "localStorage.markToken"
},
{
"name": "cached_org_tree",
"source": "localStorage.yxClassList"
},
{
"name": "last_fee_control_send_time",
"source": "localStorage.zhzxFkycSendTime"
},
{
"name": "phone_and_holiday_configuration",
"source": "marketingServices/getOtherIphones"
}
],
"queueDependencies": [
{
"name": "pendingList",
"source": "queueObj.pendingList / obj.pendingList"
},
{
"name": "autoTask",
"source": "_this.autoTask",
"blockedByDefault": true
},
{
"name": "processQueue",
"source": "_this.processQueue",
"blockedByDefault": true
},
{
"name": "exeTQueue",
"source": "mac.exeTQueue",
"blockedByDefault": true
}
],
"detectPreviewCandidate": {
"defaultMode": "detect_preview",
"allowedOutputs": [
"pendingList",
"summary",
"actionPlan",
"blockedSideEffects"
],
"allowedReads": [
"localStorage reads",
"business query APIs",
"localhost read/config APIs"
],
"blockedWrites": [
"dispatch",
"SMS",
"phone call",
"audio play",
"monitor/log writes unless dry-run isolated",
"queue continuation"
]
},
"blockedByDefault": [
"repetCtrlSend",
"mac.sendMessages",
"mac.callOutLogin",
"mac.audioPlay",
"_this.autoTask",
"_this.processQueue",
"mac.exeTQueue",
"setDisposeLog",
"setMonitorData",
"setMonitorLog",
"setSendMessageLog",
"setAudioPlayLog"
],
"nextRecommendedRoute": "monitoring-action-ir-contract"
}

View File

@@ -0,0 +1,36 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Multi Mode Fixture</title>
</head>
<body>
<script>
const sourceUrl = "http://20.76.57.61:18080/gsllys";
function queryReport(period_mode, orgno) {
if (period_mode === "month") {
return $.ajax({
url: "http://20.76.57.61:18080/gsllys/monthReport",
type: "POST",
contentType: "application/x-www-form-urlencoded",
data: { orgno, rows: 1000, page: 1, tjzq: "month" }
});
}
if (period_mode === "week") {
return $.ajax({
url: "http://20.76.57.61:18080/gsllys/weekReport",
type: "POST",
contentType: "application/x-www-form-urlencoded",
data: { orgno, rows: 1000, page: 1, tjzq: "week" }
});
}
return [];
}
function renderTable(response) {
return response.content || [];
}
</script>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More