From e5c85b394f6219dcfa56b0cb2af51a1eb9b6e7fb Mon Sep 17 00:00:00 2001 From: yaojingang Date: Sat, 13 Jun 2026 19:17:27 +0800 Subject: [PATCH] refactor: split meta skill CLI and review gates --- AGENTS.md | 2 + registry/index.json | 2 +- registry/packages/yao-meta-skill.json | 6 +- reports/adoption_drift_report.json | 2 +- reports/compiled_targets.json | 56 +-- reports/context_budget.json | 6 +- reports/install_simulation.json | 2 +- reports/output_execution_runs.json | 20 +- reports/output_execution_runs.md | 20 +- reports/package_verification.json | 4 +- reports/package_verification.md | 2 +- reports/registry_audit.json | 8 +- reports/registry_audit.md | 4 +- reports/review-studio.html | 10 +- reports/review-studio.json | 188 ++++++---- reports/security_trust_report.json | 48 ++- reports/security_trust_report.md | 12 +- reports/skill-overview.html | 2 +- reports/skill-overview.json | 34 +- reports/skill_atlas.json | 2 + reports/upgrade_check.json | 8 +- scripts/render_review_studio.py | 483 +----------------------- scripts/review_studio_gates.py | 512 +++++++++++++++++++++++++ scripts/yao.py | 496 +------------------------ scripts/yao_cli_parser.py | 513 ++++++++++++++++++++++++++ skill-ir/examples/yao-meta-skill.json | 4 +- skill_atlas/catalog.json | 2 + tests/verify_review_studio.py | 11 +- tests/verify_trust_check.py | 4 + tests/verify_yao_cli.py | 6 + 30 files changed, 1320 insertions(+), 1149 deletions(-) create mode 100644 scripts/review_studio_gates.py create mode 100644 scripts/yao_cli_parser.py diff --git a/AGENTS.md b/AGENTS.md index 47d8fee..b8c56ea 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -63,8 +63,10 @@ Clean test-only scratch directories after verification with `rm -rf tests/tmp_*` - `scripts/render_review_studio.py`: Review Studio gate orchestration. Keep gate scoring, evidence links, and action generation separate from layout helpers. - `scripts/review_studio_layout.py`: Review Studio static layout and CSS contract. - `scripts/review_studio_formatting.py`: Review Studio dictionary-to-panel formatting and Chinese metric labels. +- `scripts/review_studio_gates.py`: Review Studio gate evaluation, release decision scoring, and gate status labels. - `scripts/skill_report_model.py`, `scripts/skill_report_metrics.py`, `scripts/skill_report_charts.py`: skill overview data model, scoring, and inline SVG chart generation. - `scripts/yao_cli_config.py`: CLI target maps, archetype heuristics, diagnosis copy, and side-effect-free shaping helpers. +- `scripts/yao_cli_parser.py`: CLI argparse command surface, flags, choices, and command handler binding. New helper modules that are imported by CLI/report scripts but are not standalone commands must declare: diff --git a/registry/index.json b/registry/index.json index e4bc9b5..fef4b96 100644 --- a/registry/index.json +++ b/registry/index.json @@ -15,7 +15,7 @@ "agent-skills-compatible" ], "package_metadata": "registry/packages/yao-meta-skill.json", - "package_sha256": "742dc905b0d221c4f336e741d168861edaf7b75e97fe1e89f7d454c1cabf928f" + "package_sha256": "d53de57f6593fca3dd937832f5923bd5381250e382631a6b6616e2405de748b5" } ] } diff --git a/registry/packages/yao-meta-skill.json b/registry/packages/yao-meta-skill.json index 4fa9e8c..622bec3 100644 --- a/registry/packages/yao-meta-skill.json +++ b/registry/packages/yao-meta-skill.json @@ -15,8 +15,8 @@ "trust_level": "local", "license": "MIT", "checksums": { - "package_sha256": "742dc905b0d221c4f336e741d168861edaf7b75e97fe1e89f7d454c1cabf928f", - "archive_sha256": "7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9" + "package_sha256": "d53de57f6593fca3dd937832f5923bd5381250e382631a6b6616e2405de748b5", + "archive_sha256": "6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451" }, "compatibility": { "openai": "pass", @@ -47,7 +47,7 @@ }, "distribution": { "archive_verified": true, - "archive_sha256": "7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9", + "archive_sha256": "6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451", "package_verification": "reports/package_verification.json", "install_simulated": true, "install_simulation": "reports/install_simulation.json" diff --git a/reports/adoption_drift_report.json b/reports/adoption_drift_report.json index 7f931d0..453be36 100644 --- a/reports/adoption_drift_report.json +++ b/reports/adoption_drift_report.json @@ -1,7 +1,7 @@ { "ok": true, "schema_version": "2.0", - "generated_at": "2026-06-13T10:57:52Z", + "generated_at": "2026-06-13T11:16:31Z", "skill_dir": ".", "privacy_contract": { "storage": "local-first", diff --git a/reports/compiled_targets.json b/reports/compiled_targets.json index fc07765..02b6816 100644 --- a/reports/compiled_targets.json +++ b/reports/compiled_targets.json @@ -191,6 +191,7 @@ "scripts/render_system_model.py", "scripts/resource_boundary_check.py", "scripts/review_studio_formatting.py", + "scripts/review_studio_gates.py", "scripts/review_studio_layout.py", "scripts/run_conformance_suite.py", "scripts/run_description_optimization_suite.py", @@ -209,7 +210,8 @@ "scripts/validate_skill.py", "scripts/verify_package.py", "scripts/yao.py", - "scripts/yao_cli_config.py" + "scripts/yao_cli_config.py", + "scripts/yao_cli_parser.py" ], "assets": [ "templates/basic_skill.md.j2", @@ -260,7 +262,7 @@ ], "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 } @@ -498,7 +500,7 @@ "strategy": "Ship the neutral source tree and expose OpenAI-facing interface metadata as a generated companion file.", "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 }, @@ -509,7 +511,7 @@ }, "scripts": { "strategy": "Keep scripts as local package resources; expose help-smoke and permission metadata for reviewer approval before execution.", - "script_count": 66, + "script_count": 68, "help_smoke_failed_count": 0 }, "permissions": { @@ -721,7 +723,7 @@ "strategy": "Ship the neutral source tree and expose OpenAI-facing interface metadata as a generated companion file.", "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 }, @@ -732,7 +734,7 @@ }, "scripts": { "strategy": "Keep scripts as local package resources; expose help-smoke and permission metadata for reviewer approval before execution.", - "script_count": 66, + "script_count": 68, "help_smoke_failed_count": 0 }, "permissions": { @@ -980,6 +982,7 @@ "scripts/render_system_model.py", "scripts/resource_boundary_check.py", "scripts/review_studio_formatting.py", + "scripts/review_studio_gates.py", "scripts/review_studio_layout.py", "scripts/run_conformance_suite.py", "scripts/run_description_optimization_suite.py", @@ -998,7 +1001,8 @@ "scripts/validate_skill.py", "scripts/verify_package.py", "scripts/yao.py", - "scripts/yao_cli_config.py" + "scripts/yao_cli_config.py", + "scripts/yao_cli_parser.py" ], "assets": [ "templates/basic_skill.md.j2", @@ -1049,7 +1053,7 @@ ], "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 } @@ -1287,7 +1291,7 @@ "strategy": "Preserve the source tree directly; write target notes in targets/claude/README.md.", "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 }, @@ -1298,7 +1302,7 @@ }, "scripts": { "strategy": "Scripts remain local package resources and must be reviewed through trust and permission reports before use.", - "script_count": 66, + "script_count": 68, "help_smoke_failed_count": 0 }, "permissions": { @@ -1510,7 +1514,7 @@ "strategy": "Preserve the source tree directly; write target notes in targets/claude/README.md.", "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 }, @@ -1521,7 +1525,7 @@ }, "scripts": { "strategy": "Scripts remain local package resources and must be reviewed through trust and permission reports before use.", - "script_count": 66, + "script_count": 68, "help_smoke_failed_count": 0 }, "permissions": { @@ -1769,6 +1773,7 @@ "scripts/render_system_model.py", "scripts/resource_boundary_check.py", "scripts/review_studio_formatting.py", + "scripts/review_studio_gates.py", "scripts/review_studio_layout.py", "scripts/run_conformance_suite.py", "scripts/run_description_optimization_suite.py", @@ -1787,7 +1792,8 @@ "scripts/validate_skill.py", "scripts/verify_package.py", "scripts/yao.py", - "scripts/yao_cli_config.py" + "scripts/yao_cli_config.py", + "scripts/yao_cli_parser.py" ], "assets": [ "templates/basic_skill.md.j2", @@ -1838,7 +1844,7 @@ ], "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 } @@ -2076,7 +2082,7 @@ "strategy": "Preserve references, scripts, assets, evals, reports, and adapter metadata as relative package resources.", "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 }, @@ -2086,7 +2092,7 @@ }, "scripts": { "strategy": "Expose script and permission metadata for downstream clients or installers to enforce.", - "script_count": 66, + "script_count": 68, "help_smoke_failed_count": 0 }, "permissions": { @@ -2292,7 +2298,7 @@ "strategy": "Preserve references, scripts, assets, evals, reports, and adapter metadata as relative package resources.", "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 }, @@ -2302,7 +2308,7 @@ }, "scripts": { "strategy": "Expose script and permission metadata for downstream clients or installers to enforce.", - "script_count": 66, + "script_count": 68, "help_smoke_failed_count": 0 }, "permissions": { @@ -2542,6 +2548,7 @@ "scripts/render_system_model.py", "scripts/resource_boundary_check.py", "scripts/review_studio_formatting.py", + "scripts/review_studio_gates.py", "scripts/review_studio_layout.py", "scripts/run_conformance_suite.py", "scripts/run_description_optimization_suite.py", @@ -2560,7 +2567,8 @@ "scripts/validate_skill.py", "scripts/verify_package.py", "scripts/yao.py", - "scripts/yao_cli_config.py" + "scripts/yao_cli_config.py", + "scripts/yao_cli_parser.py" ], "assets": [ "templates/basic_skill.md.j2", @@ -2611,7 +2619,7 @@ ], "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 } @@ -2849,7 +2857,7 @@ "strategy": "Keep optional directories as relative resources next to SKILL.md.", "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 }, @@ -2860,7 +2868,7 @@ }, "scripts": { "strategy": "Scripts remain local optional resources and should advertise --help when executable.", - "script_count": 66, + "script_count": 68, "help_smoke_failed_count": 0 }, "permissions": { @@ -3065,7 +3073,7 @@ "strategy": "Keep optional directories as relative resources next to SKILL.md.", "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 }, @@ -3076,7 +3084,7 @@ }, "scripts": { "strategy": "Scripts remain local optional resources and should advertise --help when executable.", - "script_count": 66, + "script_count": 68, "help_smoke_failed_count": 0 }, "permissions": { diff --git a/reports/context_budget.json b/reports/context_budget.json index 49e96a0..3639880 100644 --- a/reports/context_budget.json +++ b/reports/context_budget.json @@ -6,10 +6,10 @@ "context_budget_tier": "production", "context_budget_limit": 1000, "skill_body_tokens": 811, - "other_text_tokens": 869504, + "other_text_tokens": 871624, "estimated_initial_load_tokens": 987, - "estimated_total_text_tokens": 870315, - "relevant_file_count": 327, + "estimated_total_text_tokens": 872435, + "relevant_file_count": 368, "unused_resource_dirs": [], "quality_signal_points": 130, "quality_density": 131.7 diff --git a/reports/install_simulation.json b/reports/install_simulation.json index 1d67799..2b9a959 100644 --- a/reports/install_simulation.json +++ b/reports/install_simulation.json @@ -8,7 +8,7 @@ "installed_skill_dir": "dist/install-simulation/simulate-yao-meta-skill/yao-meta-skill", "summary": { "archive_present": true, - "archive_entry_count": 488, + "archive_entry_count": 490, "archive_extracted": true, "entrypoint_loaded": true, "manifest_loaded": true, diff --git a/reports/output_execution_runs.json b/reports/output_execution_runs.json index 6cb2055..153ce5d 100644 --- a/reports/output_execution_runs.json +++ b/reports/output_execution_runs.json @@ -34,7 +34,7 @@ "execution_mode": "command", "model_executed": false, "command_executed": true, - "duration_ms": 23.11, + "duration_ms": 32.51, "provider": "local-output-eval-runner", "model": "", "usage": { @@ -62,7 +62,7 @@ "execution_mode": "command", "model_executed": false, "command_executed": true, - "duration_ms": 23.56, + "duration_ms": 32.64, "provider": "local-output-eval-runner", "model": "", "usage": { @@ -85,7 +85,7 @@ "execution_mode": "command", "model_executed": false, "command_executed": true, - "duration_ms": 24.17, + "duration_ms": 38.43, "provider": "local-output-eval-runner", "model": "", "usage": { @@ -113,7 +113,7 @@ "execution_mode": "command", "model_executed": false, "command_executed": true, - "duration_ms": 23.84, + "duration_ms": 31.51, "provider": "local-output-eval-runner", "model": "", "usage": { @@ -136,7 +136,7 @@ "execution_mode": "command", "model_executed": false, "command_executed": true, - "duration_ms": 22.51, + "duration_ms": 31.34, "provider": "local-output-eval-runner", "model": "", "usage": { @@ -164,7 +164,7 @@ "execution_mode": "command", "model_executed": false, "command_executed": true, - "duration_ms": 26.03, + "duration_ms": 30.94, "provider": "local-output-eval-runner", "model": "", "usage": { @@ -187,7 +187,7 @@ "execution_mode": "command", "model_executed": false, "command_executed": true, - "duration_ms": 28.48, + "duration_ms": 30.5, "provider": "local-output-eval-runner", "model": "", "usage": { @@ -214,7 +214,7 @@ "execution_mode": "command", "model_executed": false, "command_executed": true, - "duration_ms": 23.17, + "duration_ms": 31.42, "provider": "local-output-eval-runner", "model": "", "usage": { @@ -237,7 +237,7 @@ "execution_mode": "command", "model_executed": false, "command_executed": true, - "duration_ms": 23.94, + "duration_ms": 31.18, "provider": "local-output-eval-runner", "model": "", "usage": { @@ -266,7 +266,7 @@ "execution_mode": "command", "model_executed": false, "command_executed": true, - "duration_ms": 22.69, + "duration_ms": 30.97, "provider": "local-output-eval-runner", "model": "", "usage": { diff --git a/reports/output_execution_runs.md b/reports/output_execution_runs.md index d2e3be4..58e706c 100644 --- a/reports/output_execution_runs.md +++ b/reports/output_execution_runs.md @@ -23,16 +23,16 @@ Command runner evidence is present. This proves the eval harness executed an ext | Case | Variant | Mode | Model | Duration ms | Tokens | Score | Status | | --- | --- | --- | --- | ---: | ---: | ---: | --- | -| skill-package-contract | baseline | command | local-output-eval-runner | 23.11 | 33 | 0.0 | pass | -| skill-package-contract | with_skill | command | local-output-eval-runner | 23.56 | 73 | 100.0 | pass | -| output-eval-expectation | baseline | command | local-output-eval-runner | 24.17 | 36 | 0.0 | pass | -| output-eval-expectation | with_skill | command | local-output-eval-runner | 23.84 | 80 | 100.0 | pass | -| ir-before-packaging | baseline | command | local-output-eval-runner | 22.51 | 33 | 0.0 | pass | -| ir-before-packaging | with_skill | command | local-output-eval-runner | 26.03 | 80 | 100.0 | pass | -| near-neighbor-boundary | baseline | command | local-output-eval-runner | 28.48 | 36 | 0.0 | pass | -| near-neighbor-boundary | with_skill | command | local-output-eval-runner | 23.17 | 65 | 100.0 | pass | -| file-backed-governed-package | baseline | command | local-output-eval-runner | 23.94 | 37 | 0.0 | pass | -| file-backed-governed-package | with_skill | command | local-output-eval-runner | 22.69 | 98 | 100.0 | pass | +| skill-package-contract | baseline | command | local-output-eval-runner | 32.51 | 33 | 0.0 | pass | +| skill-package-contract | with_skill | command | local-output-eval-runner | 32.64 | 73 | 100.0 | pass | +| output-eval-expectation | baseline | command | local-output-eval-runner | 38.43 | 36 | 0.0 | pass | +| output-eval-expectation | with_skill | command | local-output-eval-runner | 31.51 | 80 | 100.0 | pass | +| ir-before-packaging | baseline | command | local-output-eval-runner | 31.34 | 33 | 0.0 | pass | +| ir-before-packaging | with_skill | command | local-output-eval-runner | 30.94 | 80 | 100.0 | pass | +| near-neighbor-boundary | baseline | command | local-output-eval-runner | 30.5 | 36 | 0.0 | pass | +| near-neighbor-boundary | with_skill | command | local-output-eval-runner | 31.42 | 65 | 100.0 | pass | +| file-backed-governed-package | baseline | command | local-output-eval-runner | 31.18 | 37 | 0.0 | pass | +| file-backed-governed-package | with_skill | command | local-output-eval-runner | 30.97 | 98 | 100.0 | pass | ## Next Fixes diff --git a/reports/package_verification.json b/reports/package_verification.json index 8c66a4e..56c45c8 100644 --- a/reports/package_verification.json +++ b/reports/package_verification.json @@ -8,8 +8,8 @@ "target_count": 3, "adapter_count": 3, "archive_present": true, - "archive_sha256": "7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9", - "archive_entry_count": 488, + "archive_sha256": "6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451", + "archive_entry_count": 490, "failure_count": 0, "warning_count": 0 }, diff --git a/reports/package_verification.md b/reports/package_verification.md index 71cfac0..caa1f02 100644 --- a/reports/package_verification.md +++ b/reports/package_verification.md @@ -4,7 +4,7 @@ - Package directory: `dist` - Targets: `3 / 3` adapters present - Archive present: `True` -- Archive SHA256: `7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9` +- Archive SHA256: `6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451` - Failures: `0` - Warnings: `0` diff --git a/reports/registry_audit.json b/reports/registry_audit.json index c8736dd..608ace9 100644 --- a/reports/registry_audit.json +++ b/reports/registry_audit.json @@ -20,8 +20,8 @@ "trust_level": "local", "license": "MIT", "checksums": { - "package_sha256": "742dc905b0d221c4f336e741d168861edaf7b75e97fe1e89f7d454c1cabf928f", - "archive_sha256": "7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9" + "package_sha256": "d53de57f6593fca3dd937832f5923bd5381250e382631a6b6616e2405de748b5", + "archive_sha256": "6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451" }, "compatibility": { "openai": "pass", @@ -52,7 +52,7 @@ }, "distribution": { "archive_verified": true, - "archive_sha256": "7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9", + "archive_sha256": "6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451", "package_verification": "reports/package_verification.json", "install_simulated": true, "install_simulation": "reports/install_simulation.json" @@ -76,7 +76,7 @@ "agent-skills-compatible" ], "package_metadata": "registry/packages/yao-meta-skill.json", - "package_sha256": "742dc905b0d221c4f336e741d168861edaf7b75e97fe1e89f7d454c1cabf928f" + "package_sha256": "d53de57f6593fca3dd937832f5923bd5381250e382631a6b6616e2405de748b5" } ] }, diff --git a/reports/registry_audit.md b/reports/registry_audit.md index eee4c66..8f86738 100644 --- a/reports/registry_audit.md +++ b/reports/registry_audit.md @@ -6,8 +6,8 @@ - Maturity: `governed` - Owner: `Yao Team` - License: `MIT` -- Package SHA256: `742dc905b0d221c4f336e741d168861edaf7b75e97fe1e89f7d454c1cabf928f` -- Archive SHA256: `7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9` +- Package SHA256: `d53de57f6593fca3dd937832f5923bd5381250e382631a6b6616e2405de748b5` +- Archive SHA256: `6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451` - Install simulated: `True` ## Compatibility diff --git a/reports/review-studio.html b/reports/review-studio.html index 5382095..9bfc5df 100644 --- a/reports/review-studio.html +++ b/reports/review-studio.html @@ -242,12 +242,12 @@

核心指标

-
Skill IR2.0.0

4 targets in platform-neutral contract

Compiler4/4

target contracts compiled from Skill IR

Output Delta100.0

5 cases; 1 file-backed

Exec Runs10

command 10; model 0; recorded 0

Blind A/B5

review pairs hide baseline vs with-skill labels

Review A/B0/5

adjudication decisions; pending 5

Runtime5/5

target conformance pass rate

Perm Probe3/3

0 native enforcement targets

Trust0

66 scripts scanned; secrets found

Atlas5

12 scanned skills; route collisions

Driftlow

1 metadata events; 0 missed triggers

Waivers0

0 gates covered; human risk decisions

Notes0/0

0 open blocker annotations

Registry1.1.0

4 targets; MIT license

Archivepass

488 zip entries; package verification

Installpass

3 adapters readable; local install simulation

Upgrademinor

declared minor; 0 breaking changes

+
Skill IR2.0.0

4 targets in platform-neutral contract

Compiler4/4

target contracts compiled from Skill IR

Output Delta100.0

5 cases; 1 file-backed

Exec Runs10

command 10; model 0; recorded 0

Blind A/B5

review pairs hide baseline vs with-skill labels

Review A/B0/5

adjudication decisions; pending 5

Runtime5/5

target conformance pass rate

Perm Probe3/3

0 native enforcement targets

Trust0

68 scripts scanned; secrets found

Atlas5

12 scanned skills; route collisions

Driftlow

1 metadata events; 0 missed triggers

Waivers0

0 gates covered; human risk decisions

Notes0/0

0 open blocker annotations

Registry1.1.0

4 targets; MIT license

Archivepass

490 zip entries; package verification

Installpass

3 adapters readable; local install simulation

Upgrademinor

declared minor; 0 breaking changes

审查闸门

-
通过

意图画布

intent confidence 100/100; Intent is clear enough to package the first routeable version.

reports/intent-confidence.json 证据
通过

触发实验

13 trigger cases; 0 misroutes; 0 ambiguous

reports/route_scorecard.json 证据
通过

输出实验

5/5 cases; with-skill 100.0; baseline 0.0; file-backed 1; near-neighbor 1; blind A/B 5; exec 10; command 10; model 0; recorded 0; reviewed 0/5

reports/output_quality_scorecard.json 证据
通过

上下文

initial load 987/1000; quality density 131.7

reports/context_budget.json 证据
通过

运行矩阵

5 / 5 targets pass

reports/conformance_matrix.json 证据
通过

信任报告

0 secrets; 66 scripts; 2 network-capable scripts; 0 help smoke failures

reports/security_trust_report.json 证据
通过

权限批准

3/3 permissions approved; gaps 0; required file_write, network, subprocess

reports/security_trust_report.json + security/permission_policy.json 证据
通过

权限探针

3/3 targets probed; native 0; metadata fallback 3; residual risks 3

reports/runtime_permission_probes.json 证据
通过

组合治理

12 skills, 1 actionable; 0 actionable route collisions; 0 actionable owner gaps; 0 actionable stale; 24 scoped non-actionable issues

reports/skill_atlas.json 证据
通过

运营回路

1 metadata events; adoption 100.0; missed 0; bad-output 0; risk low

reports/adoption_drift_report.json 证据
通过

人工批准

0 active waivers cover current warnings

reports/review_waivers.json 证据
通过

注册审计

yao-meta-skill 1.1.0; 6/6 compatibility entries pass; install pass with 3 adapters

reports/registry_audit.json + reports/install_simulation.json 证据
通过

发布路线

0 promote; 3 keep current; 0 blocked; upgrade minor declared / minor recommended

reports/promotion_decisions.json + reports/upgrade_check.json + docs/migration-v2.md 证据
+
通过

意图画布

intent confidence 100/100; Intent is clear enough to package the first routeable version.

reports/intent-confidence.json 证据
通过

触发实验

13 trigger cases; 0 misroutes; 0 ambiguous

reports/route_scorecard.json 证据
通过

输出实验

5/5 cases; with-skill 100.0; baseline 0.0; file-backed 1; near-neighbor 1; blind A/B 5; exec 10; command 10; model 0; recorded 0; reviewed 0/5

reports/output_quality_scorecard.json 证据
通过

上下文

initial load 987/1000; quality density 131.7

reports/context_budget.json 证据
通过

运行矩阵

5 / 5 targets pass

reports/conformance_matrix.json 证据
通过

信任报告

0 secrets; 68 scripts; 2 network-capable scripts; 0 help smoke failures

reports/security_trust_report.json 证据
通过

权限批准

3/3 permissions approved; gaps 0; required file_write, network, subprocess

reports/security_trust_report.json + security/permission_policy.json 证据
通过

权限探针

3/3 targets probed; native 0; metadata fallback 3; residual risks 3

reports/runtime_permission_probes.json 证据
通过

组合治理

12 skills, 1 actionable; 0 actionable route collisions; 0 actionable owner gaps; 0 actionable stale; 24 scoped non-actionable issues

reports/skill_atlas.json 证据
通过

运营回路

1 metadata events; adoption 100.0; missed 0; bad-output 0; risk low

reports/adoption_drift_report.json 证据
通过

人工批准

0 active waivers cover current warnings

reports/review_waivers.json 证据
通过

注册审计

yao-meta-skill 1.1.0; 6/6 compatibility entries pass; install pass with 3 adapters

reports/registry_audit.json + reports/install_simulation.json 证据
通过

发布路线

0 promote; 3 keep current; 0 blocked; upgrade minor declared / minor recommended

reports/promotion_decisions.json + reports/upgrade_check.json + docs/migration-v2.md 证据
@@ -313,7 +313,7 @@
-

信任报告

Secret
0
脚本数
66
网络脚本
2
Help 失败
0
包体哈希
742dc905b0d221c4f336e741d168861edaf7b75e97fe1e89f7d454c1cabf928f
+

信任报告

Secret
0
脚本数
68
网络脚本
2
Help 失败
0
包体哈希
d53de57f6593fca3dd937832f5923bd5381250e382631a6b6616e2405de748b5

安全边界

高风险 secret、远程 inline execution、缺失依赖策略或无法解释的脚本接口应阻断 governed release。

@@ -344,12 +344,12 @@

注册审计

yao-meta-skill 1.1.0; 6/6 compatibility entries pass; install pass with 3 adapters

-

包体元数据

名称
yao-meta-skill
版本
1.1.0
Maturity
governed
Owner
Yao Team
License
MIT
信任级别
local
目标平台
openai, claude, generic, agent-skills-compatible
兼容通过
6/6
归档哈希
7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9
+

包体元数据

名称
yao-meta-skill
版本
1.1.0
Maturity
governed
Owner
Yao Team
License
MIT
信任级别
local
目标平台
openai, claude, generic, agent-skills-compatible
兼容通过
6/6
归档哈希
6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451

发布路线

0 promote; 3 keep current; 0 blocked; upgrade minor declared / minor recommended

-

包体验证

目标数
3
Adapter
3
归档存在
Zip 条目
488
失败数
0
警告数
0
归档哈希
7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9
+

包体验证

目标数
3
Adapter
3
归档存在
Zip 条目
490
失败数
0
警告数
0
归档哈希
6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451
diff --git a/reports/review-studio.json b/reports/review-studio.json index bee0ced..4e6ba69 100644 --- a/reports/review-studio.json +++ b/reports/review-studio.json @@ -59,7 +59,7 @@ "key": "trust-report", "label": "信任报告", "status": "pass", - "detail": "0 secrets; 66 scripts; 2 network-capable scripts; 0 help smoke failures", + "detail": "0 secrets; 68 scripts; 2 network-capable scripts; 0 help smoke failures", "evidence": "reports/security_trust_report.json", "link": "security_trust_report.md" }, @@ -581,7 +581,7 @@ "path": "scripts", "label": "Deterministic helpers or local tooling", "kind": "folder", - "file_count": 66 + "file_count": 68 }, { "path": "evals", @@ -596,7 +596,7 @@ "file_count": 170 } ], - "file_count": 300, + "file_count": 302, "folder_count": 4, "distribution": [ { @@ -621,7 +621,7 @@ }, { "label": "scripts", - "value": 66 + "value": 68 }, { "label": "evals", @@ -750,7 +750,7 @@ "path": "scripts", "label": "Deterministic helpers or local tooling", "kind": "folder", - "file_count": 66 + "file_count": 68 }, { "path": "evals", @@ -1068,9 +1068,9 @@ "failures": [] }, "trust_security": { - "scanned_files": 150, - "script_count": 66, - "internal_module_count": 7, + "scanned_files": 152, + "script_count": 68, + "internal_module_count": 9, "secret_findings": 0, "dependency_files": [ "requirements-ci.txt" @@ -1088,8 +1088,8 @@ "help_smoke_failed_count": 0, "interactive_script_count": 0, "package_hash_scope": "source-contract-without-generated-reports", - "package_hash_file_count": 150, - "package_sha256": "742dc905b0d221c4f336e741d168861edaf7b75e97fe1e89f7d454c1cabf928f" + "package_hash_file_count": 152, + "package_sha256": "d53de57f6593fca3dd937832f5923bd5381250e382631a6b6616e2405de748b5" }, "skill_atlas": { "skill_count": 12, @@ -1123,8 +1123,8 @@ "trust_level": "local", "license": "MIT", "checksums": { - "package_sha256": "742dc905b0d221c4f336e741d168861edaf7b75e97fe1e89f7d454c1cabf928f", - "archive_sha256": "7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9" + "package_sha256": "d53de57f6593fca3dd937832f5923bd5381250e382631a6b6616e2405de748b5", + "archive_sha256": "6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451" }, "compatibility": { "openai": "pass", @@ -1155,7 +1155,7 @@ }, "distribution": { "archive_verified": true, - "archive_sha256": "7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9", + "archive_sha256": "6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451", "package_verification": "reports/package_verification.json", "install_simulated": true, "install_simulation": "reports/install_simulation.json" @@ -1171,8 +1171,8 @@ "target_count": 3, "adapter_count": 3, "archive_present": true, - "archive_sha256": "7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9", - "archive_entry_count": 488, + "archive_sha256": "6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451", + "archive_entry_count": 490, "failure_count": 0, "warning_count": 0 }, @@ -1183,7 +1183,7 @@ "ok": true, "summary": { "archive_present": true, - "archive_entry_count": 488, + "archive_entry_count": 490, "archive_extracted": true, "entrypoint_loaded": true, "manifest_loaded": true, @@ -1245,12 +1245,12 @@ { "field": "archive_sha256", "from": "", - "to": "7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9" + "to": "6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451" }, { "field": "package_sha256", "from": "0000000000000000000000000000000000000000000000000000000000000000", - "to": "742dc905b0d221c4f336e741d168861edaf7b75e97fe1e89f7d454c1cabf928f" + "to": "d53de57f6593fca3dd937832f5923bd5381250e382631a6b6616e2405de748b5" } ] }, @@ -2978,7 +2978,7 @@ "execution_mode": "command", "model_executed": false, "command_executed": true, - "duration_ms": 23.11, + "duration_ms": 23.49, "provider": "local-output-eval-runner", "model": "", "usage": { @@ -3006,7 +3006,7 @@ "execution_mode": "command", "model_executed": false, "command_executed": true, - "duration_ms": 23.56, + "duration_ms": 23.5, "provider": "local-output-eval-runner", "model": "", "usage": { @@ -3029,7 +3029,7 @@ "execution_mode": "command", "model_executed": false, "command_executed": true, - "duration_ms": 24.17, + "duration_ms": 22.7, "provider": "local-output-eval-runner", "model": "", "usage": { @@ -3057,7 +3057,7 @@ "execution_mode": "command", "model_executed": false, "command_executed": true, - "duration_ms": 23.84, + "duration_ms": 23.01, "provider": "local-output-eval-runner", "model": "", "usage": { @@ -3080,7 +3080,7 @@ "execution_mode": "command", "model_executed": false, "command_executed": true, - "duration_ms": 22.51, + "duration_ms": 22.98, "provider": "local-output-eval-runner", "model": "", "usage": { @@ -3108,7 +3108,7 @@ "execution_mode": "command", "model_executed": false, "command_executed": true, - "duration_ms": 26.03, + "duration_ms": 22.64, "provider": "local-output-eval-runner", "model": "", "usage": { @@ -3131,7 +3131,7 @@ "execution_mode": "command", "model_executed": false, "command_executed": true, - "duration_ms": 28.48, + "duration_ms": 22.61, "provider": "local-output-eval-runner", "model": "", "usage": { @@ -3158,7 +3158,7 @@ "execution_mode": "command", "model_executed": false, "command_executed": true, - "duration_ms": 23.17, + "duration_ms": 22.62, "provider": "local-output-eval-runner", "model": "", "usage": { @@ -3181,7 +3181,7 @@ "execution_mode": "command", "model_executed": false, "command_executed": true, - "duration_ms": 23.94, + "duration_ms": 23.24, "provider": "local-output-eval-runner", "model": "", "usage": { @@ -3210,7 +3210,7 @@ "execution_mode": "command", "model_executed": false, "command_executed": true, - "duration_ms": 22.69, + "duration_ms": 23.29, "provider": "local-output-eval-runner", "model": "", "usage": { @@ -3703,6 +3703,7 @@ "scripts/render_system_model.py", "scripts/resource_boundary_check.py", "scripts/review_studio_formatting.py", + "scripts/review_studio_gates.py", "scripts/review_studio_layout.py", "scripts/run_conformance_suite.py", "scripts/run_description_optimization_suite.py", @@ -3721,7 +3722,8 @@ "scripts/validate_skill.py", "scripts/verify_package.py", "scripts/yao.py", - "scripts/yao_cli_config.py" + "scripts/yao_cli_config.py", + "scripts/yao_cli_parser.py" ], "assets": [ "templates/basic_skill.md.j2", @@ -3772,7 +3774,7 @@ ], "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 } @@ -4010,7 +4012,7 @@ "strategy": "Ship the neutral source tree and expose OpenAI-facing interface metadata as a generated companion file.", "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 }, @@ -4021,7 +4023,7 @@ }, "scripts": { "strategy": "Keep scripts as local package resources; expose help-smoke and permission metadata for reviewer approval before execution.", - "script_count": 66, + "script_count": 68, "help_smoke_failed_count": 0 }, "permissions": { @@ -4233,7 +4235,7 @@ "strategy": "Ship the neutral source tree and expose OpenAI-facing interface metadata as a generated companion file.", "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 }, @@ -4244,7 +4246,7 @@ }, "scripts": { "strategy": "Keep scripts as local package resources; expose help-smoke and permission metadata for reviewer approval before execution.", - "script_count": 66, + "script_count": 68, "help_smoke_failed_count": 0 }, "permissions": { @@ -4492,6 +4494,7 @@ "scripts/render_system_model.py", "scripts/resource_boundary_check.py", "scripts/review_studio_formatting.py", + "scripts/review_studio_gates.py", "scripts/review_studio_layout.py", "scripts/run_conformance_suite.py", "scripts/run_description_optimization_suite.py", @@ -4510,7 +4513,8 @@ "scripts/validate_skill.py", "scripts/verify_package.py", "scripts/yao.py", - "scripts/yao_cli_config.py" + "scripts/yao_cli_config.py", + "scripts/yao_cli_parser.py" ], "assets": [ "templates/basic_skill.md.j2", @@ -4561,7 +4565,7 @@ ], "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 } @@ -4799,7 +4803,7 @@ "strategy": "Preserve the source tree directly; write target notes in targets/claude/README.md.", "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 }, @@ -4810,7 +4814,7 @@ }, "scripts": { "strategy": "Scripts remain local package resources and must be reviewed through trust and permission reports before use.", - "script_count": 66, + "script_count": 68, "help_smoke_failed_count": 0 }, "permissions": { @@ -5022,7 +5026,7 @@ "strategy": "Preserve the source tree directly; write target notes in targets/claude/README.md.", "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 }, @@ -5033,7 +5037,7 @@ }, "scripts": { "strategy": "Scripts remain local package resources and must be reviewed through trust and permission reports before use.", - "script_count": 66, + "script_count": 68, "help_smoke_failed_count": 0 }, "permissions": { @@ -5281,6 +5285,7 @@ "scripts/render_system_model.py", "scripts/resource_boundary_check.py", "scripts/review_studio_formatting.py", + "scripts/review_studio_gates.py", "scripts/review_studio_layout.py", "scripts/run_conformance_suite.py", "scripts/run_description_optimization_suite.py", @@ -5299,7 +5304,8 @@ "scripts/validate_skill.py", "scripts/verify_package.py", "scripts/yao.py", - "scripts/yao_cli_config.py" + "scripts/yao_cli_config.py", + "scripts/yao_cli_parser.py" ], "assets": [ "templates/basic_skill.md.j2", @@ -5350,7 +5356,7 @@ ], "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 } @@ -5588,7 +5594,7 @@ "strategy": "Preserve references, scripts, assets, evals, reports, and adapter metadata as relative package resources.", "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 }, @@ -5598,7 +5604,7 @@ }, "scripts": { "strategy": "Expose script and permission metadata for downstream clients or installers to enforce.", - "script_count": 66, + "script_count": 68, "help_smoke_failed_count": 0 }, "permissions": { @@ -5804,7 +5810,7 @@ "strategy": "Preserve references, scripts, assets, evals, reports, and adapter metadata as relative package resources.", "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 }, @@ -5814,7 +5820,7 @@ }, "scripts": { "strategy": "Expose script and permission metadata for downstream clients or installers to enforce.", - "script_count": 66, + "script_count": 68, "help_smoke_failed_count": 0 }, "permissions": { @@ -6054,6 +6060,7 @@ "scripts/render_system_model.py", "scripts/resource_boundary_check.py", "scripts/review_studio_formatting.py", + "scripts/review_studio_gates.py", "scripts/review_studio_layout.py", "scripts/run_conformance_suite.py", "scripts/run_description_optimization_suite.py", @@ -6072,7 +6079,8 @@ "scripts/validate_skill.py", "scripts/verify_package.py", "scripts/yao.py", - "scripts/yao_cli_config.py" + "scripts/yao_cli_config.py", + "scripts/yao_cli_parser.py" ], "assets": [ "templates/basic_skill.md.j2", @@ -6123,7 +6131,7 @@ ], "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 } @@ -6361,7 +6369,7 @@ "strategy": "Keep optional directories as relative resources next to SKILL.md.", "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 }, @@ -6372,7 +6380,7 @@ }, "scripts": { "strategy": "Scripts remain local optional resources and should advertise --help when executable.", - "script_count": 66, + "script_count": 68, "help_smoke_failed_count": 0 }, "permissions": { @@ -6577,7 +6585,7 @@ "strategy": "Keep optional directories as relative resources next to SKILL.md.", "counts": { "references": 32, - "scripts": 66, + "scripts": 68, "assets": 2, "reports": 41 }, @@ -6588,7 +6596,7 @@ }, "scripts": { "strategy": "Scripts remain local optional resources and should advertise --help when executable.", - "script_count": 66, + "script_count": 68, "help_smoke_failed_count": 0 }, "permissions": { @@ -7152,9 +7160,9 @@ "ok": true, "skill_dir": ".", "summary": { - "scanned_files": 150, - "script_count": 66, - "internal_module_count": 7, + "scanned_files": 152, + "script_count": 68, + "internal_module_count": 9, "secret_findings": 0, "dependency_files": [ "requirements-ci.txt" @@ -7172,8 +7180,8 @@ "help_smoke_failed_count": 0, "interactive_script_count": 0, "package_hash_scope": "source-contract-without-generated-reports", - "package_hash_file_count": 150, - "package_sha256": "742dc905b0d221c4f336e741d168861edaf7b75e97fe1e89f7d454c1cabf928f" + "package_hash_file_count": 152, + "package_sha256": "d53de57f6593fca3dd937832f5923bd5381250e382631a6b6616e2405de748b5" }, "failures": [], "warnings": [], @@ -7850,6 +7858,20 @@ "network_urls": [], "network_hosts": [] }, + { + "path": "scripts/review_studio_gates.py", + "interface": "internal-module", + "interface_declared": true, + "interface_reason": "Imported by render_review_studio.py to keep Review Studio gate evaluation separate from HTML rendering.", + "has_argparse": false, + "has_main_guard": false, + "uses_input": false, + "uses_network": false, + "uses_file_write": false, + "uses_subprocess": false, + "network_urls": [], + "network_hosts": [] + }, { "path": "scripts/review_studio_layout.py", "interface": "internal-module", @@ -8115,6 +8137,20 @@ "uses_subprocess": false, "network_urls": [], "network_hosts": [] + }, + { + "path": "scripts/yao_cli_parser.py", + "interface": "internal-module", + "interface_declared": true, + "interface_reason": "Imported by yao.py to keep CLI parser declarations separate from command orchestration.", + "has_argparse": true, + "has_main_guard": false, + "uses_input": false, + "uses_network": false, + "uses_file_write": false, + "uses_subprocess": false, + "network_urls": [], + "network_hosts": [] } ], "dependencies": { @@ -8150,7 +8186,7 @@ "checked_count": 59, "passed_count": 59, "failed_count": 0, - "skipped_count": 7, + "skipped_count": 9, "failed_scripts": [], "results": [ { @@ -8749,6 +8785,10 @@ "path": "scripts/review_studio_formatting.py", "reason": "internal module" }, + { + "path": "scripts/review_studio_gates.py", + "reason": "internal module" + }, { "path": "scripts/review_studio_layout.py", "reason": "internal module" @@ -8772,6 +8812,10 @@ { "path": "scripts/yao_cli_config.py", "reason": "internal module" + }, + { + "path": "scripts/yao_cli_parser.py", + "reason": "internal module" } ] }, @@ -8936,10 +8980,10 @@ "context_budget_tier": "production", "context_budget_limit": 1000, "skill_body_tokens": 811, - "other_text_tokens": 869504, + "other_text_tokens": 871465, "estimated_initial_load_tokens": 987, - "estimated_total_text_tokens": 870315, - "relevant_file_count": 327, + "estimated_total_text_tokens": 872276, + "relevant_file_count": 367, "unused_resource_dirs": [], "quality_signal_points": 130, "quality_density": 131.7 @@ -9846,6 +9890,7 @@ "scripts/render_system_model.py", "scripts/resource_boundary_check.py", "scripts/review_studio_formatting.py", + "scripts/review_studio_gates.py", "scripts/review_studio_layout.py", "scripts/run_conformance_suite.py", "scripts/run_description_optimization_suite.py", @@ -9865,6 +9910,7 @@ "scripts/verify_package.py", "scripts/yao.py", "scripts/yao_cli_config.py", + "scripts/yao_cli_parser.py", "references/artifact-design-doctrine.md", "references/authoring-discipline.md", "references/distribution-registry-method.md", @@ -10646,7 +10692,7 @@ "adoption_drift": { "ok": true, "schema_version": "2.0", - "generated_at": "2026-06-13T10:57:52Z", + "generated_at": "2026-06-13T11:10:15Z", "skill_dir": ".", "privacy_contract": { "storage": "local-first", @@ -10805,8 +10851,8 @@ "trust_level": "local", "license": "MIT", "checksums": { - "package_sha256": "742dc905b0d221c4f336e741d168861edaf7b75e97fe1e89f7d454c1cabf928f", - "archive_sha256": "7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9" + "package_sha256": "d53de57f6593fca3dd937832f5923bd5381250e382631a6b6616e2405de748b5", + "archive_sha256": "6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451" }, "compatibility": { "openai": "pass", @@ -10837,7 +10883,7 @@ }, "distribution": { "archive_verified": true, - "archive_sha256": "7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9", + "archive_sha256": "6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451", "package_verification": "reports/package_verification.json", "install_simulated": true, "install_simulation": "reports/install_simulation.json" @@ -10861,7 +10907,7 @@ "agent-skills-compatible" ], "package_metadata": "registry/packages/yao-meta-skill.json", - "package_sha256": "742dc905b0d221c4f336e741d168861edaf7b75e97fe1e89f7d454c1cabf928f" + "package_sha256": "d53de57f6593fca3dd937832f5923bd5381250e382631a6b6616e2405de748b5" } ] }, @@ -10884,8 +10930,8 @@ "target_count": 3, "adapter_count": 3, "archive_present": true, - "archive_sha256": "7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9", - "archive_entry_count": 488, + "archive_sha256": "6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451", + "archive_entry_count": 490, "failure_count": 0, "warning_count": 0 }, @@ -11400,7 +11446,7 @@ "installed_skill_dir": "dist/install-simulation/simulate-yao-meta-skill/yao-meta-skill", "summary": { "archive_present": true, - "archive_entry_count": 488, + "archive_entry_count": 490, "archive_extracted": true, "entrypoint_loaded": true, "manifest_loaded": true, @@ -11581,12 +11627,12 @@ { "field": "archive_sha256", "from": "", - "to": "7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9" + "to": "6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451" }, { "field": "package_sha256", "from": "0000000000000000000000000000000000000000000000000000000000000000", - "to": "742dc905b0d221c4f336e741d168861edaf7b75e97fe1e89f7d454c1cabf928f" + "to": "d53de57f6593fca3dd937832f5923bd5381250e382631a6b6616e2405de748b5" } ] }, diff --git a/reports/security_trust_report.json b/reports/security_trust_report.json index 75a03a7..1b18e4d 100644 --- a/reports/security_trust_report.json +++ b/reports/security_trust_report.json @@ -2,9 +2,9 @@ "ok": true, "skill_dir": ".", "summary": { - "scanned_files": 150, - "script_count": 66, - "internal_module_count": 7, + "scanned_files": 152, + "script_count": 68, + "internal_module_count": 9, "secret_findings": 0, "dependency_files": [ "requirements-ci.txt" @@ -22,8 +22,8 @@ "help_smoke_failed_count": 0, "interactive_script_count": 0, "package_hash_scope": "source-contract-without-generated-reports", - "package_hash_file_count": 150, - "package_sha256": "742dc905b0d221c4f336e741d168861edaf7b75e97fe1e89f7d454c1cabf928f" + "package_hash_file_count": 152, + "package_sha256": "d53de57f6593fca3dd937832f5923bd5381250e382631a6b6616e2405de748b5" }, "failures": [], "warnings": [], @@ -700,6 +700,20 @@ "network_urls": [], "network_hosts": [] }, + { + "path": "scripts/review_studio_gates.py", + "interface": "internal-module", + "interface_declared": true, + "interface_reason": "Imported by render_review_studio.py to keep Review Studio gate evaluation separate from HTML rendering.", + "has_argparse": false, + "has_main_guard": false, + "uses_input": false, + "uses_network": false, + "uses_file_write": false, + "uses_subprocess": false, + "network_urls": [], + "network_hosts": [] + }, { "path": "scripts/review_studio_layout.py", "interface": "internal-module", @@ -965,6 +979,20 @@ "uses_subprocess": false, "network_urls": [], "network_hosts": [] + }, + { + "path": "scripts/yao_cli_parser.py", + "interface": "internal-module", + "interface_declared": true, + "interface_reason": "Imported by yao.py to keep CLI parser declarations separate from command orchestration.", + "has_argparse": true, + "has_main_guard": false, + "uses_input": false, + "uses_network": false, + "uses_file_write": false, + "uses_subprocess": false, + "network_urls": [], + "network_hosts": [] } ], "dependencies": { @@ -1000,7 +1028,7 @@ "checked_count": 59, "passed_count": 59, "failed_count": 0, - "skipped_count": 7, + "skipped_count": 9, "failed_scripts": [], "results": [ { @@ -1599,6 +1627,10 @@ "path": "scripts/review_studio_formatting.py", "reason": "internal module" }, + { + "path": "scripts/review_studio_gates.py", + "reason": "internal module" + }, { "path": "scripts/review_studio_layout.py", "reason": "internal module" @@ -1622,6 +1654,10 @@ { "path": "scripts/yao_cli_config.py", "reason": "internal module" + }, + { + "path": "scripts/yao_cli_parser.py", + "reason": "internal module" } ] }, diff --git a/reports/security_trust_report.md b/reports/security_trust_report.md index df2c282..e006bc6 100644 --- a/reports/security_trust_report.md +++ b/reports/security_trust_report.md @@ -1,9 +1,9 @@ # Security Trust Report - OK: `True` -- Scanned files: `150` -- Scripts: `66` -- Internal script modules: `7` +- Scanned files: `152` +- Scripts: `68` +- Internal script modules: `9` - Secret findings: `0` - Network-capable scripts: `2` - Network policy covered scripts: `2` @@ -15,8 +15,8 @@ - CLI help smoke failures: `0` - Interactive scripts: `0` - Package hash scope: `source-contract-without-generated-reports` -- Package hash files: `150` -- Package SHA256: `742dc905b0d221c4f336e741d168861edaf7b75e97fe1e89f7d454c1cabf928f` +- Package hash files: `152` +- Package SHA256: `d53de57f6593fca3dd937832f5923bd5381250e382631a6b6616e2405de748b5` ## Failures @@ -109,6 +109,7 @@ | scripts/render_system_model.py | cli | False | True | True | False | False | True | False | Default CLI classification; add SCRIPT_INTERFACE for internal modules. | | scripts/resource_boundary_check.py | cli | False | True | True | False | False | False | False | Default CLI classification; add SCRIPT_INTERFACE for internal modules. | | scripts/review_studio_formatting.py | internal-module | True | False | False | False | False | False | False | Imported by render_review_studio.py to format report dictionaries as audit UI panels. | +| scripts/review_studio_gates.py | internal-module | True | False | False | False | False | False | False | Imported by render_review_studio.py to keep Review Studio gate evaluation separate from HTML rendering. | | scripts/review_studio_layout.py | internal-module | True | False | False | False | False | False | False | Imported by render_review_studio.py to keep Review Studio layout and CSS out of gate logic. | | scripts/run_conformance_suite.py | cli | False | True | True | False | False | True | False | Default CLI classification; add SCRIPT_INTERFACE for internal modules. | | scripts/run_description_optimization_suite.py | cli | False | True | True | False | False | True | False | Default CLI classification; add SCRIPT_INTERFACE for internal modules. | @@ -128,3 +129,4 @@ | scripts/verify_package.py | cli | False | True | True | False | False | True | False | Default CLI classification; add SCRIPT_INTERFACE for internal modules. | | scripts/yao.py | cli | False | True | True | False | False | False | True | Default CLI classification; add SCRIPT_INTERFACE for internal modules. | | scripts/yao_cli_config.py | internal-module | True | False | False | False | False | False | False | Imported by yao.py for CLI target maps and side-effect-free shaping helpers. | +| scripts/yao_cli_parser.py | internal-module | True | True | False | False | False | False | False | Imported by yao.py to keep CLI parser declarations separate from command orchestration. | diff --git a/reports/skill-overview.html b/reports/skill-overview.html index 6e3e209..eeced4a 100644 --- a/reports/skill-overview.html +++ b/reports/skill-overview.html @@ -771,7 +771,7 @@

让 reviewer 快速确认关键文件、目录和资产分布。Lets reviewers confirm key files, directories, and asset distribution quickly.

-
资产分布300项SKILL.mdREADME.mdagents/interface.yamlmanifest.jsonreferencesscripts
资产分布图展示当前包体的文件和目录重心。
+
资产分布302项SKILL.mdREADME.mdagents/interface.yamlmanifest.jsonreferencesscripts
资产分布图展示当前包体的文件和目录重心。
diff --git a/reports/skill-overview.json b/reports/skill-overview.json index 41de1c7..58b7545 100644 --- a/reports/skill-overview.json +++ b/reports/skill-overview.json @@ -433,7 +433,7 @@ "path": "scripts", "label": "Deterministic helpers or local tooling", "kind": "folder", - "file_count": 66 + "file_count": 68 }, { "path": "evals", @@ -448,7 +448,7 @@ "file_count": 170 } ], - "file_count": 300, + "file_count": 302, "folder_count": 4, "distribution": [ { @@ -473,7 +473,7 @@ }, { "label": "scripts", - "value": 66 + "value": 68 }, { "label": "evals", @@ -602,7 +602,7 @@ "path": "scripts", "label": "Deterministic helpers or local tooling", "kind": "folder", - "file_count": 66 + "file_count": 68 }, { "path": "evals", @@ -920,9 +920,9 @@ "failures": [] }, "trust_security": { - "scanned_files": 150, - "script_count": 66, - "internal_module_count": 7, + "scanned_files": 152, + "script_count": 68, + "internal_module_count": 9, "secret_findings": 0, "dependency_files": [ "requirements-ci.txt" @@ -940,8 +940,8 @@ "help_smoke_failed_count": 0, "interactive_script_count": 0, "package_hash_scope": "source-contract-without-generated-reports", - "package_hash_file_count": 150, - "package_sha256": "742dc905b0d221c4f336e741d168861edaf7b75e97fe1e89f7d454c1cabf928f" + "package_hash_file_count": 152, + "package_sha256": "d53de57f6593fca3dd937832f5923bd5381250e382631a6b6616e2405de748b5" }, "skill_atlas": { "skill_count": 12, @@ -975,8 +975,8 @@ "trust_level": "local", "license": "MIT", "checksums": { - "package_sha256": "742dc905b0d221c4f336e741d168861edaf7b75e97fe1e89f7d454c1cabf928f", - "archive_sha256": "7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9" + "package_sha256": "d53de57f6593fca3dd937832f5923bd5381250e382631a6b6616e2405de748b5", + "archive_sha256": "6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451" }, "compatibility": { "openai": "pass", @@ -1007,7 +1007,7 @@ }, "distribution": { "archive_verified": true, - "archive_sha256": "7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9", + "archive_sha256": "6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451", "package_verification": "reports/package_verification.json", "install_simulated": true, "install_simulation": "reports/install_simulation.json" @@ -1023,8 +1023,8 @@ "target_count": 3, "adapter_count": 3, "archive_present": true, - "archive_sha256": "7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9", - "archive_entry_count": 488, + "archive_sha256": "6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451", + "archive_entry_count": 490, "failure_count": 0, "warning_count": 0 }, @@ -1035,7 +1035,7 @@ "ok": true, "summary": { "archive_present": true, - "archive_entry_count": 488, + "archive_entry_count": 490, "archive_extracted": true, "entrypoint_loaded": true, "manifest_loaded": true, @@ -1097,12 +1097,12 @@ { "field": "archive_sha256", "from": "", - "to": "7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9" + "to": "6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451" }, { "field": "package_sha256", "from": "0000000000000000000000000000000000000000000000000000000000000000", - "to": "742dc905b0d221c4f336e741d168861edaf7b75e97fe1e89f7d454c1cabf928f" + "to": "d53de57f6593fca3dd937832f5923bd5381250e382631a6b6616e2405de748b5" } ] }, diff --git a/reports/skill_atlas.json b/reports/skill_atlas.json index 9e4ab39..3619321 100644 --- a/reports/skill_atlas.json +++ b/reports/skill_atlas.json @@ -107,6 +107,7 @@ "scripts/render_system_model.py", "scripts/resource_boundary_check.py", "scripts/review_studio_formatting.py", + "scripts/review_studio_gates.py", "scripts/review_studio_layout.py", "scripts/run_conformance_suite.py", "scripts/run_description_optimization_suite.py", @@ -126,6 +127,7 @@ "scripts/verify_package.py", "scripts/yao.py", "scripts/yao_cli_config.py", + "scripts/yao_cli_parser.py", "references/artifact-design-doctrine.md", "references/authoring-discipline.md", "references/distribution-registry-method.md", diff --git a/reports/upgrade_check.json b/reports/upgrade_check.json index 0607c15..77285e1 100644 --- a/reports/upgrade_check.json +++ b/reports/upgrade_check.json @@ -68,12 +68,12 @@ { "field": "archive_sha256", "from": "", - "to": "7bc83805501d24cf8e5932ef76e0454100398d5a73652e7440be47984d0cf4a9" + "to": "6972bb1d72746b6a16c7dbf1ec73f438252756dd850fe474bc3b75af8649d451" }, { "field": "package_sha256", "from": "0000000000000000000000000000000000000000000000000000000000000000", - "to": "742dc905b0d221c4f336e741d168861edaf7b75e97fe1e89f7d454c1cabf928f" + "to": "d53de57f6593fca3dd937832f5923bd5381250e382631a6b6616e2405de748b5" } ] }, @@ -88,7 +88,7 @@ "artifacts": { "previous_package": "registry/examples/yao-meta-skill-1.0.0.json", "current_package": "reports/registry_audit.json", - "json": "reports/upgrade_check.json", - "markdown": "reports/upgrade_check.md" + "json": "tests/tmp_review_studio/upgrade_check.json", + "markdown": "tests/tmp_review_studio/upgrade_check.md" } } diff --git a/scripts/render_review_studio.py b/scripts/render_review_studio.py index 74879be..b76ce52 100644 --- a/scripts/render_review_studio.py +++ b/scripts/render_review_studio.py @@ -11,14 +11,8 @@ try: except ImportError: # pragma: no cover yaml = None -try: - from trust_check import permission_governance_status as compute_permission_governance_status - from trust_check import script_inventory as trust_script_inventory -except ImportError: # pragma: no cover - compute_permission_governance_status = None - trust_script_inventory = None - from review_studio_formatting import registry_package_summary, render_kv_grid +from review_studio_gates import add_blockers_from_gate, build_gates, status_label, weighted_score from review_studio_layout import render_review_nav, review_studio_css @@ -78,9 +72,6 @@ def link_from(output_html: Path, target: Path) -> str: return os.path.relpath(target.resolve(), output_html.parent.resolve()) -def report_link(output_html: Path, skill_dir: Path, rel_path: str) -> str: - return link_from(output_html, skill_dir / rel_path) - def find_line(path: Path, patterns: list[str] | None = None) -> int | None: if not path.exists(): @@ -124,478 +115,6 @@ def source_refs( return refs -def gate(key: str, label: str, status: str, detail: str, evidence: str, link: str = "") -> dict[str, str]: - return { - "key": key, - "label": label, - "status": status, - "detail": detail, - "evidence": evidence, - "link": link, - } - - -def status_label(status: str) -> str: - return {"pass": "通过", "warn": "关注", "block": "阻断"}.get(status, status) - - -def add_blockers_from_gate(gates: list[dict[str, str]]) -> tuple[list[dict[str, str]], list[dict[str, str]]]: - blockers = [item for item in gates if item["status"] == "block"] - warnings = [item for item in gates if item["status"] == "warn"] - return blockers, warnings - - -def target_maturity(skill_dir: Path, overview: dict[str, Any]) -> str: - manifest = load_json(skill_dir / "manifest.json") - if manifest.get("maturity_tier"): - return str(manifest["maturity_tier"]) - metadata = overview.get("metadata", {}) if isinstance(overview, dict) else {} - if metadata.get("maturity_tier"): - return str(metadata["maturity_tier"]) - return "scaffold" - - -def min_output_cases(maturity: str) -> int: - if maturity in {"library", "governed"}: - return 5 - if maturity == "production": - return 3 - return 1 - - -def fallback_permission_governance(skill_dir: Path) -> dict[str, Any]: - if compute_permission_governance_status is None or trust_script_inventory is None: - return {} - try: - scripts = trust_script_inventory(skill_dir) - return compute_permission_governance_status(skill_dir, scripts) - except Exception: - return {} - - -def build_gates(skill_dir: Path, output_html: Path, data: dict[str, dict[str, Any]]) -> list[dict[str, str]]: - overview = data["overview"] - maturity = target_maturity(skill_dir, overview) - gates: list[dict[str, str]] = [] - - intent = data["intent_confidence"] - intent_score = int(intent.get("score", 0) or 0) - intent_status = "pass" if intent.get("gate_passed") or intent_score >= 75 else "warn" - gates.append( - gate( - "intent-canvas", - "意图画布", - intent_status, - f"intent confidence {intent_score}/100; {intent.get('recommended_action', 'review current intent frame')}", - "reports/intent-confidence.json", - report_link(output_html, skill_dir, "reports/intent-confidence.md"), - ) - ) - - route = data["route_scorecard"] - route_summary = route.get("summary", {}) - misroutes = int(route_summary.get("misroute_count", len(route.get("misroutes", []))) or 0) - ambiguous = int(route_summary.get("ambiguous_case_count", len(route.get("ambiguous_cases", []))) or 0) - if not route: - route_status = "warn" - route_detail = "route scorecard is missing; run route-scorecard before release review" - else: - route_status = "block" if misroutes else ("warn" if ambiguous else "pass") - route_detail = f"{route_summary.get('total_cases', 0)} trigger cases; {misroutes} misroutes; {ambiguous} ambiguous" - gates.append( - gate( - "trigger-lab", - "触发实验", - route_status, - route_detail, - "reports/route_scorecard.json", - report_link(output_html, skill_dir, "reports/route_scorecard.md"), - ) - ) - - output = data["output_quality"] - output_execution = data["output_execution"] - output_blind = data["output_blind_review"] - output_review = data["output_review_adjudication"] - output_summary = output.get("summary", {}) - output_execution_summary = output_execution.get("summary", {}) - output_blind_summary = output_blind.get("summary", {}) - output_review_summary = output_review.get("summary", {}) - required_cases = min_output_cases(maturity) - case_count = int(output_summary.get("case_count", 0) or 0) - file_backed = int(output_summary.get("file_backed_case_count", 0) or 0) - near_neighbor = int(output_summary.get("near_neighbor_case_count", 0) or 0) - boundary = int(output_summary.get("boundary_case_count", 0) or 0) - blind_pair_count = int(output_blind_summary.get("pair_count", 0) or 0) - execution_variant_count = int(output_execution_summary.get("variant_run_count", 0) or 0) - execution_command_count = int(output_execution_summary.get("command_executed_count", 0) or 0) - execution_model_count = int(output_execution_summary.get("model_executed_count", 0) or 0) - execution_recorded_count = int(output_execution_summary.get("recorded_fixture_count", 0) or 0) - review_pair_count = int(output_review_summary.get("pair_count", 0) or 0) - review_judgment_count = int(output_review_summary.get("judgment_count", 0) or 0) - review_invalid_count = int(output_review_summary.get("invalid_decision_count", 0) or 0) - blind_missing = maturity in {"production", "library", "governed"} and (not output_blind or blind_pair_count < case_count) - execution_failed = bool(output_execution) and (not output_execution.get("ok", True) or int(output_execution_summary.get("failure_count", 0) or 0) > 0) - review_invalid = bool(output_review) and (not output_review.get("ok", True) or review_invalid_count > 0) - output_blocked = ( - not output.get("ok", False) - or not output_summary.get("gate_pass", False) - or case_count < required_cases - or execution_failed - or review_invalid - ) - output_warn = file_backed == 0 or near_neighbor == 0 or boundary == 0 or blind_missing - if not output: - output_status = "warn" - output_detail = "output eval scorecard is missing; generate it before production review" - else: - output_status = "block" if output_blocked else ("warn" if output_warn else "pass") - output_detail = ( - f"{case_count}/{required_cases} cases; with-skill {output_summary.get('with_skill_pass_rate', 0)}; " - f"baseline {output_summary.get('baseline_pass_rate', 0)}; file-backed {file_backed}; near-neighbor {near_neighbor}; " - f"blind A/B {blind_pair_count}" - + ( - f"; exec {execution_variant_count}; command {execution_command_count}; " - f"model {execution_model_count}; recorded {execution_recorded_count}" - if output_execution - else "" - ) - + (f"; reviewed {review_judgment_count}/{review_pair_count}" if output_review else "") - ) - gates.append( - gate( - "output-lab", - "输出实验", - output_status, - output_detail, - "reports/output_quality_scorecard.json", - report_link(output_html, skill_dir, "reports/output_quality_scorecard.md"), - ) - ) - - context = data["context_budget"] - context_stats = context.get("stats", {}) - context_status = "pass" if context.get("ok") else "block" - if context.get("warnings"): - context_status = "warn" if context_status == "pass" else context_status - if not context: - context_status = "warn" - context_detail = ( - f"initial load {context_stats.get('estimated_initial_load_tokens', 'n/a')}/" - f"{context_stats.get('context_budget_limit', 'n/a')}; quality density {context_stats.get('quality_density', 'n/a')}" - ) - gates.append( - gate( - "context-budget", - "上下文", - context_status, - context_detail, - "reports/context_budget.json", - report_link(output_html, skill_dir, "reports/context_budget.md"), - ) - ) - - conformance = data["conformance"] - conformance_summary = conformance.get("summary", {}) - fail_count = int(conformance_summary.get("fail_count", 0) or 0) - if not conformance: - conformance_status = "warn" - conformance_detail = "runtime conformance matrix is missing" - else: - conformance_status = "block" if fail_count else "pass" - conformance_detail = f"{conformance_summary.get('pass_count', 0)} / {conformance_summary.get('target_count', 0)} targets pass" - gates.append( - gate( - "runtime-matrix", - "运行矩阵", - conformance_status, - conformance_detail, - "reports/conformance_matrix.json", - report_link(output_html, skill_dir, "reports/conformance_matrix.md"), - ) - ) - - trust = data["trust"] - trust_summary = trust.get("summary", {}) - if not trust: - trust_status = "warn" - trust_detail = "security trust report is missing" - else: - trust_status = "block" if trust.get("failures") else ("warn" if trust.get("warnings") else "pass") - trust_detail = ( - f"{trust_summary.get('secret_findings', 0)} secrets; " - f"{trust_summary.get('script_count', 0)} scripts; " - f"{trust_summary.get('network_script_count', 0)} network-capable scripts; " - f"{trust_summary.get('help_smoke_failed_count', 0)} help smoke failures" - ) - gates.append( - gate( - "trust-report", - "信任报告", - trust_status, - trust_detail, - "reports/security_trust_report.json", - report_link(output_html, skill_dir, "reports/security_trust_report.md"), - ) - ) - - permission_governance = trust.get("permission_governance", {}) if isinstance(trust.get("permission_governance", {}), dict) else {} - if trust and not permission_governance: - permission_governance = fallback_permission_governance(skill_dir) - if not trust: - permission_status = "warn" - permission_detail = "permission governance evidence is missing because trust report is missing" - elif not permission_governance: - permission_status = "warn" - permission_detail = "permission governance evidence is missing from trust report" - else: - required = int(permission_governance.get("required_count", 0) or 0) - approved = int(permission_governance.get("approval_count", 0) or 0) - gaps = ( - int(permission_governance.get("missing_count", 0) or 0) - + int(permission_governance.get("invalid_count", 0) or 0) - + int(permission_governance.get("expired_count", 0) or 0) - ) - if gaps: - permission_status = "block" if maturity == "governed" else "warn" - else: - permission_status = "pass" - required_names = ", ".join(permission_governance.get("required_capabilities", []) or []) or "none" - permission_detail = f"{approved}/{required} permissions approved; gaps {gaps}; required {required_names}" - gates.append( - gate( - "permission-gates", - "权限批准", - permission_status, - permission_detail, - "reports/security_trust_report.json + security/permission_policy.json", - report_link(output_html, skill_dir, "security/permission_policy.md"), - ) - ) - - runtime_permissions = data["runtime_permissions"] - runtime_permissions_summary = runtime_permissions.get("summary", {}) - if not runtime_permissions: - runtime_permission_status = "block" if maturity == "governed" else "warn" - runtime_permission_detail = "runtime permission probe report is missing" - elif runtime_permissions.get("failures"): - runtime_permission_status = "block" - runtime_permission_detail = f"{runtime_permissions_summary.get('failure_count', len(runtime_permissions.get('failures', [])))} runtime permission probe failures" - else: - runtime_permission_status = "pass" - runtime_permission_detail = ( - f"{runtime_permissions_summary.get('pass_count', 0)}/{runtime_permissions_summary.get('target_count', 0)} targets probed; " - f"native {runtime_permissions_summary.get('native_enforcement_count', 0)}; " - f"metadata fallback {runtime_permissions_summary.get('metadata_fallback_count', 0)}; " - f"residual risks {runtime_permissions_summary.get('residual_risk_count', 0)}" - ) - gates.append( - gate( - "permission-runtime", - "权限探针", - runtime_permission_status, - runtime_permission_detail, - "reports/runtime_permission_probes.json", - report_link(output_html, skill_dir, "reports/runtime_permission_probes.md"), - ) - ) - - atlas = data["atlas"] - atlas_summary = atlas.get("summary", {}) - actionable_route_collisions = int( - atlas_summary.get("actionable_route_collision_count", atlas_summary.get("route_collision_count", 0)) or 0 - ) - actionable_owner_gaps = int(atlas_summary.get("actionable_owner_gap_count", atlas_summary.get("owner_gap_count", 0)) or 0) - actionable_stale = int(atlas_summary.get("actionable_stale_count", atlas_summary.get("stale_count", 0)) or 0) - atlas_issues = actionable_route_collisions + actionable_owner_gaps + actionable_stale - if not atlas: - atlas_status = "warn" - atlas_detail = "skill atlas is missing; portfolio-level conflicts are unknown" - else: - atlas_status = "warn" if atlas_issues else "pass" - atlas_detail = ( - f"{atlas_summary.get('skill_count', 0)} skills, " - f"{atlas_summary.get('actionable_skill_count', atlas_summary.get('skill_count', 0))} actionable; " - f"{actionable_route_collisions} actionable route collisions; " - f"{actionable_owner_gaps} actionable owner gaps; " - f"{actionable_stale} actionable stale; " - f"{atlas_summary.get('non_actionable_issue_count', 0)} scoped non-actionable issues" - ) - gates.append( - gate( - "skill-atlas", - "组合治理", - atlas_status, - atlas_detail, - "reports/skill_atlas.json", - report_link(output_html, skill_dir, "reports/skill_atlas.html"), - ) - ) - - adoption = data["adoption_drift"] - adoption_summary = adoption.get("summary", {}) - if not adoption: - adoption_status = "warn" - adoption_detail = "adoption drift report is missing; real usage impact is unknown" - elif adoption.get("failures"): - adoption_status = "block" - adoption_detail = f"telemetry privacy or schema failures: {len(adoption.get('failures', []))}" - else: - risk_band = adoption_summary.get("risk_band", "no-data") - adoption_status = "warn" if risk_band in {"no-data", "medium", "high"} else "pass" - adoption_detail = ( - f"{adoption_summary.get('event_count', 0)} metadata events; " - f"adoption {adoption_summary.get('adoption_rate', 0)}; " - f"missed {adoption_summary.get('missed_trigger_count', 0)}; " - f"bad-output {adoption_summary.get('bad_output_count', 0)}; " - f"risk {risk_band}" - ) - gates.append( - gate( - "operations-loop", - "运营回路", - adoption_status, - adoption_detail, - "reports/adoption_drift_report.json", - report_link(output_html, skill_dir, "reports/adoption_drift_report.md"), - ) - ) - - waiver = data["review_waivers"] - waiver_summary = waiver.get("summary", {}) - active_covered = set(waiver_summary.get("covered_gate_keys", []) or []) - prior_blockers = [item for item in gates if item["status"] == "block"] - prior_warnings = [item for item in gates if item["status"] == "warn"] - unwaived_warnings = [item for item in prior_warnings if item["key"] not in active_covered] - if not waiver: - waiver_status = "warn" - waiver_detail = "review waiver ledger is missing; warning acceptance is not auditable" - elif waiver.get("failures"): - waiver_status = "block" - waiver_detail = f"{len(waiver.get('failures', []))} invalid waiver records" - elif prior_blockers: - waiver_status = "block" - waiver_detail = f"{len(prior_blockers)} blocker gates cannot be waived in v0" - elif unwaived_warnings: - waiver_status = "warn" - waiver_detail = ( - f"{waiver_summary.get('active_count', 0)} active waivers; " - f"{len(unwaived_warnings)} warning gates still need reviewer decision" - ) - else: - waiver_status = "pass" - waiver_detail = f"{waiver_summary.get('active_count', 0)} active waivers cover current warnings" - gates.append( - gate( - "review-waivers", - "人工批准", - waiver_status, - waiver_detail, - "reports/review_waivers.json", - report_link(output_html, skill_dir, "reports/review_waivers.md"), - ) - ) - - registry = data["registry"] - install = data["install_simulation"] - if not registry: - if maturity in {"library", "governed"}: - registry_status = "warn" - registry_detail = "registry audit is missing; package metadata is not reviewable" - else: - registry_status = "pass" - registry_detail = "registry audit is optional until team distribution is required" - else: - compatibility = registry.get("package", {}).get("compatibility", {}) - pass_count = sum(1 for status in compatibility.values() if status == "pass") - registry_status = "block" if registry.get("failures") else ("warn" if registry.get("warnings") else "pass") - registry_detail = ( - f"{registry.get('package', {}).get('name', 'package')} " - f"{registry.get('package', {}).get('version', 'n/a')}; " - f"{pass_count}/{len(compatibility)} compatibility entries pass" - ) - if install: - if install.get("failures"): - registry_status = "block" - install_summary = install.get("summary", {}) - registry_detail += ( - f"; install {'pass' if install.get('ok') else 'fail'}" - f" with {install_summary.get('adapter_count', 0)} adapters" - ) - gates.append( - gate( - "registry-audit", - "注册审计", - registry_status, - registry_detail, - "reports/registry_audit.json + reports/install_simulation.json", - report_link(output_html, skill_dir, "reports/registry_audit.md"), - ) - ) - - promotion = data["promotion"] - migration_path = ROOT / "docs" / "migration-v2.md" - if promotion: - promotion_summary = promotion.get("summary", {}) - blocked = int(promotion_summary.get("blocked", 0) or 0) - release_status = "block" if blocked else "pass" - release_detail = f"{promotion_summary.get('promote', 0)} promote; {promotion_summary.get('keep_current', 0)} keep current; {blocked} blocked" - else: - release_status = "warn" - release_detail = "promotion decisions are missing; release notes need reviewer confirmation" - upgrade = data["upgrade_check"] - if upgrade: - upgrade_summary = upgrade.get("summary", {}) - if upgrade.get("failures"): - release_status = "block" - elif upgrade.get("warnings") and release_status == "pass": - release_status = "warn" - release_detail += ( - f"; upgrade {upgrade_summary.get('declared_bump', 'n/a')}" - f" declared / {upgrade_summary.get('recommended_bump', 'n/a')} recommended" - ) - gates.append( - gate( - "release-notes", - "发布路线", - release_status, - release_detail, - "reports/promotion_decisions.json + reports/upgrade_check.json + docs/migration-v2.md", - report_link(output_html, skill_dir, "reports/promotion_decisions.md") if promotion else str(migration_path), - ) - ) - - return gates - - -def weighted_score(gates: list[dict[str, str]]) -> int: - weights = { - "trigger-lab": 15, - "output-lab": 20, - "context-budget": 10, - "runtime-matrix": 10, - "trust-report": 10, - "permission-gates": 10, - "permission-runtime": 10, - "skill-atlas": 10, - "operations-loop": 10, - "review-waivers": 10, - "registry-audit": 10, - "release-notes": 10, - "intent-canvas": 10, - } - earned = 0.0 - total = 0.0 - for item in gates: - weight = weights.get(item["key"], 5) - total += weight - if item["status"] == "pass": - earned += weight - elif item["status"] == "warn": - earned += weight * 0.6 - return int(round(earned / total * 100)) if total else 0 - - def evidence_paths(skill_dir: Path) -> dict[str, str]: rels = { "skill_overview": "reports/skill-overview.html", diff --git a/scripts/review_studio_gates.py b/scripts/review_studio_gates.py new file mode 100644 index 0000000..cdd6279 --- /dev/null +++ b/scripts/review_studio_gates.py @@ -0,0 +1,512 @@ +#!/usr/bin/env python3 +"""Gate evaluation contract for Review Studio 2.0.""" + +import json +import os +from pathlib import Path +from typing import Any + +try: + from trust_check import permission_governance_status as compute_permission_governance_status + from trust_check import script_inventory as trust_script_inventory +except ImportError: # pragma: no cover + compute_permission_governance_status = None + trust_script_inventory = None + + +SCRIPT_INTERFACE = "internal-module" +SCRIPT_INTERFACE_REASON = "Imported by render_review_studio.py to keep Review Studio gate evaluation separate from HTML rendering." + + +ROOT = Path(__file__).resolve().parent.parent + + +def _load_json(path: Path) -> dict[str, Any]: + if not path.exists(): + return {} + try: + payload = json.loads(path.read_text(encoding="utf-8")) + except json.JSONDecodeError: + return {} + return payload if isinstance(payload, dict) else {} + + +def _link_from(output_html: Path, target: Path) -> str: + return os.path.relpath(target.resolve(), output_html.parent.resolve()) + + +def _report_link(output_html: Path, skill_dir: Path, rel_path: str) -> str: + return _link_from(output_html, skill_dir / rel_path) + + +def gate(key: str, label: str, status: str, detail: str, evidence: str, link: str = "") -> dict[str, str]: + return { + "key": key, + "label": label, + "status": status, + "detail": detail, + "evidence": evidence, + "link": link, + } + + +def status_label(status: str) -> str: + return {"pass": "通过", "warn": "关注", "block": "阻断"}.get(status, status) + + +def add_blockers_from_gate(gates: list[dict[str, str]]) -> tuple[list[dict[str, str]], list[dict[str, str]]]: + blockers = [item for item in gates if item["status"] == "block"] + warnings = [item for item in gates if item["status"] == "warn"] + return blockers, warnings + + +def target_maturity(skill_dir: Path, overview: dict[str, Any]) -> str: + manifest = _load_json(skill_dir / "manifest.json") + if manifest.get("maturity_tier"): + return str(manifest["maturity_tier"]) + metadata = overview.get("metadata", {}) if isinstance(overview, dict) else {} + if metadata.get("maturity_tier"): + return str(metadata["maturity_tier"]) + return "scaffold" + + +def min_output_cases(maturity: str) -> int: + if maturity in {"library", "governed"}: + return 5 + if maturity == "production": + return 3 + return 1 + + +def fallback_permission_governance(skill_dir: Path) -> dict[str, Any]: + if compute_permission_governance_status is None or trust_script_inventory is None: + return {} + try: + scripts = trust_script_inventory(skill_dir) + return compute_permission_governance_status(skill_dir, scripts) + except Exception: + return {} + + +def build_gates(skill_dir: Path, output_html: Path, data: dict[str, dict[str, Any]]) -> list[dict[str, str]]: + overview = data["overview"] + maturity = target_maturity(skill_dir, overview) + gates: list[dict[str, str]] = [] + + intent = data["intent_confidence"] + intent_score = int(intent.get("score", 0) or 0) + intent_status = "pass" if intent.get("gate_passed") or intent_score >= 75 else "warn" + gates.append( + gate( + "intent-canvas", + "意图画布", + intent_status, + f"intent confidence {intent_score}/100; {intent.get('recommended_action', 'review current intent frame')}", + "reports/intent-confidence.json", + _report_link(output_html, skill_dir, "reports/intent-confidence.md"), + ) + ) + + route = data["route_scorecard"] + route_summary = route.get("summary", {}) + misroutes = int(route_summary.get("misroute_count", len(route.get("misroutes", []))) or 0) + ambiguous = int(route_summary.get("ambiguous_case_count", len(route.get("ambiguous_cases", []))) or 0) + if not route: + route_status = "warn" + route_detail = "route scorecard is missing; run route-scorecard before release review" + else: + route_status = "block" if misroutes else ("warn" if ambiguous else "pass") + route_detail = f"{route_summary.get('total_cases', 0)} trigger cases; {misroutes} misroutes; {ambiguous} ambiguous" + gates.append( + gate( + "trigger-lab", + "触发实验", + route_status, + route_detail, + "reports/route_scorecard.json", + _report_link(output_html, skill_dir, "reports/route_scorecard.md"), + ) + ) + + output = data["output_quality"] + output_execution = data["output_execution"] + output_blind = data["output_blind_review"] + output_review = data["output_review_adjudication"] + output_summary = output.get("summary", {}) + output_execution_summary = output_execution.get("summary", {}) + output_blind_summary = output_blind.get("summary", {}) + output_review_summary = output_review.get("summary", {}) + required_cases = min_output_cases(maturity) + case_count = int(output_summary.get("case_count", 0) or 0) + file_backed = int(output_summary.get("file_backed_case_count", 0) or 0) + near_neighbor = int(output_summary.get("near_neighbor_case_count", 0) or 0) + boundary = int(output_summary.get("boundary_case_count", 0) or 0) + blind_pair_count = int(output_blind_summary.get("pair_count", 0) or 0) + execution_variant_count = int(output_execution_summary.get("variant_run_count", 0) or 0) + execution_command_count = int(output_execution_summary.get("command_executed_count", 0) or 0) + execution_model_count = int(output_execution_summary.get("model_executed_count", 0) or 0) + execution_recorded_count = int(output_execution_summary.get("recorded_fixture_count", 0) or 0) + review_pair_count = int(output_review_summary.get("pair_count", 0) or 0) + review_judgment_count = int(output_review_summary.get("judgment_count", 0) or 0) + review_invalid_count = int(output_review_summary.get("invalid_decision_count", 0) or 0) + blind_missing = maturity in {"production", "library", "governed"} and (not output_blind or blind_pair_count < case_count) + execution_failed = bool(output_execution) and (not output_execution.get("ok", True) or int(output_execution_summary.get("failure_count", 0) or 0) > 0) + review_invalid = bool(output_review) and (not output_review.get("ok", True) or review_invalid_count > 0) + output_blocked = ( + not output.get("ok", False) + or not output_summary.get("gate_pass", False) + or case_count < required_cases + or execution_failed + or review_invalid + ) + output_warn = file_backed == 0 or near_neighbor == 0 or boundary == 0 or blind_missing + if not output: + output_status = "warn" + output_detail = "output eval scorecard is missing; generate it before production review" + else: + output_status = "block" if output_blocked else ("warn" if output_warn else "pass") + output_detail = ( + f"{case_count}/{required_cases} cases; with-skill {output_summary.get('with_skill_pass_rate', 0)}; " + f"baseline {output_summary.get('baseline_pass_rate', 0)}; file-backed {file_backed}; near-neighbor {near_neighbor}; " + f"blind A/B {blind_pair_count}" + + ( + f"; exec {execution_variant_count}; command {execution_command_count}; " + f"model {execution_model_count}; recorded {execution_recorded_count}" + if output_execution + else "" + ) + + (f"; reviewed {review_judgment_count}/{review_pair_count}" if output_review else "") + ) + gates.append( + gate( + "output-lab", + "输出实验", + output_status, + output_detail, + "reports/output_quality_scorecard.json", + _report_link(output_html, skill_dir, "reports/output_quality_scorecard.md"), + ) + ) + + context = data["context_budget"] + context_stats = context.get("stats", {}) + context_status = "pass" if context.get("ok") else "block" + if context.get("warnings"): + context_status = "warn" if context_status == "pass" else context_status + if not context: + context_status = "warn" + context_detail = ( + f"initial load {context_stats.get('estimated_initial_load_tokens', 'n/a')}/" + f"{context_stats.get('context_budget_limit', 'n/a')}; quality density {context_stats.get('quality_density', 'n/a')}" + ) + gates.append( + gate( + "context-budget", + "上下文", + context_status, + context_detail, + "reports/context_budget.json", + _report_link(output_html, skill_dir, "reports/context_budget.md"), + ) + ) + + conformance = data["conformance"] + conformance_summary = conformance.get("summary", {}) + fail_count = int(conformance_summary.get("fail_count", 0) or 0) + if not conformance: + conformance_status = "warn" + conformance_detail = "runtime conformance matrix is missing" + else: + conformance_status = "block" if fail_count else "pass" + conformance_detail = f"{conformance_summary.get('pass_count', 0)} / {conformance_summary.get('target_count', 0)} targets pass" + gates.append( + gate( + "runtime-matrix", + "运行矩阵", + conformance_status, + conformance_detail, + "reports/conformance_matrix.json", + _report_link(output_html, skill_dir, "reports/conformance_matrix.md"), + ) + ) + + trust = data["trust"] + trust_summary = trust.get("summary", {}) + if not trust: + trust_status = "warn" + trust_detail = "security trust report is missing" + else: + trust_status = "block" if trust.get("failures") else ("warn" if trust.get("warnings") else "pass") + trust_detail = ( + f"{trust_summary.get('secret_findings', 0)} secrets; " + f"{trust_summary.get('script_count', 0)} scripts; " + f"{trust_summary.get('network_script_count', 0)} network-capable scripts; " + f"{trust_summary.get('help_smoke_failed_count', 0)} help smoke failures" + ) + gates.append( + gate( + "trust-report", + "信任报告", + trust_status, + trust_detail, + "reports/security_trust_report.json", + _report_link(output_html, skill_dir, "reports/security_trust_report.md"), + ) + ) + + permission_governance = trust.get("permission_governance", {}) if isinstance(trust.get("permission_governance", {}), dict) else {} + if trust and not permission_governance: + permission_governance = fallback_permission_governance(skill_dir) + if not trust: + permission_status = "warn" + permission_detail = "permission governance evidence is missing because trust report is missing" + elif not permission_governance: + permission_status = "warn" + permission_detail = "permission governance evidence is missing from trust report" + else: + required = int(permission_governance.get("required_count", 0) or 0) + approved = int(permission_governance.get("approval_count", 0) or 0) + gaps = ( + int(permission_governance.get("missing_count", 0) or 0) + + int(permission_governance.get("invalid_count", 0) or 0) + + int(permission_governance.get("expired_count", 0) or 0) + ) + if gaps: + permission_status = "block" if maturity == "governed" else "warn" + else: + permission_status = "pass" + required_names = ", ".join(permission_governance.get("required_capabilities", []) or []) or "none" + permission_detail = f"{approved}/{required} permissions approved; gaps {gaps}; required {required_names}" + gates.append( + gate( + "permission-gates", + "权限批准", + permission_status, + permission_detail, + "reports/security_trust_report.json + security/permission_policy.json", + _report_link(output_html, skill_dir, "security/permission_policy.md"), + ) + ) + + runtime_permissions = data["runtime_permissions"] + runtime_permissions_summary = runtime_permissions.get("summary", {}) + if not runtime_permissions: + runtime_permission_status = "block" if maturity == "governed" else "warn" + runtime_permission_detail = "runtime permission probe report is missing" + elif runtime_permissions.get("failures"): + runtime_permission_status = "block" + runtime_permission_detail = f"{runtime_permissions_summary.get('failure_count', len(runtime_permissions.get('failures', [])))} runtime permission probe failures" + else: + runtime_permission_status = "pass" + runtime_permission_detail = ( + f"{runtime_permissions_summary.get('pass_count', 0)}/{runtime_permissions_summary.get('target_count', 0)} targets probed; " + f"native {runtime_permissions_summary.get('native_enforcement_count', 0)}; " + f"metadata fallback {runtime_permissions_summary.get('metadata_fallback_count', 0)}; " + f"residual risks {runtime_permissions_summary.get('residual_risk_count', 0)}" + ) + gates.append( + gate( + "permission-runtime", + "权限探针", + runtime_permission_status, + runtime_permission_detail, + "reports/runtime_permission_probes.json", + _report_link(output_html, skill_dir, "reports/runtime_permission_probes.md"), + ) + ) + + atlas = data["atlas"] + atlas_summary = atlas.get("summary", {}) + actionable_route_collisions = int( + atlas_summary.get("actionable_route_collision_count", atlas_summary.get("route_collision_count", 0)) or 0 + ) + actionable_owner_gaps = int(atlas_summary.get("actionable_owner_gap_count", atlas_summary.get("owner_gap_count", 0)) or 0) + actionable_stale = int(atlas_summary.get("actionable_stale_count", atlas_summary.get("stale_count", 0)) or 0) + atlas_issues = actionable_route_collisions + actionable_owner_gaps + actionable_stale + if not atlas: + atlas_status = "warn" + atlas_detail = "skill atlas is missing; portfolio-level conflicts are unknown" + else: + atlas_status = "warn" if atlas_issues else "pass" + atlas_detail = ( + f"{atlas_summary.get('skill_count', 0)} skills, " + f"{atlas_summary.get('actionable_skill_count', atlas_summary.get('skill_count', 0))} actionable; " + f"{actionable_route_collisions} actionable route collisions; " + f"{actionable_owner_gaps} actionable owner gaps; " + f"{actionable_stale} actionable stale; " + f"{atlas_summary.get('non_actionable_issue_count', 0)} scoped non-actionable issues" + ) + gates.append( + gate( + "skill-atlas", + "组合治理", + atlas_status, + atlas_detail, + "reports/skill_atlas.json", + _report_link(output_html, skill_dir, "reports/skill_atlas.html"), + ) + ) + + adoption = data["adoption_drift"] + adoption_summary = adoption.get("summary", {}) + if not adoption: + adoption_status = "warn" + adoption_detail = "adoption drift report is missing; real usage impact is unknown" + elif adoption.get("failures"): + adoption_status = "block" + adoption_detail = f"telemetry privacy or schema failures: {len(adoption.get('failures', []))}" + else: + risk_band = adoption_summary.get("risk_band", "no-data") + adoption_status = "warn" if risk_band in {"no-data", "medium", "high"} else "pass" + adoption_detail = ( + f"{adoption_summary.get('event_count', 0)} metadata events; " + f"adoption {adoption_summary.get('adoption_rate', 0)}; " + f"missed {adoption_summary.get('missed_trigger_count', 0)}; " + f"bad-output {adoption_summary.get('bad_output_count', 0)}; " + f"risk {risk_band}" + ) + gates.append( + gate( + "operations-loop", + "运营回路", + adoption_status, + adoption_detail, + "reports/adoption_drift_report.json", + _report_link(output_html, skill_dir, "reports/adoption_drift_report.md"), + ) + ) + + waiver = data["review_waivers"] + waiver_summary = waiver.get("summary", {}) + active_covered = set(waiver_summary.get("covered_gate_keys", []) or []) + prior_blockers = [item for item in gates if item["status"] == "block"] + prior_warnings = [item for item in gates if item["status"] == "warn"] + unwaived_warnings = [item for item in prior_warnings if item["key"] not in active_covered] + if not waiver: + waiver_status = "warn" + waiver_detail = "review waiver ledger is missing; warning acceptance is not auditable" + elif waiver.get("failures"): + waiver_status = "block" + waiver_detail = f"{len(waiver.get('failures', []))} invalid waiver records" + elif prior_blockers: + waiver_status = "block" + waiver_detail = f"{len(prior_blockers)} blocker gates cannot be waived in v0" + elif unwaived_warnings: + waiver_status = "warn" + waiver_detail = ( + f"{waiver_summary.get('active_count', 0)} active waivers; " + f"{len(unwaived_warnings)} warning gates still need reviewer decision" + ) + else: + waiver_status = "pass" + waiver_detail = f"{waiver_summary.get('active_count', 0)} active waivers cover current warnings" + gates.append( + gate( + "review-waivers", + "人工批准", + waiver_status, + waiver_detail, + "reports/review_waivers.json", + _report_link(output_html, skill_dir, "reports/review_waivers.md"), + ) + ) + + registry = data["registry"] + install = data["install_simulation"] + if not registry: + if maturity in {"library", "governed"}: + registry_status = "warn" + registry_detail = "registry audit is missing; package metadata is not reviewable" + else: + registry_status = "pass" + registry_detail = "registry audit is optional until team distribution is required" + else: + compatibility = registry.get("package", {}).get("compatibility", {}) + pass_count = sum(1 for status in compatibility.values() if status == "pass") + registry_status = "block" if registry.get("failures") else ("warn" if registry.get("warnings") else "pass") + registry_detail = ( + f"{registry.get('package', {}).get('name', 'package')} " + f"{registry.get('package', {}).get('version', 'n/a')}; " + f"{pass_count}/{len(compatibility)} compatibility entries pass" + ) + if install: + if install.get("failures"): + registry_status = "block" + install_summary = install.get("summary", {}) + registry_detail += ( + f"; install {'pass' if install.get('ok') else 'fail'}" + f" with {install_summary.get('adapter_count', 0)} adapters" + ) + gates.append( + gate( + "registry-audit", + "注册审计", + registry_status, + registry_detail, + "reports/registry_audit.json + reports/install_simulation.json", + _report_link(output_html, skill_dir, "reports/registry_audit.md"), + ) + ) + + promotion = data["promotion"] + migration_path = ROOT / "docs" / "migration-v2.md" + if promotion: + promotion_summary = promotion.get("summary", {}) + blocked = int(promotion_summary.get("blocked", 0) or 0) + release_status = "block" if blocked else "pass" + release_detail = f"{promotion_summary.get('promote', 0)} promote; {promotion_summary.get('keep_current', 0)} keep current; {blocked} blocked" + else: + release_status = "warn" + release_detail = "promotion decisions are missing; release notes need reviewer confirmation" + upgrade = data["upgrade_check"] + if upgrade: + upgrade_summary = upgrade.get("summary", {}) + if upgrade.get("failures"): + release_status = "block" + elif upgrade.get("warnings") and release_status == "pass": + release_status = "warn" + release_detail += ( + f"; upgrade {upgrade_summary.get('declared_bump', 'n/a')}" + f" declared / {upgrade_summary.get('recommended_bump', 'n/a')} recommended" + ) + gates.append( + gate( + "release-notes", + "发布路线", + release_status, + release_detail, + "reports/promotion_decisions.json + reports/upgrade_check.json + docs/migration-v2.md", + _report_link(output_html, skill_dir, "reports/promotion_decisions.md") if promotion else str(migration_path), + ) + ) + + return gates + + +def weighted_score(gates: list[dict[str, str]]) -> int: + weights = { + "trigger-lab": 15, + "output-lab": 20, + "context-budget": 10, + "runtime-matrix": 10, + "trust-report": 10, + "permission-gates": 10, + "permission-runtime": 10, + "skill-atlas": 10, + "operations-loop": 10, + "review-waivers": 10, + "registry-audit": 10, + "release-notes": 10, + "intent-canvas": 10, + } + earned = 0.0 + total = 0.0 + for item in gates: + weight = weights.get(item["key"], 5) + total += weight + if item["status"] == "pass": + earned += weight + elif item["status"] == "warn": + earned += weight * 0.6 + return int(round(earned / total * 100)) if total else 0 + diff --git a/scripts/yao.py b/scripts/yao.py index 013ed5a..ed903a9 100644 --- a/scripts/yao.py +++ b/scripts/yao.py @@ -21,11 +21,13 @@ from yao_cli_config import ( resolve_promotion_target, resolve_target, ) +from yao_cli_parser import build_parser as build_cli_parser ROOT = Path(__file__).resolve().parent.parent SCRIPTS = ROOT / "scripts" + def script_path(name: str) -> str: return str(SCRIPTS / name) @@ -1157,499 +1159,7 @@ def command_check_update(args: argparse.Namespace) -> int: def build_parser() -> argparse.ArgumentParser: - parser = argparse.ArgumentParser(description="Unified authoring CLI for yao-meta-skill.") - subparsers = parser.add_subparsers(dest="command", required=True) - - init_cmd = subparsers.add_parser("init", help="Initialize a minimal skill package.") - init_cmd.add_argument("name") - init_cmd.add_argument("--description", default="Describe what the skill does and when to use it.") - init_cmd.add_argument("--title") - init_cmd.add_argument("--output-dir", default=".") - init_cmd.add_argument("--mode", choices=["scaffold", "production", "library", "governed"], default="scaffold") - init_cmd.add_argument("--archetype", choices=["scaffold", "production", "library", "governed"], default="scaffold") - init_cmd.add_argument("--external-reference", action="append", default=[]) - init_cmd.add_argument("--user-reference", action="append", default=[]) - init_cmd.add_argument("--local-constraint", action="append", default=[]) - init_cmd.add_argument("--github-query") - init_cmd.add_argument("--github-top-n", type=int, default=3) - init_cmd.add_argument("--github-fixture-dir") - init_cmd.add_argument("--intent-job") - init_cmd.add_argument("--intent-real-input", action="append", default=[]) - init_cmd.add_argument("--intent-primary-output") - init_cmd.add_argument("--intent-exclusion", action="append", default=[]) - init_cmd.add_argument("--intent-constraint", action="append", default=[]) - init_cmd.add_argument("--intent-standard", action="append", default=[]) - init_cmd.add_argument("--intent-correction") - init_cmd.set_defaults(func=command_init) - - quickstart_cmd = subparsers.add_parser( - "quickstart", - help="Interactive fast path for creating a scaffold-first skill package.", - ) - quickstart_cmd.add_argument("--name") - quickstart_cmd.add_argument("--job") - quickstart_cmd.add_argument("--real-input", action="append", default=[]) - quickstart_cmd.add_argument("--primary-output") - quickstart_cmd.add_argument("--description") - quickstart_cmd.add_argument("--title") - quickstart_cmd.add_argument("--output-dir", default=".") - quickstart_cmd.add_argument("--mode", choices=["scaffold", "production", "library", "governed"]) - quickstart_cmd.add_argument("--archetype", choices=["scaffold", "production", "library", "governed"]) - quickstart_cmd.add_argument("--external-reference", action="append", default=[]) - quickstart_cmd.add_argument("--user-reference", action="append", default=[]) - quickstart_cmd.add_argument("--local-constraint", action="append", default=[]) - quickstart_cmd.add_argument("--constraint", action="append", default=[]) - quickstart_cmd.add_argument("--github-query") - quickstart_cmd.add_argument("--github-top-n", type=int, default=3) - quickstart_cmd.add_argument("--github-fixture-dir") - quickstart_cmd.add_argument("--no-update-check", action="store_true") - quickstart_cmd.set_defaults(func=command_quickstart) - - validate_cmd = subparsers.add_parser("validate", help="Run validate, lint, governance, and resource checks.") - validate_cmd.add_argument("skill_dir", nargs="?", default=".") - validate_cmd.add_argument("--require-manifest", action="store_true") - validate_cmd.set_defaults(func=command_validate) - - optimize_cmd = subparsers.add_parser("optimize-description", help="Optimize description candidates for a target.") - optimize_cmd.add_argument( - "--target", - choices=["root", "team-frontend-review", "governed-incident-command", "all"], - default="root", - ) - optimize_cmd.add_argument("--write", action="store_true", help="Write default report artifacts for the target.") - optimize_cmd.set_defaults(func=command_optimize_description) - - promote_cmd = subparsers.add_parser("promote-check", help="Apply promotion policy and build iteration bundles.") - promote_cmd.set_defaults(func=command_promote_check) - - review_cmd = subparsers.add_parser("review", help="Locate the current bundle and human review stub for a target.") - review_cmd.add_argument( - "--target", - choices=["root", "team-frontend-review", "governed-incident-command"], - default="root", - ) - review_cmd.set_defaults(func=command_review) - - snapshot_cmd = subparsers.add_parser("release-snapshot", help="Create a versioned snapshot from current promotion outputs.") - snapshot_cmd.add_argument( - "--target", - choices=["root", "team-frontend-review", "governed-incident-command"], - default="root", - ) - snapshot_cmd.add_argument("--label", default="manual") - snapshot_cmd.set_defaults(func=command_release_snapshot) - - flow_cmd = subparsers.add_parser( - "workspace-flow", - help="Run optimize, promotion, review refresh, and release snapshots as one authoring flow.", - ) - flow_cmd.add_argument( - "--target", - choices=["root", "team-frontend-review", "governed-incident-command", "all"], - default="root", - ) - flow_cmd.add_argument("--label", default="manual") - flow_cmd.set_defaults(func=command_workspace_flow) - - report_cmd = subparsers.add_parser("report", help="Render route, iteration, regression, and context reports.") - report_cmd.add_argument("--refresh-optimization", action="store_true") - report_cmd.set_defaults(func=command_report) - - skill_report_cmd = subparsers.add_parser("skill-report", help="Render the HTML skill report for a skill package.") - skill_report_cmd.add_argument("skill_dir", nargs="?", default=".") - skill_report_cmd.add_argument("--output-html") - skill_report_cmd.add_argument("--output-json") - skill_report_cmd.set_defaults(func=command_skill_report) - - review_viewer_cmd = subparsers.add_parser("review-viewer", help="Render a compact HTML review page for a skill package.") - review_viewer_cmd.add_argument("skill_dir", nargs="?", default=".") - review_viewer_cmd.add_argument("--output-html") - review_viewer_cmd.add_argument("--output-json") - review_viewer_cmd.set_defaults(func=command_review_viewer) - - review_studio_cmd = subparsers.add_parser("review-studio", help="Render Review Studio 2.0 for a skill package.") - review_studio_cmd.add_argument("skill_dir", nargs="?", default=".") - review_studio_cmd.add_argument("--output-html") - review_studio_cmd.add_argument("--output-json") - review_studio_cmd.set_defaults(func=command_review_studio) - - reference_scan_cmd = subparsers.add_parser( - "reference-scan", - help="Render a controlled benchmark scan report for a skill package.", - ) - reference_scan_cmd.add_argument("skill_dir", nargs="?", default=".") - reference_scan_cmd.add_argument("--reference", action="append", default=[]) - reference_scan_cmd.add_argument("--external-reference", action="append", default=[]) - reference_scan_cmd.add_argument("--user-reference", action="append", default=[]) - reference_scan_cmd.add_argument("--local-constraint", action="append", default=[]) - reference_scan_cmd.add_argument("--output-md") - reference_scan_cmd.add_argument("--output-json") - reference_scan_cmd.set_defaults(func=command_reference_scan) - - github_scan_cmd = subparsers.add_parser( - "github-benchmark-scan", - help="Search top public GitHub repositories and extract borrow or avoid patterns for a skill.", - ) - github_scan_cmd.add_argument("skill_dir", nargs="?", default=".") - github_scan_cmd.add_argument("--query", required=True) - github_scan_cmd.add_argument("--top-n", type=int, default=3) - github_scan_cmd.add_argument("--fixture-dir") - github_scan_cmd.add_argument("--output-md") - github_scan_cmd.add_argument("--output-json") - github_scan_cmd.set_defaults(func=command_github_benchmark_scan) - - intent_confidence_cmd = subparsers.add_parser( - "intent-confidence", - help="Render a confidence report for how well the real job, inputs, outputs, and exclusions are understood.", - ) - intent_confidence_cmd.add_argument("skill_dir", nargs="?", default=".") - intent_confidence_cmd.add_argument("--context-json") - intent_confidence_cmd.add_argument("--output-md") - intent_confidence_cmd.add_argument("--output-json") - intent_confidence_cmd.set_defaults(func=command_intent_confidence) - - intent_dialogue_cmd = subparsers.add_parser( - "intent-dialogue", - help="Render a front-loaded intent dialogue guide for a skill package.", - ) - intent_dialogue_cmd.add_argument("skill_dir", nargs="?", default=".") - intent_dialogue_cmd.add_argument("--output-md") - intent_dialogue_cmd.add_argument("--output-json") - intent_dialogue_cmd.set_defaults(func=command_intent_dialogue) - - reference_synthesis_cmd = subparsers.add_parser( - "reference-synthesis", - help="Render a multi-source reference synthesis report for a skill package.", - ) - reference_synthesis_cmd.add_argument("skill_dir", nargs="?", default=".") - reference_synthesis_cmd.add_argument("--output-md") - reference_synthesis_cmd.add_argument("--output-json") - reference_synthesis_cmd.set_defaults(func=command_reference_synthesis) - - output_risk_cmd = subparsers.add_parser( - "output-risk-profile", - help="Render predicted output failure modes and self-repair checks for a skill package.", - ) - output_risk_cmd.add_argument("skill_dir", nargs="?", default=".") - output_risk_cmd.add_argument("--output-md") - output_risk_cmd.add_argument("--output-json") - output_risk_cmd.set_defaults(func=command_output_risk_profile) - - artifact_design_cmd = subparsers.add_parser( - "artifact-design-profile", - help="Render artifact design direction and visual quality gates for a skill package.", - ) - artifact_design_cmd.add_argument("skill_dir", nargs="?", default=".") - artifact_design_cmd.add_argument("--output-md") - artifact_design_cmd.add_argument("--output-json") - artifact_design_cmd.set_defaults(func=command_artifact_design_profile) - - prompt_quality_cmd = subparsers.add_parser( - "prompt-quality-profile", - help="Render prompt-facing need model, RTF mapping, complexity, and quality checks for a skill package.", - ) - prompt_quality_cmd.add_argument("skill_dir", nargs="?", default=".") - prompt_quality_cmd.add_argument("--output-md") - prompt_quality_cmd.add_argument("--output-json") - prompt_quality_cmd.set_defaults(func=command_prompt_quality_profile) - - system_model_cmd = subparsers.add_parser( - "system-model", - help="Render a systems-thinking model for boundaries, feedback loops, drift, and leverage points.", - ) - system_model_cmd.add_argument("skill_dir", nargs="?", default=".") - system_model_cmd.add_argument("--output-md") - system_model_cmd.add_argument("--output-json") - system_model_cmd.set_defaults(func=command_system_model) - - iteration_directions_cmd = subparsers.add_parser( - "iteration-directions", - help="Render the top three next iteration directions for a skill package.", - ) - iteration_directions_cmd.add_argument("skill_dir", nargs="?", default=".") - iteration_directions_cmd.add_argument("--output-md") - iteration_directions_cmd.add_argument("--output-json") - iteration_directions_cmd.set_defaults(func=command_iteration_directions) - - feedback_cmd = subparsers.add_parser( - "feedback", - help="Capture lightweight reviewer feedback without running the full promotion flow.", - ) - feedback_cmd.add_argument("skill_dir", nargs="?", default=".") - feedback_cmd.add_argument("--note") - feedback_cmd.add_argument("--rating", type=int, default=3) - feedback_cmd.add_argument("--category", default="general") - feedback_cmd.add_argument("--recommended-action", default="review") - feedback_cmd.set_defaults(func=command_feedback) - - adoption_drift_cmd = subparsers.add_parser( - "adoption-drift", - help="Render local-first metadata-only adoption and drift telemetry for a skill package.", - ) - adoption_drift_cmd.add_argument("skill_dir", nargs="?", default=".") - adoption_drift_cmd.add_argument("--events-jsonl") - adoption_drift_cmd.add_argument("--output-json") - adoption_drift_cmd.add_argument("--output-md") - adoption_drift_cmd.add_argument("--generated-at") - adoption_drift_cmd.add_argument( - "--record-event", - choices=["review_event", "script_run", "skill_activation", "skill_output"], - ) - adoption_drift_cmd.add_argument( - "--activation-type", - choices=["explicit", "implicit", "manual", "unknown"], - default="unknown", - ) - adoption_drift_cmd.add_argument( - "--outcome", - choices=["accepted", "edited", "failed", "missed", "rejected", "reviewed", "unknown"], - default="unknown", - ) - adoption_drift_cmd.add_argument( - "--failure-type", - choices=[ - "bad_output", - "missing_resource", - "none", - "review_overdue", - "script_error", - "under_trigger", - "wrong_trigger", - ], - default="none", - ) - adoption_drift_cmd.add_argument("--timestamp") - adoption_drift_cmd.add_argument("--skill-name") - adoption_drift_cmd.add_argument("--version") - adoption_drift_cmd.set_defaults(func=command_adoption_drift) - - review_waivers_cmd = subparsers.add_parser( - "review-waivers", - help="Render or update human reviewer waiver evidence for Review Studio.", - ) - review_waivers_cmd.add_argument("skill_dir", nargs="?", default=".") - review_waivers_cmd.add_argument("--waivers-json") - review_waivers_cmd.add_argument("--output-json") - review_waivers_cmd.add_argument("--output-md") - review_waivers_cmd.add_argument("--generated-at") - review_waivers_cmd.add_argument("--add-waiver", action="store_true") - review_waivers_cmd.add_argument( - "--gate-key", - choices=[ - "context-budget", - "intent-canvas", - "operations-loop", - "output-lab", - "registry-audit", - "release-notes", - "runtime-matrix", - "skill-atlas", - "trigger-lab", - "trust-report", - "permission-gates", - "permission-runtime", - ], - ) - review_waivers_cmd.add_argument( - "--decision", - choices=["accepted-risk", "false-positive", "temporary-exception"], - default="accepted-risk", - ) - review_waivers_cmd.add_argument("--reviewer") - review_waivers_cmd.add_argument("--reason") - review_waivers_cmd.add_argument("--expires-at") - review_waivers_cmd.add_argument("--created-at") - review_waivers_cmd.add_argument("--evidence") - review_waivers_cmd.add_argument("--scope", default="current-release") - review_waivers_cmd.set_defaults(func=command_review_waivers) - - review_annotations_cmd = subparsers.add_parser( - "review-annotations", - help="Render or update inline reviewer annotations for Review Studio gates and source paths.", - ) - review_annotations_cmd.add_argument("skill_dir", nargs="?", default=".") - review_annotations_cmd.add_argument("--annotations-json") - review_annotations_cmd.add_argument("--output-json") - review_annotations_cmd.add_argument("--output-md") - review_annotations_cmd.add_argument("--write-template", action="store_true") - review_annotations_cmd.add_argument("--add-annotation", action="store_true") - review_annotations_cmd.add_argument("--annotation-id") - review_annotations_cmd.add_argument( - "--gate-key", - choices=[ - "context-budget", - "intent-canvas", - "operations-loop", - "output-lab", - "registry-audit", - "release-notes", - "review-waivers", - "runtime-matrix", - "skill-atlas", - "trigger-lab", - "trust-report", - "permission-gates", - "permission-runtime", - ], - ) - review_annotations_cmd.add_argument("--target-path") - review_annotations_cmd.add_argument("--line", type=int) - review_annotations_cmd.add_argument("--severity", choices=["blocker", "info", "note", "warning"], default="note") - review_annotations_cmd.add_argument("--status", choices=["deferred", "open", "resolved"], default="open") - review_annotations_cmd.add_argument("--reviewer") - review_annotations_cmd.add_argument("--created-at") - review_annotations_cmd.add_argument("--body") - review_annotations_cmd.add_argument("--suggested-action") - review_annotations_cmd.add_argument("--evidence") - review_annotations_cmd.set_defaults(func=command_review_annotations) - - baseline_compare_cmd = subparsers.add_parser( - "baseline-compare", - help="Render a lightweight with-skill vs baseline comparison across tracked targets.", - ) - baseline_compare_cmd.set_defaults(func=command_baseline_compare) - - skill_ir_cmd = subparsers.add_parser("skill-ir", help="Export platform-neutral Skill IR for a skill package.") - skill_ir_cmd.add_argument("skill_dir", nargs="?", default=".") - skill_ir_cmd.add_argument("--output-json") - skill_ir_cmd.add_argument("--validate-only", action="store_true") - skill_ir_cmd.set_defaults(func=command_skill_ir) - - compile_skill_cmd = subparsers.add_parser( - "compile-skill", - help="Compile Skill IR into target-specific semantic contracts.", - ) - compile_skill_cmd.add_argument("skill_dir", nargs="?", default=".") - compile_skill_cmd.add_argument("--target", action="append") - compile_skill_cmd.add_argument("--output-json") - compile_skill_cmd.add_argument("--output-md") - compile_skill_cmd.add_argument("--generated-at") - compile_skill_cmd.set_defaults(func=command_compile_skill) - - output_eval_cmd = subparsers.add_parser("output-eval", help="Run Output Eval Lab assertion grading.") - output_eval_cmd.add_argument("--cases") - output_eval_cmd.add_argument("--output-json") - output_eval_cmd.add_argument("--output-md") - output_eval_cmd.add_argument("--blind-pack-json") - output_eval_cmd.add_argument("--blind-pack-md") - output_eval_cmd.add_argument("--blind-answer-key-json") - output_eval_cmd.set_defaults(func=command_output_eval) - - output_execution_cmd = subparsers.add_parser( - "output-exec", - help="Record output-eval execution evidence, timing, and token usage.", - ) - output_execution_cmd.add_argument("--cases") - output_execution_cmd.add_argument("--output-json") - output_execution_cmd.add_argument("--output-md") - output_execution_cmd.add_argument("--runner-command") - output_execution_cmd.add_argument("--timeout-seconds", type=float) - output_execution_cmd.set_defaults(func=command_output_execution) - - output_review_cmd = subparsers.add_parser( - "output-review", - help="Adjudicate blind A/B output review decisions against the answer key.", - ) - output_review_cmd.add_argument("--blind-pack") - output_review_cmd.add_argument("--answer-key") - output_review_cmd.add_argument("--decisions") - output_review_cmd.add_argument("--output-json") - output_review_cmd.add_argument("--output-md") - output_review_cmd.add_argument("--write-template", action="store_true") - output_review_cmd.set_defaults(func=command_output_review) - - conformance_cmd = subparsers.add_parser("conformance", help="Run runtime conformance checks for Skill OS targets.") - conformance_cmd.add_argument("skill_dir", nargs="?", default=".") - conformance_cmd.add_argument("--target", action="append", choices=["openai", "claude", "agent-skills", "vscode", "generic"]) - conformance_cmd.add_argument("--output-json") - conformance_cmd.add_argument("--output-md") - conformance_cmd.set_defaults(func=command_conformance) - - runtime_permissions_cmd = subparsers.add_parser( - "runtime-permissions", - help="Probe generated target adapters for runtime permission enforcement metadata.", - ) - runtime_permissions_cmd.add_argument("skill_dir", nargs="?", default=".") - runtime_permissions_cmd.add_argument("--package-dir", default="dist") - runtime_permissions_cmd.add_argument("--target", action="append", choices=["openai", "claude", "generic"]) - runtime_permissions_cmd.add_argument("--output-json") - runtime_permissions_cmd.add_argument("--output-md") - runtime_permissions_cmd.set_defaults(func=command_runtime_permissions) - - trust_cmd = subparsers.add_parser("trust", help="Run trust and security checks for a skill package.") - trust_cmd.add_argument("skill_dir", nargs="?", default=".") - trust_cmd.add_argument("--output-json") - trust_cmd.add_argument("--output-md") - trust_cmd.set_defaults(func=command_trust) - - skill_atlas_cmd = subparsers.add_parser("skill-atlas", help="Build a portfolio-level Skill Atlas for a workspace.") - skill_atlas_cmd.add_argument("--workspace-root", default=".") - skill_atlas_cmd.add_argument("--output-dir") - skill_atlas_cmd.add_argument("--report-html") - skill_atlas_cmd.add_argument("--report-json") - skill_atlas_cmd.add_argument("--overlap-threshold", type=float) - skill_atlas_cmd.add_argument("--today") - skill_atlas_cmd.set_defaults(func=command_skill_atlas) - - registry_audit_cmd = subparsers.add_parser("registry-audit", help="Build and audit Skill OS registry package metadata.") - registry_audit_cmd.add_argument("skill_dir", nargs="?", default=".") - registry_audit_cmd.add_argument("--registry-dir") - registry_audit_cmd.add_argument("--output-json") - registry_audit_cmd.add_argument("--output-md") - registry_audit_cmd.add_argument("--generated-at") - registry_audit_cmd.set_defaults(func=command_registry_audit) - - package_cmd = subparsers.add_parser("package", help="Export compatibility artifacts for selected targets.") - package_cmd.add_argument("skill_dir", nargs="?", default=".") - package_cmd.add_argument("--platform", action="append") - package_cmd.add_argument("--output-dir", default="dist") - package_cmd.add_argument("--expectations") - package_cmd.add_argument("--zip", action="store_true") - package_cmd.set_defaults(func=command_package) - - package_verify_cmd = subparsers.add_parser("package-verify", help="Verify generated package artifacts, archive safety, and registry parity.") - package_verify_cmd.add_argument("skill_dir", nargs="?", default=".") - package_verify_cmd.add_argument("--package-dir", default="dist") - package_verify_cmd.add_argument("--expectations", default="evals/packaging_expectations.json") - package_verify_cmd.add_argument("--registry-json", default="reports/registry_audit.json") - package_verify_cmd.add_argument("--output-json") - package_verify_cmd.add_argument("--output-md") - package_verify_cmd.add_argument("--require-zip", action="store_true") - package_verify_cmd.add_argument("--generated-at") - package_verify_cmd.set_defaults(func=command_package_verify) - - install_simulate_cmd = subparsers.add_parser("install-simulate", help="Simulate installing a generated package into a temporary local skill root.") - install_simulate_cmd.add_argument("skill_dir", nargs="?", default=".") - install_simulate_cmd.add_argument("--package-dir", default="dist") - install_simulate_cmd.add_argument("--install-root") - install_simulate_cmd.add_argument("--output-json") - install_simulate_cmd.add_argument("--output-md") - install_simulate_cmd.add_argument("--generated-at") - install_simulate_cmd.set_defaults(func=command_install_simulate) - - upgrade_check_cmd = subparsers.add_parser("upgrade-check", help="Compare current and previous registry package metadata for upgrade readiness.") - upgrade_check_cmd.add_argument("skill_dir", nargs="?", default=".") - upgrade_check_cmd.add_argument("--previous-package-json", required=True) - upgrade_check_cmd.add_argument("--current-package-json", default="reports/registry_audit.json") - upgrade_check_cmd.add_argument("--output-json") - upgrade_check_cmd.add_argument("--output-md") - upgrade_check_cmd.add_argument("--generated-at") - upgrade_check_cmd.set_defaults(func=command_upgrade_check) - - test_cmd = subparsers.add_parser("test", help="Run a Makefile test target.") - test_cmd.add_argument("--target", default="test") - test_cmd.set_defaults(func=command_test) - - update_cmd = subparsers.add_parser("check-update", help="Check whether a newer yao-meta-skill version is available.") - update_cmd.add_argument("--force", action="store_true") - update_cmd.add_argument("--no-cache", action="store_true") - update_cmd.add_argument("--version-url") - update_cmd.add_argument("--manifest-url") - update_cmd.add_argument("--timeout", type=float, default=3.0) - update_cmd.add_argument("--allow-custom-update-url", action="store_true") - update_cmd.set_defaults(func=command_check_update) - - return parser + return build_cli_parser({name: value for name, value in globals().items() if name.startswith("command_")}) def main() -> None: diff --git a/scripts/yao_cli_parser.py b/scripts/yao_cli_parser.py new file mode 100644 index 0000000..2fb993a --- /dev/null +++ b/scripts/yao_cli_parser.py @@ -0,0 +1,513 @@ +#!/usr/bin/env python3 +"""Argparse surface for the Yao CLI.""" + +import argparse +from collections.abc import Callable + + +SCRIPT_INTERFACE = "internal-module" +SCRIPT_INTERFACE_REASON = "Imported by yao.py to keep CLI parser declarations separate from command orchestration." + + +def _handler(command_handlers: dict[str, Callable[[argparse.Namespace], int]], name: str) -> Callable[[argparse.Namespace], int]: + if name not in command_handlers: + raise KeyError(f"Missing CLI command handler: {name}") + return command_handlers[name] + + +def build_parser(command_handlers: dict[str, Callable[[argparse.Namespace], int]]) -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description="Unified authoring CLI for yao-meta-skill.") + subparsers = parser.add_subparsers(dest="command", required=True) + + init_cmd = subparsers.add_parser("init", help="Initialize a minimal skill package.") + init_cmd.add_argument("name") + init_cmd.add_argument("--description", default="Describe what the skill does and when to use it.") + init_cmd.add_argument("--title") + init_cmd.add_argument("--output-dir", default=".") + init_cmd.add_argument("--mode", choices=["scaffold", "production", "library", "governed"], default="scaffold") + init_cmd.add_argument("--archetype", choices=["scaffold", "production", "library", "governed"], default="scaffold") + init_cmd.add_argument("--external-reference", action="append", default=[]) + init_cmd.add_argument("--user-reference", action="append", default=[]) + init_cmd.add_argument("--local-constraint", action="append", default=[]) + init_cmd.add_argument("--github-query") + init_cmd.add_argument("--github-top-n", type=int, default=3) + init_cmd.add_argument("--github-fixture-dir") + init_cmd.add_argument("--intent-job") + init_cmd.add_argument("--intent-real-input", action="append", default=[]) + init_cmd.add_argument("--intent-primary-output") + init_cmd.add_argument("--intent-exclusion", action="append", default=[]) + init_cmd.add_argument("--intent-constraint", action="append", default=[]) + init_cmd.add_argument("--intent-standard", action="append", default=[]) + init_cmd.add_argument("--intent-correction") + init_cmd.set_defaults(func=_handler(command_handlers, "command_init")) + + quickstart_cmd = subparsers.add_parser( + "quickstart", + help="Interactive fast path for creating a scaffold-first skill package.", + ) + quickstart_cmd.add_argument("--name") + quickstart_cmd.add_argument("--job") + quickstart_cmd.add_argument("--real-input", action="append", default=[]) + quickstart_cmd.add_argument("--primary-output") + quickstart_cmd.add_argument("--description") + quickstart_cmd.add_argument("--title") + quickstart_cmd.add_argument("--output-dir", default=".") + quickstart_cmd.add_argument("--mode", choices=["scaffold", "production", "library", "governed"]) + quickstart_cmd.add_argument("--archetype", choices=["scaffold", "production", "library", "governed"]) + quickstart_cmd.add_argument("--external-reference", action="append", default=[]) + quickstart_cmd.add_argument("--user-reference", action="append", default=[]) + quickstart_cmd.add_argument("--local-constraint", action="append", default=[]) + quickstart_cmd.add_argument("--constraint", action="append", default=[]) + quickstart_cmd.add_argument("--github-query") + quickstart_cmd.add_argument("--github-top-n", type=int, default=3) + quickstart_cmd.add_argument("--github-fixture-dir") + quickstart_cmd.add_argument("--no-update-check", action="store_true") + quickstart_cmd.set_defaults(func=_handler(command_handlers, "command_quickstart")) + + validate_cmd = subparsers.add_parser("validate", help="Run validate, lint, governance, and resource checks.") + validate_cmd.add_argument("skill_dir", nargs="?", default=".") + validate_cmd.add_argument("--require-manifest", action="store_true") + validate_cmd.set_defaults(func=_handler(command_handlers, "command_validate")) + + optimize_cmd = subparsers.add_parser("optimize-description", help="Optimize description candidates for a target.") + optimize_cmd.add_argument( + "--target", + choices=["root", "team-frontend-review", "governed-incident-command", "all"], + default="root", + ) + optimize_cmd.add_argument("--write", action="store_true", help="Write default report artifacts for the target.") + optimize_cmd.set_defaults(func=_handler(command_handlers, "command_optimize_description")) + + promote_cmd = subparsers.add_parser("promote-check", help="Apply promotion policy and build iteration bundles.") + promote_cmd.set_defaults(func=_handler(command_handlers, "command_promote_check")) + + review_cmd = subparsers.add_parser("review", help="Locate the current bundle and human review stub for a target.") + review_cmd.add_argument( + "--target", + choices=["root", "team-frontend-review", "governed-incident-command"], + default="root", + ) + review_cmd.set_defaults(func=_handler(command_handlers, "command_review")) + + snapshot_cmd = subparsers.add_parser("release-snapshot", help="Create a versioned snapshot from current promotion outputs.") + snapshot_cmd.add_argument( + "--target", + choices=["root", "team-frontend-review", "governed-incident-command"], + default="root", + ) + snapshot_cmd.add_argument("--label", default="manual") + snapshot_cmd.set_defaults(func=_handler(command_handlers, "command_release_snapshot")) + + flow_cmd = subparsers.add_parser( + "workspace-flow", + help="Run optimize, promotion, review refresh, and release snapshots as one authoring flow.", + ) + flow_cmd.add_argument( + "--target", + choices=["root", "team-frontend-review", "governed-incident-command", "all"], + default="root", + ) + flow_cmd.add_argument("--label", default="manual") + flow_cmd.set_defaults(func=_handler(command_handlers, "command_workspace_flow")) + + report_cmd = subparsers.add_parser("report", help="Render route, iteration, regression, and context reports.") + report_cmd.add_argument("--refresh-optimization", action="store_true") + report_cmd.set_defaults(func=_handler(command_handlers, "command_report")) + + skill_report_cmd = subparsers.add_parser("skill-report", help="Render the HTML skill report for a skill package.") + skill_report_cmd.add_argument("skill_dir", nargs="?", default=".") + skill_report_cmd.add_argument("--output-html") + skill_report_cmd.add_argument("--output-json") + skill_report_cmd.set_defaults(func=_handler(command_handlers, "command_skill_report")) + + review_viewer_cmd = subparsers.add_parser("review-viewer", help="Render a compact HTML review page for a skill package.") + review_viewer_cmd.add_argument("skill_dir", nargs="?", default=".") + review_viewer_cmd.add_argument("--output-html") + review_viewer_cmd.add_argument("--output-json") + review_viewer_cmd.set_defaults(func=_handler(command_handlers, "command_review_viewer")) + + review_studio_cmd = subparsers.add_parser("review-studio", help="Render Review Studio 2.0 for a skill package.") + review_studio_cmd.add_argument("skill_dir", nargs="?", default=".") + review_studio_cmd.add_argument("--output-html") + review_studio_cmd.add_argument("--output-json") + review_studio_cmd.set_defaults(func=_handler(command_handlers, "command_review_studio")) + + reference_scan_cmd = subparsers.add_parser( + "reference-scan", + help="Render a controlled benchmark scan report for a skill package.", + ) + reference_scan_cmd.add_argument("skill_dir", nargs="?", default=".") + reference_scan_cmd.add_argument("--reference", action="append", default=[]) + reference_scan_cmd.add_argument("--external-reference", action="append", default=[]) + reference_scan_cmd.add_argument("--user-reference", action="append", default=[]) + reference_scan_cmd.add_argument("--local-constraint", action="append", default=[]) + reference_scan_cmd.add_argument("--output-md") + reference_scan_cmd.add_argument("--output-json") + reference_scan_cmd.set_defaults(func=_handler(command_handlers, "command_reference_scan")) + + github_scan_cmd = subparsers.add_parser( + "github-benchmark-scan", + help="Search top public GitHub repositories and extract borrow or avoid patterns for a skill.", + ) + github_scan_cmd.add_argument("skill_dir", nargs="?", default=".") + github_scan_cmd.add_argument("--query", required=True) + github_scan_cmd.add_argument("--top-n", type=int, default=3) + github_scan_cmd.add_argument("--fixture-dir") + github_scan_cmd.add_argument("--output-md") + github_scan_cmd.add_argument("--output-json") + github_scan_cmd.set_defaults(func=_handler(command_handlers, "command_github_benchmark_scan")) + + intent_confidence_cmd = subparsers.add_parser( + "intent-confidence", + help="Render a confidence report for how well the real job, inputs, outputs, and exclusions are understood.", + ) + intent_confidence_cmd.add_argument("skill_dir", nargs="?", default=".") + intent_confidence_cmd.add_argument("--context-json") + intent_confidence_cmd.add_argument("--output-md") + intent_confidence_cmd.add_argument("--output-json") + intent_confidence_cmd.set_defaults(func=_handler(command_handlers, "command_intent_confidence")) + + intent_dialogue_cmd = subparsers.add_parser( + "intent-dialogue", + help="Render a front-loaded intent dialogue guide for a skill package.", + ) + intent_dialogue_cmd.add_argument("skill_dir", nargs="?", default=".") + intent_dialogue_cmd.add_argument("--output-md") + intent_dialogue_cmd.add_argument("--output-json") + intent_dialogue_cmd.set_defaults(func=_handler(command_handlers, "command_intent_dialogue")) + + reference_synthesis_cmd = subparsers.add_parser( + "reference-synthesis", + help="Render a multi-source reference synthesis report for a skill package.", + ) + reference_synthesis_cmd.add_argument("skill_dir", nargs="?", default=".") + reference_synthesis_cmd.add_argument("--output-md") + reference_synthesis_cmd.add_argument("--output-json") + reference_synthesis_cmd.set_defaults(func=_handler(command_handlers, "command_reference_synthesis")) + + output_risk_cmd = subparsers.add_parser( + "output-risk-profile", + help="Render predicted output failure modes and self-repair checks for a skill package.", + ) + output_risk_cmd.add_argument("skill_dir", nargs="?", default=".") + output_risk_cmd.add_argument("--output-md") + output_risk_cmd.add_argument("--output-json") + output_risk_cmd.set_defaults(func=_handler(command_handlers, "command_output_risk_profile")) + + artifact_design_cmd = subparsers.add_parser( + "artifact-design-profile", + help="Render artifact design direction and visual quality gates for a skill package.", + ) + artifact_design_cmd.add_argument("skill_dir", nargs="?", default=".") + artifact_design_cmd.add_argument("--output-md") + artifact_design_cmd.add_argument("--output-json") + artifact_design_cmd.set_defaults(func=_handler(command_handlers, "command_artifact_design_profile")) + + prompt_quality_cmd = subparsers.add_parser( + "prompt-quality-profile", + help="Render prompt-facing need model, RTF mapping, complexity, and quality checks for a skill package.", + ) + prompt_quality_cmd.add_argument("skill_dir", nargs="?", default=".") + prompt_quality_cmd.add_argument("--output-md") + prompt_quality_cmd.add_argument("--output-json") + prompt_quality_cmd.set_defaults(func=_handler(command_handlers, "command_prompt_quality_profile")) + + system_model_cmd = subparsers.add_parser( + "system-model", + help="Render a systems-thinking model for boundaries, feedback loops, drift, and leverage points.", + ) + system_model_cmd.add_argument("skill_dir", nargs="?", default=".") + system_model_cmd.add_argument("--output-md") + system_model_cmd.add_argument("--output-json") + system_model_cmd.set_defaults(func=_handler(command_handlers, "command_system_model")) + + iteration_directions_cmd = subparsers.add_parser( + "iteration-directions", + help="Render the top three next iteration directions for a skill package.", + ) + iteration_directions_cmd.add_argument("skill_dir", nargs="?", default=".") + iteration_directions_cmd.add_argument("--output-md") + iteration_directions_cmd.add_argument("--output-json") + iteration_directions_cmd.set_defaults(func=_handler(command_handlers, "command_iteration_directions")) + + feedback_cmd = subparsers.add_parser( + "feedback", + help="Capture lightweight reviewer feedback without running the full promotion flow.", + ) + feedback_cmd.add_argument("skill_dir", nargs="?", default=".") + feedback_cmd.add_argument("--note") + feedback_cmd.add_argument("--rating", type=int, default=3) + feedback_cmd.add_argument("--category", default="general") + feedback_cmd.add_argument("--recommended-action", default="review") + feedback_cmd.set_defaults(func=_handler(command_handlers, "command_feedback")) + + adoption_drift_cmd = subparsers.add_parser( + "adoption-drift", + help="Render local-first metadata-only adoption and drift telemetry for a skill package.", + ) + adoption_drift_cmd.add_argument("skill_dir", nargs="?", default=".") + adoption_drift_cmd.add_argument("--events-jsonl") + adoption_drift_cmd.add_argument("--output-json") + adoption_drift_cmd.add_argument("--output-md") + adoption_drift_cmd.add_argument("--generated-at") + adoption_drift_cmd.add_argument( + "--record-event", + choices=["review_event", "script_run", "skill_activation", "skill_output"], + ) + adoption_drift_cmd.add_argument( + "--activation-type", + choices=["explicit", "implicit", "manual", "unknown"], + default="unknown", + ) + adoption_drift_cmd.add_argument( + "--outcome", + choices=["accepted", "edited", "failed", "missed", "rejected", "reviewed", "unknown"], + default="unknown", + ) + adoption_drift_cmd.add_argument( + "--failure-type", + choices=[ + "bad_output", + "missing_resource", + "none", + "review_overdue", + "script_error", + "under_trigger", + "wrong_trigger", + ], + default="none", + ) + adoption_drift_cmd.add_argument("--timestamp") + adoption_drift_cmd.add_argument("--skill-name") + adoption_drift_cmd.add_argument("--version") + adoption_drift_cmd.set_defaults(func=_handler(command_handlers, "command_adoption_drift")) + + review_waivers_cmd = subparsers.add_parser( + "review-waivers", + help="Render or update human reviewer waiver evidence for Review Studio.", + ) + review_waivers_cmd.add_argument("skill_dir", nargs="?", default=".") + review_waivers_cmd.add_argument("--waivers-json") + review_waivers_cmd.add_argument("--output-json") + review_waivers_cmd.add_argument("--output-md") + review_waivers_cmd.add_argument("--generated-at") + review_waivers_cmd.add_argument("--add-waiver", action="store_true") + review_waivers_cmd.add_argument( + "--gate-key", + choices=[ + "context-budget", + "intent-canvas", + "operations-loop", + "output-lab", + "registry-audit", + "release-notes", + "runtime-matrix", + "skill-atlas", + "trigger-lab", + "trust-report", + "permission-gates", + "permission-runtime", + ], + ) + review_waivers_cmd.add_argument( + "--decision", + choices=["accepted-risk", "false-positive", "temporary-exception"], + default="accepted-risk", + ) + review_waivers_cmd.add_argument("--reviewer") + review_waivers_cmd.add_argument("--reason") + review_waivers_cmd.add_argument("--expires-at") + review_waivers_cmd.add_argument("--created-at") + review_waivers_cmd.add_argument("--evidence") + review_waivers_cmd.add_argument("--scope", default="current-release") + review_waivers_cmd.set_defaults(func=_handler(command_handlers, "command_review_waivers")) + + review_annotations_cmd = subparsers.add_parser( + "review-annotations", + help="Render or update inline reviewer annotations for Review Studio gates and source paths.", + ) + review_annotations_cmd.add_argument("skill_dir", nargs="?", default=".") + review_annotations_cmd.add_argument("--annotations-json") + review_annotations_cmd.add_argument("--output-json") + review_annotations_cmd.add_argument("--output-md") + review_annotations_cmd.add_argument("--write-template", action="store_true") + review_annotations_cmd.add_argument("--add-annotation", action="store_true") + review_annotations_cmd.add_argument("--annotation-id") + review_annotations_cmd.add_argument( + "--gate-key", + choices=[ + "context-budget", + "intent-canvas", + "operations-loop", + "output-lab", + "registry-audit", + "release-notes", + "review-waivers", + "runtime-matrix", + "skill-atlas", + "trigger-lab", + "trust-report", + "permission-gates", + "permission-runtime", + ], + ) + review_annotations_cmd.add_argument("--target-path") + review_annotations_cmd.add_argument("--line", type=int) + review_annotations_cmd.add_argument("--severity", choices=["blocker", "info", "note", "warning"], default="note") + review_annotations_cmd.add_argument("--status", choices=["deferred", "open", "resolved"], default="open") + review_annotations_cmd.add_argument("--reviewer") + review_annotations_cmd.add_argument("--created-at") + review_annotations_cmd.add_argument("--body") + review_annotations_cmd.add_argument("--suggested-action") + review_annotations_cmd.add_argument("--evidence") + review_annotations_cmd.set_defaults(func=_handler(command_handlers, "command_review_annotations")) + + baseline_compare_cmd = subparsers.add_parser( + "baseline-compare", + help="Render a lightweight with-skill vs baseline comparison across tracked targets.", + ) + baseline_compare_cmd.set_defaults(func=_handler(command_handlers, "command_baseline_compare")) + + skill_ir_cmd = subparsers.add_parser("skill-ir", help="Export platform-neutral Skill IR for a skill package.") + skill_ir_cmd.add_argument("skill_dir", nargs="?", default=".") + skill_ir_cmd.add_argument("--output-json") + skill_ir_cmd.add_argument("--validate-only", action="store_true") + skill_ir_cmd.set_defaults(func=_handler(command_handlers, "command_skill_ir")) + + compile_skill_cmd = subparsers.add_parser( + "compile-skill", + help="Compile Skill IR into target-specific semantic contracts.", + ) + compile_skill_cmd.add_argument("skill_dir", nargs="?", default=".") + compile_skill_cmd.add_argument("--target", action="append") + compile_skill_cmd.add_argument("--output-json") + compile_skill_cmd.add_argument("--output-md") + compile_skill_cmd.add_argument("--generated-at") + compile_skill_cmd.set_defaults(func=_handler(command_handlers, "command_compile_skill")) + + output_eval_cmd = subparsers.add_parser("output-eval", help="Run Output Eval Lab assertion grading.") + output_eval_cmd.add_argument("--cases") + output_eval_cmd.add_argument("--output-json") + output_eval_cmd.add_argument("--output-md") + output_eval_cmd.add_argument("--blind-pack-json") + output_eval_cmd.add_argument("--blind-pack-md") + output_eval_cmd.add_argument("--blind-answer-key-json") + output_eval_cmd.set_defaults(func=_handler(command_handlers, "command_output_eval")) + + output_execution_cmd = subparsers.add_parser( + "output-exec", + help="Record output-eval execution evidence, timing, and token usage.", + ) + output_execution_cmd.add_argument("--cases") + output_execution_cmd.add_argument("--output-json") + output_execution_cmd.add_argument("--output-md") + output_execution_cmd.add_argument("--runner-command") + output_execution_cmd.add_argument("--timeout-seconds", type=float) + output_execution_cmd.set_defaults(func=_handler(command_handlers, "command_output_execution")) + + output_review_cmd = subparsers.add_parser( + "output-review", + help="Adjudicate blind A/B output review decisions against the answer key.", + ) + output_review_cmd.add_argument("--blind-pack") + output_review_cmd.add_argument("--answer-key") + output_review_cmd.add_argument("--decisions") + output_review_cmd.add_argument("--output-json") + output_review_cmd.add_argument("--output-md") + output_review_cmd.add_argument("--write-template", action="store_true") + output_review_cmd.set_defaults(func=_handler(command_handlers, "command_output_review")) + + conformance_cmd = subparsers.add_parser("conformance", help="Run runtime conformance checks for Skill OS targets.") + conformance_cmd.add_argument("skill_dir", nargs="?", default=".") + conformance_cmd.add_argument("--target", action="append", choices=["openai", "claude", "agent-skills", "vscode", "generic"]) + conformance_cmd.add_argument("--output-json") + conformance_cmd.add_argument("--output-md") + conformance_cmd.set_defaults(func=_handler(command_handlers, "command_conformance")) + + runtime_permissions_cmd = subparsers.add_parser( + "runtime-permissions", + help="Probe generated target adapters for runtime permission enforcement metadata.", + ) + runtime_permissions_cmd.add_argument("skill_dir", nargs="?", default=".") + runtime_permissions_cmd.add_argument("--package-dir", default="dist") + runtime_permissions_cmd.add_argument("--target", action="append", choices=["openai", "claude", "generic"]) + runtime_permissions_cmd.add_argument("--output-json") + runtime_permissions_cmd.add_argument("--output-md") + runtime_permissions_cmd.set_defaults(func=_handler(command_handlers, "command_runtime_permissions")) + + trust_cmd = subparsers.add_parser("trust", help="Run trust and security checks for a skill package.") + trust_cmd.add_argument("skill_dir", nargs="?", default=".") + trust_cmd.add_argument("--output-json") + trust_cmd.add_argument("--output-md") + trust_cmd.set_defaults(func=_handler(command_handlers, "command_trust")) + + skill_atlas_cmd = subparsers.add_parser("skill-atlas", help="Build a portfolio-level Skill Atlas for a workspace.") + skill_atlas_cmd.add_argument("--workspace-root", default=".") + skill_atlas_cmd.add_argument("--output-dir") + skill_atlas_cmd.add_argument("--report-html") + skill_atlas_cmd.add_argument("--report-json") + skill_atlas_cmd.add_argument("--overlap-threshold", type=float) + skill_atlas_cmd.add_argument("--today") + skill_atlas_cmd.set_defaults(func=_handler(command_handlers, "command_skill_atlas")) + + registry_audit_cmd = subparsers.add_parser("registry-audit", help="Build and audit Skill OS registry package metadata.") + registry_audit_cmd.add_argument("skill_dir", nargs="?", default=".") + registry_audit_cmd.add_argument("--registry-dir") + registry_audit_cmd.add_argument("--output-json") + registry_audit_cmd.add_argument("--output-md") + registry_audit_cmd.add_argument("--generated-at") + registry_audit_cmd.set_defaults(func=_handler(command_handlers, "command_registry_audit")) + + package_cmd = subparsers.add_parser("package", help="Export compatibility artifacts for selected targets.") + package_cmd.add_argument("skill_dir", nargs="?", default=".") + package_cmd.add_argument("--platform", action="append") + package_cmd.add_argument("--output-dir", default="dist") + package_cmd.add_argument("--expectations") + package_cmd.add_argument("--zip", action="store_true") + package_cmd.set_defaults(func=_handler(command_handlers, "command_package")) + + package_verify_cmd = subparsers.add_parser("package-verify", help="Verify generated package artifacts, archive safety, and registry parity.") + package_verify_cmd.add_argument("skill_dir", nargs="?", default=".") + package_verify_cmd.add_argument("--package-dir", default="dist") + package_verify_cmd.add_argument("--expectations", default="evals/packaging_expectations.json") + package_verify_cmd.add_argument("--registry-json", default="reports/registry_audit.json") + package_verify_cmd.add_argument("--output-json") + package_verify_cmd.add_argument("--output-md") + package_verify_cmd.add_argument("--require-zip", action="store_true") + package_verify_cmd.add_argument("--generated-at") + package_verify_cmd.set_defaults(func=_handler(command_handlers, "command_package_verify")) + + install_simulate_cmd = subparsers.add_parser("install-simulate", help="Simulate installing a generated package into a temporary local skill root.") + install_simulate_cmd.add_argument("skill_dir", nargs="?", default=".") + install_simulate_cmd.add_argument("--package-dir", default="dist") + install_simulate_cmd.add_argument("--install-root") + install_simulate_cmd.add_argument("--output-json") + install_simulate_cmd.add_argument("--output-md") + install_simulate_cmd.add_argument("--generated-at") + install_simulate_cmd.set_defaults(func=_handler(command_handlers, "command_install_simulate")) + + upgrade_check_cmd = subparsers.add_parser("upgrade-check", help="Compare current and previous registry package metadata for upgrade readiness.") + upgrade_check_cmd.add_argument("skill_dir", nargs="?", default=".") + upgrade_check_cmd.add_argument("--previous-package-json", required=True) + upgrade_check_cmd.add_argument("--current-package-json", default="reports/registry_audit.json") + upgrade_check_cmd.add_argument("--output-json") + upgrade_check_cmd.add_argument("--output-md") + upgrade_check_cmd.add_argument("--generated-at") + upgrade_check_cmd.set_defaults(func=_handler(command_handlers, "command_upgrade_check")) + + test_cmd = subparsers.add_parser("test", help="Run a Makefile test target.") + test_cmd.add_argument("--target", default="test") + test_cmd.set_defaults(func=_handler(command_handlers, "command_test")) + + update_cmd = subparsers.add_parser("check-update", help="Check whether a newer yao-meta-skill version is available.") + update_cmd.add_argument("--force", action="store_true") + update_cmd.add_argument("--no-cache", action="store_true") + update_cmd.add_argument("--version-url") + update_cmd.add_argument("--manifest-url") + update_cmd.add_argument("--timeout", type=float, default=3.0) + update_cmd.add_argument("--allow-custom-update-url", action="store_true") + update_cmd.set_defaults(func=_handler(command_handlers, "command_check_update")) + + return parser + + diff --git a/skill-ir/examples/yao-meta-skill.json b/skill-ir/examples/yao-meta-skill.json index 8875667..9ff3297 100644 --- a/skill-ir/examples/yao-meta-skill.json +++ b/skill-ir/examples/yao-meta-skill.json @@ -155,6 +155,7 @@ "scripts/render_system_model.py", "scripts/resource_boundary_check.py", "scripts/review_studio_formatting.py", + "scripts/review_studio_gates.py", "scripts/review_studio_layout.py", "scripts/run_conformance_suite.py", "scripts/run_description_optimization_suite.py", @@ -173,7 +174,8 @@ "scripts/validate_skill.py", "scripts/verify_package.py", "scripts/yao.py", - "scripts/yao_cli_config.py" + "scripts/yao_cli_config.py", + "scripts/yao_cli_parser.py" ], "assets": [ "templates/basic_skill.md.j2", diff --git a/skill_atlas/catalog.json b/skill_atlas/catalog.json index cfa9108..d6dcc92 100644 --- a/skill_atlas/catalog.json +++ b/skill_atlas/catalog.json @@ -66,6 +66,7 @@ "scripts/render_system_model.py", "scripts/resource_boundary_check.py", "scripts/review_studio_formatting.py", + "scripts/review_studio_gates.py", "scripts/review_studio_layout.py", "scripts/run_conformance_suite.py", "scripts/run_description_optimization_suite.py", @@ -85,6 +86,7 @@ "scripts/verify_package.py", "scripts/yao.py", "scripts/yao_cli_config.py", + "scripts/yao_cli_parser.py", "references/artifact-design-doctrine.md", "references/authoring-discipline.md", "references/distribution-registry-method.md", diff --git a/tests/verify_review_studio.py b/tests/verify_review_studio.py index 23cab6f..1048c10 100644 --- a/tests/verify_review_studio.py +++ b/tests/verify_review_studio.py @@ -11,6 +11,7 @@ SCRIPT = ROOT / "scripts" / "render_review_studio.py" sys.path.insert(0, str(ROOT / "scripts")) import render_review_studio as review_studio # noqa: E402 import review_studio_formatting as review_formatting # noqa: E402 +import review_studio_gates as review_gates # noqa: E402 import review_studio_layout as review_layout # noqa: E402 @@ -79,9 +80,9 @@ def main() -> None: "--install-root", str(tmp_root / "install-root"), "--output-json", - str(ROOT / "reports" / "install_simulation.json"), + str(tmp_root / "install_simulation.json"), "--output-md", - str(ROOT / "reports" / "install_simulation.md"), + str(tmp_root / "install_simulation.md"), "--generated-at", "2026-06-13", ], @@ -374,6 +375,12 @@ def main() -> None: assert "案例数" in formatted, formatted assert "abc123" in formatted, formatted assert review_formatting.value_text({"case_count": 5}) == "案例数: 5" + assert review_gates.min_output_cases("scaffold") == 1 + assert review_gates.min_output_cases("production") == 3 + assert review_gates.min_output_cases("governed") == 5 + assert review_gates.status_label("warn") == "关注" + assert review_gates.weighted_score([{"key": "output-lab", "status": "pass"}]) == 100 + assert review_gates.weighted_score([{"key": "output-lab", "status": "warn"}]) == 60 assert len(review_layout.REVIEW_STUDIO_NAV) == 15, review_layout.REVIEW_STUDIO_NAV assert "position: sticky" in review_layout.review_studio_css(), review_layout.review_studio_css()[:400] assert "#overview" in review_layout.render_review_nav(), review_layout.render_review_nav() diff --git a/tests/verify_trust_check.py b/tests/verify_trust_check.py index 49ace96..c068774 100644 --- a/tests/verify_trust_check.py +++ b/tests/verify_trust_check.py @@ -88,23 +88,27 @@ def main() -> None: script_map = {item["path"]: item for item in payload["scripts"]} for internal_module in [ "scripts/review_studio_formatting.py", + "scripts/review_studio_gates.py", "scripts/review_studio_layout.py", "scripts/skill_report_charts.py", "scripts/skill_report_layout.py", "scripts/skill_report_metrics.py", "scripts/skill_report_model.py", "scripts/yao_cli_config.py", + "scripts/yao_cli_parser.py", ]: assert script_map[internal_module]["interface"] == "internal-module", script_map[internal_module] assert script_map[internal_module]["interface_declared"], script_map[internal_module] warning_text = "\n".join(payload["warnings"]) assert "review_studio_formatting.py" not in warning_text, payload["warnings"] + assert "review_studio_gates.py" not in warning_text, payload["warnings"] assert "review_studio_layout.py" not in warning_text, payload["warnings"] assert "skill_report_charts.py" not in warning_text, payload["warnings"] assert "skill_report_layout.py" not in warning_text, payload["warnings"] assert "skill_report_metrics.py" not in warning_text, payload["warnings"] assert "skill_report_model.py" not in warning_text, payload["warnings"] assert "yao_cli_config.py" not in warning_text, payload["warnings"] + assert "yao_cli_parser.py" not in warning_text, payload["warnings"] assert "render_context_reports.py" not in warning_text, payload["warnings"] assert "render_social_preview.py" not in warning_text, payload["warnings"] assert "Network-capable scripts require bounded host policy" not in warning_text, payload["warnings"] diff --git a/tests/verify_yao_cli.py b/tests/verify_yao_cli.py index 7b4aaff..7305ae4 100644 --- a/tests/verify_yao_cli.py +++ b/tests/verify_yao_cli.py @@ -10,7 +10,9 @@ ROOT = Path(__file__).resolve().parent.parent CLI = ROOT / "scripts" / "yao.py" BENCHMARK_FIXTURE_DIR = ROOT / "tests" / "fixtures" / "github_benchmark_scan" sys.path.insert(0, str(ROOT / "scripts")) +import yao as yao_cli_module # noqa: E402 import yao_cli_config # noqa: E402 +import yao_cli_parser # noqa: E402 def run(*args: str, input_text: str | None = None) -> dict: @@ -43,6 +45,10 @@ def main() -> None: assert yao_cli_config.infer_archetype("Standardize team review workflow.", "")[0] == "production" assert yao_cli_config.infer_archetype("Govern release policy.", "")[0] == "governed" assert "--entry" in yao_cli_config.baseline_compare_args() + assert yao_cli_parser.SCRIPT_INTERFACE == "internal-module" + parser_help = yao_cli_module.build_parser().format_help() + assert "quickstart" in parser_help, parser_help + assert "review-studio" in parser_help, parser_help init_result = run("init", "cli-demo-skill", "--description", "CLI demo skill.", "--output-dir", str(tmp_root)) assert init_result["ok"], init_result
路径Path作用Role类型Type
SKILL.mdSkill 入口文件Skill entrypoint文件file
README.md人类可读使用说明Human-readable usage guide文件file
agents/interface.yaml跨平台接口元数据Neutral interface metadata文件file
manifest.json生命周期与打包元数据Lifecycle and portability metadata文件file
references扩展指导与复用资料Extended guidance and reusable notes目录folder
scripts确定性脚本或本地工具Deterministic helpers or local tooling目录folder
evals触发与质量检查Trigger and quality checks目录folder
reports生成的证据与总结报告Generated evidence and overview artifacts目录folder