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
|
@@ -6,12 +6,36 @@ import json
|
|
|
6
6
|
import re
|
|
7
7
|
import sys
|
|
8
8
|
from copy import deepcopy
|
|
9
|
+
from functools import lru_cache
|
|
9
10
|
from dataclasses import dataclass
|
|
10
11
|
from pathlib import Path
|
|
11
12
|
from typing import Any, Mapping, Sequence
|
|
12
13
|
|
|
14
|
+
from .clarification_items.sidecars import (
|
|
15
|
+
attached_response_sections,
|
|
16
|
+
response_source_report,
|
|
17
|
+
)
|
|
18
|
+
from .user_response_values import parse_user_response_entries
|
|
13
19
|
from .convergence_store import write_json_atomic
|
|
20
|
+
from .final_report_schema import load_schema_version
|
|
14
21
|
from .json_boundary import JsonBoundaryError, load_owned_object
|
|
22
|
+
from .report_contract import CURRENT_REPORT_SCHEMA_VERSION
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@lru_cache(maxsize=None)
|
|
26
|
+
def _schema_enum(definition: str) -> frozenset[str]:
|
|
27
|
+
"""리포트 스키마의 ``$defs`` enum 을 그대로 읽는다.
|
|
28
|
+
|
|
29
|
+
이 원장의 행은 그대로 final-report 의 ``clarificationItems`` 가 된다. 값 목록을
|
|
30
|
+
여기에 다시 타이핑하면 스키마와 따로 흐르므로 정본에서 읽는다.
|
|
31
|
+
"""
|
|
32
|
+
schema = load_schema_version(CURRENT_REPORT_SCHEMA_VERSION)
|
|
33
|
+
values = (schema.get("$defs") or {}).get(definition, {}).get("enum")
|
|
34
|
+
if not isinstance(values, list) or not values:
|
|
35
|
+
raise ApprovalDecisionError(
|
|
36
|
+
f"report schema has no enum for {definition!r}"
|
|
37
|
+
)
|
|
38
|
+
return frozenset(str(value) for value in values)
|
|
15
39
|
|
|
16
40
|
|
|
17
41
|
DISPOSITIONS = frozenset({"select", "accept-risk", "request-revision", "reject"})
|
|
@@ -103,10 +127,23 @@ def _ledger(path: Path, task_key: str, task_type: str, run_seq: str) -> dict[str
|
|
|
103
127
|
expected = (task_key, task_type, run_seq)
|
|
104
128
|
actual = (ledger.get("taskKey"), ledger.get("taskType"), ledger.get("runSeq"))
|
|
105
129
|
if actual != expected:
|
|
106
|
-
|
|
130
|
+
# 원장은 `runSeq` 를 세 자리 문자열로 적는다. 정수 `4` 를 넘긴 호출은
|
|
131
|
+
# 원장을 덤프해 보기 전까지 무엇이 달랐는지 알 수 없었다.
|
|
132
|
+
raise ApprovalDecisionError(
|
|
133
|
+
"approval ledger identity does not match this run: ledger has "
|
|
134
|
+
f"taskKey={actual[0]!r} taskType={actual[1]!r} runSeq={actual[2]!r}; "
|
|
135
|
+
f"this call passed taskKey={expected[0]!r} taskType={expected[1]!r} "
|
|
136
|
+
f"runSeq={expected[2]!r}"
|
|
137
|
+
)
|
|
107
138
|
return ledger
|
|
108
139
|
|
|
109
140
|
|
|
141
|
+
def normalize_run_seq(value: str) -> str:
|
|
142
|
+
"""`4` → `004`. 원장과 run 산출물은 세 자리 0 패딩 문자열을 쓴다."""
|
|
143
|
+
text = str(value).strip()
|
|
144
|
+
return text.zfill(3) if text.isdigit() else text
|
|
145
|
+
|
|
146
|
+
|
|
110
147
|
def _validate_option_set(
|
|
111
148
|
options: Sequence[DecisionOption], classification: str,
|
|
112
149
|
recommended_disposition: str,
|
|
@@ -127,6 +164,23 @@ def _validate_option_set(
|
|
|
127
164
|
)
|
|
128
165
|
|
|
129
166
|
|
|
167
|
+
def _reject_off_enum(value: str, field: str, definition: str) -> None:
|
|
168
|
+
"""스키마 밖 값을 원장 진입 지점에서 거절한다.
|
|
169
|
+
|
|
170
|
+
종전에는 두 provenance 필드가 비어 있지 않기만 하면 통과했다. 리포트 조립이
|
|
171
|
+
스키마로 잡아 내기는 하지만 그때는 이미 레코드를 디스크에 쓴 뒤라, 잘못된 값이
|
|
172
|
+
원장과 리포트 양쪽에 남아 이후의 모든 읽기(`okstra user-response`)를 막았다.
|
|
173
|
+
"""
|
|
174
|
+
if not value:
|
|
175
|
+
return
|
|
176
|
+
allowed = _schema_enum(definition)
|
|
177
|
+
if value not in allowed:
|
|
178
|
+
raise ApprovalDecisionError(
|
|
179
|
+
f"invalid {field}: {value!r}. Allowed values: "
|
|
180
|
+
+ ", ".join(sorted(allowed))
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
|
|
130
184
|
def _decision_row(
|
|
131
185
|
*, clarification_id: str, ticket_id: str, statement: str,
|
|
132
186
|
expected_form: str, classification: str, origin: str,
|
|
@@ -135,6 +189,10 @@ def _decision_row(
|
|
|
135
189
|
) -> dict[str, Any]:
|
|
136
190
|
if classification not in CLASSIFICATIONS:
|
|
137
191
|
raise ApprovalDecisionError(f"invalid classification: {classification}")
|
|
192
|
+
_reject_off_enum(origin, "origin", "ClarificationOrigin")
|
|
193
|
+
_reject_off_enum(
|
|
194
|
+
user_confirmation, "user_confirmation", "ClarificationUserConfirmation"
|
|
195
|
+
)
|
|
138
196
|
if recommended_disposition not in DISPOSITIONS:
|
|
139
197
|
raise ApprovalDecisionError(
|
|
140
198
|
f"invalid recommended_disposition: {recommended_disposition}"
|
|
@@ -235,7 +293,18 @@ def _options_from_args(args: argparse.Namespace) -> tuple[DecisionOption, ...]:
|
|
|
235
293
|
args.option_added_work, args.option_direction_change,
|
|
236
294
|
)
|
|
237
295
|
if len({len(values) for values in fields}) != 1:
|
|
238
|
-
|
|
296
|
+
names = (
|
|
297
|
+
"role", "answer", "rationale", "disposition", "reach",
|
|
298
|
+
"scope-effect", "added-work", "direction-change",
|
|
299
|
+
)
|
|
300
|
+
counts = ", ".join(
|
|
301
|
+
f"--option-{name}={len(values)}" for name, values in zip(names, fields)
|
|
302
|
+
)
|
|
303
|
+
raise ApprovalDecisionError(
|
|
304
|
+
"every repeated option field needs the same count — repeat each "
|
|
305
|
+
f"--option-* flag once per option, including the ones --help marks "
|
|
306
|
+
f"optional: {counts}"
|
|
307
|
+
)
|
|
239
308
|
return tuple(
|
|
240
309
|
DecisionOption(role, answer, rationale, disposition, reach,
|
|
241
310
|
tuple(effect.split(",")) if effect else (), added, direction)
|
|
@@ -260,8 +329,21 @@ def _add_open_arguments(parser: argparse.ArgumentParser) -> None:
|
|
|
260
329
|
parser.add_argument(f"--option-{flag}", action="append", default=[])
|
|
261
330
|
|
|
262
331
|
|
|
332
|
+
_CLI_EPILOG = r"""Usage:
|
|
333
|
+
okstra approval-decision open --ledger <path> [decision fields]
|
|
334
|
+
okstra approval-decision resolve --ledger <path> --clarification-id <C-NNN> [resolution fields]
|
|
335
|
+
okstra approval-decision carry --ledger <path> --from-responses <clarification-response.md> --clarification-id <C-NNN> [--clarification-id <C-NNN> ...]
|
|
336
|
+
okstra approval-decision carry --ledger <path> --source-ledger <path> --source-run-ref <ref> --clarification-id <C-NNN>
|
|
337
|
+
"""
|
|
338
|
+
_CLI_DESCRIPTION = "Record lead-owned approval inputs."
|
|
339
|
+
|
|
340
|
+
|
|
263
341
|
def _parser() -> argparse.ArgumentParser:
|
|
264
|
-
parser = argparse.ArgumentParser(
|
|
342
|
+
parser = argparse.ArgumentParser(
|
|
343
|
+
description=_CLI_DESCRIPTION,
|
|
344
|
+
epilog=_CLI_EPILOG,
|
|
345
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
346
|
+
prog="okstra approval-decision")
|
|
265
347
|
commands = parser.add_subparsers(dest="command", required=True)
|
|
266
348
|
opened = commands.add_parser("open")
|
|
267
349
|
opened.add_argument("--ledger", type=Path, required=True)
|
|
@@ -275,9 +357,38 @@ def _parser() -> argparse.ArgumentParser:
|
|
|
275
357
|
resolved.add_argument("--check-ref", action="append", default=[])
|
|
276
358
|
carried = commands.add_parser("carry")
|
|
277
359
|
carried.add_argument("--ledger", type=Path, required=True)
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
360
|
+
source = carried.add_mutually_exclusive_group(required=True)
|
|
361
|
+
source.add_argument(
|
|
362
|
+
"--from-responses",
|
|
363
|
+
type=Path,
|
|
364
|
+
help=(
|
|
365
|
+
"attached user-responses bundle (`instruction-set/"
|
|
366
|
+
"clarification-response.md`). It is the source of truth for the "
|
|
367
|
+
"answer; the question's own fields come from the report each "
|
|
368
|
+
"response section names. Task-level and cumulative, so no prior "
|
|
369
|
+
"run seq has to be located."
|
|
370
|
+
),
|
|
371
|
+
)
|
|
372
|
+
source.add_argument(
|
|
373
|
+
"--source-ledger",
|
|
374
|
+
type=Path,
|
|
375
|
+
help="a prior run's approval ledger, when it is still on disk",
|
|
376
|
+
)
|
|
377
|
+
carried.add_argument(
|
|
378
|
+
"--source-run-ref",
|
|
379
|
+
default="",
|
|
380
|
+
help=(
|
|
381
|
+
"provenance recorded on the carried row. Required with "
|
|
382
|
+
"--source-ledger; with --from-responses it defaults to the "
|
|
383
|
+
"response section the answer came from."
|
|
384
|
+
),
|
|
385
|
+
)
|
|
386
|
+
carried.add_argument(
|
|
387
|
+
"--clarification-id",
|
|
388
|
+
action="append",
|
|
389
|
+
required=True,
|
|
390
|
+
help="repeat to carry several ids in one call",
|
|
391
|
+
)
|
|
281
392
|
return parser
|
|
282
393
|
|
|
283
394
|
|
|
@@ -285,19 +396,181 @@ def _open_from_args(args: argparse.Namespace) -> None:
|
|
|
285
396
|
values = vars(args).copy()
|
|
286
397
|
values.pop("command")
|
|
287
398
|
values["ledger_path"] = values.pop("ledger")
|
|
399
|
+
values["run_seq"] = normalize_run_seq(values["run_seq"])
|
|
288
400
|
for key in tuple(values):
|
|
289
401
|
if key.startswith("option_"):
|
|
290
402
|
values.pop(key)
|
|
291
403
|
open_decision(**values, options=_options_from_args(args))
|
|
292
404
|
|
|
293
405
|
|
|
406
|
+
# `kind: decision` 인 행은 스키마가 옵션 메뉴를 요구하므로 함께 가져온다.
|
|
407
|
+
# `resolution` 은 가져오지 않는다 — 그 `checkRefs` 는 답을 기록한 run 의 활동
|
|
408
|
+
# 행이고, 이월 행은 `answered` 로 실린다.
|
|
409
|
+
_QUESTION_FIELDS = (
|
|
410
|
+
"id", "ticketId", "kind", "statement", "expectedForm", "blocks", "origin",
|
|
411
|
+
"options",
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def _responses_index(path: Path) -> dict[str, tuple[Any, str, str, str]]:
|
|
416
|
+
"""묶음 파일의 답을 ``{id: (entry, 구간 이름, 리포트 기록 이름, task-type)}`` 로.
|
|
417
|
+
|
|
418
|
+
같은 id 를 여러 run 이 답했으면 뒤 구간이 이긴다 — 묶음은 시간순으로 쌓이고
|
|
419
|
+
최신 답이 정본이다.
|
|
420
|
+
"""
|
|
421
|
+
try:
|
|
422
|
+
text = path.read_text(encoding="utf-8")
|
|
423
|
+
except OSError as exc:
|
|
424
|
+
raise ApprovalDecisionError(f"cannot read {path}: {exc}") from exc
|
|
425
|
+
sections = attached_response_sections(text)
|
|
426
|
+
if not sections:
|
|
427
|
+
raise ApprovalDecisionError(
|
|
428
|
+
f"not an attached user-responses bundle (no `## user-response-*.md` "
|
|
429
|
+
f"section): {path}"
|
|
430
|
+
)
|
|
431
|
+
index: dict[str, tuple[Any, str, str, str]] = {}
|
|
432
|
+
for name, body in sections:
|
|
433
|
+
report = response_source_report(body)
|
|
434
|
+
task_type = _frontmatter_task_type(body)
|
|
435
|
+
for entry in parse_user_response_entries(body):
|
|
436
|
+
index[entry.response_id] = (entry, name, report, task_type)
|
|
437
|
+
return index
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def _frontmatter_task_type(section_body: str) -> str:
|
|
441
|
+
match = re.search(r"^task-type:\s*(\S.*?)\s*$", section_body, re.MULTILINE)
|
|
442
|
+
return match.group(1) if match else ""
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def _prior_question_row(
|
|
446
|
+
responses_path: Path, clarification_id: str, report_name: str, task_type: str,
|
|
447
|
+
) -> dict[str, Any]:
|
|
448
|
+
"""질문 메타데이터의 출처는 그 질문을 낸 리포트다.
|
|
449
|
+
|
|
450
|
+
묶음 파일은 답만 담는다. `ticketId`·`statement`·`expectedForm` 은 스키마가
|
|
451
|
+
요구하는데 묶음에 없으므로, 지어내는 대신 구간 frontmatter 가 지목한
|
|
452
|
+
리포트에서 읽는다. 그 리드가 seq 를 찾아 헤매지 않게 하는 것이 이 경로의
|
|
453
|
+
요점이다.
|
|
454
|
+
"""
|
|
455
|
+
if not report_name or not task_type:
|
|
456
|
+
raise ApprovalDecisionError(
|
|
457
|
+
f"{clarification_id}: its response section names no source report; "
|
|
458
|
+
"carry it with --source-ledger instead"
|
|
459
|
+
)
|
|
460
|
+
task_root = responses_path.resolve().parent.parent
|
|
461
|
+
report_path = (
|
|
462
|
+
task_root / "runs" / task_type / "reports" / Path(report_name).name
|
|
463
|
+
)
|
|
464
|
+
if not report_path.is_file():
|
|
465
|
+
raise ApprovalDecisionError(
|
|
466
|
+
f"{clarification_id}: source report not found: {report_path}"
|
|
467
|
+
)
|
|
468
|
+
try:
|
|
469
|
+
data = load_owned_object(report_path, artifact="prior final report")
|
|
470
|
+
except (JsonBoundaryError, OSError) as exc:
|
|
471
|
+
raise ApprovalDecisionError(f"cannot read {report_path}: {exc}") from exc
|
|
472
|
+
rows = data.get("clarificationItems") if isinstance(data, Mapping) else None
|
|
473
|
+
match = next(
|
|
474
|
+
(
|
|
475
|
+
row for row in (rows or [])
|
|
476
|
+
if isinstance(row, Mapping) and row.get("id") == clarification_id
|
|
477
|
+
),
|
|
478
|
+
None,
|
|
479
|
+
)
|
|
480
|
+
if match is None:
|
|
481
|
+
raise ApprovalDecisionError(
|
|
482
|
+
f"{clarification_id}: not defined in {report_path.name}"
|
|
483
|
+
)
|
|
484
|
+
row = {key: match[key] for key in _QUESTION_FIELDS if key in match}
|
|
485
|
+
if isinstance(row.get("options"), list):
|
|
486
|
+
row["options"] = [
|
|
487
|
+
_contract_v3_option(option, clarification_id)
|
|
488
|
+
for option in row["options"]
|
|
489
|
+
if isinstance(option, Mapping)
|
|
490
|
+
]
|
|
491
|
+
if "approvalContext" in match:
|
|
492
|
+
row["approval"] = match["approvalContext"]
|
|
493
|
+
return row
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
_REACH_TOKENS = ("in-repo", "cross-repo")
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
def _contract_v3_option(option: Mapping[str, Any], clarification_id: str) -> dict[str, Any]:
|
|
500
|
+
"""계약 2.0 의 `scopeImpact` 를 3.0 의 `reach` + `scopeEffects` 로 되돌린다.
|
|
501
|
+
|
|
502
|
+
두 열거는 정확히 분할 관계다 — 2.0 의 토큰 집합
|
|
503
|
+
`{in-repo, cross-repo, new-schema, deferrable}` 이 3.0 에서 `reach`
|
|
504
|
+
(`in-repo|cross-repo`, 정확히 하나)와 `scopeEffects`(나머지)로 갈렸다.
|
|
505
|
+
그래서 이 변환은 값을 지어내지 않는다. 이미 3.0 모양이면 그대로 둔다.
|
|
506
|
+
"""
|
|
507
|
+
row = dict(option)
|
|
508
|
+
if "reach" in row:
|
|
509
|
+
row.pop("scopeImpact", None)
|
|
510
|
+
return row
|
|
511
|
+
tokens = row.pop("scopeImpact", None)
|
|
512
|
+
if not isinstance(tokens, list):
|
|
513
|
+
raise ApprovalDecisionError(
|
|
514
|
+
f"{clarification_id}: an option states neither `reach` nor "
|
|
515
|
+
"`scopeImpact`; carry it with --source-ledger instead"
|
|
516
|
+
)
|
|
517
|
+
reach = [token for token in tokens if token in _REACH_TOKENS]
|
|
518
|
+
if len(reach) != 1:
|
|
519
|
+
raise ApprovalDecisionError(
|
|
520
|
+
f"{clarification_id}: an option's `scopeImpact` names {len(reach)} "
|
|
521
|
+
"reach token(s); exactly one is needed to state `reach`"
|
|
522
|
+
)
|
|
523
|
+
row["reach"] = reach[0]
|
|
524
|
+
effects = [token for token in tokens if token not in _REACH_TOKENS]
|
|
525
|
+
if effects:
|
|
526
|
+
row["scopeEffects"] = effects
|
|
527
|
+
return row
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
def _carry_from_responses(args: argparse.Namespace) -> None:
|
|
531
|
+
index = _responses_index(args.from_responses)
|
|
532
|
+
for clarification_id in args.clarification_id:
|
|
533
|
+
found = index.get(clarification_id)
|
|
534
|
+
if found is None:
|
|
535
|
+
raise ApprovalDecisionError(
|
|
536
|
+
f"clarification not answered in {args.from_responses}: "
|
|
537
|
+
f"{clarification_id}"
|
|
538
|
+
)
|
|
539
|
+
entry, section, report_name, task_type = found
|
|
540
|
+
if not entry.value.strip():
|
|
541
|
+
raise ApprovalDecisionError(
|
|
542
|
+
f"{clarification_id}: its answer in {section} has no Value"
|
|
543
|
+
)
|
|
544
|
+
decision = _prior_question_row(
|
|
545
|
+
args.from_responses, clarification_id, report_name, task_type
|
|
546
|
+
)
|
|
547
|
+
# 답이 정본인 자리는 여기다. `resolutionInput` 은 쓰지 않는다 —
|
|
548
|
+
# 그 모양은 `checkRefs` 로 이번 run 의 활동 행을 요구하는데, 이월된
|
|
549
|
+
# 답에는 이번 run 의 활동이 없다(`report_assembly` 의 이월 분기).
|
|
550
|
+
decision["userConfirmation"] = "asked-and-answered"
|
|
551
|
+
decision["userInput"] = entry.value
|
|
552
|
+
carry_decision(
|
|
553
|
+
args.ledger,
|
|
554
|
+
source_run_ref=args.source_run_ref or section,
|
|
555
|
+
decision=decision,
|
|
556
|
+
)
|
|
557
|
+
|
|
558
|
+
|
|
294
559
|
def _carry_from_args(args: argparse.Namespace) -> None:
|
|
295
560
|
source = _read_ledger(args.source_ledger)
|
|
296
561
|
rows = source.get("activeClarifications") or []
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
562
|
+
for clarification_id in args.clarification_id:
|
|
563
|
+
matches = [
|
|
564
|
+
row for row in rows
|
|
565
|
+
if isinstance(row, dict) and row.get("id") == clarification_id
|
|
566
|
+
]
|
|
567
|
+
if len(matches) != 1:
|
|
568
|
+
raise ApprovalDecisionError(
|
|
569
|
+
f"source clarification not found: {clarification_id}"
|
|
570
|
+
)
|
|
571
|
+
carry_decision(
|
|
572
|
+
args.ledger, source_run_ref=args.source_run_ref, decision=matches[0]
|
|
573
|
+
)
|
|
301
574
|
|
|
302
575
|
|
|
303
576
|
def _run(args: argparse.Namespace) -> None:
|
|
@@ -309,7 +582,11 @@ def _run(args: argparse.Namespace) -> None:
|
|
|
309
582
|
user_text=args.user_text, user_response_ref=args.user_response_ref,
|
|
310
583
|
check_refs=args.check_ref,
|
|
311
584
|
)
|
|
585
|
+
elif args.from_responses:
|
|
586
|
+
_carry_from_responses(args)
|
|
312
587
|
else:
|
|
588
|
+
if not args.source_run_ref:
|
|
589
|
+
raise ApprovalDecisionError("--source-ledger requires --source-run-ref")
|
|
313
590
|
_carry_from_args(args)
|
|
314
591
|
|
|
315
592
|
|
|
@@ -91,18 +91,6 @@ class AssignmentContext:
|
|
|
91
91
|
environment: AssignmentEnvironment
|
|
92
92
|
|
|
93
93
|
|
|
94
|
-
@dataclass(frozen=True)
|
|
95
|
-
class RoleCountSelection:
|
|
96
|
-
role: str
|
|
97
|
-
count: int
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
@dataclass(frozen=True)
|
|
101
|
-
class RoleModelSelection:
|
|
102
|
-
role: str
|
|
103
|
-
model_refs: tuple[str, ...]
|
|
104
|
-
|
|
105
|
-
|
|
106
94
|
@dataclass(frozen=True)
|
|
107
95
|
class RoleInstance:
|
|
108
96
|
role: str
|
|
@@ -3,13 +3,17 @@ from __future__ import annotations
|
|
|
3
3
|
|
|
4
4
|
import hashlib
|
|
5
5
|
import json
|
|
6
|
-
from dataclasses import dataclass
|
|
6
|
+
from dataclasses import dataclass, replace
|
|
7
7
|
from datetime import datetime, timezone
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
from typing import Any, Mapping, Sequence
|
|
10
10
|
|
|
11
11
|
from .domain.worker_stream import host_event_row
|
|
12
|
-
from .execution_identity import
|
|
12
|
+
from .execution_identity import (
|
|
13
|
+
Attempt,
|
|
14
|
+
ExecutionManifestError,
|
|
15
|
+
MutationRecoveryDecision,
|
|
16
|
+
)
|
|
13
17
|
from .execution_manifest import read_execution_manifest
|
|
14
18
|
from .execution_manifest import _replace_manifest, _write_manifest_over_existing
|
|
15
19
|
from .jsonl import append_jsonl
|
|
@@ -221,15 +225,10 @@ def finalize_attempt(
|
|
|
221
225
|
raise AttemptEvidenceError("attempt to seal is unknown")
|
|
222
226
|
existing = manifest.attempts[index]
|
|
223
227
|
if terminal.interrupted_before_record:
|
|
224
|
-
closed =
|
|
225
|
-
|
|
226
|
-
attempt=existing.attempt,
|
|
227
|
-
started_at=existing.started_at,
|
|
228
|
+
closed = replace(
|
|
229
|
+
existing,
|
|
228
230
|
finished_at=_utc_now(),
|
|
229
231
|
status="evidence-unsealed",
|
|
230
|
-
result_path=existing.result_path,
|
|
231
|
-
error_path=existing.error_path,
|
|
232
|
-
change_summary=dict(existing.change_summary),
|
|
233
232
|
evidence_seal_ref=None,
|
|
234
233
|
)
|
|
235
234
|
attempts = list(manifest.attempts)
|
|
@@ -252,15 +251,10 @@ def finalize_attempt(
|
|
|
252
251
|
if not _same_observation(existing_seal, terminal):
|
|
253
252
|
raise AttemptEvidenceError("attempt already sealed with different observation")
|
|
254
253
|
return existing_seal
|
|
255
|
-
closed =
|
|
256
|
-
|
|
257
|
-
attempt=existing.attempt,
|
|
258
|
-
started_at=existing.started_at,
|
|
254
|
+
closed = replace(
|
|
255
|
+
existing,
|
|
259
256
|
finished_at=existing.finished_at or _utc_now(),
|
|
260
257
|
status=terminal.status,
|
|
261
|
-
result_path=existing.result_path,
|
|
262
|
-
error_path=existing.error_path,
|
|
263
|
-
change_summary=dict(existing.change_summary),
|
|
264
258
|
evidence_seal_ref=seal.seal_ref,
|
|
265
259
|
)
|
|
266
260
|
attempts = list(manifest.attempts)
|
|
@@ -285,7 +279,6 @@ def reject_unsealed_attempt(
|
|
|
285
279
|
task_key: str,
|
|
286
280
|
):
|
|
287
281
|
"""Close an unsealed attempt and record a cleanup-only reject."""
|
|
288
|
-
from .mutation_recovery import MutationRecoveryDecision
|
|
289
282
|
|
|
290
283
|
invocation_ref, attempt_number = _split_attempt_ref(attempt_ref)
|
|
291
284
|
with task_mutex(task_key):
|
|
@@ -301,15 +294,10 @@ def reject_unsealed_attempt(
|
|
|
301
294
|
if index is None:
|
|
302
295
|
raise AttemptEvidenceError("attempt to reject is unknown")
|
|
303
296
|
existing = manifest.attempts[index]
|
|
304
|
-
closed =
|
|
305
|
-
|
|
306
|
-
attempt=existing.attempt,
|
|
307
|
-
started_at=existing.started_at,
|
|
297
|
+
closed = replace(
|
|
298
|
+
existing,
|
|
308
299
|
finished_at=existing.finished_at or _utc_now(),
|
|
309
300
|
status="evidence-unsealed",
|
|
310
|
-
result_path=existing.result_path,
|
|
311
|
-
error_path=existing.error_path,
|
|
312
|
-
change_summary=dict(existing.change_summary),
|
|
313
301
|
evidence_seal_ref=None,
|
|
314
302
|
)
|
|
315
303
|
decision = MutationRecoveryDecision(
|