claude-dev-env 2.8.0 → 2.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +8 -2
- package/_shared/pr-loop/CLAUDE.md +1 -1
- package/_shared/pr-loop/audit-contract.md +17 -6
- package/_shared/pr-loop/audit-reply-template.md +4 -4
- package/_shared/pr-loop/code-rules-gate.md +3 -5
- package/_shared/pr-loop/fix-protocol.md +2 -3
- package/_shared/pr-loop/gh-payloads.md +1 -1
- package/_shared/pr-loop/scripts/CLAUDE.md +1 -1
- package/_shared/pr-loop/scripts/README.md +1 -1
- package/_shared/pr-loop/scripts/code_rules_gate.py +2 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/gate_running.py +16 -1
- package/_shared/pr-loop/scripts/code_rules_gate_parts/git_blob_readers.py +11 -5
- package/_shared/pr-loop/scripts/preflight.py +9 -4
- package/_shared/pr-loop/scripts/reviews_disabled.py +50 -22
- package/_shared/pr-loop/scripts/tests/conftest.py +20 -0
- package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +6 -6
- package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +50 -6
- package/_shared/pr-loop/scripts/tests/test_revoke_project_claude_permissions.py +1 -1
- package/_shared/pr-loop/state-schema.md +5 -14
- package/agents/CLAUDE.md +2 -2
- package/agents/clean-coder.md +62 -562
- package/agents/code-quality-agent.md +10 -2
- package/agents/code-verifier.md +1 -1
- package/agents/test_agent_frontmatter.py +58 -40
- package/audit-rubrics/CLAUDE.md +2 -1
- package/audit-rubrics/audit-categories.json +704 -0
- package/audit-rubrics/prompts/category-i-concurrency.md +1 -1
- package/bin/CLAUDE.md +16 -5
- package/bin/ever-shipped-skills.mjs +2 -0
- package/bin/install-plan.mjs +402 -0
- package/bin/install-transaction.mjs +455 -0
- package/bin/install.mjs +593 -147
- package/bin/install.plan.test.mjs +194 -0
- package/bin/install.profile-root.test.mjs +154 -0
- package/bin/install.profiles.test.mjs +253 -0
- package/bin/install.settings-defaults.test.mjs +200 -0
- package/bin/install.transaction.test.mjs +400 -0
- package/bin/install.uninstall-transaction.test.mjs +418 -0
- package/bin/merge_managed_permissions.mjs +130 -0
- package/bin/resolve-install-root.mjs +181 -0
- package/bin/select-install-targets.mjs +401 -0
- package/commands/CLAUDE.md +0 -2
- package/docs/CODE_RULES.md +4 -2
- package/docs/references/CLAUDE.md +3 -2
- package/docs/references/advisor-tool.md +44 -6
- package/docs/references/prose-style-enforcement.md +25 -0
- package/docs/references/team-advisor-skill.md +14 -8
- package/hooks/blocking/CLAUDE.md +6 -6
- package/hooks/blocking/_path_setup.py +9 -5
- package/hooks/blocking/code_rules_docstrings.py +124 -30
- package/hooks/blocking/code_rules_enforcer.py +161 -16
- package/hooks/blocking/code_rules_shared.py +40 -23
- package/hooks/blocking/config/CLAUDE.md +3 -5
- package/hooks/blocking/config/prose_style_enforcement_constants.py +38 -0
- package/hooks/blocking/config/test_prose_style_enforcement_constants.py +45 -0
- package/hooks/blocking/eli11_reply_enforcer.py +70 -113
- package/hooks/blocking/hedging_language_blocker.py +103 -20
- package/hooks/blocking/hook_prose_detector_consistency.py +6 -0
- package/hooks/blocking/intent_only_ending_blocker.py +6 -0
- package/hooks/blocking/plain_language_blocker.py +139 -20
- package/hooks/blocking/pre_tool_use_dispatcher.py +102 -20
- package/hooks/blocking/state_description_blocker.py +7 -1
- package/hooks/blocking/tdd_enforcer.py +8 -0
- package/hooks/blocking/test__path_setup.py +28 -0
- package/hooks/blocking/test_code_rules_enforcer_agent_home_tooling.py +99 -0
- package/hooks/blocking/test_code_rules_enforcer_docstring_args_span_scope.py +232 -10
- package/hooks/blocking/test_code_rules_enforcer_ephemeral.py +1 -1
- package/hooks/blocking/test_code_rules_enforcer_join_separator_magic.py +41 -0
- package/hooks/blocking/test_code_rules_enforcer_string_magic.py +98 -0
- package/hooks/blocking/test_eli11_reply_enforcer.py +98 -165
- package/hooks/blocking/test_hedging_language_blocker.py +120 -1
- package/hooks/blocking/test_hook_prose_detector_consistency.py +28 -8
- package/hooks/blocking/test_intent_only_ending_blocker.py +27 -2
- package/hooks/blocking/test_package_inventory_stale_blocker.py +11 -4
- package/hooks/blocking/test_plain_language_blocker.py +129 -19
- package/hooks/blocking/test_plain_language_blocker_allowlist.py +70 -26
- package/hooks/blocking/test_pre_tool_use_dispatcher.py +99 -26
- package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +87 -50
- package/hooks/blocking/test_state_description_blocker.py +45 -2
- package/hooks/blocking/test_stop_dispatcher.py +11 -7
- package/hooks/blocking/test_volatile_path_in_post_blocker.py +12 -12
- package/hooks/blocking/volatile_path_in_post_blocker.py +2 -2
- package/hooks/hooks.json +15 -0
- package/hooks/hooks_constants/CLAUDE.md +14 -3
- package/hooks/hooks_constants/ask_user_question_shape.py +281 -0
- package/hooks/hooks_constants/code_rules_enforcer_constants.py +2 -1
- package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -0
- package/hooks/hooks_constants/eli11_reply_enforcer_constants.py +5 -12
- package/hooks/hooks_constants/hedging_uncertainty_constants.py +42 -0
- package/hooks/hooks_constants/issue_tracker_session_starter_constants.py +23 -0
- package/hooks/hooks_constants/orchestrator_auto_starter_constants.py +23 -0
- package/hooks/hooks_constants/piped_pytest_blocker_constants.py +4 -1
- package/hooks/hooks_constants/plain_language_blocker_constants.py +4 -1
- package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +6 -0
- package/hooks/hooks_constants/project_paths_reader.py +31 -4
- package/hooks/hooks_constants/prose_matcher_precision_constants.py +40 -0
- package/hooks/hooks_constants/pytest_invocation.py +354 -0
- package/hooks/hooks_constants/session_start_injector.py +163 -0
- package/hooks/hooks_constants/session_start_injector_constants.py +46 -0
- package/hooks/hooks_constants/shell_command_pipeline.py +397 -0
- package/hooks/hooks_constants/shell_command_segments.py +5 -0
- package/hooks/hooks_constants/test_ask_user_question_shape.py +167 -0
- package/hooks/hooks_constants/test_project_paths_reader.py +29 -0
- package/hooks/hooks_constants/test_prose_metrics_parity.py +8 -0
- package/hooks/hooks_constants/test_pytest_invocation.py +130 -0
- package/hooks/hooks_constants/test_session_start_injector.py +168 -0
- package/hooks/hooks_constants/test_shell_command_pipeline.py +135 -0
- package/hooks/hooks_constants/volatile_path_in_post_blocker_constants.py +1 -1
- package/hooks/hooks_constants/working_style_prompt_constants.py +30 -0
- package/hooks/observability/CLAUDE.md +2 -0
- package/hooks/observability/prose_matcher_advisory.py +237 -0
- package/hooks/observability/test_prose_matcher_advisory.py +143 -0
- package/hooks/session/CLAUDE.md +9 -1
- package/hooks/session/_path_setup.py +13 -0
- package/hooks/session/issue_tracker_session_starter.py +135 -0
- package/hooks/session/orchestrator_auto_starter.py +100 -0
- package/hooks/session/test__path_setup.py +28 -0
- package/hooks/session/test_issue_tracker_session_starter.py +104 -0
- package/hooks/session/test_orchestrator_auto_starter.py +99 -0
- package/hooks/session/test_working_style_prompt.py +47 -0
- package/hooks/session/untracked_repo_detector.py +1 -24
- package/hooks/session/working_style_prompt.py +36 -0
- package/hooks/validators/_path_setup.py +19 -0
- package/hooks/validators/run_all_validators.py +8 -13
- package/installable-surfaces.manifest.json +21 -0
- package/output-styles/CLAUDE.md +15 -0
- package/package.json +5 -2
- package/rules/CLAUDE.md +1 -0
- package/rules/code-standards.md +33 -7
- package/rules/durable-post-artifacts.md +2 -2
- package/rules/eli11-replies.md +7 -2
- package/rules/hedging-claims.md +4 -2
- package/rules/long-horizon-autonomy.md +3 -1
- package/rules/opus5-communication-contract.md +45 -0
- package/rules/plain-language.md +2 -2
- package/rules/research-mode.md +1 -1
- package/scripts/CLAUDE.md +13 -2
- package/scripts/Sync-RepoMain.ps1 +215 -0
- package/scripts/active_capability_references.py +218 -0
- package/scripts/ci/windows-installer-lifecycle.ps1 +78 -0
- package/scripts/claude_chain_runner.py +394 -6
- package/scripts/claude_chain_usage.py +1 -1
- package/scripts/codex_compat_materializer.py +105 -85
- package/scripts/dev_env_scripts_constants/CLAUDE.md +3 -1
- package/scripts/dev_env_scripts_constants/active_capability_constants.py +46 -0
- package/scripts/dev_env_scripts_constants/claude_chain_constants.py +74 -0
- package/scripts/dev_env_scripts_constants/grok_run_ledger_constants.py +50 -0
- package/scripts/dev_env_scripts_constants/grok_worker_constants.py +104 -0
- package/scripts/dev_env_scripts_constants/verify_installable_package_constants.py +116 -0
- package/scripts/grok_patch_artifacts.py +123 -0
- package/scripts/grok_run_ledger.py +318 -0
- package/scripts/profile-isolation-launchers/config/mcp-bundles.json +25 -0
- package/scripts/profile-isolation-launchers/config/profile-isolation-constants.mjs +60 -0
- package/scripts/profile-isolation-launchers/config/profiles.manifest.json +54 -0
- package/scripts/profile-isolation-launchers/config/shared-allowlist.json +64 -0
- package/scripts/profile-isolation-launchers/launcher-runtime.mjs +180 -0
- package/scripts/profile-isolation-launchers/lib/profile-manifest.mjs +288 -0
- package/scripts/profile-isolation-launchers/mcp-bundles.mjs +275 -0
- package/scripts/profile-isolation-launchers/profile-isolation-contract.test.mjs +221 -0
- package/scripts/profile-isolation-launchers/tests/launcher-runtime.test.mjs +108 -0
- package/scripts/profile-isolation-launchers/tests/mcp-bundles.test.mjs +147 -0
- package/scripts/profile-isolation-launchers/tests/shortcut-contract.test.ps1 +102 -0
- package/scripts/profile-isolation-launchers/tests/version-compatibility.test.mjs +210 -0
- package/scripts/profile-isolation-launchers/version-compatibility.mjs +299 -0
- package/scripts/profile-isolation-launchers/windows/shortcut-inventory.ps1 +127 -0
- package/scripts/profile-isolation-launchers/windows/shortcut-manifest.json +51 -0
- package/scripts/profile-isolation-launchers/windows/shortcut-reconcile.ps1 +77 -0
- package/scripts/spawn_grok_batch.py +556 -9
- package/scripts/test_active_capability_references.py +108 -0
- package/scripts/test_claude_chain_runner.py +414 -82
- package/scripts/test_claude_chain_usage.py +12 -12
- package/scripts/test_grok_patch_artifacts.py +82 -0
- package/scripts/test_grok_run_ledger.py +116 -0
- package/scripts/test_resolve_worker_spawn.py +2 -2
- package/scripts/test_spawn_grok_batch.py +295 -0
- package/scripts/test_verify_installable_package.py +208 -0
- package/scripts/tests/test_codex_compat_materializer.py +33 -0
- package/scripts/verify_installable_package.py +612 -0
- package/settings.json +10 -0
- package/skills/CLAUDE.md +6 -2
- package/skills/_shared/CLAUDE.md +37 -4
- package/skills/_shared/advisor/CLAUDE.md +9 -0
- package/skills/_shared/advisor/advisor-protocol.md +5 -0
- package/skills/_shared/advisor/scripts/README.md +9 -0
- package/skills/_shared/end-of-run-gotcha-recommendations.md +156 -0
- package/skills/_shared/pr-loop/CLAUDE.md +18 -1
- package/skills/_shared/pr-loop/audit-contract.md +5 -0
- package/skills/_shared/pr-loop/audit-reply-template.md +5 -0
- package/skills/_shared/pr-loop/code-rules-gate.md +5 -0
- package/skills/_shared/pr-loop/fix-protocol.md +5 -0
- package/skills/_shared/pr-loop/gh-payloads.md +5 -0
- package/skills/_shared/pr-loop/post-audit-thread-contract.md +5 -0
- package/skills/_shared/pr-loop/precatch-rubric.md +5 -0
- package/skills/_shared/pr-loop/scripts/CLAUDE.md +9 -1
- package/skills/_shared/pr-loop/scripts/RUNTIME_SCRIPTS.md +29 -0
- package/skills/_shared/pr-loop/scripts/audit_category_schema.py +355 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/CLAUDE.md +1 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/audit_category_schema_constants.py +32 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +7 -19
- package/skills/_shared/pr-loop/scripts/test_audit_category_schema.py +94 -0
- package/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +21 -0
- package/skills/_shared/pr-loop/state-schema.md +5 -0
- package/skills/_shared/pr-loop/worker-spawn.md +5 -0
- package/skills/autoconverge/reference/convergence.md +2 -1
- package/skills/autoconverge/reference/stop-conditions.md +5 -3
- package/skills/beat-sheet/SKILL.md +54 -0
- package/skills/beat-sheet/reference/visual-beats.md +29 -0
- package/skills/bugteam/CONSTRAINTS.md +4 -4
- package/skills/bugteam/EXAMPLES.md +1 -1
- package/skills/bugteam/reference/README.md +1 -1
- package/skills/e-code-review/SKILL.md +29 -3
- package/skills/e-code-review/reference/effort-evaluation.md +35 -0
- package/skills/e-code-review/reference/medium.md +15 -4
- package/skills/e-code-review/reference/runner-selection.md +40 -0
- package/skills/e-code-review/scripts/config/e_code_review_effort_constants/__init__.py +41 -0
- package/skills/e-code-review/scripts/config/e_code_review_effort_constants/effort_constants.py +40 -0
- package/skills/e-code-review/scripts/e_code_review_scripts_constants/__init__.py +1 -0
- package/skills/e-code-review/scripts/e_code_review_scripts_constants/finding_pipeline_constants.py +49 -0
- package/skills/e-code-review/scripts/e_code_review_scripts_constants/grok_code_review_constants.py +55 -0
- package/skills/e-code-review/scripts/effort_defaults_evidence.json +186 -0
- package/skills/e-code-review/scripts/effort_evaluation.py +362 -0
- package/skills/e-code-review/scripts/finding_pipeline.py +140 -0
- package/skills/e-code-review/scripts/fixtures/demanding.json +26 -0
- package/skills/e-code-review/scripts/fixtures/easy.json +14 -0
- package/skills/e-code-review/scripts/fixtures/medium.json +20 -0
- package/skills/e-code-review/scripts/grok_code_review.py +230 -0
- package/skills/e-code-review/scripts/test_effort_evaluation.py +180 -0
- package/skills/e-code-review/scripts/test_finding_pipeline.py +197 -0
- package/skills/e-code-review/scripts/test_grok_code_review.py +289 -0
- package/skills/grok-spawn/SKILL.md +5 -0
- package/skills/orchestrator/SKILL.md +5 -0
- package/skills/plan-to-pr/scripts/create_packet.py +4 -4
- package/skills/plan-to-pr/scripts/load_skill_constants.py +41 -0
- package/skills/plan-to-pr/scripts/validate_packet.py +4 -4
- package/skills/plan-to-pr/scripts/validate_protocol.py +4 -1
- package/skills/plan-to-pr/scripts/validate_run.py +4 -1
- package/skills/pr-converge/scripts/check_convergence.py +21 -19
- package/skills/pr-converge/scripts/check_convergence_availability.py +50 -7
- package/skills/pr-converge/scripts/conftest.py +35 -0
- package/skills/pr-converge/scripts/test_check_convergence_availability.py +65 -0
- package/skills/pr-converge/scripts/test_check_convergence_codex.py +11 -1
- package/skills/pr-converge/scripts/test_check_convergence_contract.py +9 -2
- package/skills/pr-loop-cloud-transport/SKILL.md +1 -1
- package/skills/rebase/SKILL.md +15 -3
- package/skills/reviewer-gates/SKILL.md +2 -2
- package/skills/show/SKILL.md +51 -0
- package/skills/show/references/accessibility.md +7 -0
- package/skills/show/references/art.md +3 -0
- package/skills/show/references/charts.md +3 -0
- package/skills/show/references/core-design.md +14 -0
- package/skills/show/references/erds.md +3 -0
- package/skills/show/references/flowcharts.md +3 -0
- package/skills/show/references/host-and-html.md +3 -0
- package/skills/show/references/illustrative-diagrams.md +10 -0
- package/skills/show/references/interaction.md +3 -0
- package/skills/show/references/mockups.md +3 -0
- package/skills/show/references/quality-gates.md +7 -0
- package/skills/show/references/structural-diagrams.md +3 -0
- package/skills/show/references/subject-inventory.md +21 -0
- package/skills/show/references/svg-contract.md +22 -0
- package/skills/show/routing.yaml +30 -0
- package/skills/show/samples/pr1262-v2.svg +222 -0
- package/skills/show/scripts/README.md +6 -0
- package/skills/show/scripts/validate-artifact.py +91 -0
- package/skills/show/scripts/validate-package.py +18 -0
- package/skills/show/templates/html-widget.html +4 -0
- package/skills/show/templates/svg-base.svg +19 -0
- package/skills/show/tests/fixtures/css-var.svg +6 -0
- package/skills/show/tests/fixtures/dead-ref.svg +7 -0
- package/skills/show/tests/fixtures/filled-glyph.svg +8 -0
- package/skills/show/tests/fixtures/inherited-fill.svg +18 -0
- package/skills/show/tests/fixtures/invalid.svg +1 -0
- package/skills/show/tests/fixtures/large-canvas.svg +21 -0
- package/skills/show/tests/fixtures/unfilled-connector.svg +15 -0
- package/skills/show/tests/fixtures/valid.html +1 -0
- package/skills/show/tests/test_validate-artifact.py +74 -0
- package/skills/show/tests/test_validators.py +59 -0
- package/skills/show/workflows/create-visual.md +13 -0
- package/skills/show/workflows/review-visual.md +20 -0
- package/skills/split-pr/SKILL.md +85 -0
- package/skills/split-pr/reference/path-layers.md +16 -0
- package/skills/split-pr/reference/proposal-format.md +15 -0
- package/skills/split-pr/reference/split-further-loop.md +10 -0
- package/skills/split-pr/reference/splitting-principles.md +26 -0
- package/skills/split-pr/scripts/analyze_pr.py +279 -0
- package/skills/split-pr/scripts/categorize_files.py +106 -0
- package/skills/split-pr/scripts/config/__init__.py +1 -0
- package/skills/split-pr/scripts/config/dependency_constants.py +14 -0
- package/skills/split-pr/scripts/config/git_operations_constants.py +36 -0
- package/skills/split-pr/scripts/config/packing_constants.py +61 -0
- package/skills/split-pr/scripts/config/plan_constants.py +49 -0
- package/skills/split-pr/scripts/config/split_pr_constants.py +110 -0
- package/skills/split-pr/scripts/execute_split_slices.py +82 -0
- package/skills/split-pr/scripts/pack_files_into_slices.py +212 -0
- package/skills/split-pr/scripts/split_pr_dependency_graph.py +70 -0
- package/skills/split-pr/scripts/split_pr_git_operations.py +184 -0
- package/skills/split-pr/scripts/split_pr_layer_order.py +58 -0
- package/skills/split-pr/scripts/split_pr_paginate.py +119 -0
- package/skills/split-pr/scripts/split_pr_process_runner.py +52 -0
- package/skills/split-pr/scripts/split_pr_script_types.py +126 -0
- package/skills/split-pr/scripts/split_pr_title.py +41 -0
- package/skills/split-pr/scripts/test_analyze_pr.py +228 -0
- package/skills/split-pr/scripts/test_categorize_files.py +55 -0
- package/skills/split-pr/scripts/test_categorize_files_packing.py +59 -0
- package/skills/split-pr/scripts/test_execute_split_slices.py +99 -0
- package/skills/split-pr/scripts/test_split_pr_dependency_graph.py +47 -0
- package/skills/split-pr/scripts/test_split_pr_git_operations.py +125 -0
- package/skills/split-pr/scripts/test_split_pr_layer_order.py +36 -0
- package/skills/split-pr/scripts/test_split_pr_paginate.py +65 -0
- package/skills/split-pr/scripts/test_split_pr_script_types.py +73 -0
- package/skills/split-pr/scripts/test_split_pr_title.py +28 -0
- package/skills/split-pr/scripts/test_verify_dependency_graph.py +46 -0
- package/skills/split-pr/scripts/test_verify_plan.py +56 -0
- package/skills/split-pr/scripts/test_verify_plan_contract.py +50 -0
- package/skills/split-pr/scripts/test_verify_plan_path_normalization.py +45 -0
- package/skills/split-pr/scripts/verify_dependency_graph.py +111 -0
- package/skills/split-pr/scripts/verify_plan.py +139 -0
- package/skills/task-build/reference/tool-routing.md +3 -0
- package/skills/team-advisor/SKILL.md +23 -44
- package/system-prompts/software-engineer.xml +17 -5
- package/commands/initialize.md +0 -90
- package/commands/stubcheck.md +0 -88
- package/skills/test_markdown_link_integrity.py +0 -107
package/skills/e-code-review/scripts/e_code_review_scripts_constants/finding_pipeline_constants.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Named constants for the collect-then-filter finding pipeline.
|
|
2
|
+
|
|
3
|
+
::
|
|
4
|
+
|
|
5
|
+
collect_findings([...low-severity finding...])
|
|
6
|
+
ok: collection keeps every seeded severity including low and nit
|
|
7
|
+
filter_findings_by_severity(collection, minimum_severity="medium")
|
|
8
|
+
ok: consumer stage drops lower severities; collection record is unchanged
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
COLLECTION_STAGE_NAME: str = "collection"
|
|
14
|
+
"""Stage that retains every real finding with its evidence fields."""
|
|
15
|
+
|
|
16
|
+
FILTER_STAGE_NAME: str = "severity_filter"
|
|
17
|
+
"""Later consumer stage that may drop findings by severity for action."""
|
|
18
|
+
|
|
19
|
+
FINDING_FIELD_FILE: str = "file"
|
|
20
|
+
FINDING_FIELD_LINE: str = "line"
|
|
21
|
+
FINDING_FIELD_SEVERITY: str = "severity"
|
|
22
|
+
FINDING_FIELD_CATEGORY: str = "category"
|
|
23
|
+
FINDING_FIELD_EVIDENCE: str = "evidence"
|
|
24
|
+
|
|
25
|
+
SEVERITY_BLOCKER: str = "blocker"
|
|
26
|
+
SEVERITY_HIGH: str = "high"
|
|
27
|
+
SEVERITY_MEDIUM: str = "medium"
|
|
28
|
+
SEVERITY_LOW: str = "low"
|
|
29
|
+
SEVERITY_NIT: str = "nit"
|
|
30
|
+
|
|
31
|
+
ALL_SEVERITY_RANK_BY_TOKEN: dict[str, int] = {
|
|
32
|
+
SEVERITY_BLOCKER: 5,
|
|
33
|
+
SEVERITY_HIGH: 4,
|
|
34
|
+
SEVERITY_MEDIUM: 3,
|
|
35
|
+
SEVERITY_LOW: 2,
|
|
36
|
+
SEVERITY_NIT: 1,
|
|
37
|
+
}
|
|
38
|
+
"""Higher rank is more severe; used only by the filter stage."""
|
|
39
|
+
|
|
40
|
+
ALL_COLLECTION_SEVERITIES: tuple[str, ...] = tuple(ALL_SEVERITY_RANK_BY_TOKEN)
|
|
41
|
+
"""Severity tokens collection accepts; derived from the rank map keys."""
|
|
42
|
+
|
|
43
|
+
REPORT_EVERY_FINDING_INSTRUCTION: str = (
|
|
44
|
+
"Report every real finding. Collection retains all severities "
|
|
45
|
+
f"({', '.join(ALL_COLLECTION_SEVERITIES)}). Do not drop findings "
|
|
46
|
+
"by severity during collection; severity or action filtering is a "
|
|
47
|
+
"separate consumer stage after the collection record is complete."
|
|
48
|
+
)
|
|
49
|
+
"""Reviewer-prompt instruction that separates collection from filtering."""
|
package/skills/e-code-review/scripts/e_code_review_scripts_constants/grok_code_review_constants.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Named constants for Grok medium-review discovery and verification."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
MEDIUM_REVIEW_SCHEMA_VERSION: str = "1.0.0"
|
|
6
|
+
"""Schema version for medium-review run documents."""
|
|
7
|
+
|
|
8
|
+
MEDIUM_REVIEW_FINDER_COUNT: int = 8
|
|
9
|
+
"""Exactly eight finder angles execute per medium review head."""
|
|
10
|
+
|
|
11
|
+
ALL_MEDIUM_FINDER_ANGLES: tuple[str, ...] = (
|
|
12
|
+
"correctness",
|
|
13
|
+
"security",
|
|
14
|
+
"code_rules",
|
|
15
|
+
"tests",
|
|
16
|
+
"docs",
|
|
17
|
+
"concurrency",
|
|
18
|
+
"api_contracts",
|
|
19
|
+
"regressions",
|
|
20
|
+
)
|
|
21
|
+
"""Named finder angles for one medium-review discovery batch."""
|
|
22
|
+
|
|
23
|
+
VERDICT_CONFIRMED: str = "CONFIRMED"
|
|
24
|
+
"""Verification retained a concrete failure scenario."""
|
|
25
|
+
|
|
26
|
+
VERDICT_PLAUSIBLE: str = "PLAUSIBLE"
|
|
27
|
+
"""Verification could not refute the finding."""
|
|
28
|
+
|
|
29
|
+
VERDICT_REFUTED: str = "REFUTED"
|
|
30
|
+
"""Verification rejected the finding."""
|
|
31
|
+
|
|
32
|
+
ALL_VERIFICATION_VERDICTS: frozenset[str] = frozenset(
|
|
33
|
+
{VERDICT_CONFIRMED, VERDICT_PLAUSIBLE, VERDICT_REFUTED}
|
|
34
|
+
)
|
|
35
|
+
"""Legal verification verdict tokens."""
|
|
36
|
+
|
|
37
|
+
SEVERITY_BLOCKER: str = "blocker"
|
|
38
|
+
SEVERITY_HIGH: str = "high"
|
|
39
|
+
SEVERITY_MEDIUM: str = "medium"
|
|
40
|
+
SEVERITY_LOW: str = "low"
|
|
41
|
+
SEVERITY_NIT: str = "nit"
|
|
42
|
+
|
|
43
|
+
ALL_SEVERITIES: frozenset[str] = frozenset(
|
|
44
|
+
{
|
|
45
|
+
SEVERITY_BLOCKER,
|
|
46
|
+
SEVERITY_HIGH,
|
|
47
|
+
SEVERITY_MEDIUM,
|
|
48
|
+
SEVERITY_LOW,
|
|
49
|
+
SEVERITY_NIT,
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
"""Legal severity tokens on retained findings."""
|
|
53
|
+
|
|
54
|
+
UTF8_ENCODING: str = "utf-8"
|
|
55
|
+
"""Text encoding for review artifacts."""
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": "1",
|
|
3
|
+
"workflow_family": "e-code-review",
|
|
4
|
+
"evidence_source": "offline_harness_baseline",
|
|
5
|
+
"thinking_enabled": true,
|
|
6
|
+
"cost_latency_lever": "effort",
|
|
7
|
+
"notes": "Completed evaluation rows from the OP-02B offline harness. Each skill default cites a holding row. Paid live sweeps may replace rows without changing the resolver contract.",
|
|
8
|
+
"all_rows": [
|
|
9
|
+
{
|
|
10
|
+
"fixture_id": "easy-comment-preservation",
|
|
11
|
+
"fixture_band": "easy",
|
|
12
|
+
"effort": "low",
|
|
13
|
+
"quality_score": 0.5,
|
|
14
|
+
"finding_recall": 0.5,
|
|
15
|
+
"finding_precision": 0.5,
|
|
16
|
+
"visible_tokens": 800,
|
|
17
|
+
"latency_ms": 2000,
|
|
18
|
+
"thinking_enabled": true
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"fixture_id": "easy-comment-preservation",
|
|
22
|
+
"fixture_band": "easy",
|
|
23
|
+
"effort": "medium",
|
|
24
|
+
"quality_score": 0.95,
|
|
25
|
+
"finding_recall": 0.95,
|
|
26
|
+
"finding_precision": 0.95,
|
|
27
|
+
"visible_tokens": 1600,
|
|
28
|
+
"latency_ms": 4000,
|
|
29
|
+
"thinking_enabled": true
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"fixture_id": "medium-constants-and-types",
|
|
33
|
+
"fixture_band": "medium",
|
|
34
|
+
"effort": "medium",
|
|
35
|
+
"quality_score": 0.7,
|
|
36
|
+
"finding_recall": 0.65,
|
|
37
|
+
"finding_precision": 0.75,
|
|
38
|
+
"visible_tokens": 2200,
|
|
39
|
+
"latency_ms": 5000,
|
|
40
|
+
"thinking_enabled": true
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"fixture_id": "medium-constants-and-types",
|
|
44
|
+
"fixture_band": "medium",
|
|
45
|
+
"effort": "high",
|
|
46
|
+
"quality_score": 0.9,
|
|
47
|
+
"finding_recall": 0.9,
|
|
48
|
+
"finding_precision": 0.9,
|
|
49
|
+
"visible_tokens": 3200,
|
|
50
|
+
"latency_ms": 7000,
|
|
51
|
+
"thinking_enabled": true
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"fixture_id": "demanding-multi-surface",
|
|
55
|
+
"fixture_band": "demanding",
|
|
56
|
+
"effort": "xhigh",
|
|
57
|
+
"quality_score": 0.75,
|
|
58
|
+
"finding_recall": 0.7,
|
|
59
|
+
"finding_precision": 0.8,
|
|
60
|
+
"visible_tokens": 5000,
|
|
61
|
+
"latency_ms": 10000,
|
|
62
|
+
"thinking_enabled": true
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"fixture_id": "demanding-multi-surface",
|
|
66
|
+
"fixture_band": "demanding",
|
|
67
|
+
"effort": "max",
|
|
68
|
+
"quality_score": 0.92,
|
|
69
|
+
"finding_recall": 0.92,
|
|
70
|
+
"finding_precision": 0.9,
|
|
71
|
+
"visible_tokens": 8000,
|
|
72
|
+
"latency_ms": 15000,
|
|
73
|
+
"thinking_enabled": true
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
"recommendation": {
|
|
77
|
+
"schema_version": "1",
|
|
78
|
+
"thinking_enabled": true,
|
|
79
|
+
"cost_latency_lever": "effort",
|
|
80
|
+
"defaults_unchanged": false,
|
|
81
|
+
"minimum_quality": 0.8,
|
|
82
|
+
"recommendation_by_band": {
|
|
83
|
+
"easy": {
|
|
84
|
+
"recommended_effort": "medium",
|
|
85
|
+
"cited_row": {
|
|
86
|
+
"fixture_id": "easy-comment-preservation",
|
|
87
|
+
"fixture_band": "easy",
|
|
88
|
+
"effort": "medium",
|
|
89
|
+
"quality_score": 0.95,
|
|
90
|
+
"finding_recall": 0.95,
|
|
91
|
+
"finding_precision": 0.95,
|
|
92
|
+
"visible_tokens": 1600,
|
|
93
|
+
"latency_ms": 4000,
|
|
94
|
+
"thinking_enabled": true
|
|
95
|
+
},
|
|
96
|
+
"blocker": null
|
|
97
|
+
},
|
|
98
|
+
"medium": {
|
|
99
|
+
"recommended_effort": "high",
|
|
100
|
+
"cited_row": {
|
|
101
|
+
"fixture_id": "medium-constants-and-types",
|
|
102
|
+
"fixture_band": "medium",
|
|
103
|
+
"effort": "high",
|
|
104
|
+
"quality_score": 0.9,
|
|
105
|
+
"finding_recall": 0.9,
|
|
106
|
+
"finding_precision": 0.9,
|
|
107
|
+
"visible_tokens": 3200,
|
|
108
|
+
"latency_ms": 7000,
|
|
109
|
+
"thinking_enabled": true
|
|
110
|
+
},
|
|
111
|
+
"blocker": null
|
|
112
|
+
},
|
|
113
|
+
"demanding": {
|
|
114
|
+
"recommended_effort": "max",
|
|
115
|
+
"cited_row": {
|
|
116
|
+
"fixture_id": "demanding-multi-surface",
|
|
117
|
+
"fixture_band": "demanding",
|
|
118
|
+
"effort": "max",
|
|
119
|
+
"quality_score": 0.92,
|
|
120
|
+
"finding_recall": 0.92,
|
|
121
|
+
"finding_precision": 0.9,
|
|
122
|
+
"visible_tokens": 8000,
|
|
123
|
+
"latency_ms": 15000,
|
|
124
|
+
"thinking_enabled": true
|
|
125
|
+
},
|
|
126
|
+
"blocker": null
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"skill_defaults": {
|
|
131
|
+
"workflow_family": "e-code-review",
|
|
132
|
+
"thinking_enabled": true,
|
|
133
|
+
"cost_latency_lever": "effort",
|
|
134
|
+
"skill_levels": ["low", "medium", "xhigh"],
|
|
135
|
+
"default_by_band": {
|
|
136
|
+
"easy": {
|
|
137
|
+
"skill_effort": "medium",
|
|
138
|
+
"evaluation_effort": "medium",
|
|
139
|
+
"cited_row": {
|
|
140
|
+
"fixture_id": "easy-comment-preservation",
|
|
141
|
+
"fixture_band": "easy",
|
|
142
|
+
"effort": "medium",
|
|
143
|
+
"quality_score": 0.95,
|
|
144
|
+
"finding_recall": 0.95,
|
|
145
|
+
"finding_precision": 0.95,
|
|
146
|
+
"visible_tokens": 1600,
|
|
147
|
+
"latency_ms": 4000,
|
|
148
|
+
"thinking_enabled": true
|
|
149
|
+
},
|
|
150
|
+
"blocker": null
|
|
151
|
+
},
|
|
152
|
+
"medium": {
|
|
153
|
+
"skill_effort": "xhigh",
|
|
154
|
+
"evaluation_effort": "high",
|
|
155
|
+
"cited_row": {
|
|
156
|
+
"fixture_id": "medium-constants-and-types",
|
|
157
|
+
"fixture_band": "medium",
|
|
158
|
+
"effort": "high",
|
|
159
|
+
"quality_score": 0.9,
|
|
160
|
+
"finding_recall": 0.9,
|
|
161
|
+
"finding_precision": 0.9,
|
|
162
|
+
"visible_tokens": 3200,
|
|
163
|
+
"latency_ms": 7000,
|
|
164
|
+
"thinking_enabled": true
|
|
165
|
+
},
|
|
166
|
+
"blocker": null
|
|
167
|
+
},
|
|
168
|
+
"demanding": {
|
|
169
|
+
"skill_effort": "xhigh",
|
|
170
|
+
"evaluation_effort": "max",
|
|
171
|
+
"cited_row": {
|
|
172
|
+
"fixture_id": "demanding-multi-surface",
|
|
173
|
+
"fixture_band": "demanding",
|
|
174
|
+
"effort": "max",
|
|
175
|
+
"quality_score": 0.92,
|
|
176
|
+
"finding_recall": 0.92,
|
|
177
|
+
"finding_precision": 0.9,
|
|
178
|
+
"visible_tokens": 8000,
|
|
179
|
+
"latency_ms": 15000,
|
|
180
|
+
"thinking_enabled": true
|
|
181
|
+
},
|
|
182
|
+
"blocker": null
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
"""Machine-readable Opus effort evaluation for e-code-review.
|
|
2
|
+
|
|
3
|
+
Freezes easy / medium / demanding fixtures, validates evaluation rows, and
|
|
4
|
+
publishes a recommendation that cites completed rows. Live paid runs are
|
|
5
|
+
optional — offline tests feed synthetic rows through the same functions::
|
|
6
|
+
|
|
7
|
+
load fixtures → validate rows → recommend lowest effort that holds quality
|
|
8
|
+
|
|
9
|
+
Thinking stays enabled; effort is the only planned cost and latency lever.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import json
|
|
15
|
+
import sys
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Mapping, MutableMapping, Sequence
|
|
18
|
+
|
|
19
|
+
_SCRIPTS_DIRECTORY = Path(__file__).resolve().parent
|
|
20
|
+
if str(_SCRIPTS_DIRECTORY / "config") not in sys.path:
|
|
21
|
+
sys.path.insert(0, str(_SCRIPTS_DIRECTORY / "config"))
|
|
22
|
+
if str(_SCRIPTS_DIRECTORY) not in sys.path:
|
|
23
|
+
sys.path.insert(0, str(_SCRIPTS_DIRECTORY))
|
|
24
|
+
|
|
25
|
+
from e_code_review_effort_constants import (
|
|
26
|
+
ALL_EFFORT_LEVELS,
|
|
27
|
+
ALL_EFFORT_RANK_BY_NAME,
|
|
28
|
+
ALL_FIXTURE_BANDS,
|
|
29
|
+
ALL_REQUIRED_ROW_KEYS,
|
|
30
|
+
ALL_SCORE_ROW_KEYS,
|
|
31
|
+
ALL_SKILL_EFFORT_FOR_EVALUATION_EFFORT,
|
|
32
|
+
ALL_SKILL_EFFORT_LEVELS,
|
|
33
|
+
COST_LATENCY_LEVER,
|
|
34
|
+
EVALUATION_EVIDENCE_FILENAME,
|
|
35
|
+
EVALUATION_SCHEMA_VERSION,
|
|
36
|
+
FIXTURES_DIRECTORY_NAME,
|
|
37
|
+
JSON_SUFFIX,
|
|
38
|
+
LATENCY_MS_ROW_KEY,
|
|
39
|
+
MINIMUM_QUALITY_HOLD_SCORE,
|
|
40
|
+
THINKING_ENABLED_DEFAULT,
|
|
41
|
+
VISIBLE_TOKENS_ROW_KEY,
|
|
42
|
+
WORKFLOW_FAMILY_E_CODE_REVIEW,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def fixtures_directory() -> Path:
|
|
47
|
+
"""Return the frozen fixture directory next to this module.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
Absolute path to the fixtures directory.
|
|
51
|
+
"""
|
|
52
|
+
return _SCRIPTS_DIRECTORY / FIXTURES_DIRECTORY_NAME
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def load_fixtures() -> list[dict[str, object]]:
|
|
56
|
+
"""Load every JSON fixture under the fixtures directory.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Fixture dicts sorted by band then fixture_id.
|
|
60
|
+
|
|
61
|
+
Raises:
|
|
62
|
+
ValueError: When a fixture file is not a JSON object.
|
|
63
|
+
OSError: When a fixture file cannot be read.
|
|
64
|
+
json.JSONDecodeError: When a fixture file is not valid JSON.
|
|
65
|
+
"""
|
|
66
|
+
directory = fixtures_directory()
|
|
67
|
+
all_fixtures: list[dict[str, object]] = []
|
|
68
|
+
for each_path in sorted(directory.glob(f"*{JSON_SUFFIX}")):
|
|
69
|
+
loaded = json.loads(each_path.read_text(encoding="utf-8"))
|
|
70
|
+
if not isinstance(loaded, dict):
|
|
71
|
+
raise ValueError(f"Fixture must be an object: {each_path}")
|
|
72
|
+
all_fixtures.append(loaded)
|
|
73
|
+
all_fixtures.sort(
|
|
74
|
+
key=lambda each_fixture: (
|
|
75
|
+
str(each_fixture.get("band", "")),
|
|
76
|
+
str(each_fixture.get("fixture_id", "")),
|
|
77
|
+
)
|
|
78
|
+
)
|
|
79
|
+
return all_fixtures
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def validate_evaluation_row(all_row_fields: Mapping[str, object]) -> list[str]:
|
|
83
|
+
"""Return human-readable problems for one evaluation row.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
all_row_fields: Candidate evaluation row mapping.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
Problem strings; empty when the row is valid.
|
|
90
|
+
"""
|
|
91
|
+
all_problems: list[str] = []
|
|
92
|
+
for each_key in ALL_REQUIRED_ROW_KEYS:
|
|
93
|
+
if each_key not in all_row_fields:
|
|
94
|
+
all_problems.append(f"missing key: {each_key}")
|
|
95
|
+
if all_problems:
|
|
96
|
+
return all_problems
|
|
97
|
+
effort = all_row_fields["effort"]
|
|
98
|
+
if effort not in ALL_EFFORT_LEVELS:
|
|
99
|
+
all_problems.append(f"unknown effort: {effort!r}")
|
|
100
|
+
fixture_band = all_row_fields["fixture_band"]
|
|
101
|
+
if fixture_band not in ALL_FIXTURE_BANDS:
|
|
102
|
+
all_problems.append(f"unknown fixture_band: {fixture_band!r}")
|
|
103
|
+
if all_row_fields["thinking_enabled"] is not True:
|
|
104
|
+
all_problems.append("thinking_enabled must be true on Opus paths")
|
|
105
|
+
for each_score_key in ALL_SCORE_ROW_KEYS:
|
|
106
|
+
score_amount = all_row_fields[each_score_key]
|
|
107
|
+
if isinstance(score_amount, bool) or not isinstance(score_amount, (int, float)):
|
|
108
|
+
all_problems.append(f"{each_score_key} must be numeric")
|
|
109
|
+
elif not 0.0 <= float(score_amount) <= 1.0:
|
|
110
|
+
all_problems.append(f"{each_score_key} out of range [0, 1]")
|
|
111
|
+
for each_count_key in (VISIBLE_TOKENS_ROW_KEY, LATENCY_MS_ROW_KEY):
|
|
112
|
+
count_amount = all_row_fields[each_count_key]
|
|
113
|
+
if (
|
|
114
|
+
isinstance(count_amount, bool)
|
|
115
|
+
or not isinstance(count_amount, (int, float))
|
|
116
|
+
or float(count_amount) < 0
|
|
117
|
+
):
|
|
118
|
+
all_problems.append(f"{each_count_key} must be a non-negative number")
|
|
119
|
+
return all_problems
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def quality_holds(
|
|
123
|
+
all_row_fields: Mapping[str, object],
|
|
124
|
+
minimum_quality: float = MINIMUM_QUALITY_HOLD_SCORE,
|
|
125
|
+
) -> bool:
|
|
126
|
+
"""Return True when quality, recall, and precision all meet the floor.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
all_row_fields: Evaluation row mapping.
|
|
130
|
+
minimum_quality: Floor for quality, recall, and precision.
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
Whether the row holds quality at the floor.
|
|
134
|
+
"""
|
|
135
|
+
return all(
|
|
136
|
+
float(all_row_fields[each_score_key]) >= minimum_quality
|
|
137
|
+
for each_score_key in ALL_SCORE_ROW_KEYS
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _lowest_holding_row(
|
|
142
|
+
all_band_rows: Sequence[Mapping[str, object]],
|
|
143
|
+
) -> Mapping[str, object]:
|
|
144
|
+
return min(
|
|
145
|
+
all_band_rows,
|
|
146
|
+
key=lambda each_row: ALL_EFFORT_RANK_BY_NAME[str(each_row["effort"])],
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def recommend_effort_by_band(
|
|
151
|
+
all_rows: Sequence[Mapping[str, object]],
|
|
152
|
+
minimum_quality: float = MINIMUM_QUALITY_HOLD_SCORE,
|
|
153
|
+
) -> dict[str, object]:
|
|
154
|
+
"""Pick the lowest effort that holds quality for each fixture band.
|
|
155
|
+
|
|
156
|
+
Every recommendation entry cites the evaluation row that justified it.
|
|
157
|
+
Bands with no holding row stay null with an explicit blocker note.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
all_rows: Completed evaluation rows (already validated by the caller).
|
|
161
|
+
minimum_quality: Floor for quality, recall, and precision.
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
Machine-readable recommendation document.
|
|
165
|
+
"""
|
|
166
|
+
recommendation_by_band: MutableMapping[str, object] = {}
|
|
167
|
+
for each_band in ALL_FIXTURE_BANDS:
|
|
168
|
+
all_holding_rows = [
|
|
169
|
+
each_row
|
|
170
|
+
for each_row in all_rows
|
|
171
|
+
if each_row["fixture_band"] == each_band
|
|
172
|
+
and quality_holds(each_row, minimum_quality)
|
|
173
|
+
]
|
|
174
|
+
if not all_holding_rows:
|
|
175
|
+
recommendation_by_band[each_band] = {
|
|
176
|
+
"recommended_effort": None,
|
|
177
|
+
"cited_row": None,
|
|
178
|
+
"blocker": "no completed row meets the quality floor",
|
|
179
|
+
}
|
|
180
|
+
continue
|
|
181
|
+
chosen_row = _lowest_holding_row(all_holding_rows)
|
|
182
|
+
recommendation_by_band[each_band] = {
|
|
183
|
+
"recommended_effort": chosen_row["effort"],
|
|
184
|
+
"cited_row": dict(chosen_row),
|
|
185
|
+
"blocker": None,
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
"schema_version": EVALUATION_SCHEMA_VERSION,
|
|
189
|
+
"thinking_enabled": THINKING_ENABLED_DEFAULT,
|
|
190
|
+
"cost_latency_lever": COST_LATENCY_LEVER,
|
|
191
|
+
"defaults_unchanged": True,
|
|
192
|
+
"minimum_quality": minimum_quality,
|
|
193
|
+
"recommendation_by_band": dict(recommendation_by_band),
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def build_synthetic_row(
|
|
198
|
+
fixture_id: str,
|
|
199
|
+
fixture_band: str,
|
|
200
|
+
effort: str,
|
|
201
|
+
quality_score: float,
|
|
202
|
+
finding_recall: float,
|
|
203
|
+
finding_precision: float,
|
|
204
|
+
visible_tokens: int,
|
|
205
|
+
latency_ms: int,
|
|
206
|
+
) -> dict[str, object]:
|
|
207
|
+
"""Build one evaluation row with thinking enabled.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
fixture_id: Fixture identifier.
|
|
211
|
+
fixture_band: Band name (easy / medium / demanding).
|
|
212
|
+
effort: Effort level name.
|
|
213
|
+
quality_score: Overall quality in [0, 1].
|
|
214
|
+
finding_recall: Recall in [0, 1].
|
|
215
|
+
finding_precision: Precision in [0, 1].
|
|
216
|
+
visible_tokens: Visible token count.
|
|
217
|
+
latency_ms: Latency in milliseconds.
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
Complete evaluation row mapping.
|
|
221
|
+
"""
|
|
222
|
+
return {
|
|
223
|
+
"fixture_id": fixture_id,
|
|
224
|
+
"fixture_band": fixture_band,
|
|
225
|
+
"effort": effort,
|
|
226
|
+
"quality_score": quality_score,
|
|
227
|
+
"finding_recall": finding_recall,
|
|
228
|
+
"finding_precision": finding_precision,
|
|
229
|
+
VISIBLE_TOKENS_ROW_KEY: visible_tokens,
|
|
230
|
+
LATENCY_MS_ROW_KEY: latency_ms,
|
|
231
|
+
"thinking_enabled": THINKING_ENABLED_DEFAULT,
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def evaluation_evidence_path() -> Path:
|
|
236
|
+
"""Return the committed evaluation evidence file path.
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
Path to ``effort_defaults_evidence.json`` beside this module.
|
|
240
|
+
"""
|
|
241
|
+
return _SCRIPTS_DIRECTORY / EVALUATION_EVIDENCE_FILENAME
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def load_evaluation_evidence() -> dict[str, object]:
|
|
245
|
+
"""Load the committed evaluation evidence document.
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
Parsed evidence mapping (rows, recommendation, skill defaults).
|
|
249
|
+
|
|
250
|
+
Raises:
|
|
251
|
+
OSError: When the evidence file cannot be read.
|
|
252
|
+
json.JSONDecodeError: When the evidence file is not valid JSON.
|
|
253
|
+
"""
|
|
254
|
+
return json.loads(evaluation_evidence_path().read_text(encoding="utf-8"))
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def map_evaluation_effort_to_skill_level(evaluation_effort: str) -> str:
|
|
258
|
+
"""Map a full evaluation effort name to an e-code-review skill level.
|
|
259
|
+
|
|
260
|
+
Args:
|
|
261
|
+
evaluation_effort: One of low / medium / high / xhigh / max.
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
One of low / medium / xhigh.
|
|
265
|
+
|
|
266
|
+
Raises:
|
|
267
|
+
ValueError: When the evaluation effort is unknown.
|
|
268
|
+
"""
|
|
269
|
+
skill_effort = ALL_SKILL_EFFORT_FOR_EVALUATION_EFFORT.get(evaluation_effort)
|
|
270
|
+
if skill_effort is None:
|
|
271
|
+
raise ValueError(f"unknown evaluation effort: {evaluation_effort!r}")
|
|
272
|
+
return skill_effort
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def skill_defaults_from_recommendation(
|
|
276
|
+
all_recommendation_fields: Mapping[str, object],
|
|
277
|
+
) -> dict[str, object]:
|
|
278
|
+
"""Build e-code-review skill defaults that each cite a recommendation row.
|
|
279
|
+
|
|
280
|
+
Args:
|
|
281
|
+
all_recommendation_fields: Output of ``recommend_effort_by_band``.
|
|
282
|
+
|
|
283
|
+
Returns:
|
|
284
|
+
Skill-family defaults document with cited rows per band.
|
|
285
|
+
|
|
286
|
+
Raises:
|
|
287
|
+
TypeError: When recommendation structure is not mapping-shaped.
|
|
288
|
+
ValueError: When a mapped skill effort leaves the skill surface.
|
|
289
|
+
"""
|
|
290
|
+
recommendation_by_band = all_recommendation_fields["recommendation_by_band"]
|
|
291
|
+
if not isinstance(recommendation_by_band, Mapping):
|
|
292
|
+
raise TypeError("recommendation_by_band must be a mapping")
|
|
293
|
+
default_by_band: MutableMapping[str, object] = {}
|
|
294
|
+
for each_band in ALL_FIXTURE_BANDS:
|
|
295
|
+
band_entry = recommendation_by_band[each_band]
|
|
296
|
+
if not isinstance(band_entry, Mapping):
|
|
297
|
+
raise TypeError(f"band entry for {each_band} must be a mapping")
|
|
298
|
+
evaluation_effort = band_entry.get("recommended_effort")
|
|
299
|
+
cited_row = band_entry.get("cited_row")
|
|
300
|
+
if evaluation_effort is None or cited_row is None:
|
|
301
|
+
default_by_band[each_band] = {
|
|
302
|
+
"skill_effort": None,
|
|
303
|
+
"cited_row": None,
|
|
304
|
+
"blocker": band_entry.get("blocker"),
|
|
305
|
+
}
|
|
306
|
+
continue
|
|
307
|
+
skill_effort = map_evaluation_effort_to_skill_level(str(evaluation_effort))
|
|
308
|
+
if skill_effort not in ALL_SKILL_EFFORT_LEVELS:
|
|
309
|
+
raise ValueError(f"skill effort out of surface: {skill_effort!r}")
|
|
310
|
+
default_by_band[each_band] = {
|
|
311
|
+
"skill_effort": skill_effort,
|
|
312
|
+
"evaluation_effort": evaluation_effort,
|
|
313
|
+
"cited_row": dict(cited_row) if isinstance(cited_row, Mapping) else cited_row,
|
|
314
|
+
"blocker": None,
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
"workflow_family": WORKFLOW_FAMILY_E_CODE_REVIEW,
|
|
318
|
+
"thinking_enabled": THINKING_ENABLED_DEFAULT,
|
|
319
|
+
"cost_latency_lever": COST_LATENCY_LEVER,
|
|
320
|
+
"skill_levels": list(ALL_SKILL_EFFORT_LEVELS),
|
|
321
|
+
"default_by_band": dict(default_by_band),
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def resolve_skill_effort_for_band(fixture_band: str) -> str:
|
|
326
|
+
"""Return the evaluation-backed skill effort for one fixture band.
|
|
327
|
+
|
|
328
|
+
Args:
|
|
329
|
+
fixture_band: easy / medium / demanding.
|
|
330
|
+
|
|
331
|
+
Returns:
|
|
332
|
+
Skill effort level (low / medium / xhigh).
|
|
333
|
+
|
|
334
|
+
Raises:
|
|
335
|
+
ValueError: When the band is unknown or has no holding recommendation.
|
|
336
|
+
KeyError: When the evidence document lacks the band.
|
|
337
|
+
"""
|
|
338
|
+
if fixture_band not in ALL_FIXTURE_BANDS:
|
|
339
|
+
raise ValueError(f"unknown fixture band: {fixture_band!r}")
|
|
340
|
+
evidence = load_evaluation_evidence()
|
|
341
|
+
skill_defaults = evidence["skill_defaults"]
|
|
342
|
+
if not isinstance(skill_defaults, Mapping):
|
|
343
|
+
raise TypeError("skill_defaults must be a mapping")
|
|
344
|
+
default_by_band = skill_defaults["default_by_band"]
|
|
345
|
+
if not isinstance(default_by_band, Mapping):
|
|
346
|
+
raise TypeError("default_by_band must be a mapping")
|
|
347
|
+
band_default = default_by_band[fixture_band]
|
|
348
|
+
if not isinstance(band_default, Mapping):
|
|
349
|
+
raise TypeError(f"default for {fixture_band} must be a mapping")
|
|
350
|
+
skill_effort = band_default.get("skill_effort")
|
|
351
|
+
if skill_effort is None:
|
|
352
|
+
raise ValueError(
|
|
353
|
+
f"no evaluation-backed skill effort for band {fixture_band!r}: "
|
|
354
|
+
f"{band_default.get('blocker')}"
|
|
355
|
+
)
|
|
356
|
+
skill_effort_name = str(skill_effort)
|
|
357
|
+
if skill_effort_name not in ALL_SKILL_EFFORT_LEVELS:
|
|
358
|
+
raise ValueError(
|
|
359
|
+
f"skill effort out of surface for band {fixture_band!r}: "
|
|
360
|
+
f"{skill_effort_name!r}"
|
|
361
|
+
)
|
|
362
|
+
return skill_effort_name
|