diff --git a/README.md b/README.md index 25545623..a3cd8cb5 100644 --- a/README.md +++ b/README.md @@ -94,9 +94,9 @@ cargo build --locked -p codeguard-cli Version output includes `cli_version`, `target`, and protocol information. Discovery and init preview return observations and unknowns. Dry-run creates neither `AGENTS.md` nor a project data directory. Add Cargo `--offline` only when dependencies are cached. -The workspace requires `std`. The opt-in `wasm-precheck` build feature uses a bounded Rust worker with pinned Java/TypeScript grammar candidates. It currently reaches only single-file `lint java` and `lint typescript` requests without explicit native context; it is absent from the published npm `0.1.2` package. No `no_std`, completed project-wide WASM fallback, zero-unsafe, or fastest-runtime claim is made. Runtime OS calls require safety review; a comprehensive security audit is not claimed. +The workspace requires `std`. The opt-in `wasm-precheck` build feature uses a bounded Rust worker with pinned Java, TypeScript, and TSX grammar candidates. It currently reaches only single-file `lint java` and `lint typescript` requests without explicit native context; `.tsx` uses its own grammar. It is absent from the published npm `0.1.2` package. No `no_std`, completed project-wide WASM fallback, zero-unsafe, or fastest-runtime claim is made. Runtime OS calls require safety review; a comprehensive security audit is not claimed. -The current source-built CLI's `codeguard grammar status --format=json` reports the coverage gap without loading grammars or running lint: the pinned CodeGraph source has 30 vendored WASM files plus two distinct grammars resolved through its dependency; CodeGuard has two unqualified candidates and zero released syntax capabilities. The separate [coverage inventory](grammars/codegraph-coverage.json) is not an approved asset manifest. COBOL's 16.4 MB source asset also exceeds the current Rust loader's 8 MiB limit. +The current source-built CLI's `codeguard grammar status --format=json` reports the coverage gap without loading grammars or running lint: the pinned CodeGraph source has 30 vendored WASM files plus two distinct grammars resolved through its dependency; CodeGuard has three unqualified candidates and zero released syntax capabilities. The separate [coverage inventory](grammars/codegraph-coverage.json) is not an approved asset manifest. COBOL's 16.4 MB source asset also exceeds the current Rust loader's 8 MiB limit. ### npm installation and one-off use diff --git a/README.zh-CN.md b/README.zh-CN.md index e223ce3a..d116c971 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -94,9 +94,9 @@ cargo build --locked -p codeguard-cli 版本输出包含 `cli_version`、`target` 和协议信息。发现与 init 预览返回观察及未知项。Dry-run 不创建 `AGENTS.md` 或项目数据目录。仅在依赖已缓存时为 Cargo 添加 `--offline`。 -工作区要求 `std`。可选 `wasm-precheck` 构建特性已用固定的 Java/TypeScript grammar 候选资产与有界 Rust worker,为缺少显式原生上下文的 `lint java`、`lint typescript` 单文件请求提供疑似语法观察;公开 npm `0.1.2` 不含该路径。不声称 `no_std`、已完成项目级 WASM 兜底、零 unsafe 或性能最快。运行层系统调用需要安全审查,当前不宣称已完成整体安全审计。 +工作区要求 `std`。可选 `wasm-precheck` 构建特性已用固定的 Java、TypeScript、TSX grammar 候选资产与有界 Rust worker,为缺少显式原生上下文的 `lint java`、`lint typescript` 单文件请求提供疑似语法观察;`.tsx` 使用独立 grammar。公开 npm `0.1.2` 不含该路径。不声称 `no_std`、已完成项目级 WASM 兜底、零 unsafe 或性能最快。运行层系统调用需要安全审查,当前不宣称已完成整体安全审计。 -当前源码构建的 CLI 可用 `codeguard grammar status --format=json` 只读展示来源覆盖缺口,不加载 grammar 或运行 lint:固定 CodeGraph 来源含 30 份随仓 WASM,另有两种独立 grammar 从其依赖取得;CodeGuard 当前只有两份未验收候选,已发行语法能力为零。[覆盖库存](grammars/codegraph-coverage.json)不是已批准资产清单。COBOL 来源资产约 16.4 MB,还超过当前 Rust 加载器的 8 MiB 限额。 +当前源码构建的 CLI 可用 `codeguard grammar status --format=json` 只读展示来源覆盖缺口,不加载 grammar 或运行 lint:固定 CodeGraph 来源含 30 份随仓 WASM,另有两种独立 grammar 从其依赖取得;CodeGuard 当前有三份未验收候选,已发行语法能力为零。[覆盖库存](grammars/codegraph-coverage.json)不是已批准资产清单。COBOL 来源资产约 16.4 MB,还超过当前 Rust 加载器的 8 MiB 限额。 ### npm 安装与一次性调用 diff --git a/crates/codeguard-adapters/src/grammar_asset_manifest.rs b/crates/codeguard-adapters/src/grammar_asset_manifest.rs index e1979b0f..83b8f843 100644 --- a/crates/codeguard-adapters/src/grammar_asset_manifest.rs +++ b/crates/codeguard-adapters/src/grammar_asset_manifest.rs @@ -68,7 +68,7 @@ pub struct GrammarAsset { pub release_status: String, } -/// 读取仓内固定清单,并检查 CodeGraph 许可证及两份资产的原始字节。 +/// 读取仓内固定清单,并检查 CodeGraph 许可证及三份资产的原始字节。 pub fn bundled_grammar_candidates() -> Result { let manifest = parse_grammar_asset_manifest(include_bytes!("../../../grammars/manifest.json"))?; let codegraph_license = include_bytes!("../../../grammars/LICENSE.codegraph"); @@ -85,6 +85,10 @@ pub fn bundled_grammar_candidates() -> Result { include_bytes!("../../../grammars/typescript/parser.wasm").as_slice(), include_bytes!("../../../grammars/typescript/LICENSE").as_slice(), ), + "tsx" => ( + include_bytes!("../../../grammars/tsx/parser.wasm").as_slice(), + include_bytes!("../../../grammars/typescript/LICENSE").as_slice(), + ), _ => return Err("候选语言未知".into()), }; verify_grammar_asset(asset, wasm, license)?; @@ -106,7 +110,7 @@ pub fn parse_grammar_asset_manifest(raw: &[u8]) -> Result Result Result ( + "https://github.com/tree-sitter/tree-sitter-typescript", + TYPESCRIPT_COMMIT, + "v0.23.2", + "tsx/parser.wasm", + "8f647a1b2cafe9ab00fb2056d79021d2a144ba17a72f45511072311c1b05d08e", + 1445641, + "typescript/LICENSE", + "49bf33cf78ef5897e4e161ce1517df7de1ae5042a65b6bcfd44401e0fc606559", + ), _ => return Err("grammar 语言未知".into()), }; if asset.dialect != asset.language diff --git a/crates/codeguard-adapters/src/syntax_precheck_candidate_report.rs b/crates/codeguard-adapters/src/syntax_precheck_candidate_report.rs index c7b412b4..a5a92167 100644 --- a/crates/codeguard-adapters/src/syntax_precheck_candidate_report.rs +++ b/crates/codeguard-adapters/src/syntax_precheck_candidate_report.rs @@ -100,6 +100,9 @@ pub fn parse_syntax_precheck_candidate_report( } let mut observations = Vec::with_capacity(report.files.len()); for file in report.files { + if !path_matches_language(&file.path, &report.backend.language) { + return Err("syntax_precheck_source_dialect_mismatch".into()); + } let source = source_bytes .get(&file.path) .ok_or("syntax_precheck_source_missing")?; @@ -132,3 +135,14 @@ pub fn parse_syntax_precheck_candidate_report( } Ok(actual) } + +fn path_matches_language(path: &str, language: &str) -> bool { + match language { + "java" => path.ends_with(".java"), + "typescript" => [".ts", ".mts", ".cts"] + .iter() + .any(|suffix| path.ends_with(suffix)), + "tsx" => path.ends_with(".tsx"), + _ => false, + } +} diff --git a/crates/codeguard-adapters/tests/grammar_asset_manifest.rs b/crates/codeguard-adapters/tests/grammar_asset_manifest.rs index 6efe63b3..c5a99096 100644 --- a/crates/codeguard-adapters/tests/grammar_asset_manifest.rs +++ b/crates/codeguard-adapters/tests/grammar_asset_manifest.rs @@ -5,7 +5,7 @@ use codeguard_adapters::{ #[test] fn bundled_candidates_pin_source_bytes_license_and_abi_without_claiming_support() { let manifest = bundled_grammar_candidates().expect("bundled manifest"); - assert_eq!(manifest.assets.len(), 2); + assert_eq!(manifest.assets.len(), 3); for asset in &manifest.assets { let (wasm, license) = match asset.language.as_str() { "java" => ( @@ -16,6 +16,10 @@ fn bundled_candidates_pin_source_bytes_license_and_abi_without_claiming_support( include_bytes!("../../../grammars/typescript/parser.wasm").as_slice(), include_bytes!("../../../grammars/typescript/LICENSE").as_slice(), ), + "tsx" => ( + include_bytes!("../../../grammars/tsx/parser.wasm").as_slice(), + include_bytes!("../../../grammars/typescript/LICENSE").as_slice(), + ), other => panic!("unexpected language {other}"), }; verify_grammar_asset(asset, wasm, license).expect("pinned candidate bytes"); diff --git a/crates/codeguard-adapters/tests/syntax_precheck_report_contract.rs b/crates/codeguard-adapters/tests/syntax_precheck_report_contract.rs index 8565ff13..3e65e4b6 100644 --- a/crates/codeguard-adapters/tests/syntax_precheck_report_contract.rs +++ b/crates/codeguard-adapters/tests/syntax_precheck_report_contract.rs @@ -105,3 +105,20 @@ fn candidate_schema_declares_closed_versioned_contract() { assert_eq!(schema["additionalProperties"], false); assert_eq!(schema["properties"]["precheck"]["$ref"], "#/$defs/precheck"); } + +#[test] +fn tsx_candidate_requires_tsx_source_and_cannot_relabel_java() { + let mut report = candidate(); + report["backend"]["language"] = json!("tsx"); + report["backend"]["dialect"] = json!("tsx"); + report["backend"]["grammar_sha256"] = + json!("8f647a1b2cafe9ab00fb2056d79021d2a144ba17a72f45511072311c1b05d08e"); + assert!(read(&report).is_err()); + + report["files"][0]["path"] = json!("src/Component.tsx"); + let sources = BTreeMap::from([("src/Component.tsx".into(), b"hello".to_vec())]); + let status = + parse_syntax_precheck_candidate_report(&serde_json::to_vec(&report).unwrap(), &sources) + .unwrap(); + assert_eq!(status.status, SyntaxPrecheckStatus::Incomplete); +} diff --git a/crates/codeguard-cli/src/syntax_worker_command.rs b/crates/codeguard-cli/src/syntax_worker_command.rs index 8f911dd2..3c684c0e 100644 --- a/crates/codeguard-cli/src/syntax_worker_command.rs +++ b/crates/codeguard-cli/src/syntax_worker_command.rs @@ -63,6 +63,7 @@ fn observe(language: &str, source: &[u8]) -> Result include_bytes!("../../../grammars/java/parser.wasm").as_slice(), "typescript" => include_bytes!("../../../grammars/typescript/parser.wasm").as_slice(), + "tsx" => include_bytes!("../../../grammars/tsx/parser.wasm").as_slice(), _ => return Err("不支持的 grammar 语种".into()), }; let mut grammar = WasmGrammar::load(language, wasm, &asset.sha256, asset.abi_version as usize)?; diff --git a/crates/codeguard-cli/src/typescript_syntax_precheck.rs b/crates/codeguard-cli/src/typescript_syntax_precheck.rs index 1304535c..8d1ab151 100644 --- a/crates/codeguard-cli/src/typescript_syntax_precheck.rs +++ b/crates/codeguard-cli/src/typescript_syntax_precheck.rs @@ -28,15 +28,24 @@ pub(crate) fn eligible(args: &EslintLintArguments) -> bool { } /// 使用本轮源码快照与私有 Rust worker 补充疑似语法观察;原生仍未运行。 -/// 参数为受支持的单文件请求及共同截止时间;返回无交付权威的 0.3.0 反馈。 +/// 参数为受支持的单文件请求及共同截止时间;返回无交付权威的 TypeScript 0.3.0 或 TSX 0.4.0 反馈。 pub(crate) fn observe(args: &EslintLintArguments, deadline: Instant) -> Value { + let language = if args + .source + .extension() + .is_some_and(|extension| extension == "tsx") + { + "tsx" + } else { + "typescript" + }; let source_name = args .source .file_name() .and_then(|name| name.to_str()) .unwrap_or("source.ts"); let mut report = json!({ - "schema_version": "0.3.0", + "schema_version": if language == "tsx" { "0.4.0" } else { "0.3.0" }, "report_type": "eslint_local_feedback", "status": "incomplete", "local_coherent": false, @@ -51,7 +60,7 @@ pub(crate) fn observe(args: &EslintLintArguments, deadline: Instant) -> Value { "setup": {"requirement": "required", "reason": "native_confirmation_needed", "task_id": null}, "syntax_precheck": { "backend": "bundled_tree_sitter_wasm_candidate", - "language": "typescript", + "language": language, "status": "incomplete", "reason": "not_run", "source_path": source_name, @@ -82,7 +91,7 @@ pub(crate) fn observe(args: &EslintLintArguments, deadline: Instant) -> Value { }; let observation = match run_syntax_worker_candidate( &executable, - "typescript", + language, source_name, &source, deadline, diff --git a/crates/codeguard-cli/tests/grammar_status_cli.rs b/crates/codeguard-cli/tests/grammar_status_cli.rs index 70757069..78daef0c 100644 --- a/crates/codeguard-cli/tests/grammar_status_cli.rs +++ b/crates/codeguard-cli/tests/grammar_status_cli.rs @@ -12,7 +12,7 @@ fn codegraph_coverage_is_explicit_and_never_claims_parser_or_gate_completion() { assert_eq!(report["report_type"], "grammar_coverage_inventory"); assert_eq!(report["codegraph_grammar_count"], 32); assert_eq!(report["codegraph_vendored_count"], 30); - assert_eq!(report["candidate_count"], 2); + assert_eq!(report["candidate_count"], 3); assert_eq!(report["released_count"], 0); assert_eq!(report["authority"], "source_inventory_only"); assert_eq!(report["parser_capability"], "unverified"); @@ -25,7 +25,7 @@ fn codegraph_coverage_is_explicit_and_never_claims_parser_or_gate_completion() { assert_eq!(asset["released"], false); assert!(!asset["gap"].as_str().unwrap().is_empty()); } - for language in ["java", "typescript"] { + for language in ["java", "typescript", "tsx"] { let asset = assets .iter() .find(|row| row["language"] == language) diff --git a/crates/codeguard-cli/tests/typescript_syntax_fallback_candidate.rs b/crates/codeguard-cli/tests/typescript_syntax_fallback_candidate.rs index 61193ffe..423f9999 100644 --- a/crates/codeguard-cli/tests/typescript_syntax_fallback_candidate.rs +++ b/crates/codeguard-cli/tests/typescript_syntax_fallback_candidate.rs @@ -90,6 +90,72 @@ fn no_recovery_remains_incomplete_and_javascript_does_not_use_typescript_grammar assert!(js_report.get("syntax_precheck").is_none()); } +#[test] +fn tsx_uses_its_own_grammar_instead_of_reporting_valid_jsx_as_suspect() { + let project = Project::new(); + fs::write( + project.0.join("component.tsx"), + "const node =
hello
;\n", + ) + .unwrap(); + let (status, report) = project.lint("component.tsx"); + assert_eq!(status, 3); + assert_eq!(report["schema_version"], "0.4.0"); + assert_eq!(report["native"]["status"], "not_run"); + assert_eq!(report["syntax_precheck"]["language"], "tsx"); + assert_eq!(report["syntax_precheck"]["checked_files"], 1); + assert_eq!( + report["syntax_precheck"]["grammar_sha256"], + "8f647a1b2cafe9ab00fb2056d79021d2a144ba17a72f45511072311c1b05d08e" + ); + assert!( + report["syntax_precheck"]["observations"] + .as_array() + .unwrap() + .is_empty() + ); + assert_eq!(report["delivery_decision"], "not_evaluated"); + + fs::write( + project.0.join("broken.tsx"), + "const node =
;\n", + ) + .unwrap(); + let (_, broken) = project.lint("broken.tsx"); + assert_eq!(broken["syntax_precheck"]["language"], "tsx"); + assert!( + !broken["syntax_precheck"]["observations"] + .as_array() + .unwrap() + .is_empty() + ); + assert_eq!(broken["syntax_precheck"]["status"], "incomplete"); + assert!(broken["findings"].as_array().unwrap().is_empty()); + + let schema: Value = serde_json::from_str(include_str!( + "../../../schemas/eslint-local-feedback-v0.4.schema.json" + )) + .unwrap(); + assert_eq!(schema["properties"]["schema_version"]["const"], "0.4.0"); + assert_eq!( + schema["properties"]["syntax_precheck"]["properties"]["language"]["const"], + "tsx" + ); + let actual: std::collections::BTreeSet<_> = report + .as_object() + .unwrap() + .keys() + .map(String::as_str) + .collect(); + let required: std::collections::BTreeSet<_> = schema["required"] + .as_array() + .unwrap() + .iter() + .map(|item| item.as_str().unwrap()) + .collect(); + assert_eq!(actual, required); +} + #[test] fn candidate_feedback_schema_is_versioned_and_closed() { let schema: Value = serde_json::from_str(include_str!( diff --git a/crates/codeguard-runtime/tests/wasm_grammar_load.rs b/crates/codeguard-runtime/tests/wasm_grammar_load.rs index 347176ef..b9119d75 100644 --- a/crates/codeguard-runtime/tests/wasm_grammar_load.rs +++ b/crates/codeguard-runtime/tests/wasm_grammar_load.rs @@ -4,6 +4,7 @@ use codeguard_runtime::WasmGrammar; const JAVA: &[u8] = include_bytes!("../../../grammars/java/parser.wasm"); const TYPESCRIPT: &[u8] = include_bytes!("../../../grammars/typescript/parser.wasm"); +const TSX: &[u8] = include_bytes!("../../../grammars/tsx/parser.wasm"); #[test] fn pinned_grammars_load_offline_and_parse_valid_sources() { @@ -45,6 +46,27 @@ fn pinned_grammars_load_offline_and_parse_valid_sources() { .has_error() ); assert!(typescript.parse(&vec![b'x'; 1024 * 1024 + 1]).is_err()); + + let mut tsx = WasmGrammar::load( + "tsx", + TSX, + "8f647a1b2cafe9ab00fb2056d79021d2a144ba17a72f45511072311c1b05d08e", + 14, + ) + .expect("固定 TSX WASM 应可由 Rust 加载"); + assert_eq!(tsx.abi_version(), 14); + assert!( + !tsx.parse(b"const node =
hello
;") + .unwrap() + .root_node() + .has_error() + ); + assert!( + tsx.parse(b"const node =
;") + .unwrap() + .root_node() + .has_error() + ); } #[test] diff --git a/docs/Codeguard-Architecture.md b/docs/Codeguard-Architecture.md index 19fae3ae..6207a4d1 100644 --- a/docs/Codeguard-Architecture.md +++ b/docs/Codeguard-Architecture.md @@ -28,7 +28,7 @@ The existing [OpenSpec change](../openspec/changes/introduce-rust-codeguard-cli/ | [Core aggregation](../crates/codeguard-core/src/aggregate.rs), [delivery gate](../crates/codeguard-core/src/delivery_gate.rs) | Pure result semantics, not trusted public gate availability | | [Acceptance records](../tests/acceptance) | Scoped observations, test method, and residual gaps | -WASM requirements and 18 implementation tasks are recorded in the existing change. An opt-in Rust worker, pinned grammar candidates, and TypeScript/Java single-file feedback schemas now exist. Project-wide native-first routing, qualified grammar ranges, stable syntax tasks, and host integrations remain incomplete; design examples are not current command output. +WASM requirements and 18 implementation tasks are recorded in the existing change. An opt-in Rust worker, pinned Java/TypeScript/TSX grammar candidates, and narrow single-file feedback schemas now exist. Project-wide native-first routing, qualified grammar ranges, stable syntax tasks, and host integrations remain incomplete; design examples are not current command output. ## 2. Architectural drivers @@ -241,7 +241,7 @@ A completed native violation never selects fallback to obtain a clean result. A Reuse pinned CodeGraph grammar WASM artifacts and applicable upstream licenses, source references, patches and corpus cases. Do not copy CodeGraph's graph extraction or source-blanking heuristics into a syntax verdict. CodeGraph's `src/extraction/grammars.ts` loads language artifacts through `web-tree-sitter`; successful loading there does not prove compatibility with Codeguard's Rust runtime. The local source review on 2026-09-28 found modified grammar artifacts and about 65 MB of grammar files, so a live directory is not a release input. -The read-only `codeguard grammar status` command now projects a [pinned CodeGraph coverage inventory](../grammars/codegraph-coverage.json): 30 vendored WASM files and two dependency-provided grammars, with Java and TypeScript as CodeGuard candidates and none qualified for release. This inventory is deliberately separate from the pinned [candidate asset manifest](../grammars/manifest.json). In particular, the COBOL source file exceeds the current loader's 8 MiB input limit. Inventory rows never trigger loading or count as supported parser capability. +The read-only `codeguard grammar status` command now projects a [pinned CodeGraph coverage inventory](../grammars/codegraph-coverage.json): 30 vendored WASM files and two dependency-provided grammars, with Java, TypeScript and TSX as CodeGuard candidates and none qualified for release. This inventory is deliberately separate from the pinned [candidate asset manifest](../grammars/manifest.json). In particular, the COBOL source file exceeds the current loader's 8 MiB input limit. Inventory rows never trigger loading or count as supported parser capability. ```text grammars/ # proposed release assets, not project state diff --git a/docs/Codeguard-Architecture.zh_CN.md b/docs/Codeguard-Architecture.zh_CN.md index d6cde4b1..c206f26e 100644 --- a/docs/Codeguard-Architecture.zh_CN.md +++ b/docs/Codeguard-Architecture.zh_CN.md @@ -28,7 +28,7 @@ | [核心聚合](../crates/codeguard-core/src/aggregate.rs)、[交付门禁](../crates/codeguard-core/src/delivery_gate.rs) | 纯结果语义,不代表公开可信门禁已可用 | | [验收记录](../tests/acceptance) | 限定范围的观察、测试方法和剩余缺口 | -WASM 的规范与 18 项实施任务已纳入既有 change;可选 Rust worker、固定 grammar 候选资产和 TypeScript/Java 单文件反馈 schema 已存在。项目级原生优先调度、grammar 版本范围验收、稳定语法任务及宿主接线仍未完成;设计示例不是当前命令输出。 +WASM 的规范与 18 项实施任务已纳入既有 change;可选 Rust worker、固定 Java/TypeScript/TSX grammar 候选资产和局部单文件反馈 schema 已存在。项目级原生优先调度、grammar 版本范围验收、稳定语法任务及宿主接线仍未完成;设计示例不是当前命令输出。 ## 2. 架构驱动 @@ -241,7 +241,7 @@ flowchart TD 复用固定版本的 CodeGraph grammar WASM,以及适用的上游许可证、源码引用、补丁和语料。不能把 CodeGraph 的图提取或源码遮盖启发式直接用于语法判定。CodeGraph 的 `src/extraction/grammars.ts` 通过 `web-tree-sitter` 加载语言资产,在那里可加载不证明兼容 Codeguard 的 Rust 运行时。发行时必须固定不可变的来源与资产清单,不能把正在修改的本地目录直接当作发行输入。 -只读 `codeguard grammar status` 现投影[固定来源覆盖库存](../grammars/codegraph-coverage.json):CodeGraph 随仓 30 份 WASM,依赖提供另两种独立 grammar;CodeGuard 只有 Java、TypeScript 两份候选,尚无已验收发行能力。覆盖库存与[候选资产清单](../grammars/manifest.json)分开,不能凭库存行自动加载或宣称支持。尤其 COBOL 来源资产超过当前加载器 8 MiB 限额。 +只读 `codeguard grammar status` 现投影[固定来源覆盖库存](../grammars/codegraph-coverage.json):CodeGraph 随仓 30 份 WASM,依赖提供另两种独立 grammar;CodeGuard 有 Java、TypeScript、TSX 三份候选,尚无已验收发行能力。覆盖库存与[候选资产清单](../grammars/manifest.json)分开,不能凭库存行自动加载或宣称支持。尤其 COBOL 来源资产超过当前加载器 8 MiB 限额。 ```text grammars/ # 规划中的发行资产,不是项目状态 diff --git a/docs/Codeguard-Technical-Design.md b/docs/Codeguard-Technical-Design.md index 0b16c872..4c854190 100644 --- a/docs/Codeguard-Technical-Design.md +++ b/docs/Codeguard-Technical-Design.md @@ -14,7 +14,7 @@ The existing [OpenSpec change](../openspec/changes/introduce-rust-codeguard-cli/ Current source is the authority for callable behavior. Target contracts are labelled as such. The product priority is configuration discovery → native results → useful repair guidance. Internal consistency checks support this experience; they are not a demand for users to manually construct execution certificates. -WASM requirements and 18 implementation tasks are recorded in the existing change. Candidate Rust worker, pinned assets, and narrow TypeScript/Java single-file reports now exist behind an opt-in feature; project-wide native-first routing, qualified grammar ranges, and host integrations remain incomplete. Design examples are not current command output. +WASM requirements and 18 implementation tasks are recorded in the existing change. Candidate Rust worker, pinned Java/TypeScript/TSX assets, and narrow single-file reports now exist behind an opt-in feature; project-wide native-first routing, qualified grammar ranges, and host integrations remain incomplete. Design examples are not current command output. ## 2. Technology choices and trade-offs @@ -183,15 +183,15 @@ Core now has a local pure setup-action selector taking an upstream-verified nati When some files have suspected issues and others are unresolved, use overall `incomplete` while retaining all usable suspected observations. `clean` requires nonempty, completely checked selected scope. -These are the target semantic fields, not a shipped project-wide lint/check report. A narrow [candidate precheck schema](../schemas/syntax-precheck-candidate.schema.json) and [strict Rust reader](../crates/codeguard-adapters/src/syntax_precheck_candidate_report.rs) bind source SHA-256 and pinned grammar identity, recalculate status, and reject unknown versions or forged `clean`. Optional CLI single-file [TypeScript](../schemas/eslint-local-feedback-v0.3.schema.json) and [Java](../schemas/java-syntax-precheck-feedback-v0.1.schema.json) producers now include recovery positions and setup guidance; host rendering and durable task references remain absent. The bundled grammars remain unvalidated, so these reports cannot return `clean`. Missing required native execution remains incomplete (`3`); a suspected parser issue alone is not a confirmed violation (`1`). If a dedicated syntax-only operation is later introduced, its success must be explicitly scoped to syntax; no new `syntax` command is claimed here. +These are the target semantic fields, not a shipped project-wide lint/check report. A narrow [candidate precheck schema](../schemas/syntax-precheck-candidate.schema.json) and [strict Rust reader](../crates/codeguard-adapters/src/syntax_precheck_candidate_report.rs) bind source SHA-256, pinned grammar identity and file dialect, recalculate status, and reject unknown versions or forged `clean`. Optional CLI single-file [TypeScript](../schemas/eslint-local-feedback-v0.3.schema.json), [TSX](../schemas/eslint-local-feedback-v0.4.schema.json) and [Java](../schemas/java-syntax-precheck-feedback-v0.1.schema.json) producers include recovery positions and setup guidance; host rendering and durable task references remain absent. The bundled grammars remain unvalidated, so these reports cannot return `clean`. Missing required native execution remains incomplete (`3`); a suspected parser issue alone is not a confirmed violation (`1`). If a dedicated syntax-only operation is later introduced, its success must be explicitly scoped to syntax; no new `syntax` command is claimed here. -The opt-in CLI build now also emits [ESLint feedback 0.3.0](../schemas/eslint-local-feedback-v0.3.schema.json) for an explicit TypeScript file when no native execution context was supplied. It preserves `native=not_run` and `delivery=not_evaluated`, maps parser recoveries to suspected Unicode positions, and keeps the overall result incomplete even with zero recoveries. A partial native context or symlink does not trigger this candidate path; configured native execution stays on the original route. This is one local entry-point slice, not per-module native-first orchestration or automatic host feedback. +The opt-in CLI build emits [ESLint feedback 0.3.0](../schemas/eslint-local-feedback-v0.3.schema.json) for `.ts/.mts/.cts`, and [0.4.0](../schemas/eslint-local-feedback-v0.4.schema.json) for `.tsx`, when no native execution context was supplied. TSX uses its own pinned grammar, avoiding a TypeScript-parser false positive for valid JSX. Both preserve `native=not_run` and `delivery=not_evaluated`, map parser recoveries to suspected Unicode positions, and remain incomplete even with zero recoveries. A partial native context or symlink does not trigger this candidate path; configured native execution stays on the original route. This is one local entry-point slice, not per-module native-first orchestration or automatic host feedback. ### 5.4 Grammar import and runtime lifecycle — target Import only pinned WASM bytes with upstream license, commit/patch provenance, SHA-256, ABI, tested runtime and language/dialect ranges, corpus reference and known gaps. Verify each copied CodeGraph artifact in the selected Rust Tree-sitter runtime; do not copy TypeScript extraction logic or assume CodeGraph support equals syntax acceptance. A release manifest belongs to distribution assets, not writable `.codeguard/` project state. -Use `codeguard grammar status --format=json` to query the separate source coverage inventory. It reports 32 distinct CodeGraph grammar assets, two CodeGuard candidates, and zero released capabilities without running a parser. The two dependency-provided assets lack pinned bytes, and COBOL exceeds the current 8 MiB loader limit; these remain explicit gaps before any per-language qualification. +Use `codeguard grammar status --format=json` to query the separate source coverage inventory. It reports 32 distinct CodeGraph grammar assets, three CodeGuard candidates, and zero released capabilities without running a parser. The two dependency-provided assets lack pinned bytes, and COBOL exceeds the current 8 MiB loader limit; these remain explicit gaps before any per-language qualification. Use a parent-controlled parser worker with a total deadline, per-file input bound, memory/process limit and capped diagnostics. Lazy-load selected grammars, parse without general network/filesystem imports, and terminate a stuck worker without losing native results from other modules. Host-specific enforcement and Rust MSRV compatibility must be tested; numeric production budgets remain measurement-driven rather than invented promises. diff --git a/docs/Codeguard-Technical-Design.zh_CN.md b/docs/Codeguard-Technical-Design.zh_CN.md index 9136581f..a783b433 100644 --- a/docs/Codeguard-Technical-Design.zh_CN.md +++ b/docs/Codeguard-Technical-Design.zh_CN.md @@ -14,7 +14,7 @@ 可调用行为以当前源码为准,目标契约明确标注。产品优先级是配置发现 → 原生结果 → 有用的修复指引。内部一致性校验为这个体验服务,不要求用户手工构造执行证明。 -WASM 的规范与 18 项实施任务已纳入既有 change;可选特性下的 Rust worker、固定资产及 TypeScript/Java 单文件候选报告已存在,项目级原生优先调度、grammar 版本范围验收与宿主接线仍未完成。设计示例不是当前命令输出。 +WASM 的规范与 18 项实施任务已纳入既有 change;可选特性下的 Rust worker、固定 Java/TypeScript/TSX 资产及局部单文件候选报告已存在,项目级原生优先调度、grammar 版本范围验收与宿主接线仍未完成。设计示例不是当前命令输出。 ## 2. 技术选型与权衡 @@ -183,15 +183,15 @@ flowchart LR 部分文件有疑似异常、另有文件未解析时,总体为 `incomplete`,同时保留所有可用疑似观察。`clean` 要求选定范围非空且全部完成检查。 -这些是目标语义字段,尚非已发行的项目级 lint/check 报告。局部的[候选初检 schema](../schemas/syntax-precheck-candidate.schema.json) 与 [Rust 严格读者](../crates/codeguard-adapters/src/syntax_precheck_candidate_report.rs)已绑定源码 SHA-256 和固定 grammar 身份,重新计算状态,并拒绝未知版本及伪造的 `clean`。可选 CLI 的 [TypeScript](../schemas/eslint-local-feedback-v0.3.schema.json) 与 [Java](../schemas/java-syntax-precheck-feedback-v0.1.schema.json) 单文件生产端已提供恢复位置和准备指引;宿主渲染与持久任务引用仍缺。内置 grammar 仍是未验收候选,因此不能返回 `clean`。保持既有退出语义:必需原生执行缺失仍为未完成(`3`);解析器疑似问题本身不是已确认违规(`1`)。若未来增加独立语法操作,其成功必须限定为语法初检;本文不宣称已有 `syntax` 命令。 +这些是目标语义字段,尚非已发行的项目级 lint/check 报告。局部的[候选初检 schema](../schemas/syntax-precheck-candidate.schema.json) 与 [Rust 严格读者](../crates/codeguard-adapters/src/syntax_precheck_candidate_report.rs)已绑定源码 SHA-256、固定 grammar 身份和文件方言,重新计算状态,并拒绝未知版本及伪造的 `clean`。可选 CLI 的 [TypeScript](../schemas/eslint-local-feedback-v0.3.schema.json)、[TSX](../schemas/eslint-local-feedback-v0.4.schema.json) 与 [Java](../schemas/java-syntax-precheck-feedback-v0.1.schema.json) 单文件生产端已提供恢复位置和准备指引;宿主渲染与持久任务引用仍缺。内置 grammar 仍是未验收候选,因此不能返回 `clean`。保持既有退出语义:必需原生执行缺失仍为未完成(`3`);解析器疑似问题本身不是已确认违规(`1`)。若未来增加独立语法操作,其成功必须限定为语法初检;本文不宣称已有 `syntax` 命令。 -可选特性构建的 CLI 现在还会在显式 TypeScript 文件完全未提供原生执行上下文时输出 [ESLint 反馈 0.3.0](../schemas/eslint-local-feedback-v0.3.schema.json):保留 `native=not_run`、`delivery=not_evaluated`,恢复节点只作为 Unicode 位置的疑似观察;即使零恢复节点也保持总体未完成。部分原生上下文或符号链接不触发候选路径,已配置的原生执行继续走原路径。这只是一个局部统一入口,不代表逐模块原生优先调度或宿主自动对话已完成。 +可选特性构建的 CLI 在 `.ts/.mts/.cts` 完全未提供原生执行上下文时输出 [ESLint 反馈 0.3.0](../schemas/eslint-local-feedback-v0.3.schema.json),`.tsx` 则使用独立 grammar 输出 [0.4.0](../schemas/eslint-local-feedback-v0.4.schema.json),避免普通 TypeScript grammar 把有效 JSX 标为疑似异常。两者保留 `native=not_run`、`delivery=not_evaluated`,恢复节点只作为 Unicode 位置的疑似观察;即使零恢复节点也保持总体未完成。部分原生上下文或符号链接不触发候选路径,已配置的原生执行继续走原路径。这只是一个局部统一入口,不代表逐模块原生优先调度或宿主自动对话已完成。 ### 5.4 Grammar 引入与运行生命周期——目标 只引入固定 WASM 字节及上游许可证、提交/补丁来源、SHA-256、ABI、已验证运行时和语言/方言范围、语料引用与已知缺口。逐个验证 CodeGraph 资产与选定 Rust Tree-sitter 运行时兼容,不能复制 TypeScript 提取逻辑或把 CodeGraph 支持等同语法验收。发行清单属于分发资产,不属于可写的 `.codeguard/` 项目状态。 -可用 `codeguard grammar status --format=json` 查询独立的来源覆盖库存。它只读报告 CodeGraph 32 种独立 grammar、CodeGuard 两份候选和零项已发行能力,不运行解析器。依赖提供的两份资产尚未固定字节,COBOL 超过现有加载器的 8 MiB 限额;每语言验收前仍须解决这些缺口。 +可用 `codeguard grammar status --format=json` 查询独立的来源覆盖库存。它只读报告 CodeGraph 32 种独立 grammar、CodeGuard 三份候选和零项已发行能力,不运行解析器。依赖提供的两份资产尚未固定字节,COBOL 超过现有加载器的 8 MiB 限额;每语言验收前仍须解决这些缺口。 由父进程控制解析工作进程,设置总截止时间、单文件输入上限、内存/进程限制及诊断数量上限。按需加载 grammar,不提供通用网络/文件系统导入;终止卡住的进程时保留其它模块的原生结果。宿主约束执行和 Rust MSRV 兼容性须测试,生产数值预算须经测量后确定,不编造性能承诺。 diff --git a/docs/Codeguard-Trust-and-Distribution.md b/docs/Codeguard-Trust-and-Distribution.md index 3de80d3a..a2a38bf8 100644 --- a/docs/Codeguard-Trust-and-Distribution.md +++ b/docs/Codeguard-Trust-and-Distribution.md @@ -48,9 +48,9 @@ Network publication verifies signature and exact site permission before transfer The recorded npm `@partme.ai/codeguard@0.1.0` publication wraps an Apple Silicon macOS Rust binary. Node forwards argv/cwd/environment/streams/exit and is not another checker implementation. Current packaging has no automatic grammar download or install hook. Public installation verification is scoped in [npm acceptance](../tests/acceptance/npm-public-candidate.md); immutable source/tag and multi-platform qualification remain separate. -The repository now includes a [candidate asset manifest](../grammars/manifest.json), fixed-commit Java/TypeScript WASM bytes and three MIT licenses. The [Rust verifier](../crates/codeguard-adapters/src/grammar_asset_manifest.rs) checks provenance fields and exact bytes. Rust offline loading and basic parsing tests pass for both assets; language versions, dialects, full corpora, CLI dispatch and a real MSRV build remain unvalidated. The assets therefore remain `candidate_unvalidated`. See [scoped acceptance](../tests/acceptance/grammar-asset-candidates.md). They are not yet packaged into public npm or selected by lint. +The repository now includes a [candidate asset manifest](../grammars/manifest.json), fixed-commit Java, TypeScript and TSX WASM bytes with their CodeGraph and upstream MIT licenses. The [Rust verifier](../crates/codeguard-adapters/src/grammar_asset_manifest.rs) checks provenance fields and exact bytes. Rust offline loading and basic parsing tests pass for these three candidates; language versions, dialects, full corpora, complete CLI routing and a real MSRV build remain unvalidated. They therefore remain `candidate_unvalidated`. See [scoped acceptance](../tests/acceptance/grammar-asset-candidates.md) and [TSX correction](../tests/acceptance/tsx-grammar-candidate.md). The optional source build uses them for narrow single-file fallback; public npm still does not package or select them. -CodeGraph loads grammar WASM with JavaScript `web-tree-sitter`, which was also used for the initial ABI observation. CodeGuard's Rust [WasmGrammar](../crates/codeguard-runtime/src/wasm_grammar.rs) now loads the **same pinned bytes** through Tree-sitter `WasmStore` and parses Java/TypeScript in tests. The grammar assets are shared; the JavaScript loader is not. Node only forwards the npm command. Rust loading proves limited compatibility of this path, not syntax accuracy or completion of every OpenSpec 14.2 criterion. +CodeGraph loads grammar WASM with JavaScript `web-tree-sitter`, which was also used for the initial ABI observation. CodeGuard's Rust [WasmGrammar](../crates/codeguard-runtime/src/wasm_grammar.rs) loads the **same pinned bytes** through Tree-sitter `WasmStore` and parses Java, TypeScript and TSX in tests. The grammar assets are shared; the JavaScript loader is not. Node only forwards the npm command. Rust loading proves limited compatibility of this path, not syntax accuracy or completion of every OpenSpec 14.2 criterion. Full WASM distribution still requires pinned patches, compatibility ranges and corpora. Copying an active build directory is not a release contract. Users should not require tree-sitter-cli. The Rust parser host needs memory/time limits, safe loading, integrity verification and explicit unsupported/error status. diff --git a/docs/Codeguard-Trust-and-Distribution.zh_CN.md b/docs/Codeguard-Trust-and-Distribution.zh_CN.md index db30b8a5..a9919d23 100644 --- a/docs/Codeguard-Trust-and-Distribution.zh_CN.md +++ b/docs/Codeguard-Trust-and-Distribution.zh_CN.md @@ -71,9 +71,9 @@ Git 联合入口现进一步核对每跳已签名基线的原生祖先关系( npm 已发布 macOS arm64 0.1.0;Node 只转发到打包的 Rust 二进制,无检测或解析逻辑,无安装生命周期脚本。默认本地 private 打包与显式 public 模式分开。当前缺不可变源码/tag 绑定,多平台支持不能由打包器分支或交叉编译推断。使用方式归 [README](../README.zh-CN.md#npm-安装与一次性调用)。 -目前已有[候选资产清单](../grammars/manifest.json)及固定提交的 Java、TypeScript WASM 与三份 MIT 许可证;[Rust 校验器](../crates/codeguard-adapters/src/grammar_asset_manifest.rs)核对来源字段和原始字节。两份资产的 Rust 离线加载及基本解析测试已通过;语言版本、方言、完整语料、正式调度和 MSRV 实编仍未验收,所以资产仍标记为 `candidate_unvalidated`。详见[局部验收](../tests/acceptance/grammar-asset-candidates.md)。这些字节尚未进入公开 npm 包,也不触发 CLI 初检。 +目前已有[候选资产清单](../grammars/manifest.json)及固定提交的 Java、TypeScript、TSX WASM,保留 CodeGraph 和上游 MIT 许可证;[Rust 校验器](../crates/codeguard-adapters/src/grammar_asset_manifest.rs)核对来源字段和原始字节。三份资产的 Rust 离线加载及基本解析测试已通过;语言版本、方言、完整语料、完整调度和 MSRV 实编仍未验收,所以资产仍标记为 `candidate_unvalidated`。详见[局部验收](../tests/acceptance/grammar-asset-candidates.md)和 [TSX 纠错验收](../tests/acceptance/tsx-grammar-candidate.md)。可选源码构建已用于局部单文件兜底,公开 npm 包仍不含这些字节或检查路径。 -CodeGraph 使用 JavaScript `web-tree-sitter` 加载 grammar WASM,初始 ABI 观察也沿用该加载器。CodeGuard 的 Rust [WasmGrammar](../crates/codeguard-runtime/src/wasm_grammar.rs) 已使用 Tree-sitter `WasmStore` 加载**同一固定字节**并在测试中解析 Java/TypeScript。这里复用的是 grammar 资产,不是 JavaScript 加载器;Node 仅负责 npm 命令转发。Rust 加载成功只证明该加载路径的有限兼容性,不证明语法判定准确,也不代表 OpenSpec 14.2 的全部验收完成。 +CodeGraph 使用 JavaScript `web-tree-sitter` 加载 grammar WASM,初始 ABI 观察也沿用该加载器。CodeGuard 的 Rust [WasmGrammar](../crates/codeguard-runtime/src/wasm_grammar.rs) 已使用 Tree-sitter `WasmStore` 加载**同一固定字节**并在测试中解析 Java、TypeScript、TSX。这里复用的是 grammar 资产,不是 JavaScript 加载器;Node 仅负责 npm 命令转发。Rust 加载成功只证明该加载路径的有限兼容性,不证明语法判定准确,也不代表 OpenSpec 14.2 的全部验收完成。 完整 WASM 发行仍须固定补丁、兼容范围及语料,不得复制活动目录或运行时取 latest。包内资产应离线可用,按需加载;取消或部分覆盖不缓存 clean。升级/回滚重新核验资产和缓存身份,保留历史观察与白名单失效记录。完整生产声明还需平台、宿主、原生工具和质量评测分别验收。 diff --git a/grammars/manifest.json b/grammars/manifest.json index 0b5349eb..83405b52 100644 --- a/grammars/manifest.json +++ b/grammars/manifest.json @@ -41,6 +41,24 @@ "language_versions": [], "known_limitations": ["Rust loader smoke passed; MSRV build, dialect versions, isolation and syntax corpus are not yet validated"], "release_status": "candidate_unvalidated" + }, + { + "language": "tsx", + "dialect": "tsx", + "grammar_repository": "https://github.com/tree-sitter/tree-sitter-typescript", + "grammar_commit": "f975a621f4e7f532fe322e13c4f79495e0a7b2e7", + "grammar_version": "v0.23.2", + "path": "tsx/parser.wasm", + "sha256": "8f647a1b2cafe9ab00fb2056d79021d2a144ba17a72f45511072311c1b05d08e", + "bytes": 1445641, + "license": "typescript/LICENSE", + "license_sha256": "49bf33cf78ef5897e4e161ce1517df7de1ae5042a65b6bcfd44401e0fc606559", + "abi_version": 14, + "codegraph_runtime": "web-tree-sitter 0.25.3", + "codeguard_runtime_validation": "rust_loader_smoke_passed", + "language_versions": [], + "known_limitations": ["Rust loader smoke passed; TSX language versions, JSX dialects, isolation and syntax corpus are not yet validated"], + "release_status": "candidate_unvalidated" } ] } diff --git a/grammars/tsx/parser.wasm b/grammars/tsx/parser.wasm new file mode 100644 index 00000000..66ab8577 Binary files /dev/null and b/grammars/tsx/parser.wasm differ diff --git a/openspec/changes/introduce-rust-codeguard-cli/specs/syntax-precheck/spec.md b/openspec/changes/introduce-rust-codeguard-cli/specs/syntax-precheck/spec.md index 8d31ff60..ef82f6fa 100644 --- a/openspec/changes/introduce-rust-codeguard-cli/specs/syntax-precheck/spec.md +++ b/openspec/changes/introduce-rust-codeguard-cli/specs/syntax-precheck/spec.md @@ -105,6 +105,13 @@ Rust runtime MUST 按需加载 grammar,在受控解析工作进程中限制输 解析 MUST 同时识别 ERROR/MISSING 恢复,并按同一恢复原因归并级联节点;诊断 MUST 保留原文件位置、必要的有界脱敏上下文及 grammar 身份。不确定版本/方言、模板、宏、嵌入语言 MUST 明示覆盖限制。CodeGraph 用于提取符号的源码遮盖/启发式 MUST NOT 静默移入语法判定。仅凭恢复节点不得猜测具体缺失 token 或自动授予源码修改范围。 +同一语言族有独立 grammar 的方言 MUST 按实际文件类型选择和报告;尤其 `.tsx` MUST 使用 TSX grammar,不能拿普通 TypeScript grammar 的恢复节点当作 JSX 源码异常。候选报告读者 MUST 核对 grammar 方言与源文件扩展名一致;不匹配视为报告无效,不生成源码 finding。 + +#### Scenario: Valid JSX is parsed with a TypeScript-only grammar + +- **WHEN** `.tsx` 文件含合法 JSX,而普通 TypeScript grammar 会产生恢复节点 +- **THEN** 选用固定的 TSX grammar 并保留候选未验收状态;不得制造疑似源码异常或声称原生 lint 已执行 + #### Scenario: One unmatched delimiter produces many recovery nodes - **WHEN** 同一恢复原因造成重复或级联节点 - **THEN** 归并为可处理观察并保留受影响范围,不创建大量同义任务 diff --git a/openspec/changes/introduce-rust-codeguard-cli/tasks.md b/openspec/changes/introduce-rust-codeguard-cli/tasks.md index 4cf18ec6..cb9da0a2 100644 --- a/openspec/changes/introduce-rust-codeguard-cli/tasks.md +++ b/openspec/changes/introduce-rust-codeguard-cli/tasks.md @@ -1028,13 +1028,13 @@ TDD缺自动同步先RED。相关普通:build9、work sync15、next6,共30 状态:全部待实施。统一规格 [syntax-precheck](specs/syntax-precheck/spec.md)。依赖已有 CLI/原生调度/工作台切片,不等待整个 S13;本阶段验收进入 S12、S13。各任务须先失败样本后实现与回归;不改写原生规则。责任为模块维护职责,非已分配人员。 -- [ ] 14.1 资产清单与来源。责任:adapters / 发布。规格:SP04。依赖:无。验收:固定 CodeGraph 来源提交、grammar 版本、许可证、SHA-256、ABI、语言/方言;缺来源、错散列和不兼容样本拒绝加载。进行中:已从固定 CodeGraph 提交复制 Java/TypeScript WASM 与 MIT 许可证,清单和 Rust 校验拒绝来源/字节/声明 ABI 漂移;两份资产已由 Rust 离线加载并实测 ABI;[局部证据](../../../tests/acceptance/grammar-asset-candidates.md)。新增与批准资产清单分离的[完整来源覆盖库存](../../../grammars/codegraph-coverage.json)及只读 `grammar status`:固定提交中的 30 份随仓 WASM 已逐字节核对,另两种依赖资产标为未固定,COBOL 的 16.4 MB 超出当前 8 MiB 加载限额;[覆盖验收](../../../tests/acceptance/codegraph-grammar-coverage.md)。其余 grammar 的上游许可证/版本、Rust 加载、语言版本/方言、语料及可发行验收仍缺,不勾选。 -- [ ] 14.2 Rust WASM 加载器。责任:runtime。规格:SP04,SP05。依赖:14.1。验收:支持固定资产离线加载;不依赖 Node 解析器、CodeGraph 或用户安装 tree-sitter-cli;通过有效/损坏/错 ABI 样本及 MSRV。进行中:可选 `wasm-precheck` 特性已通过 Java/TypeScript Rust `WasmStore` 加载与反例测试,并由私有工作进程从 stdin 处理真实源码、父进程核对身份与恢复锚点,见[局部验收](../../../tests/acceptance/syntax-worker-candidate.md);本机无 Rust 1.85,MSRV 实编及正式 `lint/check` 接线尚缺。 +- [ ] 14.1 资产清单与来源。责任:adapters / 发布。规格:SP04。依赖:无。验收:固定 CodeGraph 来源提交、grammar 版本、许可证、SHA-256、ABI、语言/方言;缺来源、错散列和不兼容样本拒绝加载。进行中:已从固定 CodeGraph 提交复制 Java/TypeScript/TSX WASM 与 MIT 许可证,清单和 Rust 校验拒绝来源/字节/声明 ABI 漂移;三份资产已由 Rust 离线加载并实测 ABI;[局部证据](../../../tests/acceptance/grammar-asset-candidates.md)。新增与批准资产清单分离的[完整来源覆盖库存](../../../grammars/codegraph-coverage.json)及只读 `grammar status`:固定提交中的 30 份随仓 WASM 已逐字节核对,另两种依赖资产标为未固定,COBOL 的 16.4 MB 超出当前 8 MiB 加载限额;[覆盖验收](../../../tests/acceptance/codegraph-grammar-coverage.md)。其余 grammar 的上游许可证/版本、Rust 加载、语言版本/方言、语料及可发行验收仍缺,不勾选。 +- [ ] 14.2 Rust WASM 加载器。责任:runtime。规格:SP04,SP05。依赖:14.1。验收:支持固定资产离线加载;不依赖 Node 解析器、CodeGraph 或用户安装 tree-sitter-cli;通过有效/损坏/错 ABI 样本及 MSRV。进行中:可选 `wasm-precheck` 特性已通过 Java/TypeScript/TSX Rust `WasmStore` 加载与反例测试,并由私有工作进程从 stdin 处理真实源码、父进程核对身份与恢复锚点,见[局部验收](../../../tests/acceptance/syntax-worker-candidate.md);本机无 Rust 1.85,MSRV 实编及正式 `lint/check` 接线尚缺。 - [ ] 14.3 进程资源隔离。责任:runtime。规格:SP05。依赖:14.2。验收:验证超时、内存、输出、取消与崩溃;损坏 grammar 不阻塞其他模块、不遗留进程。进行中:Unix 候选 worker 复用受控进程组内核,输入 1 MiB、输出 64 KiB,父进程有共同截止时间和取消;崩溃后代清理、输出洪泛、运行中取消及随后正常解析均增加真实子进程反例。Linux 2 GiB `RLIMIT_AS`、3 GiB 分配负例与 worker 故障隔离在 [Ubuntu CI](https://github.com/full-stack-plugins/codeguard/actions/runs/36478461118) 真实通过;Wasmtime 虚拟预留缩小。macOS 本机硬限制实测不支持,候选仍不具内存隔离权威;见[局部验收](../../../tests/acceptance/syntax-worker-candidate.md)。其它目标平台、损坏 grammar 隔离及正式调度仍缺,不勾选。 - [ ] 14.4 语言覆盖与源码映射。责任:adapters。规格:SP06。依赖:14.2。验收:识别 ERROR/MISSING,合并恢复节点;测试 Unicode、换行、嵌入语言、新语法和未知版本,不将不支持当源码违规。进行中:Rust 已提取两类原始节点,adapters 核对 UTF-8/CRLF 字节锚点并转换 Unicode 标量列;结构祖先归组保留并列错误,预算截断保持不完整;[局部证据](../../../tests/acceptance/syntax-recovery-candidate.md)。级联归并语料、版本/嵌入语言及原生对照仍缺。 - [ ] 14.5 原生工具准备探测。责任:adapters。规格:SP01,SP03。依赖:现有配置发现。验收:识别项目本地工具、wrapper、版本和无效配置;PATH 缺失不等于未安装,不对坏配置重复建议安装。进行中:ESLint 本地包/入口及 Maven Wrapper 脚本/发行配置已有只读候选分类,`detect` 与 `check` 已输出固定路径观察的候选;`node_modules` 普通源码遍历被排除,链接和损坏配置保留阻塞;发现协议升级为 0.4.0,聚合协议升级为 0.31.0 并保留旧 schema;[局部证据](../../../tests/acceptance/native-tool-readiness-candidates.md)。显式工具、受控原生版本探针、原生优先调度、更多构建器和真实多平台验收尚缺,不勾选。 -- [ ] 14.6 逐模块原生优先调度。责任:CLI/core。规格:SP01。依赖:14.4,14.5。验收:原生可用先执行;原生违规不得被 WASM 洗白;多根分别选择并保留运行失败与兄弟结果。进行中:可选 CLI 特性在 `lint typescript`、`lint java` 显式单文件且完全缺少原生上下文时附加候选语法观察,部分原生上下文、符号链接、其它扩展名及 Javadoc/Checkstyle 选择保留原路径,见 [TypeScript 局部验收](../../../tests/acceptance/typescript-syntax-fallback-candidate.md)、[Java 局部验收](../../../tests/acceptance/java-syntax-fallback-candidate.md)。这只证明未给显式上下文,不证明原生工具缺失;本地工具自动选择、多模块调度、真实原生/初检混合保留仍缺,不勾选。 -- [ ] 14.7 初检协议与 schema。责任:core/CLI。规格:SP02,SP11。依赖:14.4。验收:固定版本和状态枚举、输入/资产身份、范围及缺口;空文件集、部分解析和未知版本不能 clean;未知 major 拒绝。进行中:core 已有状态聚合及[局部证据](../../../tests/acceptance/syntax-precheck-status-candidate.md);adapters 候选报告 1.0.0 的封闭 schema 与严格读者拒绝重复键、未知版本、身份漂移与伪造 clean,见[候选报告证据](../../../tests/acceptance/syntax-precheck-report-candidate.md);可选 CLI `lint typescript` 与 `lint java` 单文件入口分别产生 0.3.0/0.1.0 局部候选反馈及位置化疑似观察,见 [TypeScript](../../../tests/acceptance/typescript-syntax-fallback-candidate.md) 与 [Java](../../../tests/acceptance/java-syntax-fallback-candidate.md) 验收。正式全范围/嵌入区域/排除原因、持久化任务引用、所有消费者未知 major 拒绝与发布兼容仍缺,不勾选。 +- [ ] 14.6 逐模块原生优先调度。责任:CLI/core。规格:SP01。依赖:14.4,14.5。验收:原生可用先执行;原生违规不得被 WASM 洗白;多根分别选择并保留运行失败与兄弟结果。进行中:可选 CLI 特性在 `lint typescript`、`lint java` 显式单文件且完全缺少原生上下文时附加候选语法观察,部分原生上下文、符号链接、其它扩展名及 Javadoc/Checkstyle 选择保留原路径,见 [TypeScript 局部验收](../../../tests/acceptance/typescript-syntax-fallback-candidate.md)、[Java 局部验收](../../../tests/acceptance/java-syntax-fallback-candidate.md)。新增 `.tsx` 独立 grammar 的有效/无效 JSX 反例与候选报告方言绑定,见 [TSX 纠错验收](../../../tests/acceptance/tsx-grammar-candidate.md)。这只证明未给显式上下文,不证明原生工具缺失;本地工具自动选择、多模块调度、真实原生/初检混合保留仍缺,不勾选。 +- [ ] 14.7 初检协议与 schema。责任:core/CLI。规格:SP02,SP11。依赖:14.4。验收:固定版本和状态枚举、输入/资产身份、范围及缺口;空文件集、部分解析和未知版本不能 clean;未知 major 拒绝。进行中:core 已有状态聚合及[局部证据](../../../tests/acceptance/syntax-precheck-status-candidate.md);adapters 候选报告 1.0.0 的封闭 schema 与严格读者拒绝重复键、未知版本、身份漂移与伪造 clean,见[候选报告证据](../../../tests/acceptance/syntax-precheck-report-candidate.md);可选 CLI `lint typescript` 与 `lint java` 单文件入口分别产生 TypeScript 0.3.0、TSX 0.4.0、Java 0.1.0 局部候选反馈及位置化疑似观察,见 [TypeScript](../../../tests/acceptance/typescript-syntax-fallback-candidate.md) 与 [Java](../../../tests/acceptance/java-syntax-fallback-candidate.md) 验收。正式全范围/嵌入区域/排除原因、持久化任务引用、所有消费者未知 major 拒绝与发布兼容仍缺,不勾选。 - [ ] 14.8 安装建议与必须确认策略。责任:core。规格:SP03。依赖:14.6,14.7。验收:可选原生缺失且完整 clean 仅推荐;疑似或已有必需义务要求恢复原生确认;无适配器给具体决策。进行中:core 已有纯决策函数,区分缺工具、坏配置、执行失败和无适配器;仅非空、完整、已验收且无恢复节点的 clean 才允许可选建议,伪造 clean 状态不能降级。见[局部验收](../../../tests/acceptance/syntax-setup-guidance-candidate.md)。真实工具准备来源、CLI/工作台任务投影及宿主反馈尚未接线,不勾选。 - [ ] 14.9 四类可读与 JSON 报告。责任:CLI。规格:SP07,SP11。依赖:14.7,14.8。验收:覆盖原生成功、缺原生且 clean、疑似语法、初检不可用;结果范围/行动/交付语义一致;不伪造任务 ID。进行中:启用可选 WASM 特性的 TypeScript 与 Java 单文件在无显式原生上下文时提供 JSON/human 候选疑似观察;无恢复节点仍为 incomplete,任务引用为空;Java 超大输入保留 worker 未完成,见 [TypeScript](../../../tests/acceptance/typescript-syntax-fallback-candidate.md) 与 [Java](../../../tests/acceptance/java-syntax-fallback-candidate.md) 局部验收。正式四类报告、多模块范围与宿主渲染仍缺,不勾选。 - [ ] 14.10 稳定任务与下一步。责任:core/CLI。规格:SP08。依赖:14.8,14.9及现有工作台。验收:重复扫描更新同一准备/确认任务,失败尝试有记录,无进展给具体诊断;推荐项不持续占用 next。 diff --git a/schemas/eslint-local-feedback-v0.4.schema.json b/schemas/eslint-local-feedback-v0.4.schema.json new file mode 100644 index 00000000..5afc92b2 --- /dev/null +++ b/schemas/eslint-local-feedback-v0.4.schema.json @@ -0,0 +1,73 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "urn:codeguard:eslint-local-feedback:0.4.0", + "title": "Incomplete TSX lint feedback with optional candidate WASM syntax observation", + "type": "object", + "additionalProperties": false, + "required": ["schema_version", "report_type", "status", "local_coherent", "coverage_proven", "delivery_decision", "reason", "findings", "suppressed_count", "workbench_status", "workbench", "native", "setup", "syntax_precheck", "next_action"], + "properties": { + "schema_version": {"const": "0.4.0"}, + "report_type": {"const": "eslint_local_feedback"}, + "status": {"const": "incomplete"}, + "local_coherent": {"const": false}, + "coverage_proven": {"const": false}, + "delivery_decision": {"const": "not_evaluated"}, + "reason": {"const": "eslint_execution_context_missing"}, + "findings": {"const": []}, + "suppressed_count": {"const": 0}, + "workbench_status": {"const": "not_connected"}, + "workbench": {"type": "null"}, + "native": { + "type": "object", "additionalProperties": false, + "required": ["status", "reason"], + "properties": {"status": {"const": "not_run"}, "reason": {"const": "explicit_context_missing"}} + }, + "setup": { + "type": "object", "additionalProperties": false, + "required": ["requirement", "reason", "task_id"], + "properties": { + "requirement": {"const": "required"}, + "reason": {"const": "native_confirmation_needed"}, + "task_id": {"type": "null"} + } + }, + "syntax_precheck": { + "type": "object", "additionalProperties": false, + "required": ["backend", "language", "status", "reason", "source_path", "source_sha256", "grammar_sha256", "grammar_qualified", "selected_files", "checked_files", "truncated", "observations"], + "properties": { + "backend": {"const": "bundled_tree_sitter_wasm_candidate"}, + "language": {"const": "tsx"}, + "status": {"const": "incomplete"}, + "reason": {"enum": ["not_run", "source_unavailable", "worker_executable_unavailable", "worker_incomplete", "recovery_budget_truncated", "grammar_version_unqualified", "position_mapping_incomplete"]}, + "source_path": {"type": "string", "minLength": 1}, + "source_sha256": {"$ref": "#/$defs/nullable_digest"}, + "grammar_sha256": {"$ref": "#/$defs/nullable_digest"}, + "grammar_qualified": {"const": false}, + "selected_files": {"const": 1}, + "checked_files": {"enum": [0, 1]}, + "truncated": {"type": "boolean"}, + "observations": {"type": "array", "maxItems": 128, "items": {"$ref": "#/$defs/observation"}} + } + }, + "next_action": {"type": "string", "minLength": 1} + }, + "$defs": { + "nullable_digest": { + "anyOf": [{"type": "null"}, {"type": "string", "pattern": "^[0-9a-f]{64}$"}] + }, + "observation": { + "type": "object", "additionalProperties": false, + "required": ["classification", "kind", "syntax_kind", "start_line", "start_column", "end_line", "end_column", "group_id"], + "properties": { + "classification": {"const": "suspected"}, + "kind": {"enum": ["ERROR", "MISSING"]}, + "syntax_kind": {"type": "string", "minLength": 1}, + "start_line": {"type": "integer", "minimum": 1}, + "start_column": {"type": "integer", "minimum": 1}, + "end_line": {"type": "integer", "minimum": 1}, + "end_column": {"type": "integer", "minimum": 1}, + "group_id": {"type": "integer", "minimum": 1} + } + } + } +} diff --git a/schemas/grammar-asset-manifest.schema.json b/schemas/grammar-asset-manifest.schema.json index 702fb695..322f954d 100644 --- a/schemas/grammar-asset-manifest.schema.json +++ b/schemas/grammar-asset-manifest.schema.json @@ -14,8 +14,8 @@ "build_tool": {"const": "tree-sitter-cli 0.25.10 build --wasm"}, "assets": { "type": "array", - "minItems": 2, - "maxItems": 2, + "minItems": 3, + "maxItems": 3, "items": {"$ref": "#/$defs/asset"} } }, @@ -27,12 +27,12 @@ "additionalProperties": false, "required": ["language", "dialect", "grammar_repository", "grammar_commit", "grammar_version", "path", "sha256", "bytes", "license", "license_sha256", "abi_version", "codegraph_runtime", "codeguard_runtime_validation", "language_versions", "known_limitations", "release_status"], "properties": { - "language": {"enum": ["java", "typescript"]}, - "dialect": {"enum": ["java", "typescript"]}, + "language": {"enum": ["java", "typescript", "tsx"]}, + "dialect": {"enum": ["java", "typescript", "tsx"]}, "grammar_repository": {"type": "string", "pattern": "^https://github.com/tree-sitter/tree-sitter-"}, "grammar_commit": {"$ref": "#/$defs/commit"}, "grammar_version": {"type": "string", "pattern": "^v[0-9]+\\.[0-9]+\\.[0-9]+$"}, - "path": {"enum": ["java/parser.wasm", "typescript/parser.wasm"]}, + "path": {"enum": ["java/parser.wasm", "typescript/parser.wasm", "tsx/parser.wasm"]}, "sha256": {"$ref": "#/$defs/sha256"}, "bytes": {"type": "integer", "minimum": 8, "maximum": 8388608}, "license": {"enum": ["java/LICENSE", "typescript/LICENSE"]}, diff --git a/tests/acceptance/codegraph-grammar-coverage.md b/tests/acceptance/codegraph-grammar-coverage.md index f631847f..559c52b8 100644 --- a/tests/acceptance/codegraph-grammar-coverage.md +++ b/tests/acceptance/codegraph-grammar-coverage.md @@ -7,3 +7,5 @@ `cargo test --locked -p codeguard-cli --test grammar_status_cli`:2/2 通过。实际调用 `target/debug/codeguard grammar status --format=json` 返回 `grammar_coverage_inventory`、`codegraph_grammar_count=32`、`codegraph_vendored_count=30`、`candidate_count=2`、`released_count=0`、`execution=not_run`、`delivery_decision=not_evaluated`。Java/TypeScript 是 `candidate_unvalidated`;`objc`/`solidity` 为 `dependency_bytes_not_pinned`。COBOL 源文件 16,355,286 字节,超过现有 Rust 加载器 8 MiB 限额,明确显示 `current_loader_size_limit`。 未完成:其余 30 份资产的上游版本/许可证、Rust ABI 与真实加载、各语言版本/方言/语料、原生对照、运行时预算和发行打包。此库存不证明任何新增语言已可进行语法初检,不改变原生 lint 或交付门禁。 + +后续增量:[TSX 候选纠错](tsx-grammar-candidate.md)将 TSX 纳入候选资产,当前源码构建的 `grammar status` 候选数变为 3,仍无已验收发行能力。上面的 2 候选与 2/2 测试记录保留为本次覆盖库存引入时的验收快照。 diff --git a/tests/acceptance/grammar-asset-candidates.md b/tests/acceptance/grammar-asset-candidates.md index 05c63a29..f6adab8c 100644 --- a/tests/acceptance/grammar-asset-candidates.md +++ b/tests/acceptance/grammar-asset-candidates.md @@ -14,3 +14,5 @@ TDD:新增 `grammar_asset_manifest` 测试先因缺少 Rust API 编译失败 Rust 加载器的 `wasm_grammar_load` 测试先因缺少 `WasmGrammar` 编译失败;实现后覆盖 Java/TypeScript 固定资产、损坏模块、错误摘要和错误 ABI 声明。离线运行 `cargo test --locked -p codeguard-runtime -p codeguard-adapters --features codeguard-runtime/wasm-precheck`、`cargo test --workspace --locked --quiet` 均通过,前者显式覆盖新功能,后者验证默认功能回归;还通过带新特性的 runtime Clippy 检查。加载器是可选编译特性,当前仅为受控兼容性试验,不进入 CLI 调度,也未具备工作进程隔离。`cargo metadata` 显示当前解析到的依赖未声明高于 1.85 的 Rust 版本;本机未安装 Rust 1.85,实际 MSRV 编译尚未验收。 OpenSpec 14.1 和 14.2 仍不勾选:语言/方言版本边界、MSRV 实编、进程隔离、错误节点/位置和可发行验收仍需后续任务补齐。加载成功不意味着语法规则准确或原生 lint 义务已完成。 + +后续增量:[TSX 候选纠错](tsx-grammar-candidate.md)把同一来源仓库的 TSX 独立 WASM 加入固定候选清单;当前候选资产数为 3。本页的“两份”及初次验收命令属于原 Java/TypeScript 引入时的历史快照。 diff --git a/tests/acceptance/tsx-grammar-candidate.md b/tests/acceptance/tsx-grammar-candidate.md new file mode 100644 index 00000000..3c8bce06 --- /dev/null +++ b/tests/acceptance/tsx-grammar-candidate.md @@ -0,0 +1,9 @@ +# TSX grammar 候选纠错:局部验收 + +此前可选 `lint typescript` 单文件初检接受 `.tsx`,却总把源码交给普通 TypeScript grammar。有效 JSX 的回归测试先失败:报告 `syntax_precheck.language=typescript`,有把合法代码误报为疑似语法异常的风险。 + +从固定 `partme-ai/codegraph@40f112453583a2304c4b605a3a9d6545919662bd` 的 `src/extraction/wasm/tree-sitter-tsx.wasm` 复制原始字节;SHA-256 为 `8f647a1b2cafe9ab00fb2056d79021d2a144ba17a72f45511072311c1b05d08e`,长度 1,445,641 字节。TSX 与 TypeScript 来自同一 `tree-sitter/tree-sitter-typescript@f975a621f4e7f532fe322e13c4f79495e0a7b2e7`,共用仓内固定的 MIT 许可证。Rust `WasmStore` 离线加载实测 ABI 14;合法 JSX 无恢复错误,明显缺失属性值的 JSX 有恢复错误。仅测试语法恢复,不把 JSX 标签语义校验等同于 Tree-sitter 语法能力。 + +可选 `wasm-precheck` 构建下,`.tsx` 使用 TSX grammar、按其摘要绑定父子进程报告,输出独立 `eslint_local_feedback` 0.4.0;`.ts/.mts/.cts` 保留 0.3.0 TypeScript grammar 路径。两者都保持原生 `not_run`、候选 `incomplete`、交付 `not_evaluated`,不会产生原生 finding。报告读者拒绝 `.java` 路径冒充 TSX 方言,此测试同样先失败后通过。 + +验证:`cargo test --locked -p codeguard-adapters --test grammar_asset_manifest --test syntax_precheck_report_contract`、`cargo test --locked -p codeguard-runtime --features wasm-precheck --test wasm_grammar_load`、`cargo test --locked -p codeguard-cli --features wasm-precheck --test typescript_syntax_fallback_candidate`、`cargo test --locked -p codeguard-cli --test grammar_status_cli` 均通过。仍待逐语言/版本语料、原生确认、完整 lint/check 调度、公开制品和宿主真实反馈;OpenSpec S14 保持未完成。 diff --git a/tests/acceptance/typescript-syntax-fallback-candidate.md b/tests/acceptance/typescript-syntax-fallback-candidate.md index 09caa8c2..4d804c49 100644 --- a/tests/acceptance/typescript-syntax-fallback-candidate.md +++ b/tests/acceptance/typescript-syntax-fallback-candidate.md @@ -40,3 +40,5 @@ openspec validate introduce-rust-codeguard-cli --strict ``` 实际结果:TypeScript 候选路径 5 项测试通过;既有 ESLint CLI 测试 6 项通过、4 项需显式真实 Node/ESLint 环境而 ignored;Clippy 无警告;启用候选特性的完整 Rust workspace 回归退出码 0;OpenSpec 严格校验与 `git diff --check` 通过。真实 ESLint 自动选择、正式任务同步和三宿主对话仍未验收。 + +后续增量:[TSX 候选纠错](tsx-grammar-candidate.md)将 `.tsx` 从普通 TypeScript grammar 改为固定 TSX grammar,并使用独立的 0.4.0 报告;本页 0.3.0 示例仍适用于 `.ts/.mts/.cts`。上述 5 项与完整 workspace 测试结果是当时的历史验收记录。