Skip to content

Commit 8a80420

Browse files
committed
接通C和C++文档稳定任务及当前原生修复指引
1 parent ace1fbb commit 8a80420

35 files changed

Lines changed: 3326 additions & 31 deletions

‎.github/workflows/ci.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ jobs:
8686
cargo test --locked -p codeguard-cli --features wasm-precheck --test grammar_evaluation --test grammar_native_differential --test javascript_native_differential --test ruby_native_differential --test go_native_differential --test rust_formatter_differential --test go_package_structure
8787
# C/C++明确标准的原生边界与受控错版本回放必须在WASM构建下验收。
8888
# Ubuntu宿主Clang不冒充固定AppleClang21;实际条件目标另需显式已有工具。
89-
cargo test --locked -p codeguard-cli --features wasm-precheck --test clang_lint_cli --test c_family_comments_cli --test c_family_native_replay
89+
cargo test --locked -p codeguard-cli --features wasm-precheck --test clang_lint_cli --test c_family_comments_cli --test c_family_comments_workbench --test c_family_native_replay
9090
# 固定 Rustfmt 解析器的协议反例;不把 CI 预装版本当作指定原生版本。
9191
cargo test --locked -p codeguard-cli --features wasm-precheck --lib rustfmt_syntax_probe
9292
cargo test --locked -p codeguard-cli --features wasm-precheck --lib python_syntax_probe

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1125,4 +1125,4 @@ Rust CVE observations now check same-run stability of RustSec crates/rust conten
11251125

11261126
`codeguard comments c api.c --clang-tool /absolute/clang --standard c11 --format=json`; C++ selects `comments cpp api.cpp --standard c++17` with the same tool argument. The measured Apple Clang 21 documentation profile requires an explicit tool and matching standard, without installation. Three precise native SARIF rules cover empty command descriptions, unknown parameter names and return tags on void functions, with repair steps, comment-only scope and original-tool verification argv. Unknown rules remain separate. Invalid reports, changed inputs, cancellation and unresolved preprocessing cannot become source violations.
11271127

1128-
The dedicated `c_family_comments_feedback` 0.1 observation leaves project configuration unknown and detailed-contract qualification ungranted. Completely missing comments may yield zero native diagnostics. Persistent documentation tasks, project checks and Hooks are still missing here: `next=null`, exit3 or cancellation130, without automatic closure or delivery permission. See the [16-case native evidence, execution path and remaining gaps](tests/acceptance/c-family-comments-native.md).
1128+
The dedicated `c_family_comments_feedback` 0.1 observation leaves project configuration unknown and detailed-contract qualification ungranted. Completely missing comments may yield zero native diagnostics. Without a workspace, feedback remains 0.1 with `next=null`. An existing workspace now receives feedback0.2, stable file/language/standard/native-rule tasks and next0.28 with all current positions and original-tool rescan argv. Input/tool changes withdraw repair locations; clean rescans keep tasks open. Dedicated task verification, attempt journals, project checks and Hooks remain unintegrated. Exit3 or cancellation130 persists, without automatic closure or delivery permission. See the [16-case native evidence, execution path and remaining gaps](tests/acceptance/c-family-comments-native.md).

‎README.zh-CN.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1102,4 +1102,4 @@ Rust CVE局部观察现在核对同轮RustSec crates/rust内容、成员及物
11021102

11031103
`codeguard comments c api.c --clang-tool /absolute/clang --standard c11 --format=json`;C++ 使用 `comments cpp api.cpp --standard c++17` 并保留同一工具参数。当前仅适配已实测的 Apple Clang 21 独立文档警告档案,明确工具与标准,不隐式安装。原生 SARIF 的空命令描述、错误参数名及 void 返回标签三项精确规则带有修复步骤、仅文档允许范围和原工具复检 argv;未知规则单独保留。坏报告、输入变化、取消和未解析预处理不能成为源码违规。
11041104

