okstra 0.186.7 → 0.187.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/README.md +1 -1
- package/dist/cli-registry.d.mts +88 -1
- package/dist/cli-registry.mjs +68 -111
- package/dist/cli-registry.mjs.map +1 -1
- package/dist/commands/execute/render-bundle.mjs +0 -1
- package/dist/commands/execute/render-bundle.mjs.map +1 -1
- package/dist/commands/execute/run.mjs +8 -3
- package/dist/commands/execute/run.mjs.map +1 -1
- package/dist/commands/lifecycle/check-project.mjs +1 -14
- package/dist/commands/lifecycle/check-project.mjs.map +1 -1
- package/dist/commands/lifecycle/config.mjs +38 -40
- package/dist/commands/lifecycle/config.mjs.map +1 -1
- package/dist/commands/lifecycle/doctor.d.mts +22 -7
- package/dist/commands/lifecycle/doctor.mjs +77 -49
- package/dist/commands/lifecycle/doctor.mjs.map +1 -1
- package/dist/commands/lifecycle/install.d.mts +12 -10
- package/dist/commands/lifecycle/install.mjs +104 -39
- package/dist/commands/lifecycle/install.mjs.map +1 -1
- package/dist/commands/lifecycle/paths.mjs +8 -3
- package/dist/commands/lifecycle/paths.mjs.map +1 -1
- package/dist/commands/lifecycle/preflight.mjs +2 -1
- package/dist/commands/lifecycle/preflight.mjs.map +1 -1
- package/dist/commands/lifecycle/setup.mjs +22 -36
- package/dist/commands/lifecycle/setup.mjs.map +1 -1
- package/dist/commands/lifecycle/uninstall.d.mts +4 -2
- package/dist/commands/lifecycle/uninstall.mjs +59 -15
- package/dist/commands/lifecycle/uninstall.mjs.map +1 -1
- package/dist/commands/memory/memory.mjs +7 -1
- package/dist/commands/memory/memory.mjs.map +1 -1
- package/dist/lib/helper-scripts.d.mts +1 -1
- package/dist/lib/helper-scripts.mjs +10 -18
- package/dist/lib/helper-scripts.mjs.map +1 -1
- package/dist/lib/host-config.d.mts +72 -0
- package/dist/lib/host-config.mjs +404 -0
- package/dist/lib/host-config.mjs.map +1 -0
- package/dist/lib/host-registry-client.d.mts +2 -2
- package/dist/lib/host-registry-client.mjs +0 -3
- package/dist/lib/host-registry-client.mjs.map +1 -1
- package/dist/lib/install-assets.d.mts +1 -0
- package/dist/lib/install-assets.mjs +4 -0
- package/dist/lib/install-assets.mjs.map +1 -1
- package/dist/lib/proc.d.mts +2 -0
- package/dist/lib/proc.mjs +12 -0
- package/dist/lib/proc.mjs.map +1 -1
- package/dist/lib/python-command.d.mts +2 -0
- package/dist/lib/python-command.mjs +52 -0
- package/dist/lib/python-command.mjs.map +1 -0
- package/dist/lib/python-helper.d.mts +2 -5
- package/dist/lib/python-helper.mjs +3 -52
- package/dist/lib/python-helper.mjs.map +1 -1
- package/dist/lib/runtime-payload.d.mts +23 -0
- package/dist/lib/runtime-payload.mjs +57 -0
- package/dist/lib/runtime-payload.mjs.map +1 -0
- package/dist/lib/types.d.mts +24 -13
- package/docs/architecture/storage-model.md +21 -5
- package/docs/architecture.md +37 -36
- package/docs/cli.md +55 -76
- package/docs/coding-rules.md +295 -0
- package/docs/container.md +10 -36
- package/docs/contributor-change-matrix.md +1 -1
- package/docs/for-ai/skills/okstra-code-review.md +0 -1
- package/docs/for-ai/skills/okstra-container-build.md +8 -41
- package/docs/for-ai/skills/okstra-inspect.md +4 -4
- package/docs/for-ai/skills/okstra-manager.md +2 -2
- package/docs/for-ai/skills/okstra-rollup.md +0 -1
- package/docs/for-ai/skills/okstra-run.md +3 -3
- package/docs/for-ai/skills/okstra-user-response.md +0 -1
- package/docs/performance-improvement-plan-v2.md +1 -1
- package/docs/project-structure-overview.md +62 -62
- package/docs/task-process/README.md +3 -3
- package/docs/task-process/common-flow.md +1 -1
- package/docs/task-process/error-analysis.md +3 -3
- package/docs/task-process/implementation-planning.md +3 -1
- package/docs/task-process/release-handoff.md +1 -1
- package/package.json +3 -2
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/claude-worker.md +6 -11
- package/runtime/agents/workers/report-writer-worker.md +1 -1
- package/runtime/bin/lib/okstra/cli.sh +4 -0
- package/runtime/bin/lib/okstra/globals.sh +2 -0
- package/runtime/bin/lib/okstra/interactive.sh +26 -173
- package/runtime/bin/lib/okstra/project-resolver.sh +23 -61
- package/runtime/bin/lib/okstra/usage.sh +3 -3
- package/runtime/bin/okstra-compact-reminder.sh +1 -5
- package/runtime/bin/okstra-error-log.py +19 -2
- package/runtime/bin/okstra-import-check.py +26 -0
- package/runtime/bin/okstra-inject-report-index.py +5 -4
- package/runtime/bin/okstra-provider-exec.py +22 -17
- package/runtime/bin/okstra-render-final-report.py +16 -6
- package/runtime/bin/okstra-render-report-views.py +25 -18
- package/runtime/bin/okstra-report-translate.py +30 -18
- package/runtime/bin/okstra-spawn-followups.py +4 -0
- package/runtime/bin/okstra-token-usage.py +3 -0
- package/runtime/bin/okstra.sh +4 -2
- package/runtime/bin/okstra_bootstrap.py +58 -0
- package/runtime/prompts/coding-preflight/overview.md +1 -1
- package/runtime/prompts/duties/planning-worker.md +1 -1
- package/runtime/prompts/launch.template.md +35 -9
- package/runtime/prompts/lead/convergence.md +96 -87
- package/runtime/prompts/lead/okstra-lead-contract.md +63 -12
- package/runtime/prompts/lead/plan-body-verification.md +65 -46
- package/runtime/prompts/lead/report-writer.md +34 -4
- package/runtime/prompts/lead/team-contract.md +4 -1
- package/runtime/prompts/profiles/_clarification-recommendation.md +2 -1
- package/runtime/prompts/profiles/_coding-conventions-preflight.md +1 -1
- package/runtime/prompts/profiles/_common-contract.md +3 -3
- package/runtime/prompts/profiles/_coverage-critic.md +1 -1
- package/runtime/prompts/profiles/_implementation-deliverable.md +2 -2
- package/runtime/prompts/profiles/_implementation-executor.md +3 -1
- package/runtime/prompts/profiles/_implementation-verifier.md +16 -2
- package/runtime/prompts/profiles/error-analysis.md +4 -3
- package/runtime/prompts/profiles/final-verification.md +2 -2
- package/runtime/prompts/profiles/implementation-planning.md +22 -17
- package/runtime/prompts/profiles/implementation.md +3 -2
- package/runtime/prompts/profiles/requirements-discovery.md +2 -1
- package/runtime/prompts/wizard/prompts.ko.json +29 -8
- package/runtime/python/okstra_ctl/__init__.py +6 -27
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +4 -5
- package/runtime/python/okstra_ctl/adapters/hosts/codex/adapter.py +21 -2
- package/runtime/python/okstra_ctl/adapters/hosts/external/adapter.py +3 -12
- package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +40 -22
- package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +14 -21
- package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +37 -20
- package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +86 -14
- package/runtime/python/okstra_ctl/adapters/providers/kimi/adapter.py +12 -12
- package/runtime/python/okstra_ctl/adapters/runtime/cmux.py +4 -7
- package/runtime/python/okstra_ctl/agent/__init__.py +1 -0
- package/runtime/python/okstra_ctl/{agent_activity.py → agent/activity.py} +12 -1
- package/runtime/python/okstra_ctl/{agent_invocation.py → agent/invocation.py} +34 -5
- package/runtime/python/okstra_ctl/agent/prompt_cli/__init__.py +19 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/__main__.py +11 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +215 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/dynamic_verifier.py +155 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/emit.py +66 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/inputs.py +138 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +408 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/results.py +197 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/run_identity.py +107 -0
- package/runtime/python/okstra_ctl/analysis_packet.py +47 -4
- package/runtime/python/okstra_ctl/approval_decisions.py +260 -8
- package/runtime/python/okstra_ctl/assignment_resolver.py +0 -12
- package/runtime/python/okstra_ctl/attempt_evidence.py +12 -24
- package/runtime/python/okstra_ctl/blocking_checks.py +251 -0
- package/runtime/python/okstra_ctl/brief_frontmatter.py +0 -7
- package/runtime/python/okstra_ctl/clarification_items/__init__.py +102 -0
- package/runtime/python/okstra_ctl/clarification_items/carry.py +224 -0
- package/runtime/python/okstra_ctl/clarification_items/dispositions.py +135 -0
- package/runtime/python/okstra_ctl/clarification_items/parsing.py +253 -0
- package/runtime/python/okstra_ctl/clarification_items/rows.py +115 -0
- package/runtime/python/okstra_ctl/clarification_items/scan.py +215 -0
- package/runtime/python/okstra_ctl/clarification_items/sidecars.py +211 -0
- package/runtime/python/okstra_ctl/cmux.py +38 -31
- package/runtime/python/okstra_ctl/code_review_target.py +163 -1
- package/runtime/python/okstra_ctl/conformance.py +23 -0
- package/runtime/python/okstra_ctl/container.py +38 -421
- package/runtime/python/okstra_ctl/context_cost.py +16 -2
- package/runtime/python/okstra_ctl/contract_graph_cli.py +7 -0
- package/runtime/python/okstra_ctl/convergence.py +101 -15
- package/runtime/python/okstra_ctl/convergence_critic_prompt.py +345 -0
- package/runtime/python/okstra_ctl/convergence_engine.py +382 -70
- package/runtime/python/okstra_ctl/convergence_store.py +5 -29
- package/runtime/python/okstra_ctl/design_prep.py +108 -12
- package/runtime/python/okstra_ctl/design_snapshot.py +11 -1
- package/runtime/python/okstra_ctl/design_surfaces.py +29 -2
- package/runtime/python/okstra_ctl/dispatch_core.py +102 -25
- package/runtime/python/okstra_ctl/dispatch_state.py +268 -39
- package/runtime/python/okstra_ctl/doctor_cli.py +48 -0
- package/runtime/python/okstra_ctl/domain/worker_exec.py +10 -5
- package/runtime/python/okstra_ctl/domain/worker_presentation.py +21 -1
- package/runtime/python/okstra_ctl/domain/worker_stream.py +52 -21
- package/runtime/python/okstra_ctl/domain/write_policy.py +219 -0
- package/runtime/python/okstra_ctl/entrypoints/hosts.py +9 -2
- package/runtime/python/okstra_ctl/error_log_core.py +1 -1
- package/runtime/python/okstra_ctl/error_report.py +14 -0
- package/runtime/python/okstra_ctl/error_zip.py +18 -2
- package/runtime/python/okstra_ctl/execution_identity.py +100 -7
- package/runtime/python/okstra_ctl/execution_manifest.py +67 -20
- package/runtime/python/okstra_ctl/execution_mutation_audit.py +90 -8
- package/runtime/python/okstra_ctl/final_report_paths.py +17 -0
- package/runtime/python/okstra_ctl/final_report_schema.py +90 -16
- package/runtime/python/okstra_ctl/git_reconcile.py +22 -2
- package/runtime/python/okstra_ctl/handoff.py +24 -1
- package/runtime/python/okstra_ctl/ids.py +6 -16
- package/runtime/python/okstra_ctl/implementation_direction.py +142 -33
- package/runtime/python/okstra_ctl/implementation_options.py +25 -11
- package/runtime/python/okstra_ctl/implementation_outcome.py +5 -2
- package/runtime/python/okstra_ctl/improvement_lenses.py +0 -14
- package/runtime/python/okstra_ctl/incremental_carry.py +69 -8
- package/runtime/python/okstra_ctl/incremental_scope.py +173 -12
- package/runtime/python/okstra_ctl/index.py +2 -2
- package/runtime/python/okstra_ctl/initial_prompt_materialization.py +48 -8
- package/runtime/python/okstra_ctl/interactive_cli.py +223 -0
- package/runtime/python/okstra_ctl/json_boundary.py +10 -0
- package/runtime/python/okstra_ctl/listing.py +0 -91
- package/runtime/python/okstra_ctl/locks.py +5 -19
- package/runtime/python/okstra_ctl/log_report.py +14 -0
- package/runtime/python/okstra_ctl/manager_cli.py +22 -3
- package/runtime/python/okstra_ctl/manager_launch.py +4 -8
- package/runtime/python/okstra_ctl/material.py +2 -2
- package/runtime/python/okstra_ctl/migrate.py +23 -1
- package/runtime/python/okstra_ctl/model_cli.py +19 -5
- package/runtime/python/okstra_ctl/model_discovery.py +46 -47
- package/runtime/python/okstra_ctl/model_io/__init__.py +1 -0
- package/runtime/python/okstra_ctl/model_io/lines.py +163 -0
- package/runtime/python/okstra_ctl/model_io/references.py +370 -0
- package/runtime/python/okstra_ctl/model_io/renderers.py +498 -0
- package/runtime/python/okstra_ctl/model_io_cli.py +30 -945
- package/runtime/python/okstra_ctl/model_pool.py +10 -6
- package/runtime/python/okstra_ctl/models.py +8 -8
- package/runtime/python/okstra_ctl/mutation_recovery.py +5 -63
- package/runtime/python/okstra_ctl/next_phase.py +121 -69
- package/runtime/python/okstra_ctl/pane_reclaim.py +23 -0
- package/runtime/python/okstra_ctl/pane_title.py +11 -8
- package/runtime/python/okstra_ctl/path_hints.py +36 -11
- package/runtime/python/okstra_ctl/paths.py +76 -8
- package/runtime/python/okstra_ctl/plan_items.py +132 -16
- package/runtime/python/okstra_ctl/plan_items_cli.py +486 -36
- package/runtime/python/okstra_ctl/plan_run_root.py +1 -1
- package/runtime/python/okstra_ctl/plan_validate_cli.py +51 -0
- package/runtime/python/okstra_ctl/plan_verify_cli.py +80 -0
- package/runtime/python/okstra_ctl/prepare_error.py +20 -0
- package/runtime/python/okstra_ctl/prior_planning.py +157 -0
- package/runtime/python/okstra_ctl/profile_show.py +18 -1
- package/runtime/python/okstra_ctl/project_setup_cli.py +140 -0
- package/runtime/python/okstra_ctl/recap.py +22 -1
- package/runtime/python/okstra_ctl/reconcile.py +84 -0
- package/runtime/python/okstra_ctl/registry/host_registry.py +18 -1
- package/runtime/python/okstra_ctl/render.py +98 -32
- package/runtime/python/okstra_ctl/render_final_report.py +3 -7
- package/runtime/python/okstra_ctl/report_assembly.py +297 -7
- package/runtime/python/okstra_ctl/report_contract.py +30 -7
- package/runtime/python/okstra_ctl/report_finalize.py +206 -15
- package/runtime/python/okstra_ctl/report_html/common.py +2 -2
- package/runtime/python/okstra_ctl/report_html/render.py +8 -12
- package/runtime/python/okstra_ctl/report_language.py +8 -4
- package/runtime/python/okstra_ctl/report_narrative.py +90 -3
- package/runtime/python/okstra_ctl/report_projections.py +8 -2
- package/runtime/python/okstra_ctl/report_synthesis_packet.py +258 -1
- package/runtime/python/okstra_ctl/report_translation.py +2 -35
- package/runtime/python/okstra_ctl/report_views.py +4 -22
- package/runtime/python/okstra_ctl/resolve_task_key.py +13 -0
- package/runtime/python/okstra_ctl/rollup.py +13 -0
- package/runtime/python/okstra_ctl/run.py +639 -138
- package/runtime/python/okstra_ctl/run_audit.py +13 -0
- package/runtime/python/okstra_ctl/run_index_row.py +0 -12
- package/runtime/python/okstra_ctl/seeding.py +21 -11
- package/runtime/python/okstra_ctl/sequence.py +1 -1
- package/runtime/python/okstra_ctl/session.py +64 -14
- package/runtime/python/okstra_ctl/set_work_status.py +18 -0
- package/runtime/python/okstra_ctl/stage_integrate.py +15 -1
- package/runtime/python/okstra_ctl/stage_ledger.py +1 -1
- package/runtime/python/okstra_ctl/stage_map.py +57 -11
- package/runtime/python/okstra_ctl/stage_map_cli.py +83 -0
- package/runtime/python/okstra_ctl/stage_map_view.py +65 -0
- package/runtime/python/okstra_ctl/stage_targets.py +3 -12
- package/runtime/python/okstra_ctl/task_list_cli.py +138 -0
- package/runtime/python/okstra_ctl/task_show_cli.py +66 -0
- package/runtime/python/okstra_ctl/task_target.py +4 -16
- package/runtime/python/okstra_ctl/team.py +49 -2
- package/runtime/python/okstra_ctl/time_report.py +17 -2
- package/runtime/python/okstra_ctl/usage_report.py +11 -0
- package/runtime/python/okstra_ctl/user_response.py +55 -218
- package/runtime/python/okstra_ctl/user_response_values.py +242 -0
- package/runtime/python/okstra_ctl/validation_contract.py +3 -0
- package/runtime/python/okstra_ctl/verification_target.py +68 -0
- package/runtime/python/okstra_ctl/wizard.py +457 -92
- package/runtime/python/okstra_ctl/worker_artifacts.py +75 -16
- package/runtime/python/okstra_ctl/worker_audit_check.py +22 -0
- package/runtime/python/okstra_ctl/worker_dispatch.py +21 -0
- package/runtime/python/okstra_ctl/worker_liveness.py +33 -0
- package/runtime/python/okstra_ctl/worker_prompt_body.py +15 -2
- package/runtime/python/okstra_ctl/worker_prompt_contract.py +98 -7
- package/runtime/python/okstra_ctl/worker_prompt_headers.py +24 -2
- package/runtime/python/okstra_ctl/worker_prompt_policy.py +18 -3
- package/runtime/python/okstra_ctl/worker_request.py +2 -1
- package/runtime/python/okstra_ctl/worker_runner.py +16 -9
- package/runtime/python/okstra_ctl/worker_state.py +16 -1
- package/runtime/python/okstra_ctl/workflow.py +18 -1
- package/runtime/python/okstra_ctl/worktree/__init__.py +92 -0
- package/runtime/python/okstra_ctl/worktree/cleanliness.py +89 -0
- package/runtime/python/okstra_ctl/worktree/decisions.py +127 -0
- package/runtime/python/okstra_ctl/worktree/git_ops.py +165 -0
- package/runtime/python/okstra_ctl/worktree/linking.py +249 -0
- package/runtime/python/okstra_ctl/worktree/naming.py +91 -0
- package/runtime/python/okstra_ctl/worktree/provision.py +385 -0
- package/runtime/python/okstra_ctl/worktree/sync_config.py +181 -0
- package/runtime/python/okstra_ctl/worktree_cli.py +75 -0
- package/runtime/python/okstra_ctl/worktree_lookup_cli.py +39 -0
- package/runtime/python/okstra_ctl/worktree_registry.py +7 -0
- package/runtime/python/okstra_ctl/worktree_status_cli.py +53 -0
- package/runtime/python/okstra_ctl/write_policy.py +90 -213
- package/runtime/python/okstra_project/__init__.py +0 -4
- package/runtime/python/okstra_project/dirs.py +2 -2
- package/runtime/python/okstra_project/phase_pointer.py +84 -0
- package/runtime/python/okstra_project/slug.py +24 -0
- package/runtime/python/okstra_project/state.py +22 -230
- package/runtime/python/okstra_token_usage/claude.py +9 -1
- package/runtime/python/okstra_token_usage/cli.py +3 -1
- package/runtime/python/okstra_token_usage/collect.py +71 -10
- package/runtime/python/okstra_token_usage/cursor.py +2 -0
- package/runtime/python/okstra_token_usage/grok.py +1 -5
- package/runtime/python/okstra_token_usage/paths.py +26 -0
- package/runtime/python/okstra_token_usage/pricing.py +19 -7
- package/runtime/schemas/convergence-critic-results-v1.0.schema.json +5 -0
- package/runtime/schemas/execution-manifest-v2.schema.json +10 -10
- package/runtime/schemas/final-report-v2.0.schema.json +9 -26
- package/runtime/schemas/final-report-v3.0.schema.json +173 -41
- package/runtime/schemas/report-narrative-v3.0.schema.json +3 -2
- package/runtime/skills/okstra-brief-gen/SKILL.md +35 -2
- package/runtime/skills/okstra-container-build/SKILL.md +16 -47
- package/runtime/skills/okstra-inspect/facets/history.md +1 -1
- package/runtime/skills/okstra-inspect/facets/status.md +7 -6
- package/runtime/skills/okstra-pr-gen/SKILL.md +1 -1
- package/runtime/skills/okstra-run/SKILL.md +7 -5
- package/runtime/templates/report-writer-prompt-preamble.md +1 -1
- package/runtime/templates/reports/brief.template.md +6 -2
- package/runtime/templates/reports/error-analysis-input.template.md +2 -0
- package/runtime/templates/reports/final-verification-input.template.md +2 -0
- package/runtime/templates/reports/implementation-input.template.md +7 -1
- package/runtime/templates/reports/implementation-planning-input.template.md +4 -0
- package/runtime/templates/reports/quick-input.template.md +2 -0
- package/runtime/templates/reports/release-handoff-input.template.md +6 -1
- package/runtime/templates/reports/report.js +20 -3
- package/runtime/templates/reports/schedule.template.md +2 -0
- package/runtime/templates/reports/settings.template.json +0 -10
- package/runtime/templates/reports/task-brief.template.md +3 -0
- package/runtime/templates/reports/user-response.template.md +7 -3
- package/runtime/validators/checks/fixtures-01.py +57 -0
- package/runtime/validators/checks/fixtures-02.py +565 -0
- package/runtime/validators/checks/runners-01.py +108 -0
- package/runtime/validators/checks/validate-assets-01.py +60 -0
- package/runtime/validators/checks/validate-prompt-metadata-01.py +261 -0
- package/runtime/validators/checks/validate-tasks-01.py +46 -0
- package/runtime/validators/checks/validate-tasks-02.py +85 -0
- package/runtime/validators/checks/validate-tasks-03.py +61 -0
- package/runtime/validators/checks/validate-tasks-04.py +118 -0
- package/runtime/validators/forbidden_actions.py +73 -3
- package/runtime/validators/lib/common.sh +5 -0
- package/runtime/validators/lib/fixtures.sh +7 -591
- package/runtime/validators/lib/paths.sh +13 -0
- package/runtime/validators/lib/runners.sh +6 -104
- package/runtime/validators/lib/summary.sh +1 -1
- package/runtime/validators/lib/validate-assets.sh +6 -56
- package/runtime/validators/lib/validate-prompt-metadata.sh +6 -257
- package/runtime/validators/lib/validate-tasks.sh +9 -294
- package/runtime/validators/validate-implementation-plan-stages.py +4 -4
- package/runtime/validators/validate-run.py +1369 -2654
- package/runtime/validators/validate-workflow.sh +56 -16
- package/runtime/validators/validate_improvement_report.py +2 -1
- package/runtime/validators/validate_session_conformance.py +295 -49
- package/dist/commands/execute/agent-prompt.d.mts +0 -1
- package/dist/commands/execute/agent-prompt.mjs +0 -24
- package/dist/commands/execute/agent-prompt.mjs.map +0 -1
- package/dist/commands/execute/codex-dispatch.d.mts +0 -3
- package/dist/commands/execute/codex-dispatch.mjs +0 -6
- package/dist/commands/execute/codex-dispatch.mjs.map +0 -1
- package/dist/commands/execute/codex-run.d.mts +0 -3
- package/dist/commands/execute/codex-run.mjs +0 -62
- package/dist/commands/execute/codex-run.mjs.map +0 -1
- package/dist/commands/execute/convergence.d.mts +0 -1
- package/dist/commands/execute/convergence.mjs +0 -38
- package/dist/commands/execute/convergence.mjs.map +0 -1
- package/dist/commands/execute/error-log.d.mts +0 -1
- package/dist/commands/execute/error-log.mjs +0 -18
- package/dist/commands/execute/error-log.mjs.map +0 -1
- package/dist/commands/execute/git-reconcile.d.mts +0 -1
- package/dist/commands/execute/git-reconcile.mjs +0 -30
- package/dist/commands/execute/git-reconcile.mjs.map +0 -1
- package/dist/commands/execute/handoff.d.mts +0 -1
- package/dist/commands/execute/handoff.mjs +0 -31
- package/dist/commands/execute/handoff.mjs.map +0 -1
- package/dist/commands/execute/incremental-carry.d.mts +0 -1
- package/dist/commands/execute/incremental-carry.mjs +0 -20
- package/dist/commands/execute/incremental-carry.mjs.map +0 -1
- package/dist/commands/execute/incremental-scope.d.mts +0 -1
- package/dist/commands/execute/incremental-scope.mjs +0 -29
- package/dist/commands/execute/incremental-scope.mjs.map +0 -1
- package/dist/commands/execute/integrate-stages.d.mts +0 -1
- package/dist/commands/execute/integrate-stages.mjs +0 -24
- package/dist/commands/execute/integrate-stages.mjs.map +0 -1
- package/dist/commands/execute/pane-title.d.mts +0 -1
- package/dist/commands/execute/pane-title.mjs +0 -20
- package/dist/commands/execute/pane-title.mjs.map +0 -1
- package/dist/commands/execute/plan-items.d.mts +0 -1
- package/dist/commands/execute/plan-items.mjs +0 -9
- package/dist/commands/execute/plan-items.mjs.map +0 -1
- package/dist/commands/execute/plan-validate.d.mts +0 -1
- package/dist/commands/execute/plan-validate.mjs +0 -68
- package/dist/commands/execute/plan-validate.mjs.map +0 -1
- package/dist/commands/execute/plan-verify.d.mts +0 -1
- package/dist/commands/execute/plan-verify.mjs +0 -43
- package/dist/commands/execute/plan-verify.mjs.map +0 -1
- package/dist/commands/execute/spawn-followups.d.mts +0 -1
- package/dist/commands/execute/spawn-followups.mjs +0 -22
- package/dist/commands/execute/spawn-followups.mjs.map +0 -1
- package/dist/commands/execute/team.d.mts +0 -3
- package/dist/commands/execute/team.mjs +0 -66
- package/dist/commands/execute/team.mjs.map +0 -1
- package/dist/commands/execute/token-usage.d.mts +0 -1
- package/dist/commands/execute/token-usage.mjs +0 -19
- package/dist/commands/execute/token-usage.mjs.map +0 -1
- package/dist/commands/execute/worker-audit-check.d.mts +0 -1
- package/dist/commands/execute/worker-audit-check.mjs +0 -34
- package/dist/commands/execute/worker-audit-check.mjs.map +0 -1
- package/dist/commands/execute/worker-dispatch.d.mts +0 -7
- package/dist/commands/execute/worker-dispatch.mjs +0 -64
- package/dist/commands/execute/worker-dispatch.mjs.map +0 -1
- package/dist/commands/execute/worker-state.d.mts +0 -1
- package/dist/commands/execute/worker-state.mjs +0 -28
- package/dist/commands/execute/worker-state.mjs.map +0 -1
- package/dist/commands/execute/worktree-lookup.d.mts +0 -1
- package/dist/commands/execute/worktree-lookup.mjs +0 -92
- package/dist/commands/execute/worktree-lookup.mjs.map +0 -1
- package/dist/commands/execute/worktree-status.d.mts +0 -1
- package/dist/commands/execute/worktree-status.mjs +0 -121
- package/dist/commands/execute/worktree-status.mjs.map +0 -1
- package/dist/commands/inspect/code-review.d.mts +0 -1
- package/dist/commands/inspect/code-review.mjs +0 -32
- package/dist/commands/inspect/code-review.mjs.map +0 -1
- package/dist/commands/inspect/container.d.mts +0 -1
- package/dist/commands/inspect/container.mjs +0 -25
- package/dist/commands/inspect/container.mjs.map +0 -1
- package/dist/commands/inspect/context-cost.d.mts +0 -1
- package/dist/commands/inspect/context-cost.mjs +0 -25
- package/dist/commands/inspect/context-cost.mjs.map +0 -1
- package/dist/commands/inspect/design-prep.d.mts +0 -1
- package/dist/commands/inspect/design-prep.mjs +0 -22
- package/dist/commands/inspect/design-prep.mjs.map +0 -1
- package/dist/commands/inspect/error-report.d.mts +0 -1
- package/dist/commands/inspect/error-report.mjs +0 -25
- package/dist/commands/inspect/error-report.mjs.map +0 -1
- package/dist/commands/inspect/error-zip.d.mts +0 -1
- package/dist/commands/inspect/error-zip.mjs +0 -24
- package/dist/commands/inspect/error-zip.mjs.map +0 -1
- package/dist/commands/inspect/log-report.d.mts +0 -1
- package/dist/commands/inspect/log-report.mjs +0 -26
- package/dist/commands/inspect/log-report.mjs.map +0 -1
- package/dist/commands/inspect/model-io.d.mts +0 -1
- package/dist/commands/inspect/model-io.mjs +0 -25
- package/dist/commands/inspect/model-io.mjs.map +0 -1
- package/dist/commands/inspect/profile-show.d.mts +0 -1
- package/dist/commands/inspect/profile-show.mjs +0 -28
- package/dist/commands/inspect/profile-show.mjs.map +0 -1
- package/dist/commands/inspect/recap.d.mts +0 -1
- package/dist/commands/inspect/recap.mjs +0 -30
- package/dist/commands/inspect/recap.mjs.map +0 -1
- package/dist/commands/inspect/resolve-task-key.d.mts +0 -1
- package/dist/commands/inspect/resolve-task-key.mjs +0 -24
- package/dist/commands/inspect/resolve-task-key.mjs.map +0 -1
- package/dist/commands/inspect/rollup.d.mts +0 -1
- package/dist/commands/inspect/rollup.mjs +0 -25
- package/dist/commands/inspect/rollup.mjs.map +0 -1
- package/dist/commands/inspect/run-audit.d.mts +0 -1
- package/dist/commands/inspect/run-audit.mjs +0 -25
- package/dist/commands/inspect/run-audit.mjs.map +0 -1
- package/dist/commands/inspect/set-work-status.d.mts +0 -1
- package/dist/commands/inspect/set-work-status.mjs +0 -29
- package/dist/commands/inspect/set-work-status.mjs.map +0 -1
- package/dist/commands/inspect/stage-map.d.mts +0 -1
- package/dist/commands/inspect/stage-map.mjs +0 -131
- package/dist/commands/inspect/stage-map.mjs.map +0 -1
- package/dist/commands/inspect/task-list.d.mts +0 -1
- package/dist/commands/inspect/task-list.mjs +0 -149
- package/dist/commands/inspect/task-list.mjs.map +0 -1
- package/dist/commands/inspect/task-show.d.mts +0 -1
- package/dist/commands/inspect/task-show.mjs +0 -108
- package/dist/commands/inspect/task-show.mjs.map +0 -1
- package/dist/commands/inspect/time-report.d.mts +0 -1
- package/dist/commands/inspect/time-report.mjs +0 -24
- package/dist/commands/inspect/time-report.mjs.map +0 -1
- package/dist/commands/inspect/usage-report.d.mts +0 -1
- package/dist/commands/inspect/usage-report.mjs +0 -23
- package/dist/commands/inspect/usage-report.mjs.map +0 -1
- package/dist/commands/inspect/user-response.d.mts +0 -1
- package/dist/commands/inspect/user-response.mjs +0 -35
- package/dist/commands/inspect/user-response.mjs.map +0 -1
- package/dist/commands/inspect/worker-liveness.d.mts +0 -1
- package/dist/commands/inspect/worker-liveness.mjs +0 -45
- package/dist/commands/inspect/worker-liveness.mjs.map +0 -1
- package/dist/commands/lifecycle/contract-check.d.mts +0 -1
- package/dist/commands/lifecycle/contract-check.mjs +0 -18
- package/dist/commands/lifecycle/contract-check.mjs.map +0 -1
- package/dist/commands/lifecycle/migrate.d.mts +0 -1
- package/dist/commands/lifecycle/migrate.mjs +0 -30
- package/dist/commands/lifecycle/migrate.mjs.map +0 -1
- package/dist/commands/lifecycle/model.d.mts +0 -1
- package/dist/commands/lifecycle/model.mjs +0 -22
- package/dist/commands/lifecycle/model.mjs.map +0 -1
- package/dist/commands/manager.d.mts +0 -3
- package/dist/commands/manager.mjs +0 -50
- package/dist/commands/manager.mjs.map +0 -1
- package/dist/commands/report/agent-activity.d.mts +0 -1
- package/dist/commands/report/agent-activity.mjs +0 -20
- package/dist/commands/report/agent-activity.mjs.map +0 -1
- package/dist/commands/report/approval-decision.d.mts +0 -1
- package/dist/commands/report/approval-decision.mjs +0 -21
- package/dist/commands/report/approval-decision.mjs.map +0 -1
- package/dist/commands/report/design-snapshot.d.mts +0 -1
- package/dist/commands/report/design-snapshot.mjs +0 -19
- package/dist/commands/report/design-snapshot.mjs.map +0 -1
- package/dist/commands/report/finalize.d.mts +0 -4
- package/dist/commands/report/finalize.mjs +0 -64
- package/dist/commands/report/finalize.mjs.map +0 -1
- package/dist/commands/report/inject-report-index.d.mts +0 -1
- package/dist/commands/report/inject-report-index.mjs +0 -21
- package/dist/commands/report/inject-report-index.mjs.map +0 -1
- package/dist/commands/report/render-final-report.d.mts +0 -1
- package/dist/commands/report/render-final-report.mjs +0 -23
- package/dist/commands/report/render-final-report.mjs.map +0 -1
- package/dist/commands/report/render-views.d.mts +0 -1
- package/dist/commands/report/render-views.mjs +0 -27
- package/dist/commands/report/render-views.mjs.map +0 -1
- package/dist/commands/report/translate.d.mts +0 -1
- package/dist/commands/report/translate.mjs +0 -33
- package/dist/commands/report/translate.mjs.map +0 -1
- package/runtime/bin/lib/okstra/tmux-pane.sh +0 -40
- package/runtime/bin/lib/okstra-ctl/cmd-batch.sh +0 -59
- package/runtime/bin/lib/okstra-ctl/cmd-list.sh +0 -35
- package/runtime/bin/lib/okstra-ctl/cmd-open.sh +0 -36
- package/runtime/bin/lib/okstra-ctl/cmd-projects.sh +0 -26
- package/runtime/bin/lib/okstra-ctl/cmd-reconcile.sh +0 -29
- package/runtime/bin/lib/okstra-ctl/cmd-reindex.sh +0 -38
- package/runtime/bin/lib/okstra-ctl/cmd-rerun.sh +0 -345
- package/runtime/bin/lib/okstra-ctl/cmd-show.sh +0 -27
- package/runtime/bin/lib/okstra-ctl/cmd-tail.sh +0 -92
- package/runtime/bin/lib/okstra-ctl/main.sh +0 -41
- package/runtime/bin/lib/okstra-ctl/prepare.sh +0 -31
- package/runtime/bin/lib/okstra-ctl/usage.sh +0 -23
- package/runtime/bin/okstra-central.sh +0 -152
- package/runtime/bin/okstra-incremental-carry.py +0 -10
- package/runtime/bin/okstra-incremental-scope.py +0 -10
- package/runtime/bin/okstra-team-reconcile.sh +0 -36
- package/runtime/python/okstra_ctl/agent_prompt_cli.py +0 -1156
- package/runtime/python/okstra_ctl/batch.py +0 -60
- package/runtime/python/okstra_ctl/clarification_items.py +0 -1050
- package/runtime/python/okstra_ctl/container_registry.py +0 -72
- package/runtime/python/okstra_ctl/improvement_assignment.py +0 -61
- package/runtime/python/okstra_ctl/resolver.py +0 -54
- package/runtime/python/okstra_ctl/team_reconcile.py +0 -275
- package/runtime/python/okstra_ctl/tmux.py +0 -134
- package/runtime/python/okstra_ctl/worktree.py +0 -1099
|
@@ -12,7 +12,13 @@ done
|
|
|
12
12
|
SCRIPT_DIR="$(cd -P "$(dirname "$SOURCE_PATH")" && pwd)"
|
|
13
13
|
WORKSPACE_ROOT="$(cd -P "$SCRIPT_DIR/.." && pwd)"
|
|
14
14
|
PROJECT_ID="okstra-validation"
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
# shellcheck source=lib/common.sh
|
|
17
|
+
source "$SCRIPT_DIR/lib/common.sh"
|
|
18
|
+
# shellcheck source=lib/paths.sh
|
|
19
|
+
source "$SCRIPT_DIR/lib/paths.sh"
|
|
20
|
+
|
|
21
|
+
PROJECT_ROOT="$(resolve_validation_project_root)"
|
|
16
22
|
export OKSTRA_HOME="${OKSTRA_HOME:-$PROJECT_ROOT/.okstra-home}"
|
|
17
23
|
|
|
18
24
|
WORKSPACE_APP_PATH="$PROJECT_ROOT"
|
|
@@ -34,22 +40,17 @@ SECONDARY_BRIEF_FILENAME="validation-brief-secondary.md"
|
|
|
34
40
|
|
|
35
41
|
# Workflow validation is a hermetic contract test for bundle prep / discovery
|
|
36
42
|
# artifacts / validator round-trips. It must not depend on the developer or CI
|
|
37
|
-
# machine having a preinstalled ~/.okstra runtime
|
|
38
|
-
#
|
|
43
|
+
# machine having a preinstalled ~/.okstra runtime. The synthetic prepare below
|
|
44
|
+
# reconciles the run index (okstra_ctl.run._reconcile_prior_runs); it stays off
|
|
45
|
+
# unrelated local state because OKSTRA_HOME is redirected above and the
|
|
46
|
+
# reconcile is scoped to this fixture's project id.
|
|
39
47
|
export OKSTRA_SKIP_INSTALL_CHECK="${OKSTRA_SKIP_INSTALL_CHECK:-1}"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
#
|
|
43
|
-
# every machine. cmux outranks tmux when present, so a maintainer running this
|
|
44
|
-
# from inside cmux would otherwise get the cmux adapter and a lead-session
|
|
45
|
-
# requirement this fixture never simulates. The cmux path has its own coverage
|
|
48
|
+
# Same reason as the one above: the synthetic run must render the same way on
|
|
49
|
+
# every machine. A maintainer running this from inside cmux would otherwise get
|
|
50
|
+
# the cmux adapter and a lead-session requirement this fixture never simulates. The cmux path has its own coverage
|
|
46
51
|
# in tests/run/test_cmux*.py and tests/contract/test_validate_session_conformance.py.
|
|
47
52
|
export CMUX_WORKSPACE_ID=""
|
|
48
53
|
|
|
49
|
-
# shellcheck source=lib/common.sh
|
|
50
|
-
source "$SCRIPT_DIR/lib/common.sh"
|
|
51
|
-
# shellcheck source=lib/paths.sh
|
|
52
|
-
source "$SCRIPT_DIR/lib/paths.sh"
|
|
53
54
|
LATEST_TASK_RELATIVE_PATH="$OKSTRA_DIR/discovery/latest-task.json"
|
|
54
55
|
TASK_CATALOG_RELATIVE_PATH="$OKSTRA_DIR/discovery/task-catalog.json"
|
|
55
56
|
# shellcheck source=lib/fixtures.sh
|
|
@@ -67,6 +68,23 @@ source "$SCRIPT_DIR/lib/summary.sh"
|
|
|
67
68
|
|
|
68
69
|
trap 'on_error "$LINENO"' ERR
|
|
69
70
|
|
|
71
|
+
# 기본(mktemp) 루트는 이 실행이 소유한다: 성공 시 제거, 실패 시 진단을 위해
|
|
72
|
+
# 보존. OKSTRA_VALIDATION_PROJECT_ROOT 가 지정된 루트의 수명은 호출자 소유.
|
|
73
|
+
cleanup_validation_root() {
|
|
74
|
+
local exit_code=$?
|
|
75
|
+
|
|
76
|
+
if [[ -n "${OKSTRA_VALIDATION_PROJECT_ROOT:-}" ]]; then
|
|
77
|
+
return
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
if [[ "$exit_code" -eq 0 ]]; then
|
|
81
|
+
rm -rf "$PROJECT_ROOT"
|
|
82
|
+
else
|
|
83
|
+
printf '[INFO] Validation root retained for inspection: %s\n' "$PROJECT_ROOT" >&2
|
|
84
|
+
fi
|
|
85
|
+
}
|
|
86
|
+
trap cleanup_validation_root EXIT
|
|
87
|
+
|
|
70
88
|
require_file "$OKSTRA_SCRIPT"
|
|
71
89
|
require_file "$RUN_VALIDATOR_PATH"
|
|
72
90
|
|
|
@@ -134,19 +152,19 @@ step "Preparing validator fixture artifacts for the primary task"
|
|
|
134
152
|
# repo root so the heredoc can import okstra_ctl.report_views and load
|
|
135
153
|
# inline assets from templates/reports/.
|
|
136
154
|
export OKSTRA_WORKSPACE_ROOT_FOR_FIXTURE="$WORKSPACE_ROOT"
|
|
137
|
-
if ! prepare_run_validator_fixture "$PRIMARY_TASK_GROUP" "$PRIMARY_TASK_ID" codex; then
|
|
155
|
+
if ! prepare_run_validator_fixture "$PRIMARY_TASK_GROUP" "$PRIMARY_TASK_ID" codex-analyser; then
|
|
138
156
|
fail "Failed to prepare validator fixture artifacts for the primary task"
|
|
139
157
|
fi
|
|
140
158
|
pass "Primary task validator fixture prepared with an intentionally missing Codex prompt history file"
|
|
141
159
|
|
|
142
160
|
step "Ensuring the run validator rejects attempted workers without prompt history"
|
|
143
|
-
if ! run_validator_expectation "$PRIMARY_TASK_GROUP" "$PRIMARY_TASK_ID" failed "Codex
|
|
161
|
+
if ! run_validator_expectation "$PRIMARY_TASK_GROUP" "$PRIMARY_TASK_ID" failed "Codex analyser with status \`timeout\` is missing worker prompt history file"; then
|
|
144
162
|
fail "Run validator did not reject the missing worker prompt history artifact"
|
|
145
163
|
fi
|
|
146
164
|
pass "Run validator rejected the missing worker prompt history artifact as expected"
|
|
147
165
|
|
|
148
166
|
step "Restoring the missing worker prompt history file and rerunning the validator"
|
|
149
|
-
if ! write_worker_prompt_history_fixture "$PRIMARY_TASK_GROUP" "$PRIMARY_TASK_ID" codex; then
|
|
167
|
+
if ! write_worker_prompt_history_fixture "$PRIMARY_TASK_GROUP" "$PRIMARY_TASK_ID" codex-analyser; then
|
|
150
168
|
fail "Failed to write the missing worker prompt history fixture"
|
|
151
169
|
fi
|
|
152
170
|
if ! run_validator_expectation "$PRIMARY_TASK_GROUP" "$PRIMARY_TASK_ID" passed; then
|
|
@@ -154,6 +172,28 @@ if ! run_validator_expectation "$PRIMARY_TASK_GROUP" "$PRIMARY_TASK_ID" passed;
|
|
|
154
172
|
fi
|
|
155
173
|
pass "Run validator passed after the missing worker prompt history artifact was restored"
|
|
156
174
|
|
|
175
|
+
step "Checking that the validated run is settled in the central run index"
|
|
176
|
+
# The global index (~/.okstra) records a run's start via record_start and never
|
|
177
|
+
# its end; validate-run is what writes the end
|
|
178
|
+
# (record_validation_in_central_index). Without that edge the row stays
|
|
179
|
+
# `prepared`/`running` forever and run-audit reads it as a run that has not
|
|
180
|
+
# produced its report yet. This run was validated twice here — `failed`, then
|
|
181
|
+
# `passed` — so a passing row also proves the second verdict overwrote the first.
|
|
182
|
+
RECENT_INDEX="$OKSTRA_HOME/recent.jsonl"
|
|
183
|
+
require_file "$RECENT_INDEX"
|
|
184
|
+
PRIMARY_RUN_ID="$PROJECT_ID/$PRIMARY_TASK_GROUP/$PRIMARY_TASK_ID/$TASK_TYPE/r01"
|
|
185
|
+
PRIMARY_INDEX_ROW="$(grep -F "\"runId\":\"$PRIMARY_RUN_ID\"" "$RECENT_INDEX" || true)"
|
|
186
|
+
if [[ -z "$PRIMARY_INDEX_ROW" ]]; then
|
|
187
|
+
fail "No central run-index row for $PRIMARY_RUN_ID"
|
|
188
|
+
fi
|
|
189
|
+
if ! printf '%s' "$PRIMARY_INDEX_ROW" | grep -qF '"status":"completed"'; then
|
|
190
|
+
fail "Central run-index row for $PRIMARY_RUN_ID is not completed: $PRIMARY_INDEX_ROW"
|
|
191
|
+
fi
|
|
192
|
+
if ! printf '%s' "$PRIMARY_INDEX_ROW" | grep -qF '"validation":"passed"'; then
|
|
193
|
+
fail "Central run-index row for $PRIMARY_RUN_ID does not carry the passing verdict: $PRIMARY_INDEX_ROW"
|
|
194
|
+
fi
|
|
195
|
+
pass "Central run-index row for the primary run reads completed/passed"
|
|
196
|
+
|
|
157
197
|
step "Running a second render-only okstra validation for the secondary task"
|
|
158
198
|
if ! run_okstra "$SECONDARY_TASK_GROUP" "$SECONDARY_TASK_ID" "$SECONDARY_BRIEF_FILENAME"; then
|
|
159
199
|
fail "Render-only validation for the secondary task failed"
|
|
@@ -26,6 +26,7 @@ from okstra_ctl.improvement_lenses import (
|
|
|
26
26
|
ABSOLUTE_CANDIDATE_CAP,
|
|
27
27
|
SOURCE_WORKERS,
|
|
28
28
|
)
|
|
29
|
+
from okstra_ctl.final_report_paths import final_report_data_path
|
|
29
30
|
from okstra_ctl.final_report_schema import (
|
|
30
31
|
load_schema_version,
|
|
31
32
|
validate as validate_final_report_data,
|
|
@@ -349,7 +350,7 @@ def validate_improvement_report(
|
|
|
349
350
|
errors.append(f"report file not found: {report_path}")
|
|
350
351
|
return ValidationResult(ok=False, errors=errors)
|
|
351
352
|
|
|
352
|
-
data_path = report_path
|
|
353
|
+
data_path = final_report_data_path(report_path)
|
|
353
354
|
if data_path.exists():
|
|
354
355
|
try:
|
|
355
356
|
data = json.loads(data_path.read_text(encoding="utf-8"))
|
|
@@ -45,14 +45,13 @@ from okstra_ctl.lead_events import ( # noqa: E402
|
|
|
45
45
|
LeadEventParseError,
|
|
46
46
|
read_lead_events,
|
|
47
47
|
)
|
|
48
|
-
from okstra_ctl.
|
|
48
|
+
from okstra_ctl.agent.activity import ACTIVITY_FIELDS # noqa: E402
|
|
49
49
|
from okstra_ctl.domain.host import HostNotRegistered # noqa: E402
|
|
50
50
|
from okstra_ctl.final_report_paths import final_report_data_path # noqa: E402
|
|
51
51
|
from okstra_ctl.registry.host_registry import default_host_registry # noqa: E402
|
|
52
52
|
from okstra_ctl.wrapper_status import read_wrapper_status # noqa: E402
|
|
53
53
|
|
|
54
54
|
_DISPATCHED_STATUSES = {"completed", "timeout", "error", "in-progress"}
|
|
55
|
-
_WORKER_DISPATCH_MODES = {"cli-wrapper", "mixed"}
|
|
56
55
|
_ATTEMPTED_STATUSES = {"completed", "timeout", "error"}
|
|
57
56
|
_LIVENESS_AUDIT_HEARTBEAT = "audit-heartbeat"
|
|
58
57
|
_LIVENESS_WRAPPER_STATUS = "wrapper-status"
|
|
@@ -90,6 +89,8 @@ _IN_STAGE_PREFIX = IN_STAGE_PREFIX
|
|
|
90
89
|
|
|
91
90
|
_LEAD_CONTRACT_CITE = "prompts/lead/okstra-lead-contract.md 'Entry guard (BLOCKING)'"
|
|
92
91
|
_HOST_RULES_CITE = "prompts/launch.template.md 'Host Orchestration Rules'"
|
|
92
|
+
_CONVERGENCE_CITE = "prompts/lead/convergence.md"
|
|
93
|
+
_PLAN_BODY_CITE = "prompts/lead/plan-body-verification.md"
|
|
93
94
|
|
|
94
95
|
|
|
95
96
|
class _EntryGuardRead(NamedTuple):
|
|
@@ -102,17 +103,29 @@ class _EntryGuardRead(NamedTuple):
|
|
|
102
103
|
cite: str
|
|
103
104
|
# True 면 run 이 이 파일을 instruction-set 에 스테이징했을 때만 요구한다.
|
|
104
105
|
staged_per_run: bool = False
|
|
106
|
+
# 이 행이 도는 task-type. None 이면 task-type 을 가리지 않는다.
|
|
107
|
+
task_types: frozenset[str] | None = None
|
|
108
|
+
# 이 PROGRESS phase 가 run 에 실제로 나타났을 때만 요구한다. None 이면
|
|
109
|
+
# 무조건 요구한다. task-type 목록을 손으로 적는 것보다 정확하다 — 수렴은
|
|
110
|
+
# 여러 phase 에서 돌고, 어느 run 이 실제로 돌렸는지는 그 run 의 체크포인트가
|
|
111
|
+
# 말해 준다.
|
|
112
|
+
required_when: str | None = None
|
|
105
113
|
|
|
106
114
|
|
|
115
|
+
_IMPLEMENTATION_ONLY = frozenset({"implementation"})
|
|
116
|
+
|
|
107
117
|
_ENTRY_GUARD_READS = (
|
|
108
118
|
_EntryGuardRead(
|
|
109
|
-
"_implementation-executor.md", ("phase-6-synthesis", "at Phase 5"),
|
|
119
|
+
"_implementation-executor.md", ("phase-6-synthesis", "at Phase 5"),
|
|
120
|
+
_LEAD_CONTRACT_CITE, task_types=_IMPLEMENTATION_ONLY,
|
|
110
121
|
),
|
|
111
122
|
_EntryGuardRead(
|
|
112
|
-
"_implementation-verifier.md", ("phase-6-synthesis", "at Phase 5"),
|
|
123
|
+
"_implementation-verifier.md", ("phase-6-synthesis", "at Phase 5"),
|
|
124
|
+
_LEAD_CONTRACT_CITE, task_types=_IMPLEMENTATION_ONLY,
|
|
113
125
|
),
|
|
114
126
|
_EntryGuardRead(
|
|
115
|
-
"_implementation-deliverable.md", ("phase-7-persist", "at Phase 6"),
|
|
127
|
+
"_implementation-deliverable.md", ("phase-7-persist", "at Phase 6"),
|
|
128
|
+
_LEAD_CONTRACT_CITE, task_types=_IMPLEMENTATION_ONLY,
|
|
116
129
|
),
|
|
117
130
|
# lead 프로파일 sidecar 가 아니라, run 이 instruction-set 에 스테이징한 host
|
|
118
131
|
# orchestration 규칙이다. 세 가지가 sidecar 와 다르다.
|
|
@@ -126,7 +139,26 @@ _ENTRY_GUARD_READS = (
|
|
|
126
139
|
# 파일 때문에 막히면 안 된다. 규칙이 없는 task-type 에 conformance 가 규칙을
|
|
127
140
|
# 요구하지 않는다는 원칙과 같은 판단이다.
|
|
128
141
|
_EntryGuardRead(
|
|
129
|
-
"host-orchestration-rules.md", None, _HOST_RULES_CITE, staged_per_run=True
|
|
142
|
+
"host-orchestration-rules.md", None, _HOST_RULES_CITE, staged_per_run=True,
|
|
143
|
+
task_types=_IMPLEMENTATION_ONLY,
|
|
144
|
+
),
|
|
145
|
+
# 수렴과 계획-본문 검증은 규칙 문서가 lazy 로 남는다 — Phase 1 intake 가
|
|
146
|
+
# 읽지 않으므로, 읽지 않은 lead 는 그 라운드를 자기 기억으로 돌린다. 그
|
|
147
|
+
# 두 문서에 lead 대상 MUST 의 절반 이상이 들어 있다.
|
|
148
|
+
#
|
|
149
|
+
# task-type 이 아니라 체크포인트로 조건을 건다: 라운드를 실제로 돌린 run 만
|
|
150
|
+
# 그 문서를 요구받는다.
|
|
151
|
+
_EntryGuardRead(
|
|
152
|
+
"convergence.md",
|
|
153
|
+
("phase-5.5-convergence", "before the first convergence round"),
|
|
154
|
+
_CONVERGENCE_CITE,
|
|
155
|
+
required_when="phase-5.5-convergence",
|
|
156
|
+
),
|
|
157
|
+
_EntryGuardRead(
|
|
158
|
+
"plan-body-verification.md",
|
|
159
|
+
("phase-5.5.9-plan-verify", "before the first plan-verify round"),
|
|
160
|
+
_PLAN_BODY_CITE,
|
|
161
|
+
required_when="phase-5.5.9-plan-verify",
|
|
130
162
|
),
|
|
131
163
|
)
|
|
132
164
|
|
|
@@ -325,7 +357,7 @@ def _collect_lead_evidence(
|
|
|
325
357
|
resolve_run_window,
|
|
326
358
|
resolve_team_needles_with_source,
|
|
327
359
|
)
|
|
328
|
-
from okstra_token_usage.paths import claude_project_dir
|
|
360
|
+
from okstra_token_usage.paths import claude_project_dir, find_session_jsonl
|
|
329
361
|
|
|
330
362
|
since, until = resolve_run_window(team_state_path, team_state, relax_start=False)
|
|
331
363
|
lead_sid = (team_state.get("lead") or {}).get("sessionId") or ""
|
|
@@ -337,12 +369,17 @@ def _collect_lead_evidence(
|
|
|
337
369
|
)
|
|
338
370
|
# `claude --resume` 로 fork 되거나 leadSessionIds[] 에 기록된 lead 세대는
|
|
339
371
|
# team 태그 needle 로 안 잡힐 수 있어 명시적으로 후보에 추가한다.
|
|
372
|
+
#
|
|
373
|
+
# 기록된 id 는 프로젝트 디렉터리 밖에 있을 수 있다 — 리드 세션의 cwd 가
|
|
374
|
+
# 대상 프로젝트 루트와 다르면(`okstra preflight --cwd <다른 프로젝트>`)
|
|
375
|
+
# transcript 는 리드 cwd 로 인코딩된 디렉터리에 놓인다. 그래서 id 로 찾는다.
|
|
340
376
|
proj_dir = claude_project_dir(project_root, projects_root)
|
|
341
|
-
|
|
377
|
+
recorded_ids = [lead_sid, *(team_state.get("leadSessionIds") or [])]
|
|
378
|
+
for sid in recorded_ids:
|
|
342
379
|
if not isinstance(sid, str) or not sid:
|
|
343
380
|
continue
|
|
344
|
-
candidate =
|
|
345
|
-
if candidate
|
|
381
|
+
candidate = find_session_jsonl(sid, project_root, projects_root)
|
|
382
|
+
if candidate is not None:
|
|
346
383
|
sessions.setdefault(sid, candidate)
|
|
347
384
|
evidence = _LeadEvidence(window=(since, until))
|
|
348
385
|
for sid, path in sorted(sessions.items()):
|
|
@@ -355,7 +392,8 @@ def _collect_lead_evidence(
|
|
|
355
392
|
evidence.sidecar_reads.setdefault(base, []).extend(ts_list)
|
|
356
393
|
if not evidence.scanned_files:
|
|
357
394
|
return None, (
|
|
358
|
-
f"lead session jsonl not found under {proj_dir} "
|
|
395
|
+
f"lead session jsonl not found under {proj_dir} nor anywhere under "
|
|
396
|
+
f"{(projects_root or proj_dir.parent)} by recorded session id "
|
|
359
397
|
f"(lead.sessionId={lead_sid or '<empty>'}) — selected adapter evidence "
|
|
360
398
|
"source `claude-jsonl` cannot verify the PROGRESS checkpoint / "
|
|
361
399
|
"implementation entry-guard conformance cannot be verified, which "
|
|
@@ -556,10 +594,22 @@ def _collect_artifact_lead_evidence(
|
|
|
556
594
|
def _conformance_evidence_source(
|
|
557
595
|
team_state: dict,
|
|
558
596
|
) -> tuple[str | None, str | None]:
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
597
|
+
"""리드의 증거가 어디 있는지 — 리드 회계가 정한다.
|
|
598
|
+
|
|
599
|
+
`dispatchMode` 는 **워커**를 어떻게 띄우는지를 말하는 필드다. 그 값이
|
|
600
|
+
리드 세션의 전사 여부를 바꾸지는 않는다: cmux 판으로 워커를 내보낸
|
|
601
|
+
Claude Code 리드도 자기 전사에 Read 와 PROGRESS 를 그대로 남긴다.
|
|
602
|
+
어댑터 자신도 그렇게 선언한다 —
|
|
603
|
+
`prompts/lead/adapters/cmux.md:18` 의 `sessionAccounting | unchanged`.
|
|
604
|
+
|
|
605
|
+
종전에는 이 함수가 어댑터 메타데이터를 보기 전에 `dispatchMode` 로
|
|
606
|
+
단락해 `artifact-only` 를 확정했다. 그러면 수집기가 `lead-events-*.jsonl`
|
|
607
|
+
만 보는데 거기에는 `okstra agent-activity append` 가 쓴 활동 레코드만
|
|
608
|
+
들어가고 리드 툴셋에는 PROGRESS 나 파일 읽기를 그리로 보낼 경로가 없다 —
|
|
609
|
+
실측(`fontsninja-nlpvibe` stage 10): artifact-only 로 progress 0·reads 0,
|
|
610
|
+
같은 run 을 리드 전사로 읽으면 progress 21·reads 5(entry guard 가 요구하는
|
|
611
|
+
네 파일 전부). 즉 어떤 리드가 무엇을 해도 통과할 수 없는 검사였다.
|
|
612
|
+
"""
|
|
563
613
|
adapter = team_state.get("leadAdapter")
|
|
564
614
|
if isinstance(adapter, dict):
|
|
565
615
|
accounting = str(adapter.get("sessionAccounting", "")).strip()
|
|
@@ -591,6 +641,85 @@ def _convergence_rounds_ran(run_dir: Path, suffix: str | None) -> bool:
|
|
|
591
641
|
return isinstance(doc, dict) and (doc.get("totalRounds") or 0) >= 1
|
|
592
642
|
|
|
593
643
|
|
|
644
|
+
def _verification_error_workers(run_dir: Path, suffix: str | None) -> set[str]:
|
|
645
|
+
"""이 run 의 convergence 에서 `verification-error` 를 낸 워커들."""
|
|
646
|
+
if not suffix:
|
|
647
|
+
return set()
|
|
648
|
+
path = run_dir / "state" / f"convergence-{suffix}.json"
|
|
649
|
+
try:
|
|
650
|
+
doc = json.loads(path.read_text(encoding="utf-8"))
|
|
651
|
+
except (OSError, json.JSONDecodeError):
|
|
652
|
+
return set()
|
|
653
|
+
if not isinstance(doc, dict):
|
|
654
|
+
return set()
|
|
655
|
+
workers: set[str] = set()
|
|
656
|
+
for finding in doc.get("findings") or []:
|
|
657
|
+
if not isinstance(finding, dict):
|
|
658
|
+
continue
|
|
659
|
+
for entry in finding.get("rounds") or []:
|
|
660
|
+
if not isinstance(entry, dict):
|
|
661
|
+
continue
|
|
662
|
+
for worker, vote in (entry.get("votes") or {}).items():
|
|
663
|
+
if isinstance(vote, dict) and vote.get("verdict") == "verification-error":
|
|
664
|
+
workers.add(str(worker))
|
|
665
|
+
return workers
|
|
666
|
+
|
|
667
|
+
|
|
668
|
+
def _contract_violation_agents(run_dir: Path, suffix: str | None) -> set[str]:
|
|
669
|
+
"""run 에러 로그에 `contract-violation` 으로 기록된 agent 들."""
|
|
670
|
+
if not suffix:
|
|
671
|
+
return set()
|
|
672
|
+
path = run_dir / "logs" / f"errors-{suffix}.jsonl"
|
|
673
|
+
try:
|
|
674
|
+
raw = path.read_text(encoding="utf-8")
|
|
675
|
+
except OSError:
|
|
676
|
+
return set()
|
|
677
|
+
agents: set[str] = set()
|
|
678
|
+
for line in raw.splitlines():
|
|
679
|
+
line = line.strip()
|
|
680
|
+
if not line:
|
|
681
|
+
continue
|
|
682
|
+
try:
|
|
683
|
+
row = json.loads(line)
|
|
684
|
+
except json.JSONDecodeError:
|
|
685
|
+
continue
|
|
686
|
+
if isinstance(row, dict) and row.get("errorType") == "contract-violation":
|
|
687
|
+
agent = row.get("agent") or row.get("workerId")
|
|
688
|
+
if agent:
|
|
689
|
+
agents.add(str(agent))
|
|
690
|
+
return agents
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
def _check_verification_errors_are_logged(
|
|
694
|
+
run_dir: Path, suffix: str | None, advisories: list[str]
|
|
695
|
+
) -> None:
|
|
696
|
+
"""`verification-error` 를 낸 워커는 에러 로그에도 남아야 한다.
|
|
697
|
+
|
|
698
|
+
계약(okstra-lead-contract.md §"Phase 5.5: Convergence loop")은 재검증 배치가
|
|
699
|
+
`verification-error` 로 끝나면 lead 가 위반마다 한 건씩
|
|
700
|
+
`okstra error-log append-observed --error-type contract-violation` 으로
|
|
701
|
+
기록하라고 요구한다. 기록이 없으면 워커 실패가 감사 흔적 없이 지나가고,
|
|
702
|
+
그 run 의 합의는 실제보다 적은 검증 위에 서 있다.
|
|
703
|
+
|
|
704
|
+
advisory 로 낸다. 이 파일의 구분을 따른다 — 검증기가 도는 시점에는 그 기록을
|
|
705
|
+
더 이상 쓸 수 없고(세션이 끝났다), 빠진 기록은 run 을 나중에 따라가기 어렵게
|
|
706
|
+
만들지 그 run 의 작업이 틀렸다는 뜻은 아니다.
|
|
707
|
+
"""
|
|
708
|
+
failed = _verification_error_workers(run_dir, suffix)
|
|
709
|
+
if not failed:
|
|
710
|
+
return
|
|
711
|
+
logged = _contract_violation_agents(run_dir, suffix)
|
|
712
|
+
missing = sorted(failed - logged)
|
|
713
|
+
if missing:
|
|
714
|
+
advisories.append(
|
|
715
|
+
"convergence verification-error not recorded in the run error log for: "
|
|
716
|
+
+ ", ".join(missing)
|
|
717
|
+
+ " — prompts/lead/okstra-lead-contract.md 'Phase 5.5: Convergence loop' "
|
|
718
|
+
"requires one `okstra error-log append-observed --error-type "
|
|
719
|
+
"contract-violation` event per violation."
|
|
720
|
+
)
|
|
721
|
+
|
|
722
|
+
|
|
594
723
|
def _plan_body_rounds_ran(run_dir: Path, suffix: str | None) -> int:
|
|
595
724
|
"""이 run 의 plan-body 검증이 실제로 돈 라운드 수.
|
|
596
725
|
|
|
@@ -852,19 +981,60 @@ def _allowed_automatic_rounds(self_fix_rounds: int, *, gating: bool = True) -> i
|
|
|
852
981
|
return 2 + max(self_fix_rounds, 0)
|
|
853
982
|
|
|
854
983
|
|
|
855
|
-
def
|
|
856
|
-
"""이번 런 상태 파일의 자가수정 횟수. 없으면 None — 호출자가 리포트로 폴백.
|
|
857
|
-
|
|
858
|
-
리포트 칸은 이어진 seq 의 누적이라, 이번 창의 `self-fix-applied` 건수와
|
|
859
|
-
비교하면 어긋난다.
|
|
860
|
-
"""
|
|
984
|
+
def _plan_body_state_document(run_dir: Path, suffix: str | None) -> dict | None:
|
|
861
985
|
if not suffix:
|
|
862
986
|
return None
|
|
863
987
|
try:
|
|
864
988
|
doc = json.loads(_plan_body_state_path(run_dir, suffix).read_text())
|
|
865
989
|
except (OSError, json.JSONDecodeError):
|
|
866
990
|
return None
|
|
867
|
-
if
|
|
991
|
+
return doc if isinstance(doc, dict) else None
|
|
992
|
+
|
|
993
|
+
|
|
994
|
+
def _plan_body_round_history_len(run_dir: Path, suffix: str | None) -> int | None:
|
|
995
|
+
doc = _plan_body_state_document(run_dir, suffix)
|
|
996
|
+
if doc is None:
|
|
997
|
+
return None
|
|
998
|
+
history = doc.get("roundHistory")
|
|
999
|
+
if not isinstance(history, list):
|
|
1000
|
+
return None
|
|
1001
|
+
return len(history)
|
|
1002
|
+
|
|
1003
|
+
|
|
1004
|
+
def _self_fix_event_expectation(
|
|
1005
|
+
run_dir: Path, suffix: str | None, self_fix_rounds: int,
|
|
1006
|
+
) -> int:
|
|
1007
|
+
"""selfFixRoundsApplied 는 마지막 라운드 번호다. 활동 건수는 그룹 라운드 수.
|
|
1008
|
+
|
|
1009
|
+
라운드 3 에 원인 그룹 4개를 한 번에 쓰면 필드 값은 3, 이벤트는 1이다.
|
|
1010
|
+
"""
|
|
1011
|
+
doc = _plan_body_state_document(run_dir, suffix)
|
|
1012
|
+
if doc is None:
|
|
1013
|
+
return self_fix_rounds
|
|
1014
|
+
projection = doc.get("planBodyVerification")
|
|
1015
|
+
groups = (
|
|
1016
|
+
projection.get("selfFixGroups")
|
|
1017
|
+
if isinstance(projection, dict)
|
|
1018
|
+
else None
|
|
1019
|
+
)
|
|
1020
|
+
if not isinstance(groups, list) or not groups:
|
|
1021
|
+
return self_fix_rounds
|
|
1022
|
+
rounds = {
|
|
1023
|
+
row.get("round")
|
|
1024
|
+
for row in groups
|
|
1025
|
+
if isinstance(row, dict) and isinstance(row.get("round"), int)
|
|
1026
|
+
}
|
|
1027
|
+
return len(rounds) if rounds else self_fix_rounds
|
|
1028
|
+
|
|
1029
|
+
|
|
1030
|
+
def _self_fix_rounds_from_state(run_dir: Path, suffix: str | None) -> int | None:
|
|
1031
|
+
"""이번 런 상태 파일의 자가수정 횟수. 없으면 None — 호출자가 리포트로 폴백.
|
|
1032
|
+
|
|
1033
|
+
리포트 칸은 이어진 seq 의 누적이라, 이번 창의 `self-fix-applied` 건수와
|
|
1034
|
+
비교하면 어긋난다.
|
|
1035
|
+
"""
|
|
1036
|
+
doc = _plan_body_state_document(run_dir, suffix)
|
|
1037
|
+
if doc is None:
|
|
868
1038
|
return None
|
|
869
1039
|
projection = doc.get("planBodyVerification")
|
|
870
1040
|
value = (
|
|
@@ -886,7 +1056,11 @@ def _is_plan_body_verification_activity(event: LeadEvent) -> bool:
|
|
|
886
1056
|
본문이 아니다. 픽스처 요약(`verification-round-completed for …`)은 본문이다.
|
|
887
1057
|
"""
|
|
888
1058
|
summary = str(event.details.get("summary") or "").lower()
|
|
889
|
-
|
|
1059
|
+
if "adversarial reverify" in summary or "adversarial re-verify" in summary:
|
|
1060
|
+
return False
|
|
1061
|
+
if "critic-gap" in summary:
|
|
1062
|
+
return False
|
|
1063
|
+
return True
|
|
890
1064
|
|
|
891
1065
|
|
|
892
1066
|
def _plan_body_verification(report_data: Mapping[str, Any]) -> Mapping[str, Any] | None:
|
|
@@ -1036,7 +1210,11 @@ def _check_activity_round_counts(
|
|
|
1036
1210
|
f"roundCount={verification_rounds}, "
|
|
1037
1211
|
f"humanReverificationRounds={sorted(user_reverification_rounds)}."
|
|
1038
1212
|
)
|
|
1039
|
-
|
|
1213
|
+
history_len = _plan_body_round_history_len(run_dir, suffix)
|
|
1214
|
+
if (
|
|
1215
|
+
recorded_verifications != automatic_rounds
|
|
1216
|
+
and history_len != verification_rounds
|
|
1217
|
+
):
|
|
1040
1218
|
errors.append(
|
|
1041
1219
|
"activity contract: `verification-round-completed` count must match "
|
|
1042
1220
|
f"automatic plan-body rounds={automatic_rounds} from "
|
|
@@ -1045,10 +1223,13 @@ def _check_activity_round_counts(
|
|
|
1045
1223
|
f"recorded={recorded_verifications}."
|
|
1046
1224
|
)
|
|
1047
1225
|
recorded_self_fixes = len(indexed.get("self-fix-applied", []))
|
|
1048
|
-
|
|
1226
|
+
expected_self_fixes = _self_fix_event_expectation(
|
|
1227
|
+
run_dir, suffix, self_fix_rounds,
|
|
1228
|
+
)
|
|
1229
|
+
if recorded_self_fixes != expected_self_fixes:
|
|
1049
1230
|
errors.append(
|
|
1050
1231
|
"activity contract: `self-fix-applied` count must match "
|
|
1051
|
-
f"selfFixRoundsApplied={
|
|
1232
|
+
f"selfFixRoundsApplied={expected_self_fixes}; recorded={recorded_self_fixes}."
|
|
1052
1233
|
)
|
|
1053
1234
|
|
|
1054
1235
|
|
|
@@ -1254,6 +1435,7 @@ def _check_progress_checkpoints(
|
|
|
1254
1435
|
run_dir: Path,
|
|
1255
1436
|
suffix: str | None,
|
|
1256
1437
|
report_path: Path,
|
|
1438
|
+
task_type: str,
|
|
1257
1439
|
errors: list[str],
|
|
1258
1440
|
advisories: list[str] | None = None,
|
|
1259
1441
|
) -> None:
|
|
@@ -1293,7 +1475,7 @@ def _check_progress_checkpoints(
|
|
|
1293
1475
|
"phase-3-team-create",
|
|
1294
1476
|
any_dispatched,
|
|
1295
1477
|
"in Phase 3 after recording teamCreate in team-state — the "
|
|
1296
|
-
"`using implicit team
|
|
1478
|
+
"`using implicit team` line, or the "
|
|
1297
1479
|
"`skipped (concurrent-run)` variant in the concurrent-run path",
|
|
1298
1480
|
)
|
|
1299
1481
|
_check_worker_checkpoint_lines(by_phase, analysis_workers, narration)
|
|
@@ -1313,6 +1495,28 @@ def _check_progress_checkpoints(
|
|
|
1313
1495
|
report_writer_dispatched,
|
|
1314
1496
|
"at the start of Phase 6 (report-writer dispatch)",
|
|
1315
1497
|
)
|
|
1498
|
+
if task_type == "implementation":
|
|
1499
|
+
# 이 run 이 실행하는 stage 의 공지/완료 라인 — implementation 전용 두
|
|
1500
|
+
# 체크포인트. 완료 라인은 carry 증거를 파싱한 뒤에만 낼 수 있으므로
|
|
1501
|
+
# implementer 가 완주한 run 에만 요구한다.
|
|
1502
|
+
require(
|
|
1503
|
+
"phase-5-stage",
|
|
1504
|
+
any_dispatched,
|
|
1505
|
+
"immediately before the Executor dispatch — `stage=<N> title=<title> "
|
|
1506
|
+
"steps=<count>` from the approved plan's Stage Map",
|
|
1507
|
+
)
|
|
1508
|
+
implementer_completed = any(
|
|
1509
|
+
"implementer"
|
|
1510
|
+
in _norm(str(w.get("workerId") or "") + str(w.get("role") or ""))
|
|
1511
|
+
and str(w.get("status", "")).strip() == "completed"
|
|
1512
|
+
for w in workers
|
|
1513
|
+
)
|
|
1514
|
+
require(
|
|
1515
|
+
"phase-5-stage-complete",
|
|
1516
|
+
implementer_completed,
|
|
1517
|
+
"immediately after parsing the Executor's `### Stage Carry Evidence` "
|
|
1518
|
+
"block — `stage=<N> steps=<done>/<count>` from its stepResults",
|
|
1519
|
+
)
|
|
1316
1520
|
require("phase-7-persist", True, "at the start of Phase 7")
|
|
1317
1521
|
_check_batch_cleanup_checkpoints(
|
|
1318
1522
|
by_phase, convergence_ran, report_writer_dispatched, narration
|
|
@@ -1375,6 +1579,25 @@ def _check_heartbeat_sidecar(path: Path, worker_id: str, errors: list[str]) -> N
|
|
|
1375
1579
|
f"although the worker result `{result_file.name}` exists — every "
|
|
1376
1580
|
"stage must append its own line (agents/workers/claude-worker.md 'Heartbeat')."
|
|
1377
1581
|
)
|
|
1582
|
+
# implementer(Executor)는 지금 실행 중인 plan step 을 하트비트로 알린다
|
|
1583
|
+
# (_implementation-executor.md 'Per-step heartbeat'). result 를 남기고 완주한
|
|
1584
|
+
# executor 의 사이드카에 step 라인이 하나도 없으면 이 run 의 유일한 스텝 단위
|
|
1585
|
+
# 진행 신호가 없었던 것이다. cli-wrapper executor 는 wrapper-status 경로라
|
|
1586
|
+
# 이 함수에 들어오지 않는다.
|
|
1587
|
+
if (
|
|
1588
|
+
"implementer" in _norm(worker_id)
|
|
1589
|
+
and result_file.exists()
|
|
1590
|
+
and not any(
|
|
1591
|
+
stage.removeprefix(_IN_STAGE_PREFIX).startswith("step-")
|
|
1592
|
+
for stage, _ in entries
|
|
1593
|
+
)
|
|
1594
|
+
):
|
|
1595
|
+
errors.append(
|
|
1596
|
+
f"`{rel}`: implementer heartbeat has no `- PROGRESS: step-<k> <ISO>` "
|
|
1597
|
+
"line although the worker result exists — the executor MUST announce "
|
|
1598
|
+
"each plan step as it starts "
|
|
1599
|
+
"(prompts/profiles/_implementation-executor.md 'Per-step heartbeat')."
|
|
1600
|
+
)
|
|
1378
1601
|
prev: datetime | None = None
|
|
1379
1602
|
prev_stage = ""
|
|
1380
1603
|
for stage, raw_ts in entries:
|
|
@@ -1483,10 +1706,10 @@ def _check_cmux_adapter_read(
|
|
|
1483
1706
|
return
|
|
1484
1707
|
if evidence.sidecar_reads.get(CMUX_ADAPTER_BASENAME):
|
|
1485
1708
|
return
|
|
1486
|
-
|
|
1487
|
-
if
|
|
1488
|
-
# grok 같은 artifact-only 호스트는 Read 도구 기록이 없다.
|
|
1489
|
-
#
|
|
1709
|
+
source, _error = _conformance_evidence_source(team_state)
|
|
1710
|
+
if source == "artifact-only":
|
|
1711
|
+
# grok 같은 artifact-only 호스트는 Read 도구 기록이 없다. 면제 사유는
|
|
1712
|
+
# 리드가 읽기를 남기지 못한다는 것이지 워커를 어떻게 띄웠는지가 아니다.
|
|
1490
1713
|
return
|
|
1491
1714
|
errors.append(
|
|
1492
1715
|
f"cmux adapter: no read of `{CMUX_ADAPTER_BASENAME}` (a `Read` call or a "
|
|
@@ -1497,32 +1720,53 @@ def _check_cmux_adapter_read(
|
|
|
1497
1720
|
)
|
|
1498
1721
|
|
|
1499
1722
|
|
|
1500
|
-
def
|
|
1501
|
-
|
|
1723
|
+
def _entry_guard_rows(
|
|
1724
|
+
task_type: str, seen_phases: set[str], instruction_set: Path | None
|
|
1725
|
+
) -> list[_EntryGuardRead]:
|
|
1726
|
+
"""이 run 에 실제로 걸리는 entry-guard 행."""
|
|
1727
|
+
rows = []
|
|
1728
|
+
for row in _ENTRY_GUARD_READS:
|
|
1729
|
+
if row.task_types is not None and task_type not in row.task_types:
|
|
1730
|
+
continue
|
|
1731
|
+
if row.required_when is not None and row.required_when not in seen_phases:
|
|
1732
|
+
# 그 라운드를 돌지 않은 run 이다. 돌지 않은 일의 규칙을 요구하지 않는다.
|
|
1733
|
+
continue
|
|
1734
|
+
if row.staged_per_run and not (
|
|
1735
|
+
instruction_set and (instruction_set / row.basename).is_file()
|
|
1736
|
+
):
|
|
1737
|
+
continue
|
|
1738
|
+
rows.append(row)
|
|
1739
|
+
return rows
|
|
1740
|
+
|
|
1741
|
+
|
|
1742
|
+
def _check_entry_guard_reads(
|
|
1743
|
+
evidence: _LeadEvidence,
|
|
1744
|
+
errors: list[str],
|
|
1745
|
+
instruction_set: Path | None,
|
|
1746
|
+
task_type: str,
|
|
1502
1747
|
) -> None:
|
|
1503
1748
|
"""검사 3 — entry guard. fresh-read 규칙(이전 run 기억으로 갈음 불가)은 run
|
|
1504
1749
|
윈도우 스코핑이 보장한다: 이번 윈도우 안의 Read 만 증거로 인정된다.
|
|
1505
1750
|
|
|
1506
1751
|
anchor 가 있는 행은 존재 + 순서를, anchor 가 `None` 인 행은 존재만 본다.
|
|
1507
|
-
`staged_per_run` 행은 이 run 의 instruction-set 에 실제로 있을
|
|
1752
|
+
`staged_per_run` 행은 이 run 의 instruction-set 에 실제로 있을 때만,
|
|
1753
|
+
`required_when` 행은 그 PROGRESS 체크포인트가 이 run 에 있을 때만 요구한다."""
|
|
1754
|
+
seen_phases = {phase for _ts, phase, _line in evidence.progress}
|
|
1755
|
+
anchor_phases = {row.anchor[0] for row in _ENTRY_GUARD_READS if row.anchor}
|
|
1508
1756
|
anchors: dict[str, str] = {}
|
|
1509
1757
|
for ts, phase, _line in evidence.progress: # progress 는 ts 정렬 — 첫 항목이 최초 발생
|
|
1510
|
-
if phase in
|
|
1758
|
+
if phase in anchor_phases and ts:
|
|
1511
1759
|
anchors.setdefault(phase, ts)
|
|
1512
|
-
for row in
|
|
1513
|
-
if row.staged_per_run and not (
|
|
1514
|
-
instruction_set and (instruction_set / row.basename).is_file()
|
|
1515
|
-
):
|
|
1516
|
-
continue
|
|
1760
|
+
for row in _entry_guard_rows(task_type, seen_phases, instruction_set):
|
|
1517
1761
|
ts_list = evidence.sidecar_reads.get(row.basename) or []
|
|
1518
1762
|
if not ts_list:
|
|
1519
1763
|
demand = (
|
|
1520
|
-
f"it MUST be read fresh {row.anchor[1]}
|
|
1764
|
+
f"it MUST be read fresh {row.anchor[1]}"
|
|
1521
1765
|
if row.anchor
|
|
1522
1766
|
else "the staged copy MUST be read at least once inside that window"
|
|
1523
1767
|
)
|
|
1524
1768
|
errors.append(
|
|
1525
|
-
f"
|
|
1769
|
+
f"entry guard: no read of `{row.basename}` (a `Read` call "
|
|
1526
1770
|
f"or a shell command naming it) found in "
|
|
1527
1771
|
f"the selected adapter evidence source within this run's window — "
|
|
1528
1772
|
f"{demand} ({row.cite})."
|
|
@@ -1534,7 +1778,7 @@ def _check_implementation_entry_guard(
|
|
|
1534
1778
|
anchor_ts = anchors.get(anchor_phase)
|
|
1535
1779
|
if anchor_ts and min(ts_list) >= anchor_ts:
|
|
1536
1780
|
errors.append(
|
|
1537
|
-
f"
|
|
1781
|
+
f"entry guard: `{row.basename}` was first read at "
|
|
1538
1782
|
f"{min(ts_list)}, not before the first `PROGRESS: {anchor_phase}` "
|
|
1539
1783
|
f"line ({anchor_ts}) — it must be loaded {when}, before "
|
|
1540
1784
|
f"that checkpoint ({row.cite})."
|
|
@@ -1595,9 +1839,11 @@ def validate_session_conformance(
|
|
|
1595
1839
|
run_dir,
|
|
1596
1840
|
suffix,
|
|
1597
1841
|
report_path,
|
|
1842
|
+
task_type,
|
|
1598
1843
|
result.errors,
|
|
1599
1844
|
result.advisories,
|
|
1600
1845
|
)
|
|
1846
|
+
_check_verification_errors_are_logged(run_dir, suffix, result.advisories)
|
|
1601
1847
|
_check_activity_contract(
|
|
1602
1848
|
evidence,
|
|
1603
1849
|
team_state,
|
|
@@ -1608,10 +1854,10 @@ def validate_session_conformance(
|
|
|
1608
1854
|
result.errors,
|
|
1609
1855
|
)
|
|
1610
1856
|
_check_cmux_adapter_read(evidence, team_state, result.errors)
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1857
|
+
_check_entry_guard_reads(
|
|
1858
|
+
evidence,
|
|
1859
|
+
result.errors,
|
|
1860
|
+
_instruction_set_dir(run_dir, suffix, project_root),
|
|
1861
|
+
task_type,
|
|
1862
|
+
)
|
|
1617
1863
|
return result
|