okstra 0.186.7 → 0.188.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 +107 -40
- 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 +39 -38
- 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 +47 -22
- 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/adapters/cmux.md +3 -3
- package/runtime/prompts/lead/convergence.md +99 -88
- 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 +35 -5
- 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 +63 -22
- package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +20 -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} +16 -2
- 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 +228 -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 +605 -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 +287 -10
- 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 +32 -4
- package/runtime/python/okstra_ctl/contract_graph_cli.py +7 -0
- package/runtime/python/okstra_ctl/convergence.py +107 -16
- 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 +236 -49
- package/runtime/python/okstra_ctl/dispatch_state.py +417 -41
- 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 +28 -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/exact_coverage.py +5 -0
- 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 +319 -17
- 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 +32 -13
- 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 +4 -8
- 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 +213 -16
- 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 +220 -34
- package/runtime/python/okstra_ctl/report_projections.py +8 -2
- package/runtime/python/okstra_ctl/report_synthesis_packet.py +393 -1
- package/runtime/python/okstra_ctl/report_translation.py +2 -35
- package/runtime/python/okstra_ctl/report_view_artifacts.py +42 -2
- 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/verdict_blocks.py +28 -8
- 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 +58 -17
- 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/antigravity.py +50 -12
- 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 +171 -36
- 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 +23 -8
- 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 +3 -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 +1363 -2643
- 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
|
@@ -7,10 +7,12 @@ import subprocess
|
|
|
7
7
|
import time
|
|
8
8
|
from dataclasses import dataclass, field, replace
|
|
9
9
|
from datetime import datetime, timezone
|
|
10
|
+
import os
|
|
10
11
|
from pathlib import Path
|
|
11
12
|
from typing import Any, Mapping, Sequence
|
|
12
13
|
|
|
13
14
|
from .dispatch_state import (
|
|
15
|
+
CompletedWithoutResultError,
|
|
14
16
|
BACKEND_CLI_WRAPPER,
|
|
15
17
|
BACKEND_CMUX_PANE,
|
|
16
18
|
BACKEND_MIXED,
|
|
@@ -27,6 +29,7 @@ from .dispatch_state import (
|
|
|
27
29
|
load_json_object as _load_json_object,
|
|
28
30
|
link_agent_dispatch_result as _link_agent_dispatch_result,
|
|
29
31
|
missing_completion_paths as _missing_completion_paths,
|
|
32
|
+
_plan_verify_result_aliases,
|
|
30
33
|
mutate_team_state as _mutate_team_state,
|
|
31
34
|
require_string as _require_string,
|
|
32
35
|
resolve_project_path as _resolve_project_path,
|
|
@@ -54,7 +57,7 @@ from .assignment_resolver import (
|
|
|
54
57
|
from .application.open_worker import open_worker
|
|
55
58
|
from .domain.host import HostSessionContext
|
|
56
59
|
from .domain.provider import HostModelBinding, ServedModelAttestation
|
|
57
|
-
from .domain.worker_exec import SERVED_MODEL_MISMATCH_EXIT_CODE
|
|
60
|
+
from .domain.worker_exec import NO_RESULT_EXIT_CODE, SERVED_MODEL_MISMATCH_EXIT_CODE
|
|
58
61
|
from .domain.worker_runtime import (
|
|
59
62
|
SURFACE_CMUX_PANE,
|
|
60
63
|
EnvironmentBlocked,
|
|
@@ -90,7 +93,7 @@ from .initial_prompt_materialization import (
|
|
|
90
93
|
PromptDeliveryMode,
|
|
91
94
|
materialize_initial_prompts,
|
|
92
95
|
)
|
|
93
|
-
from .
|
|
96
|
+
from .agent.invocation import AgentInvocationError, materialize_retry_invocation
|
|
94
97
|
from .path_hints import hydrate_active_run_context
|
|
95
98
|
from .schema_excerpt import (
|
|
96
99
|
bundle_excerpt_path,
|
|
@@ -102,6 +105,7 @@ from .worker_audit_ledger import (
|
|
|
102
105
|
check_worker_results_audit,
|
|
103
106
|
parse_worker_result_name,
|
|
104
107
|
)
|
|
108
|
+
from .worker_artifacts import worker_provider_id
|
|
105
109
|
from .worker_prompt_body import REPORT_WRITER_WORKER_ID
|
|
106
110
|
from .worker_prompt_headers import (
|
|
107
111
|
WorkerPromptHeaderError,
|
|
@@ -121,6 +125,7 @@ from .write_policy import (
|
|
|
121
125
|
WritePolicy,
|
|
122
126
|
build_invocation_write_contract,
|
|
123
127
|
planned_paths_from_run_manifest,
|
|
128
|
+
task_root_from_run_manifest,
|
|
124
129
|
write_enforcement_from_payload,
|
|
125
130
|
write_policy_from_payload,
|
|
126
131
|
)
|
|
@@ -914,24 +919,32 @@ def _select_workers(
|
|
|
914
919
|
options,
|
|
915
920
|
)
|
|
916
921
|
supported = set(options.supported_worker_wrappers)
|
|
922
|
+
state = team_state or {}
|
|
923
|
+
|
|
924
|
+
def _wrapper_supported(worker_id: str) -> bool:
|
|
925
|
+
return _worker_provider(state, worker_id, options) in supported
|
|
926
|
+
|
|
917
927
|
selected = (
|
|
918
928
|
list(requested_workers)
|
|
919
929
|
if requested_workers
|
|
920
930
|
else [
|
|
921
931
|
worker
|
|
922
932
|
for worker in recommended
|
|
923
|
-
if worker
|
|
933
|
+
if _wrapper_supported(worker) and worker != REPORT_WRITER_WORKER_ID
|
|
924
934
|
]
|
|
925
935
|
)
|
|
926
936
|
unknown = [worker for worker in selected if worker not in recommended]
|
|
927
937
|
if unknown:
|
|
928
938
|
raise DispatchError("requested worker(s) are not in this run roster: " + ", ".join(unknown))
|
|
929
|
-
unsupported = [worker for worker in selected if
|
|
939
|
+
unsupported = [worker for worker in selected if not _wrapper_supported(worker)]
|
|
930
940
|
if unsupported:
|
|
931
941
|
allowed = ", ".join(sorted(supported))
|
|
932
942
|
raise DispatchError(
|
|
933
943
|
f"unsupported {options.unsupported_worker_label} worker(s): "
|
|
934
|
-
+ ", ".join(
|
|
944
|
+
+ ", ".join(
|
|
945
|
+
f"{worker} (provider {_worker_provider(state, worker, options)})"
|
|
946
|
+
for worker in unsupported
|
|
947
|
+
)
|
|
935
948
|
+ f" (dispatcher supports: {allowed})"
|
|
936
949
|
)
|
|
937
950
|
return selected
|
|
@@ -1006,28 +1019,20 @@ def _translator_job_from_reservation(
|
|
|
1006
1019
|
for row in collection
|
|
1007
1020
|
if isinstance(row, Mapping)
|
|
1008
1021
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
and reservation.get("audience") == "translator"
|
|
1018
|
-
and reservation.get("dispatchKind") == "translator"
|
|
1019
|
-
and reservation.get("dutyId") == "translator"
|
|
1020
|
-
and reservation.get("participantRef") == execution.get("participantRef")
|
|
1021
|
-
and reservation.get("roleExecutionRef") == execution.get("roleExecutionRef")
|
|
1022
|
-
and _build_dispatch_id(
|
|
1023
|
-
str(reservation.get("invocationId") or ""),
|
|
1024
|
-
int(reservation.get("attempt") or 0),
|
|
1025
|
-
) not in dispatched_ids
|
|
1026
|
-
):
|
|
1027
|
-
candidates.append(reservation)
|
|
1022
|
+
run_manifest_rel = _string_value(manifest.get("runManifestPath"))
|
|
1023
|
+
candidates, seen = _translator_reservation_candidates(
|
|
1024
|
+
project_root,
|
|
1025
|
+
reservation_root,
|
|
1026
|
+
execution=execution,
|
|
1027
|
+
dispatched_ids=dispatched_ids,
|
|
1028
|
+
run_manifest_rel=run_manifest_rel,
|
|
1029
|
+
)
|
|
1028
1030
|
if len(candidates) != 1:
|
|
1031
|
+
run_label = run_manifest_rel or "run manifest path unknown"
|
|
1029
1032
|
raise DispatchError(
|
|
1030
|
-
"translator dispatch requires exactly one canonical invocation
|
|
1033
|
+
"translator dispatch requires exactly one canonical invocation "
|
|
1034
|
+
f"reservation for this run ({run_label}); found {len(candidates)}. "
|
|
1035
|
+
"Translator reservations seen: " + ("; ".join(seen) if seen else "none")
|
|
1031
1036
|
)
|
|
1032
1037
|
reservation = candidates[0]
|
|
1033
1038
|
prompt_path = _resolve_project_path(
|
|
@@ -1087,6 +1092,86 @@ def _translator_job_from_reservation(
|
|
|
1087
1092
|
)
|
|
1088
1093
|
|
|
1089
1094
|
|
|
1095
|
+
def _translator_reservation_candidates(
|
|
1096
|
+
project_root: Path,
|
|
1097
|
+
reservation_root: Path,
|
|
1098
|
+
*,
|
|
1099
|
+
execution: Mapping[str, Any],
|
|
1100
|
+
dispatched_ids: set[str],
|
|
1101
|
+
run_manifest_rel: str,
|
|
1102
|
+
) -> tuple[list[Mapping[str, Any]], list[str]]:
|
|
1103
|
+
"""이 run 이 디스패치할 수 있는 translator 예약과, 본 예약 전부의 요약.
|
|
1104
|
+
|
|
1105
|
+
예약 디렉터리(`prompts/.agent-invocations/`)는 run 이 아니라 task type 단위라
|
|
1106
|
+
같은 task 의 이전 run 이 남긴 translator 예약이 함께 놓인다. translator 는
|
|
1107
|
+
`assignmentRef` 가 접미 없는 `translator` 하나이고, 이전 run 의 디스패치는
|
|
1108
|
+
이번 run 의 team-state 에 없으므로 "아직 디스패치 안 됨" 으로 읽혀 후보가
|
|
1109
|
+
둘이 됐다 — 두 번째 run 부터 번역이 영영 막혔다(2026-09-03 실측,
|
|
1110
|
+
fontsninja-v3-site dev-10626-1 r02·r04). 예약 자체는 run 을 모르지만 그 옆의
|
|
1111
|
+
`.meta.json` 은 `contractSource.runManifestPath` 로 자기 run 을 안다. 그
|
|
1112
|
+
값을 이번 run 의 `runManifestPath` 와 대조한다. 매니페스트가 그 경로를 안
|
|
1113
|
+
가진 레거시 run 은 종전대로 run 을 가리지 않는다.
|
|
1114
|
+
"""
|
|
1115
|
+
candidates: list[Mapping[str, Any]] = []
|
|
1116
|
+
seen: list[str] = []
|
|
1117
|
+
for path in sorted(reservation_root.glob("*.json")):
|
|
1118
|
+
reservation = _load_json_object(path, "agent invocation reservation")
|
|
1119
|
+
if not (
|
|
1120
|
+
set(reservation) == _TRANSLATOR_RESERVATION_KEYS
|
|
1121
|
+
and reservation.get("schemaVersion") == "2.0"
|
|
1122
|
+
and reservation.get("executionIdentityVersion") == 2
|
|
1123
|
+
and reservation.get("assignmentRef") == "translator"
|
|
1124
|
+
and reservation.get("audience") == "translator"
|
|
1125
|
+
and reservation.get("dispatchKind") == "translator"
|
|
1126
|
+
and reservation.get("dutyId") == "translator"
|
|
1127
|
+
):
|
|
1128
|
+
continue
|
|
1129
|
+
invocation_id = str(reservation.get("invocationId") or "")
|
|
1130
|
+
reservation_run = _reservation_run_manifest_rel(project_root, reservation)
|
|
1131
|
+
dispatched = _build_dispatch_id(
|
|
1132
|
+
invocation_id, int(reservation.get("attempt") or 0),
|
|
1133
|
+
) in dispatched_ids
|
|
1134
|
+
seen.append(
|
|
1135
|
+
f"{invocation_id} (run {reservation_run or 'unknown'}"
|
|
1136
|
+
+ (", dispatched" if dispatched else "")
|
|
1137
|
+
+ ")"
|
|
1138
|
+
)
|
|
1139
|
+
if dispatched:
|
|
1140
|
+
continue
|
|
1141
|
+
if (
|
|
1142
|
+
reservation.get("participantRef") != execution.get("participantRef")
|
|
1143
|
+
or reservation.get("roleExecutionRef") != execution.get("roleExecutionRef")
|
|
1144
|
+
):
|
|
1145
|
+
continue
|
|
1146
|
+
if run_manifest_rel and (
|
|
1147
|
+
reservation_run is None
|
|
1148
|
+
or os.path.normpath(reservation_run) != os.path.normpath(run_manifest_rel)
|
|
1149
|
+
):
|
|
1150
|
+
continue
|
|
1151
|
+
candidates.append(reservation)
|
|
1152
|
+
return candidates, seen
|
|
1153
|
+
|
|
1154
|
+
|
|
1155
|
+
def _reservation_run_manifest_rel(
|
|
1156
|
+
project_root: Path, reservation: Mapping[str, Any],
|
|
1157
|
+
) -> str | None:
|
|
1158
|
+
"""예약 옆 `.meta.json` 의 `contractSource.runManifestPath`. 못 읽으면 None."""
|
|
1159
|
+
metadata_value = _string_value(reservation.get("metadataPath"))
|
|
1160
|
+
if not metadata_value:
|
|
1161
|
+
return None
|
|
1162
|
+
try:
|
|
1163
|
+
metadata = _load_json_object(
|
|
1164
|
+
_resolve_project_path(project_root, metadata_value),
|
|
1165
|
+
"agent invocation metadata",
|
|
1166
|
+
)
|
|
1167
|
+
except DispatchError:
|
|
1168
|
+
return None
|
|
1169
|
+
source = metadata.get("contractSource")
|
|
1170
|
+
if not isinstance(source, Mapping):
|
|
1171
|
+
return None
|
|
1172
|
+
return _string_value(source.get("runManifestPath")) or None
|
|
1173
|
+
|
|
1174
|
+
|
|
1090
1175
|
def _translator_prompt_outputs(
|
|
1091
1176
|
project_root: Path, prompt_path: Path,
|
|
1092
1177
|
) -> tuple[Path, Path]:
|
|
@@ -1162,13 +1247,11 @@ def _is_cli_wrapper_assignment(
|
|
|
1162
1247
|
options: _BuildOptions,
|
|
1163
1248
|
) -> bool:
|
|
1164
1249
|
state = _worker_state(team_state, worker_id)
|
|
1165
|
-
provider = _string_value(state.get("provider")) or _provider_for_worker(
|
|
1166
|
-
worker_id,
|
|
1167
|
-
options,
|
|
1168
|
-
)
|
|
1169
1250
|
return (
|
|
1170
1251
|
_string_value(state.get("runner")) or BACKEND_CLI_WRAPPER
|
|
1171
|
-
) == BACKEND_CLI_WRAPPER and
|
|
1252
|
+
) == BACKEND_CLI_WRAPPER and _worker_provider(
|
|
1253
|
+
team_state, worker_id, options
|
|
1254
|
+
) in options.supported_worker_wrappers
|
|
1172
1255
|
|
|
1173
1256
|
|
|
1174
1257
|
def _runner_for_worker(team_state: Mapping[str, Any], worker_id: str) -> str:
|
|
@@ -1203,6 +1286,7 @@ def _job_from_roster_worker(
|
|
|
1203
1286
|
completion_paths=_completion_paths(
|
|
1204
1287
|
fact.worker_id, result_path, manifest, project_root
|
|
1205
1288
|
),
|
|
1289
|
+
result_aliases=_plan_verify_result_aliases(result_path, manifest),
|
|
1206
1290
|
worktree_path=_worktree_path(manifest, active_context),
|
|
1207
1291
|
role=fact.role,
|
|
1208
1292
|
idle_timeout_seconds=options.idle_timeout_seconds,
|
|
@@ -1484,26 +1568,28 @@ def _persisted_write_contract(
|
|
|
1484
1568
|
if not job.has_execution_identity:
|
|
1485
1569
|
return None
|
|
1486
1570
|
manifest = read_execution_manifest(plan.manifest_path)
|
|
1487
|
-
|
|
1571
|
+
# 계약은 attempt 소유다 — 재시도는 attempt 마다 다른 프롬프트 파생 파일을
|
|
1572
|
+
# 쓰므로, invocation 으로 찾으면 1회차의 허용 경로를 2회차에 물린다.
|
|
1573
|
+
attempt = next(
|
|
1488
1574
|
(
|
|
1489
|
-
row for row in manifest.
|
|
1490
|
-
if row.invocation_ref == job.invocation_ref
|
|
1575
|
+
row for row in manifest.attempts
|
|
1576
|
+
if row.invocation_ref == job.invocation_ref and row.attempt == job.attempt
|
|
1491
1577
|
),
|
|
1492
1578
|
None,
|
|
1493
1579
|
)
|
|
1494
|
-
if
|
|
1495
|
-
raise DispatchError("worker
|
|
1580
|
+
if attempt is None:
|
|
1581
|
+
raise DispatchError("worker attempt write policy was not persisted")
|
|
1496
1582
|
try:
|
|
1497
1583
|
enforcement = write_enforcement_from_payload(
|
|
1498
|
-
|
|
1584
|
+
attempt.write_enforcement
|
|
1499
1585
|
)
|
|
1500
1586
|
policy = replace(
|
|
1501
|
-
write_policy_from_payload(
|
|
1587
|
+
write_policy_from_payload(attempt.write_policy),
|
|
1502
1588
|
maximum_boundary_precision=enforcement.boundary_precision,
|
|
1503
1589
|
)
|
|
1504
1590
|
except (TypeError, ValueError) as exc:
|
|
1505
1591
|
raise DispatchError(f"persisted worker write policy is invalid: {exc}") from exc
|
|
1506
|
-
if policy.digest !=
|
|
1592
|
+
if policy.digest != attempt.write_policy_digest:
|
|
1507
1593
|
raise DispatchError("persisted worker write policy digest changed")
|
|
1508
1594
|
return policy, enforcement
|
|
1509
1595
|
|
|
@@ -1555,9 +1641,6 @@ def _record_execution_attempt(plan: DispatchPlan, job: WorkerJob) -> None:
|
|
|
1555
1641
|
dispatch_kind=job.dispatch_kind,
|
|
1556
1642
|
round=_dispatch_round(job.dispatch_kind),
|
|
1557
1643
|
input_digest=job.prompt_digest,
|
|
1558
|
-
write_policy=write_policy.to_payload(),
|
|
1559
|
-
write_policy_digest=write_policy.digest,
|
|
1560
|
-
write_enforcement=write_enforcement.to_payload(),
|
|
1561
1644
|
),
|
|
1562
1645
|
Attempt(
|
|
1563
1646
|
invocation_ref=job.invocation_ref,
|
|
@@ -1569,6 +1652,9 @@ def _record_execution_attempt(plan: DispatchPlan, job: WorkerJob) -> None:
|
|
|
1569
1652
|
error_path=None,
|
|
1570
1653
|
change_summary={},
|
|
1571
1654
|
evidence_seal_ref=None,
|
|
1655
|
+
write_policy=write_policy.to_payload(),
|
|
1656
|
+
write_policy_digest=write_policy.digest,
|
|
1657
|
+
write_enforcement=write_enforcement.to_payload(),
|
|
1572
1658
|
),
|
|
1573
1659
|
task_key=task_key,
|
|
1574
1660
|
)
|
|
@@ -1603,6 +1689,9 @@ def _canonical_write_contract(
|
|
|
1603
1689
|
project_root=plan.project_root,
|
|
1604
1690
|
worktree=worktree,
|
|
1605
1691
|
artifact_paths=artifacts,
|
|
1692
|
+
task_root=task_root_from_run_manifest(
|
|
1693
|
+
plan.project_root, plan.manifest
|
|
1694
|
+
),
|
|
1606
1695
|
maximum_precision=capability.max_boundary_precision,
|
|
1607
1696
|
planned_paths=planned[0],
|
|
1608
1697
|
planned_paths_declared=planned[1],
|
|
@@ -1913,10 +2002,10 @@ def _finish_attempt(
|
|
|
1913
2002
|
"mutation-present-unresolved",
|
|
1914
2003
|
}:
|
|
1915
2004
|
reason = _mutation_failure_reason(mutation)
|
|
1916
|
-
_transition_job_status(plan, job, "error", reason)
|
|
1917
2005
|
_update_dispatch_status(
|
|
1918
2006
|
plan.team_state_path, job, attempt, "error", reason
|
|
1919
2007
|
)
|
|
2008
|
+
_transition_job_status(plan, job, "error", reason)
|
|
1920
2009
|
details = _failure_details(job, attempt, outcome, reason)
|
|
1921
2010
|
details["mutationAudit"] = mutation.change_summary()
|
|
1922
2011
|
_append_event(plan, "worker-failed", details)
|
|
@@ -1925,13 +2014,20 @@ def _finish_attempt(
|
|
|
1925
2014
|
settlement = _settle(plan, job, attempt, outcome)
|
|
1926
2015
|
if settlement.completed:
|
|
1927
2016
|
result_link = _link_result(plan, job, attempt)
|
|
1928
|
-
|
|
2017
|
+
# 디스패치 행을 먼저 종결한다. 명부 전이가 거절될 수 있고, 그 거절이
|
|
2018
|
+
# 행보다 앞서면 행은 `running` 으로 남아 다음 await 가 같은 sidecar 를
|
|
2019
|
+
# 다시 읽고 같은 자리에서 죽는다(`_link_result` 와 같은 결함 형태).
|
|
2020
|
+
roster_refusal = _transition_roster_completed(plan, job, attempt)
|
|
1929
2021
|
_update_dispatch_status(
|
|
1930
2022
|
plan.team_state_path,
|
|
1931
2023
|
job,
|
|
1932
2024
|
attempt,
|
|
1933
2025
|
"completed",
|
|
1934
|
-
"; ".join(
|
|
2026
|
+
"; ".join(
|
|
2027
|
+
part
|
|
2028
|
+
for part in (settlement.note, result_link["reason"], roster_refusal)
|
|
2029
|
+
if part
|
|
2030
|
+
),
|
|
1935
2031
|
)
|
|
1936
2032
|
details = _result_details(job, attempt, outcome)
|
|
1937
2033
|
details["resultLink"] = result_link
|
|
@@ -1946,8 +2042,8 @@ def _finish_attempt(
|
|
|
1946
2042
|
return False
|
|
1947
2043
|
reason = settlement.reason
|
|
1948
2044
|
status = "timeout" if outcome.timeout else "error"
|
|
1949
|
-
_transition_job_status(plan, job, status, reason)
|
|
1950
2045
|
_update_dispatch_status(plan.team_state_path, job, attempt, status, reason)
|
|
2046
|
+
_transition_job_status(plan, job, status, reason)
|
|
1951
2047
|
details = _failure_details(job, attempt, outcome, reason)
|
|
1952
2048
|
if settlement.error_log_append is not None:
|
|
1953
2049
|
details["errorLogAppend"] = settlement.error_log_append
|
|
@@ -1958,6 +2054,35 @@ def _finish_attempt(
|
|
|
1958
2054
|
return mutation.retry_allowed if mutation is not None else True
|
|
1959
2055
|
|
|
1960
2056
|
|
|
2057
|
+
def _transition_roster_completed(
|
|
2058
|
+
plan: DispatchPlan, job: WorkerJob, attempt: int,
|
|
2059
|
+
) -> str:
|
|
2060
|
+
"""명부 행을 completed 로 올리되, 거절은 이벤트와 사유로 돌려세운다.
|
|
2061
|
+
|
|
2062
|
+
명부는 `resultPath` 파일이 있어야 completed 를 받는다
|
|
2063
|
+
(`_reject_completed_without_result`). 디스패치의 산출물은 전부 있는데 그
|
|
2064
|
+
파일이 다른 경우 — 리드가 명부와 다른 포인터 경로로 재디스패치한 뒤 —
|
|
2065
|
+
그 거절이 예외로 `await` 를 죽였고, 행이 `running` 으로 남아 다음 await 도
|
|
2066
|
+
같은 자리에서 죽었다. 실측(2026-09-02~03, fontsninja-v3-site dev-10626-1
|
|
2067
|
+
r04): report-writer a2·a3 행이 그렇게 남아, 정본 경로로 보낸 a4 가 도는
|
|
2068
|
+
동안에도 `await` 가 즉시 exit 2 였다.
|
|
2069
|
+
|
|
2070
|
+
명부는 손대지 않는다 — 그 불변식(completed ⇒ 파일 있음)은 그대로다. 정본
|
|
2071
|
+
경로를 쓰는 다음 디스패치가 그 파일을 쓰면 그때 completed 가 된다.
|
|
2072
|
+
"""
|
|
2073
|
+
try:
|
|
2074
|
+
_transition_job_status(plan, job, "completed", "")
|
|
2075
|
+
except CompletedWithoutResultError as exc:
|
|
2076
|
+
reason = f"roster not updated: {exc}"
|
|
2077
|
+
_append_event(plan, "worker-roster-not-updated", {
|
|
2078
|
+
**_event_execution_identity(job, attempt),
|
|
2079
|
+
"dispatchWorkerResultPath": str(job.worker_result_path),
|
|
2080
|
+
"reason": reason,
|
|
2081
|
+
})
|
|
2082
|
+
return reason
|
|
2083
|
+
return ""
|
|
2084
|
+
|
|
2085
|
+
|
|
1961
2086
|
def _audit_attempt(
|
|
1962
2087
|
job: WorkerJob,
|
|
1963
2088
|
outcome: WorkerOutcome,
|
|
@@ -2573,6 +2698,7 @@ def _dispatch_record(
|
|
|
2573
2698
|
"modelExecutionValue": job.model_execution_value,
|
|
2574
2699
|
"wrapperPath": str(job.wrapper_path),
|
|
2575
2700
|
"completionPaths": [str(path) for path in job.completion_paths],
|
|
2701
|
+
"resultAliases": [str(path) for path in job.result_aliases],
|
|
2576
2702
|
"worktreePath": job.worktree_path,
|
|
2577
2703
|
}
|
|
2578
2704
|
if job.invocation_id:
|
|
@@ -2713,12 +2839,14 @@ def _skip_reasons(
|
|
|
2713
2839
|
if worker_id not in set(selected)
|
|
2714
2840
|
}
|
|
2715
2841
|
supported = set(options.supported_worker_wrappers)
|
|
2842
|
+
state = team_state or {}
|
|
2716
2843
|
return {
|
|
2717
2844
|
worker_id: (
|
|
2718
2845
|
"skipped by worker dispatch default: worker is not supported by this dispatcher"
|
|
2719
2846
|
)
|
|
2720
2847
|
for worker_id in recommended
|
|
2721
|
-
if worker_id not in set(selected)
|
|
2848
|
+
if worker_id not in set(selected)
|
|
2849
|
+
and _worker_provider(state, worker_id, options) not in supported
|
|
2722
2850
|
}
|
|
2723
2851
|
|
|
2724
2852
|
|
|
@@ -2857,7 +2985,7 @@ def _retry_details(job: WorkerJob, attempt: int, outcome: WorkerOutcome) -> dict
|
|
|
2857
2985
|
def _outcome_from_status(record: Mapping[str, Any], status) -> WorkerOutcome:
|
|
2858
2986
|
return WorkerOutcome(
|
|
2859
2987
|
returncode=status.exit_code if status.exit_code is not None else 1,
|
|
2860
|
-
missing_completion_paths=
|
|
2988
|
+
missing_completion_paths=_record_missing_completion_paths(record),
|
|
2861
2989
|
pane_id=_string_value(record.get("paneId")),
|
|
2862
2990
|
status_sidecar_path=status.path,
|
|
2863
2991
|
timeout=status.timeout,
|
|
@@ -2925,8 +3053,43 @@ def _record_completion_paths(record: Mapping[str, Any]) -> list[Path]:
|
|
|
2925
3053
|
return [Path(path) for path in _string_list(record.get("completionPaths"))]
|
|
2926
3054
|
|
|
2927
3055
|
|
|
3056
|
+
def _record_missing_completion_paths(record: Mapping[str, Any]) -> tuple[Path, ...]:
|
|
3057
|
+
aliases = {Path(path) for path in _string_list(record.get("resultAliases"))}
|
|
3058
|
+
result_path = Path(_string_value(record.get("resultPath")))
|
|
3059
|
+
worker_result = Path(_string_value(record.get("workerResultPath")))
|
|
3060
|
+
missing: list[Path] = []
|
|
3061
|
+
for path in _record_completion_paths(record):
|
|
3062
|
+
if path.is_file():
|
|
3063
|
+
continue
|
|
3064
|
+
if path in {result_path, worker_result} and any(alias.is_file() for alias in aliases):
|
|
3065
|
+
continue
|
|
3066
|
+
missing.append(path)
|
|
3067
|
+
return tuple(missing)
|
|
3068
|
+
|
|
3069
|
+
|
|
2928
3070
|
def _should_retry(outcome: WorkerOutcome, attempt: int) -> bool:
|
|
2929
|
-
|
|
3071
|
+
"""결과가 없으면 재시도한다 — 기준은 종료 코드가 아니라 산출물이다.
|
|
3072
|
+
|
|
3073
|
+
종전에는 `returncode == 0` 을 요구했다. 그래서 시작하자마자 죽은 CLI 는
|
|
3074
|
+
재시도를 **한 번도** 못 받았고, 150초를 태우고 0 으로 끝난 CLI 만 받았다.
|
|
3075
|
+
비용 순서가 거꾸로였다.
|
|
3076
|
+
|
|
3077
|
+
실측(fontsninja-v3-site `dev-10341`, grok 워커 13회 디스패치): 세션 생성이
|
|
3078
|
+
거부돼 1.6~4.7초 만에 코드 1 로 죽은 경우가 4회다. 그중
|
|
3079
|
+
`requirements-discovery-002` 는 그것이 1차 시도였는데 재시도가 없어 분석자
|
|
3080
|
+
한 명이 그대로 사라졌고, 바로 다음 디스패치(`-003`)는 222초를 정상 수행했다.
|
|
3081
|
+
같은 명령을 지금 돌리면 동시 3회까지 전부 성공한다 — 조건은 분 단위로
|
|
3082
|
+
풀리는 일시적인 것이고, 재시도 비용은 2초다.
|
|
3083
|
+
|
|
3084
|
+
산출물이 이미 나왔으면 종료 코드가 무엇이든 재시도하지 않는다. 일이 끝났기
|
|
3085
|
+
때문이다. 타임아웃도 재시도하지 않는다 — 그것은 예산을 다 쓴 실패라
|
|
3086
|
+
재시도가 같은 예산을 한 번 더 쓴다.
|
|
3087
|
+
"""
|
|
3088
|
+
if outcome.timeout:
|
|
3089
|
+
return False
|
|
3090
|
+
if attempt >= MAX_WORKER_ATTEMPTS:
|
|
3091
|
+
return False
|
|
3092
|
+
return bool(outcome.missing_completion_paths)
|
|
2930
3093
|
|
|
2931
3094
|
|
|
2932
3095
|
def _job_for_next_attempt(job: WorkerJob) -> WorkerJob:
|
|
@@ -2946,6 +3109,8 @@ def _job_for_next_attempt(job: WorkerJob) -> WorkerJob:
|
|
|
2946
3109
|
def _failure_reason(outcome: WorkerOutcome) -> str:
|
|
2947
3110
|
if outcome.timeout:
|
|
2948
3111
|
return "worker wrapper timed out"
|
|
3112
|
+
if outcome.returncode == NO_RESULT_EXIT_CODE:
|
|
3113
|
+
return "CLI ended cleanly without emitting a result event"
|
|
2949
3114
|
if outcome.returncode != 0:
|
|
2950
3115
|
return f"wrapper exited with code {outcome.returncode}"
|
|
2951
3116
|
if outcome.missing_completion_paths:
|
|
@@ -2982,6 +3147,28 @@ def _resolve_wrapper(provider: str, workspace_root: Path, options: _BuildOptions
|
|
|
2982
3147
|
raise DispatchError(f"{script} not found (searched: {', '.join(str(c) for c in candidates)})")
|
|
2983
3148
|
|
|
2984
3149
|
|
|
3150
|
+
def _worker_provider(
|
|
3151
|
+
team_state: Mapping[str, Any],
|
|
3152
|
+
worker_id: str,
|
|
3153
|
+
options: _BuildOptions | None = None,
|
|
3154
|
+
) -> str:
|
|
3155
|
+
"""이 슬롯이 실제로 실행할 provider.
|
|
3156
|
+
|
|
3157
|
+
로스터의 worker_id 는 provider 이름이 아니다. 한 provider 가 두 역할을 맡으면
|
|
3158
|
+
`grok-implementer` · `grok-verifier` 처럼 역할 접미사가 붙기 때문이다. 지원 여부는
|
|
3159
|
+
항상 이 해석을 거친 provider 로 판정한다 — id 를 provider 집합과 직접 비교하면
|
|
3160
|
+
역할 접미사가 붙은 슬롯이 전부 미지원으로 떨어진다.
|
|
3161
|
+
"""
|
|
3162
|
+
workers = team_state.get("workers")
|
|
3163
|
+
recorded = ""
|
|
3164
|
+
if isinstance(workers, list):
|
|
3165
|
+
for worker in workers:
|
|
3166
|
+
if isinstance(worker, Mapping) and worker.get("workerId") == worker_id:
|
|
3167
|
+
recorded = _string_value(worker.get("provider"))
|
|
3168
|
+
break
|
|
3169
|
+
return recorded or _provider_for_worker(worker_id, options)
|
|
3170
|
+
|
|
3171
|
+
|
|
2985
3172
|
def _provider_for_worker(
|
|
2986
3173
|
worker_id: str,
|
|
2987
3174
|
options: _BuildOptions | None = None,
|
|
@@ -2992,7 +3179,7 @@ def _provider_for_worker(
|
|
|
2992
3179
|
return configured
|
|
2993
3180
|
if worker_id == REPORT_WRITER_WORKER_ID:
|
|
2994
3181
|
return "claude"
|
|
2995
|
-
return worker_id
|
|
3182
|
+
return worker_provider_id(worker_id)
|
|
2996
3183
|
|
|
2997
3184
|
|
|
2998
3185
|
|