1105-
这是 `c_family_comments_feedback` 0.1 的局部观察:项目原配置未知,完整详细契约未授予资格;Clang完全缺失注释也可能零诊断。本阶段未持久化文档任务或接入项目/Hook;`next=null`、退出3,取消130,不自动关闭任务或授予门禁。真实16例、执行路径和剩余缺口见[原生文档验收](tests/acceptance/c-family-comments-native.md)。
1105+
这是 `c_family_comments_feedback` 0.1 的局部观察:项目原配置未知,完整详细契约未授予资格;Clang完全缺失注释也可能零诊断。未绑定工作台时保留0.1/`next=null`;已有工作台现在提供0.2反馈、按文件/语言标准/原规则归并的稳定任务和next0.28,保留全部当前位置及原工具复扫argv。输入或工具变化撤回修复定位,清洁复扫保留开放任务。专用task verify、尝试日志、项目检查和Hook仍待接通;退出3,取消130,不自动关闭任务或授予门禁。真实16例、执行路径和剩余缺口见[原生文档验收](tests/acceptance/c-family-comments-native.md)。

‎crates/codeguard-cli/src/c_family_comments_arguments.rs‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,6 @@ impl CFamilyCommentsArguments {
1717
if request.clang_tool.is_none() || request.standard.is_none() {
1818
return Err("C/C++文档检查必须提供--clang-tool绝对路径与匹配的--standard".into());
1919
}
20-
if request.workspace.is_some() {
21-
return Err("C/C++文档单文件探针尚未支持工作台导入;不接受--workspace".into());
22-
}
2320
Ok(Self(request))
2421
}
2522
}

‎crates/codeguard-cli/src/c_family_comments_command.rs‎

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,17 @@ pub fn run(args: &[String]) -> ExitCode {
1818
}
1919
};
2020
let deadline = Instant::now() + Duration::from_millis(request.timeout_ms);
21+
let workspace = match crate::c_family_comments_workbench::resolve_root(
22+
&request.source,
23+
request.workspace.as_deref(),
24+
) {
25+
Ok(workspace) => workspace,
26+
Err(reason) if request.workspace.is_some() => {
27+
eprintln!("{reason}");
28+
return ExitCode::from(2);
29+
}
30+
Err(_) => None,
31+
};
2132
let path = request
2233
.source
2334
.canonicalize()
@@ -104,7 +115,7 @@ pub fn run(args: &[String]) -> ExitCode {
104115
Some("completed" | "diagnostics_observed")
105116
) && !has_native_errors;
106117
let exit = if cancelled { 130 } else { 3 };
107-
let report = json!({"schema_version":"0.1.0","report_type":"c_family_comments_feedback","operation":"comments","language":request.language,
118+
let mut report = json!({"schema_version":"0.1.0","report_type":"c_family_comments_feedback","operation":"comments","language":request.language,
108119
"command_status":if cancelled {"cancelled"} else {"incomplete"},"exit_code":exit,"authority":"local_unverified","coverage_proven":false,"delivery_decision":"not_evaluated",
109120
"local_scan_complete":complete,"detailed_contract_qualification":"not_granted","workspace_binding":"not_bound","next":null,
110121
"reason":if has_native_errors {"native_syntax_errors_limit_documentation"} else {"native_documentation_coverage_unverified"},
@@ -113,6 +124,17 @@ pub fn run(args: &[String]) -> ExitCode {
113124
"native":native,"documentation_findings":documentation_findings,"unclassified_native_diagnostics":unclassified,
114125
"next_actions":["按原生规则和位置修正文档,再使用本报告原工具与标准命令复检;完整项目文档政策和任务持久闭环仍须接入。",
115126
"Clang此档案不检查所有缺失注释或用途/异常/行为说明;零诊断不能证明详细文档合规,不能关闭历史任务或授予生产资格。"]});
127+
if let Some(root) = workspace {
128+
crate::c_family_comments_workbench::connect(
129+
&root,
130+
request.clang_tool.as_deref().expect("工具已校验"),
131+
&mut report,
132+
deadline,
133+
);
134+
report["next_actions"][0] = json!(
135+
"按当前原生规则和位置修正文档并运行原工具复扫;稳定任务已接入,专用task verify及可信关闭仍待实现。"
136+
);
137+
}
116138
if request.json {
117139
println!("{report}");
118140
} else {
@@ -124,6 +146,12 @@ pub fn run(args: &[String]) -> ExitCode {
124146
"原生状态 {};原因 {}",
125147
report["native"]["status"], report["native"]["reason"]
126148
);
149+
if !report["workbench"].is_null() {
150+
println!(
151+
"工作台 {};任务 {}",
152+
report["workbench"]["status"], report["workbench"]["task_ids"]
153+
);
154+
}
127155
for row in report["documentation_findings"]
128156
.as_array()
129157
.into_iter()
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
//! 原生文档观察绑定已有工作台,不初始化或签发关闭。
2+
use serde_json::{Value, json};
3+
use std::{
4+
path::{Path, PathBuf},
5+
sync::atomic::{AtomicU64, Ordering},
6+
time::{Instant, SystemTime, UNIX_EPOCH},
7+
};
8+
static NEXT: AtomicU64 = AtomicU64::new(0);
9+
/// 定位已有工作台;显式范围越界在原生启动前拒绝。
10+
pub(crate) fn resolve_root(
11+
source: &Path,
12+
explicit: Option<&Path>,
13+
) -> Result<Option<PathBuf>, String> {
14+
// 先拒绝链接/父跳转等不适用源码;不能按链接目标去写另一项目的工作台。
15+
crate::plain_syntax_source::read_plain_source(source)
16+
.map_err(|_| "C/C++工作台源码范围不适用")?;
17+
let absolute = source.canonicalize().map_err(|_| "C/C++工作台源码不可读")?;
18+
if let Some(root) = explicit {
19+
let root = root.canonicalize().map_err(|_| "C/C++工作台根不可读")?;
20+
if !root.is_dir() || !absolute.starts_with(&root) {
21+
return Err("C/C++文档源码不属于显式工作台".into());
22+
}
23+
return Ok(Some(root));
24+
}
25+
Ok(absolute
26+
.parent()
27+
.into_iter()
28+
.flat_map(Path::ancestors)
29+
.find(|root| std::fs::symlink_metadata(root.join(".codeguard")).is_ok())
30+
.map(Path::to_path_buf))
31+
}
32+
/// 保存并同步局部观察;中断后不开始新的持久化阶段。
33+
pub(crate) fn connect(root: &Path, tool: &Path, report: &mut Value, deadline: Instant) {
34+
report["schema_version"] = json!("0.2.0");
35+
report["task_workflow_status"] = json!("partial");
36+
let argv = report["verification_command"]
37+
.as_array_mut()
38+
.expect("固定复检命令为数组");
39+
argv.pop();
40+
argv.push(json!("--workspace"));
41+
argv.push(json!(root));
42+
argv.push(json!("--format=json"));
43+
report["workbench"] = json!({"status":"incomplete","reason":"clang_documentation_workspace_unavailable","workspace_id":null,"run_id":null,"task_ids":[],"sync":null});
44+
if codeguard_runtime::sigint_cancellation_requested() || Instant::now() >= deadline {
45+
report["workbench"]["reason"] = json!("request_interrupted");
46+
return;
47+
}
48+
let Some(id) = crate::workspace_refresh::read_workspace_baseline(root)
49+
.ok()
50+
.flatten()
51+
.and_then(|b| b.workspace_id().map(str::to_owned))
52+
else {
53+
return;
54+
};
55+
let Some(path) = report["path"]
56+
.as_str()
57+
.and_then(|s| Path::new(s).strip_prefix(root).ok())
58+
.and_then(Path::to_str)
59+
else {
60+
return;
61+
};
62+
let run = format!(
63+
"clangdoc-{}-{}-{}",
64+
std::process::id(),
65+
NEXT.fetch_add(1, Ordering::Relaxed),
66+
SystemTime::now()
67+
.duration_since(UNIX_EPOCH)
68+
.map_or(0, |d| d.as_nanos())
69+
);
70+
let packet = json!({"schema_version":"0.1.0","report_type":"clang_documentation_workbench_observation","workspace_binding":"bound","workspace_id":id,"run_id":run,"path":path,"language":report["language"],"standard":report["documentation_configuration"]["standard"],"profile":"clang-documentation-v1","selected_tool":tool,"source_sha256":report["source_sha256"],"local_scan_complete":report["local_scan_complete"],"native":report["native"],"authority":"local_unverified","coverage_proven":false,"delivery_decision":"not_evaluated"});
71+
report["workbench"]["workspace_id"] = json!(id);
72+
report["workbench"]["run_id"] = json!(run);
73+
if !crate::work_sync::c_family_comments_report::valid_shape(&packet) {
74+
report["workbench"]["reason"] = json!("clang_documentation_packet_invalid");
75+
return;
76+
}
77+
if crate::work_sync::save_local_report(root, &packet).is_err() {
78+
report["workbench"]["reason"] = json!("clang_documentation_report_write_failed");
79+
return;
80+
}
81+
if codeguard_runtime::sigint_cancellation_requested() || Instant::now() >= deadline {
82+
report["workbench"]["reason"] = json!("request_interrupted");
83+
return;
84+
}
85+
match crate::work_sync::sync_local_workspace(root) {
86+
Ok(s) if s.failed_reports == 0 => {
87+
report["workspace_binding"] = json!("bound");
88+
report["workbench"]["status"] = json!("synced_partial");
89+
report["workbench"]["reason"] = Value::Null;
90+
report["workbench"]["sync"] = json!({"new_findings":s.new_findings,"new_blockers":s.new_blockers,"imported_reports":s.imported_reports,"already_consumed_reports":s.already_consumed_reports,"historical_findings":s.historical_findings});
91+
report["workbench"]["task_ids"] = json!(
92+
crate::work_sync::c_family_comments_report::task_ids(root, &packet)
93+
);
94+
if !codeguard_runtime::sigint_cancellation_requested() && Instant::now() < deadline {
95+
match crate::next_command::read_local_brief_for_checker(
96+
root,
97+
crate::work_sync::c_family_comments_report::checker(&packet),
98+
) {
99+
Ok(next) => {
100+
report["next"] = if next["repair_brief"].is_null() {
101+
Value::Null
102+
} else {
103+
next
104+
}
105+
}
106+
Err(_) => {
107+
report["workbench"]["reason"] =
108+
json!("clang_documentation_next_unavailable")
109+
}
110+
}
111+
}
112+
}
113+
_ => report["workbench"]["reason"] = json!("clang_documentation_sync_failed"),
114+
}
115+
}

‎crates/codeguard-cli/src/command_examples.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub(crate) fn examples(command: &str) -> &'static [&'static str] {
2020
],
2121
"comments" => &[
2222
"codeguard comments c api.c --clang-tool /absolute/clang --standard c11 --format json",
23+
"codeguard comments c /absolute/project/api.c --workspace /absolute/project --clang-tool /absolute/clang --standard c11 --format json",
2324
"codeguard comments cpp api.cpp --clang-tool /absolute/clang --standard c++17 --format json",
2425
"codeguard comments java File.java --java-home /absolute/jdk21 --format json",
2526
"codeguard comments java File.java --workspace . --java-home /absolute/jdk21 --format json",

‎crates/codeguard-cli/src/lib.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,8 @@ mod c_family_comments_arguments;
511511
#[cfg(unix)]
512512
pub mod c_family_comments_command;
513513
#[cfg(unix)]
514+
mod c_family_comments_workbench;
515+
#[cfg(unix)]
514516
mod clang_lint_feedback;
515517

516518
#[cfg(feature = "wasm-precheck")]

‎crates/codeguard-cli/src/next_command.rs‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use crate::workspace_refresh::read_workspace_baseline;
1414

1515
const MAX_FACT_BYTES: u64 = 128 * 1024;
1616
const MAX_SOURCE_BYTES: u64 = 16 * 1024 * 1024;
17+
#[cfg(unix)]
18+
mod c_family_comments_candidate;
1719

1820
struct Arguments {
1921
root: PathBuf,
@@ -443,6 +445,13 @@ fn independent_source_task_index(root: &Path, candidates: &[Candidate]) -> Optio
443445
}
444446

445447
fn candidate(root: &Path, id: &str, fact: &Value) -> Result<Candidate, &'static str> {
448+
#[cfg(unix)]
449+
if matches!(
450+
fact["checker_id"].as_str(),
451+
Some("c.clang.documentation" | "cpp.clang.documentation")
452+
) {
453+
return c_family_comments_candidate::candidate(root, id, fact);
454+
}
446455
let kind = fact["kind"].as_str().ok_or("finding_kind_invalid")?;
447456
let fingerprint = fact["fingerprint"]
448457
.as_str()
@@ -2420,7 +2429,7 @@ fn run_sequence(run_id: &str) -> Option<u128> {
24202429

24212430
fn view(disposition: &str, reason: &str, brief: Value, actions: Value) -> Value {
24222431
json!({
2423-
"schema_version":if brief["schema_version"] == "0.27.0" {json!("0.27.0")}else if brief["schema_version"] == "0.26.0" {json!("0.26.0")}else if brief["schema_version"] == "0.25.0" {json!("0.25.0")}else if brief["schema_version"] == "0.24.0" {json!("0.24.0")}else if brief["schema_version"] == "0.23.0" {json!("0.23.0")}else if brief["schema_version"] == "0.22.0" {json!("0.22.0")}else if brief["schema_version"] == "0.21.0" {json!("0.21.0")}else if brief["schema_version"] == "0.20.0" {json!("0.20.0")}else if brief["checker_id"] == "shell.shellcheck" {json!("0.17.0")} else if brief["checker_id"] == "go.vet" {json!("0.13.0")} else if brief["checker_id"] == "syntax.native_confirmation" {brief["schema_version"].clone()} else {json!("0.1.0")}, "report_type":"repair_brief_preview",
2432+
"schema_version":if brief["schema_version"] == "0.28.0" {json!("0.28.0")}else if brief["schema_version"] == "0.27.0" {json!("0.27.0")}else if brief["schema_version"] == "0.26.0" {json!("0.26.0")}else if brief["schema_version"] == "0.25.0" {json!("0.25.0")}else if brief["schema_version"] == "0.24.0" {json!("0.24.0")}else if brief["schema_version"] == "0.23.0" {json!("0.23.0")}else if brief["schema_version"] == "0.22.0" {json!("0.22.0")}else if brief["schema_version"] == "0.21.0" {json!("0.21.0")}else if brief["schema_version"] == "0.20.0" {json!("0.20.0")}else if brief["checker_id"] == "shell.shellcheck" {json!("0.17.0")} else if brief["checker_id"] == "go.vet" {json!("0.13.0")} else if brief["checker_id"] == "syntax.native_confirmation" {brief["schema_version"].clone()} else {json!("0.1.0")}, "report_type":"repair_brief_preview",
24242433
"operation":"next", "command_status":"complete", "exit_code":0,
24252434
"disposition":disposition, "reason":reason,
24262435
"repair_brief":brief, "next_actions":actions,

0 commit comments

Comments
 (0)