okstra 0.186.7 → 0.187.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli-registry.d.mts +88 -1
- package/dist/cli-registry.mjs +68 -111
- package/dist/cli-registry.mjs.map +1 -1
- package/dist/commands/execute/render-bundle.mjs +0 -1
- package/dist/commands/execute/render-bundle.mjs.map +1 -1
- package/dist/commands/execute/run.mjs +8 -3
- package/dist/commands/execute/run.mjs.map +1 -1
- package/dist/commands/lifecycle/check-project.mjs +1 -14
- package/dist/commands/lifecycle/check-project.mjs.map +1 -1
- package/dist/commands/lifecycle/config.mjs +38 -40
- package/dist/commands/lifecycle/config.mjs.map +1 -1
- package/dist/commands/lifecycle/doctor.d.mts +22 -7
- package/dist/commands/lifecycle/doctor.mjs +77 -49
- package/dist/commands/lifecycle/doctor.mjs.map +1 -1
- package/dist/commands/lifecycle/install.d.mts +12 -10
- package/dist/commands/lifecycle/install.mjs +104 -39
- package/dist/commands/lifecycle/install.mjs.map +1 -1
- package/dist/commands/lifecycle/paths.mjs +8 -3
- package/dist/commands/lifecycle/paths.mjs.map +1 -1
- package/dist/commands/lifecycle/preflight.mjs +2 -1
- package/dist/commands/lifecycle/preflight.mjs.map +1 -1
- package/dist/commands/lifecycle/setup.mjs +22 -36
- package/dist/commands/lifecycle/setup.mjs.map +1 -1
- package/dist/commands/lifecycle/uninstall.d.mts +4 -2
- package/dist/commands/lifecycle/uninstall.mjs +59 -15
- package/dist/commands/lifecycle/uninstall.mjs.map +1 -1
- package/dist/commands/memory/memory.mjs +7 -1
- package/dist/commands/memory/memory.mjs.map +1 -1
- package/dist/lib/helper-scripts.d.mts +1 -1
- package/dist/lib/helper-scripts.mjs +10 -18
- package/dist/lib/helper-scripts.mjs.map +1 -1
- package/dist/lib/host-config.d.mts +72 -0
- package/dist/lib/host-config.mjs +404 -0
- package/dist/lib/host-config.mjs.map +1 -0
- package/dist/lib/host-registry-client.d.mts +2 -2
- package/dist/lib/host-registry-client.mjs +0 -3
- package/dist/lib/host-registry-client.mjs.map +1 -1
- package/dist/lib/install-assets.d.mts +1 -0
- package/dist/lib/install-assets.mjs +4 -0
- package/dist/lib/install-assets.mjs.map +1 -1
- package/dist/lib/proc.d.mts +2 -0
- package/dist/lib/proc.mjs +12 -0
- package/dist/lib/proc.mjs.map +1 -1
- package/dist/lib/python-command.d.mts +2 -0
- package/dist/lib/python-command.mjs +52 -0
- package/dist/lib/python-command.mjs.map +1 -0
- package/dist/lib/python-helper.d.mts +2 -5
- package/dist/lib/python-helper.mjs +3 -52
- package/dist/lib/python-helper.mjs.map +1 -1
- package/dist/lib/runtime-payload.d.mts +23 -0
- package/dist/lib/runtime-payload.mjs +57 -0
- package/dist/lib/runtime-payload.mjs.map +1 -0
- package/dist/lib/types.d.mts +24 -13
- package/docs/architecture/storage-model.md +21 -5
- package/docs/architecture.md +37 -36
- package/docs/cli.md +55 -76
- package/docs/coding-rules.md +295 -0
- package/docs/container.md +10 -36
- package/docs/contributor-change-matrix.md +1 -1
- package/docs/for-ai/skills/okstra-code-review.md +0 -1
- package/docs/for-ai/skills/okstra-container-build.md +8 -41
- package/docs/for-ai/skills/okstra-inspect.md +4 -4
- package/docs/for-ai/skills/okstra-manager.md +2 -2
- package/docs/for-ai/skills/okstra-rollup.md +0 -1
- package/docs/for-ai/skills/okstra-run.md +3 -3
- package/docs/for-ai/skills/okstra-user-response.md +0 -1
- package/docs/performance-improvement-plan-v2.md +1 -1
- package/docs/project-structure-overview.md +62 -62
- package/docs/task-process/README.md +3 -3
- package/docs/task-process/common-flow.md +1 -1
- package/docs/task-process/error-analysis.md +3 -3
- package/docs/task-process/implementation-planning.md +3 -1
- package/docs/task-process/release-handoff.md +1 -1
- package/package.json +3 -2
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/claude-worker.md +6 -11
- package/runtime/agents/workers/report-writer-worker.md +1 -1
- package/runtime/bin/lib/okstra/cli.sh +4 -0
- package/runtime/bin/lib/okstra/globals.sh +2 -0
- package/runtime/bin/lib/okstra/interactive.sh +26 -173
- package/runtime/bin/lib/okstra/project-resolver.sh +23 -61
- package/runtime/bin/lib/okstra/usage.sh +3 -3
- package/runtime/bin/okstra-compact-reminder.sh +1 -5
- package/runtime/bin/okstra-error-log.py +19 -2
- package/runtime/bin/okstra-import-check.py +26 -0
- package/runtime/bin/okstra-inject-report-index.py +5 -4
- package/runtime/bin/okstra-provider-exec.py +22 -17
- package/runtime/bin/okstra-render-final-report.py +16 -6
- package/runtime/bin/okstra-render-report-views.py +25 -18
- package/runtime/bin/okstra-report-translate.py +30 -18
- package/runtime/bin/okstra-spawn-followups.py +4 -0
- package/runtime/bin/okstra-token-usage.py +3 -0
- package/runtime/bin/okstra.sh +4 -2
- package/runtime/bin/okstra_bootstrap.py +58 -0
- package/runtime/prompts/coding-preflight/overview.md +1 -1
- package/runtime/prompts/duties/planning-worker.md +1 -1
- package/runtime/prompts/launch.template.md +35 -9
- package/runtime/prompts/lead/convergence.md +96 -87
- package/runtime/prompts/lead/okstra-lead-contract.md +63 -12
- package/runtime/prompts/lead/plan-body-verification.md +65 -46
- package/runtime/prompts/lead/report-writer.md +34 -4
- package/runtime/prompts/lead/team-contract.md +4 -1
- package/runtime/prompts/profiles/_clarification-recommendation.md +2 -1
- package/runtime/prompts/profiles/_coding-conventions-preflight.md +1 -1
- package/runtime/prompts/profiles/_common-contract.md +3 -3
- package/runtime/prompts/profiles/_coverage-critic.md +1 -1
- package/runtime/prompts/profiles/_implementation-deliverable.md +2 -2
- package/runtime/prompts/profiles/_implementation-executor.md +3 -1
- package/runtime/prompts/profiles/_implementation-verifier.md +16 -2
- package/runtime/prompts/profiles/error-analysis.md +4 -3
- package/runtime/prompts/profiles/final-verification.md +2 -2
- package/runtime/prompts/profiles/implementation-planning.md +22 -17
- package/runtime/prompts/profiles/implementation.md +3 -2
- package/runtime/prompts/profiles/requirements-discovery.md +2 -1
- package/runtime/prompts/wizard/prompts.ko.json +29 -8
- package/runtime/python/okstra_ctl/__init__.py +6 -27
- package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +4 -5
- package/runtime/python/okstra_ctl/adapters/hosts/codex/adapter.py +21 -2
- package/runtime/python/okstra_ctl/adapters/hosts/external/adapter.py +3 -12
- package/runtime/python/okstra_ctl/adapters/providers/antigravity/adapter.py +40 -22
- package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +14 -21
- package/runtime/python/okstra_ctl/adapters/providers/codex/adapter.py +37 -20
- package/runtime/python/okstra_ctl/adapters/providers/grok/adapter.py +86 -14
- package/runtime/python/okstra_ctl/adapters/providers/kimi/adapter.py +12 -12
- package/runtime/python/okstra_ctl/adapters/runtime/cmux.py +4 -7
- package/runtime/python/okstra_ctl/agent/__init__.py +1 -0
- package/runtime/python/okstra_ctl/{agent_activity.py → agent/activity.py} +12 -1
- package/runtime/python/okstra_ctl/{agent_invocation.py → agent/invocation.py} +34 -5
- package/runtime/python/okstra_ctl/agent/prompt_cli/__init__.py +19 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/__main__.py +11 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/cli.py +215 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/dynamic_verifier.py +155 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/emit.py +66 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/inputs.py +138 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/materialize.py +408 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/results.py +197 -0
- package/runtime/python/okstra_ctl/agent/prompt_cli/run_identity.py +107 -0
- package/runtime/python/okstra_ctl/analysis_packet.py +47 -4
- package/runtime/python/okstra_ctl/approval_decisions.py +260 -8
- package/runtime/python/okstra_ctl/assignment_resolver.py +0 -12
- package/runtime/python/okstra_ctl/attempt_evidence.py +12 -24
- package/runtime/python/okstra_ctl/blocking_checks.py +251 -0
- package/runtime/python/okstra_ctl/brief_frontmatter.py +0 -7
- package/runtime/python/okstra_ctl/clarification_items/__init__.py +102 -0
- package/runtime/python/okstra_ctl/clarification_items/carry.py +224 -0
- package/runtime/python/okstra_ctl/clarification_items/dispositions.py +135 -0
- package/runtime/python/okstra_ctl/clarification_items/parsing.py +253 -0
- package/runtime/python/okstra_ctl/clarification_items/rows.py +115 -0
- package/runtime/python/okstra_ctl/clarification_items/scan.py +215 -0
- package/runtime/python/okstra_ctl/clarification_items/sidecars.py +211 -0
- package/runtime/python/okstra_ctl/cmux.py +38 -31
- package/runtime/python/okstra_ctl/code_review_target.py +163 -1
- package/runtime/python/okstra_ctl/conformance.py +23 -0
- package/runtime/python/okstra_ctl/container.py +38 -421
- package/runtime/python/okstra_ctl/context_cost.py +16 -2
- package/runtime/python/okstra_ctl/contract_graph_cli.py +7 -0
- package/runtime/python/okstra_ctl/convergence.py +101 -15
- package/runtime/python/okstra_ctl/convergence_critic_prompt.py +345 -0
- package/runtime/python/okstra_ctl/convergence_engine.py +382 -70
- package/runtime/python/okstra_ctl/convergence_store.py +5 -29
- package/runtime/python/okstra_ctl/design_prep.py +108 -12
- package/runtime/python/okstra_ctl/design_snapshot.py +11 -1
- package/runtime/python/okstra_ctl/design_surfaces.py +29 -2
- package/runtime/python/okstra_ctl/dispatch_core.py +102 -25
- package/runtime/python/okstra_ctl/dispatch_state.py +268 -39
- package/runtime/python/okstra_ctl/doctor_cli.py +48 -0
- package/runtime/python/okstra_ctl/domain/worker_exec.py +10 -5
- package/runtime/python/okstra_ctl/domain/worker_presentation.py +21 -1
- package/runtime/python/okstra_ctl/domain/worker_stream.py +52 -21
- package/runtime/python/okstra_ctl/domain/write_policy.py +219 -0
- package/runtime/python/okstra_ctl/entrypoints/hosts.py +9 -2
- package/runtime/python/okstra_ctl/error_log_core.py +1 -1
- package/runtime/python/okstra_ctl/error_report.py +14 -0
- package/runtime/python/okstra_ctl/error_zip.py +18 -2
- package/runtime/python/okstra_ctl/execution_identity.py +100 -7
- package/runtime/python/okstra_ctl/execution_manifest.py +67 -20
- package/runtime/python/okstra_ctl/execution_mutation_audit.py +90 -8
- package/runtime/python/okstra_ctl/final_report_paths.py +17 -0
- package/runtime/python/okstra_ctl/final_report_schema.py +90 -16
- package/runtime/python/okstra_ctl/git_reconcile.py +22 -2
- package/runtime/python/okstra_ctl/handoff.py +24 -1
- package/runtime/python/okstra_ctl/ids.py +6 -16
- package/runtime/python/okstra_ctl/implementation_direction.py +142 -33
- package/runtime/python/okstra_ctl/implementation_options.py +25 -11
- package/runtime/python/okstra_ctl/implementation_outcome.py +5 -2
- package/runtime/python/okstra_ctl/improvement_lenses.py +0 -14
- package/runtime/python/okstra_ctl/incremental_carry.py +69 -8
- package/runtime/python/okstra_ctl/incremental_scope.py +173 -12
- package/runtime/python/okstra_ctl/index.py +2 -2
- package/runtime/python/okstra_ctl/initial_prompt_materialization.py +48 -8
- package/runtime/python/okstra_ctl/interactive_cli.py +223 -0
- package/runtime/python/okstra_ctl/json_boundary.py +10 -0
- package/runtime/python/okstra_ctl/listing.py +0 -91
- package/runtime/python/okstra_ctl/locks.py +5 -19
- package/runtime/python/okstra_ctl/log_report.py +14 -0
- package/runtime/python/okstra_ctl/manager_cli.py +22 -3
- package/runtime/python/okstra_ctl/manager_launch.py +4 -8
- package/runtime/python/okstra_ctl/material.py +2 -2
- package/runtime/python/okstra_ctl/migrate.py +23 -1
- package/runtime/python/okstra_ctl/model_cli.py +19 -5
- package/runtime/python/okstra_ctl/model_discovery.py +46 -47
- package/runtime/python/okstra_ctl/model_io/__init__.py +1 -0
- package/runtime/python/okstra_ctl/model_io/lines.py +163 -0
- package/runtime/python/okstra_ctl/model_io/references.py +370 -0
- package/runtime/python/okstra_ctl/model_io/renderers.py +498 -0
- package/runtime/python/okstra_ctl/model_io_cli.py +30 -945
- package/runtime/python/okstra_ctl/model_pool.py +10 -6
- package/runtime/python/okstra_ctl/models.py +8 -8
- package/runtime/python/okstra_ctl/mutation_recovery.py +5 -63
- package/runtime/python/okstra_ctl/next_phase.py +121 -69
- package/runtime/python/okstra_ctl/pane_reclaim.py +23 -0
- package/runtime/python/okstra_ctl/pane_title.py +11 -8
- package/runtime/python/okstra_ctl/path_hints.py +36 -11
- package/runtime/python/okstra_ctl/paths.py +76 -8
- package/runtime/python/okstra_ctl/plan_items.py +132 -16
- package/runtime/python/okstra_ctl/plan_items_cli.py +486 -36
- package/runtime/python/okstra_ctl/plan_run_root.py +1 -1
- package/runtime/python/okstra_ctl/plan_validate_cli.py +51 -0
- package/runtime/python/okstra_ctl/plan_verify_cli.py +80 -0
- package/runtime/python/okstra_ctl/prepare_error.py +20 -0
- package/runtime/python/okstra_ctl/prior_planning.py +157 -0
- package/runtime/python/okstra_ctl/profile_show.py +18 -1
- package/runtime/python/okstra_ctl/project_setup_cli.py +140 -0
- package/runtime/python/okstra_ctl/recap.py +22 -1
- package/runtime/python/okstra_ctl/reconcile.py +84 -0
- package/runtime/python/okstra_ctl/registry/host_registry.py +18 -1
- package/runtime/python/okstra_ctl/render.py +98 -32
- package/runtime/python/okstra_ctl/render_final_report.py +3 -7
- package/runtime/python/okstra_ctl/report_assembly.py +297 -7
- package/runtime/python/okstra_ctl/report_contract.py +30 -7
- package/runtime/python/okstra_ctl/report_finalize.py +206 -15
- package/runtime/python/okstra_ctl/report_html/common.py +2 -2
- package/runtime/python/okstra_ctl/report_html/render.py +8 -12
- package/runtime/python/okstra_ctl/report_language.py +8 -4
- package/runtime/python/okstra_ctl/report_narrative.py +90 -3
- package/runtime/python/okstra_ctl/report_projections.py +8 -2
- package/runtime/python/okstra_ctl/report_synthesis_packet.py +258 -1
- package/runtime/python/okstra_ctl/report_translation.py +2 -35
- package/runtime/python/okstra_ctl/report_views.py +4 -22
- package/runtime/python/okstra_ctl/resolve_task_key.py +13 -0
- package/runtime/python/okstra_ctl/rollup.py +13 -0
- package/runtime/python/okstra_ctl/run.py +639 -138
- package/runtime/python/okstra_ctl/run_audit.py +13 -0
- package/runtime/python/okstra_ctl/run_index_row.py +0 -12
- package/runtime/python/okstra_ctl/seeding.py +21 -11
- package/runtime/python/okstra_ctl/sequence.py +1 -1
- package/runtime/python/okstra_ctl/session.py +64 -14
- package/runtime/python/okstra_ctl/set_work_status.py +18 -0
- package/runtime/python/okstra_ctl/stage_integrate.py +15 -1
- package/runtime/python/okstra_ctl/stage_ledger.py +1 -1
- package/runtime/python/okstra_ctl/stage_map.py +57 -11
- package/runtime/python/okstra_ctl/stage_map_cli.py +83 -0
- package/runtime/python/okstra_ctl/stage_map_view.py +65 -0
- package/runtime/python/okstra_ctl/stage_targets.py +3 -12
- package/runtime/python/okstra_ctl/task_list_cli.py +138 -0
- package/runtime/python/okstra_ctl/task_show_cli.py +66 -0
- package/runtime/python/okstra_ctl/task_target.py +4 -16
- package/runtime/python/okstra_ctl/team.py +49 -2
- package/runtime/python/okstra_ctl/time_report.py +17 -2
- package/runtime/python/okstra_ctl/usage_report.py +11 -0
- package/runtime/python/okstra_ctl/user_response.py +55 -218
- package/runtime/python/okstra_ctl/user_response_values.py +242 -0
- package/runtime/python/okstra_ctl/validation_contract.py +3 -0
- package/runtime/python/okstra_ctl/verification_target.py +68 -0
- package/runtime/python/okstra_ctl/wizard.py +457 -92
- package/runtime/python/okstra_ctl/worker_artifacts.py +75 -16
- package/runtime/python/okstra_ctl/worker_audit_check.py +22 -0
- package/runtime/python/okstra_ctl/worker_dispatch.py +21 -0
- package/runtime/python/okstra_ctl/worker_liveness.py +33 -0
- package/runtime/python/okstra_ctl/worker_prompt_body.py +15 -2
- package/runtime/python/okstra_ctl/worker_prompt_contract.py +98 -7
- package/runtime/python/okstra_ctl/worker_prompt_headers.py +24 -2
- package/runtime/python/okstra_ctl/worker_prompt_policy.py +18 -3
- package/runtime/python/okstra_ctl/worker_request.py +2 -1
- package/runtime/python/okstra_ctl/worker_runner.py +16 -9
- package/runtime/python/okstra_ctl/worker_state.py +16 -1
- package/runtime/python/okstra_ctl/workflow.py +18 -1
- package/runtime/python/okstra_ctl/worktree/__init__.py +92 -0
- package/runtime/python/okstra_ctl/worktree/cleanliness.py +89 -0
- package/runtime/python/okstra_ctl/worktree/decisions.py +127 -0
- package/runtime/python/okstra_ctl/worktree/git_ops.py +165 -0
- package/runtime/python/okstra_ctl/worktree/linking.py +249 -0
- package/runtime/python/okstra_ctl/worktree/naming.py +91 -0
- package/runtime/python/okstra_ctl/worktree/provision.py +385 -0
- package/runtime/python/okstra_ctl/worktree/sync_config.py +181 -0
- package/runtime/python/okstra_ctl/worktree_cli.py +75 -0
- package/runtime/python/okstra_ctl/worktree_lookup_cli.py +39 -0
- package/runtime/python/okstra_ctl/worktree_registry.py +7 -0
- package/runtime/python/okstra_ctl/worktree_status_cli.py +53 -0
- package/runtime/python/okstra_ctl/write_policy.py +90 -213
- package/runtime/python/okstra_project/__init__.py +0 -4
- package/runtime/python/okstra_project/dirs.py +2 -2
- package/runtime/python/okstra_project/phase_pointer.py +84 -0
- package/runtime/python/okstra_project/slug.py +24 -0
- package/runtime/python/okstra_project/state.py +22 -230
- package/runtime/python/okstra_token_usage/claude.py +9 -1
- package/runtime/python/okstra_token_usage/cli.py +3 -1
- package/runtime/python/okstra_token_usage/collect.py +71 -10
- package/runtime/python/okstra_token_usage/cursor.py +2 -0
- package/runtime/python/okstra_token_usage/grok.py +1 -5
- package/runtime/python/okstra_token_usage/paths.py +26 -0
- package/runtime/python/okstra_token_usage/pricing.py +19 -7
- package/runtime/schemas/convergence-critic-results-v1.0.schema.json +5 -0
- package/runtime/schemas/execution-manifest-v2.schema.json +10 -10
- package/runtime/schemas/final-report-v2.0.schema.json +9 -26
- package/runtime/schemas/final-report-v3.0.schema.json +173 -41
- package/runtime/schemas/report-narrative-v3.0.schema.json +3 -2
- package/runtime/skills/okstra-brief-gen/SKILL.md +35 -2
- package/runtime/skills/okstra-container-build/SKILL.md +16 -47
- package/runtime/skills/okstra-inspect/facets/history.md +1 -1
- package/runtime/skills/okstra-inspect/facets/status.md +7 -6
- package/runtime/skills/okstra-pr-gen/SKILL.md +1 -1
- package/runtime/skills/okstra-run/SKILL.md +7 -5
- package/runtime/templates/report-writer-prompt-preamble.md +1 -1
- package/runtime/templates/reports/brief.template.md +6 -2
- package/runtime/templates/reports/error-analysis-input.template.md +2 -0
- package/runtime/templates/reports/final-verification-input.template.md +2 -0
- package/runtime/templates/reports/implementation-input.template.md +7 -1
- package/runtime/templates/reports/implementation-planning-input.template.md +4 -0
- package/runtime/templates/reports/quick-input.template.md +2 -0
- package/runtime/templates/reports/release-handoff-input.template.md +6 -1
- package/runtime/templates/reports/report.js +20 -3
- package/runtime/templates/reports/schedule.template.md +2 -0
- package/runtime/templates/reports/settings.template.json +0 -10
- package/runtime/templates/reports/task-brief.template.md +3 -0
- package/runtime/templates/reports/user-response.template.md +7 -3
- package/runtime/validators/checks/fixtures-01.py +57 -0
- package/runtime/validators/checks/fixtures-02.py +565 -0
- package/runtime/validators/checks/runners-01.py +108 -0
- package/runtime/validators/checks/validate-assets-01.py +60 -0
- package/runtime/validators/checks/validate-prompt-metadata-01.py +261 -0
- package/runtime/validators/checks/validate-tasks-01.py +46 -0
- package/runtime/validators/checks/validate-tasks-02.py +85 -0
- package/runtime/validators/checks/validate-tasks-03.py +61 -0
- package/runtime/validators/checks/validate-tasks-04.py +118 -0
- package/runtime/validators/forbidden_actions.py +73 -3
- package/runtime/validators/lib/common.sh +5 -0
- package/runtime/validators/lib/fixtures.sh +7 -591
- package/runtime/validators/lib/paths.sh +13 -0
- package/runtime/validators/lib/runners.sh +6 -104
- package/runtime/validators/lib/summary.sh +1 -1
- package/runtime/validators/lib/validate-assets.sh +6 -56
- package/runtime/validators/lib/validate-prompt-metadata.sh +6 -257
- package/runtime/validators/lib/validate-tasks.sh +9 -294
- package/runtime/validators/validate-implementation-plan-stages.py +4 -4
- package/runtime/validators/validate-run.py +1369 -2654
- package/runtime/validators/validate-workflow.sh +56 -16
- package/runtime/validators/validate_improvement_report.py +2 -1
- package/runtime/validators/validate_session_conformance.py +295 -49
- package/dist/commands/execute/agent-prompt.d.mts +0 -1
- package/dist/commands/execute/agent-prompt.mjs +0 -24
- package/dist/commands/execute/agent-prompt.mjs.map +0 -1
- package/dist/commands/execute/codex-dispatch.d.mts +0 -3
- package/dist/commands/execute/codex-dispatch.mjs +0 -6
- package/dist/commands/execute/codex-dispatch.mjs.map +0 -1
- package/dist/commands/execute/codex-run.d.mts +0 -3
- package/dist/commands/execute/codex-run.mjs +0 -62
- package/dist/commands/execute/codex-run.mjs.map +0 -1
- package/dist/commands/execute/convergence.d.mts +0 -1
- package/dist/commands/execute/convergence.mjs +0 -38
- package/dist/commands/execute/convergence.mjs.map +0 -1
- package/dist/commands/execute/error-log.d.mts +0 -1
- package/dist/commands/execute/error-log.mjs +0 -18
- package/dist/commands/execute/error-log.mjs.map +0 -1
- package/dist/commands/execute/git-reconcile.d.mts +0 -1
- package/dist/commands/execute/git-reconcile.mjs +0 -30
- package/dist/commands/execute/git-reconcile.mjs.map +0 -1
- package/dist/commands/execute/handoff.d.mts +0 -1
- package/dist/commands/execute/handoff.mjs +0 -31
- package/dist/commands/execute/handoff.mjs.map +0 -1
- package/dist/commands/execute/incremental-carry.d.mts +0 -1
- package/dist/commands/execute/incremental-carry.mjs +0 -20
- package/dist/commands/execute/incremental-carry.mjs.map +0 -1
- package/dist/commands/execute/incremental-scope.d.mts +0 -1
- package/dist/commands/execute/incremental-scope.mjs +0 -29
- package/dist/commands/execute/incremental-scope.mjs.map +0 -1
- package/dist/commands/execute/integrate-stages.d.mts +0 -1
- package/dist/commands/execute/integrate-stages.mjs +0 -24
- package/dist/commands/execute/integrate-stages.mjs.map +0 -1
- package/dist/commands/execute/pane-title.d.mts +0 -1
- package/dist/commands/execute/pane-title.mjs +0 -20
- package/dist/commands/execute/pane-title.mjs.map +0 -1
- package/dist/commands/execute/plan-items.d.mts +0 -1
- package/dist/commands/execute/plan-items.mjs +0 -9
- package/dist/commands/execute/plan-items.mjs.map +0 -1
- package/dist/commands/execute/plan-validate.d.mts +0 -1
- package/dist/commands/execute/plan-validate.mjs +0 -68
- package/dist/commands/execute/plan-validate.mjs.map +0 -1
- package/dist/commands/execute/plan-verify.d.mts +0 -1
- package/dist/commands/execute/plan-verify.mjs +0 -43
- package/dist/commands/execute/plan-verify.mjs.map +0 -1
- package/dist/commands/execute/spawn-followups.d.mts +0 -1
- package/dist/commands/execute/spawn-followups.mjs +0 -22
- package/dist/commands/execute/spawn-followups.mjs.map +0 -1
- package/dist/commands/execute/team.d.mts +0 -3
- package/dist/commands/execute/team.mjs +0 -66
- package/dist/commands/execute/team.mjs.map +0 -1
- package/dist/commands/execute/token-usage.d.mts +0 -1
- package/dist/commands/execute/token-usage.mjs +0 -19
- package/dist/commands/execute/token-usage.mjs.map +0 -1
- package/dist/commands/execute/worker-audit-check.d.mts +0 -1
- package/dist/commands/execute/worker-audit-check.mjs +0 -34
- package/dist/commands/execute/worker-audit-check.mjs.map +0 -1
- package/dist/commands/execute/worker-dispatch.d.mts +0 -7
- package/dist/commands/execute/worker-dispatch.mjs +0 -64
- package/dist/commands/execute/worker-dispatch.mjs.map +0 -1
- package/dist/commands/execute/worker-state.d.mts +0 -1
- package/dist/commands/execute/worker-state.mjs +0 -28
- package/dist/commands/execute/worker-state.mjs.map +0 -1
- package/dist/commands/execute/worktree-lookup.d.mts +0 -1
- package/dist/commands/execute/worktree-lookup.mjs +0 -92
- package/dist/commands/execute/worktree-lookup.mjs.map +0 -1
- package/dist/commands/execute/worktree-status.d.mts +0 -1
- package/dist/commands/execute/worktree-status.mjs +0 -121
- package/dist/commands/execute/worktree-status.mjs.map +0 -1
- package/dist/commands/inspect/code-review.d.mts +0 -1
- package/dist/commands/inspect/code-review.mjs +0 -32
- package/dist/commands/inspect/code-review.mjs.map +0 -1
- package/dist/commands/inspect/container.d.mts +0 -1
- package/dist/commands/inspect/container.mjs +0 -25
- package/dist/commands/inspect/container.mjs.map +0 -1
- package/dist/commands/inspect/context-cost.d.mts +0 -1
- package/dist/commands/inspect/context-cost.mjs +0 -25
- package/dist/commands/inspect/context-cost.mjs.map +0 -1
- package/dist/commands/inspect/design-prep.d.mts +0 -1
- package/dist/commands/inspect/design-prep.mjs +0 -22
- package/dist/commands/inspect/design-prep.mjs.map +0 -1
- package/dist/commands/inspect/error-report.d.mts +0 -1
- package/dist/commands/inspect/error-report.mjs +0 -25
- package/dist/commands/inspect/error-report.mjs.map +0 -1
- package/dist/commands/inspect/error-zip.d.mts +0 -1
- package/dist/commands/inspect/error-zip.mjs +0 -24
- package/dist/commands/inspect/error-zip.mjs.map +0 -1
- package/dist/commands/inspect/log-report.d.mts +0 -1
- package/dist/commands/inspect/log-report.mjs +0 -26
- package/dist/commands/inspect/log-report.mjs.map +0 -1
- package/dist/commands/inspect/model-io.d.mts +0 -1
- package/dist/commands/inspect/model-io.mjs +0 -25
- package/dist/commands/inspect/model-io.mjs.map +0 -1
- package/dist/commands/inspect/profile-show.d.mts +0 -1
- package/dist/commands/inspect/profile-show.mjs +0 -28
- package/dist/commands/inspect/profile-show.mjs.map +0 -1
- package/dist/commands/inspect/recap.d.mts +0 -1
- package/dist/commands/inspect/recap.mjs +0 -30
- package/dist/commands/inspect/recap.mjs.map +0 -1
- package/dist/commands/inspect/resolve-task-key.d.mts +0 -1
- package/dist/commands/inspect/resolve-task-key.mjs +0 -24
- package/dist/commands/inspect/resolve-task-key.mjs.map +0 -1
- package/dist/commands/inspect/rollup.d.mts +0 -1
- package/dist/commands/inspect/rollup.mjs +0 -25
- package/dist/commands/inspect/rollup.mjs.map +0 -1
- package/dist/commands/inspect/run-audit.d.mts +0 -1
- package/dist/commands/inspect/run-audit.mjs +0 -25
- package/dist/commands/inspect/run-audit.mjs.map +0 -1
- package/dist/commands/inspect/set-work-status.d.mts +0 -1
- package/dist/commands/inspect/set-work-status.mjs +0 -29
- package/dist/commands/inspect/set-work-status.mjs.map +0 -1
- package/dist/commands/inspect/stage-map.d.mts +0 -1
- package/dist/commands/inspect/stage-map.mjs +0 -131
- package/dist/commands/inspect/stage-map.mjs.map +0 -1
- package/dist/commands/inspect/task-list.d.mts +0 -1
- package/dist/commands/inspect/task-list.mjs +0 -149
- package/dist/commands/inspect/task-list.mjs.map +0 -1
- package/dist/commands/inspect/task-show.d.mts +0 -1
- package/dist/commands/inspect/task-show.mjs +0 -108
- package/dist/commands/inspect/task-show.mjs.map +0 -1
- package/dist/commands/inspect/time-report.d.mts +0 -1
- package/dist/commands/inspect/time-report.mjs +0 -24
- package/dist/commands/inspect/time-report.mjs.map +0 -1
- package/dist/commands/inspect/usage-report.d.mts +0 -1
- package/dist/commands/inspect/usage-report.mjs +0 -23
- package/dist/commands/inspect/usage-report.mjs.map +0 -1
- package/dist/commands/inspect/user-response.d.mts +0 -1
- package/dist/commands/inspect/user-response.mjs +0 -35
- package/dist/commands/inspect/user-response.mjs.map +0 -1
- package/dist/commands/inspect/worker-liveness.d.mts +0 -1
- package/dist/commands/inspect/worker-liveness.mjs +0 -45
- package/dist/commands/inspect/worker-liveness.mjs.map +0 -1
- package/dist/commands/lifecycle/contract-check.d.mts +0 -1
- package/dist/commands/lifecycle/contract-check.mjs +0 -18
- package/dist/commands/lifecycle/contract-check.mjs.map +0 -1
- package/dist/commands/lifecycle/migrate.d.mts +0 -1
- package/dist/commands/lifecycle/migrate.mjs +0 -30
- package/dist/commands/lifecycle/migrate.mjs.map +0 -1
- package/dist/commands/lifecycle/model.d.mts +0 -1
- package/dist/commands/lifecycle/model.mjs +0 -22
- package/dist/commands/lifecycle/model.mjs.map +0 -1
- package/dist/commands/manager.d.mts +0 -3
- package/dist/commands/manager.mjs +0 -50
- package/dist/commands/manager.mjs.map +0 -1
- package/dist/commands/report/agent-activity.d.mts +0 -1
- package/dist/commands/report/agent-activity.mjs +0 -20
- package/dist/commands/report/agent-activity.mjs.map +0 -1
- package/dist/commands/report/approval-decision.d.mts +0 -1
- package/dist/commands/report/approval-decision.mjs +0 -21
- package/dist/commands/report/approval-decision.mjs.map +0 -1
- package/dist/commands/report/design-snapshot.d.mts +0 -1
- package/dist/commands/report/design-snapshot.mjs +0 -19
- package/dist/commands/report/design-snapshot.mjs.map +0 -1
- package/dist/commands/report/finalize.d.mts +0 -4
- package/dist/commands/report/finalize.mjs +0 -64
- package/dist/commands/report/finalize.mjs.map +0 -1
- package/dist/commands/report/inject-report-index.d.mts +0 -1
- package/dist/commands/report/inject-report-index.mjs +0 -21
- package/dist/commands/report/inject-report-index.mjs.map +0 -1
- package/dist/commands/report/render-final-report.d.mts +0 -1
- package/dist/commands/report/render-final-report.mjs +0 -23
- package/dist/commands/report/render-final-report.mjs.map +0 -1
- package/dist/commands/report/render-views.d.mts +0 -1
- package/dist/commands/report/render-views.mjs +0 -27
- package/dist/commands/report/render-views.mjs.map +0 -1
- package/dist/commands/report/translate.d.mts +0 -1
- package/dist/commands/report/translate.mjs +0 -33
- package/dist/commands/report/translate.mjs.map +0 -1
- package/runtime/bin/lib/okstra/tmux-pane.sh +0 -40
- package/runtime/bin/lib/okstra-ctl/cmd-batch.sh +0 -59
- package/runtime/bin/lib/okstra-ctl/cmd-list.sh +0 -35
- package/runtime/bin/lib/okstra-ctl/cmd-open.sh +0 -36
- package/runtime/bin/lib/okstra-ctl/cmd-projects.sh +0 -26
- package/runtime/bin/lib/okstra-ctl/cmd-reconcile.sh +0 -29
- package/runtime/bin/lib/okstra-ctl/cmd-reindex.sh +0 -38
- package/runtime/bin/lib/okstra-ctl/cmd-rerun.sh +0 -345
- package/runtime/bin/lib/okstra-ctl/cmd-show.sh +0 -27
- package/runtime/bin/lib/okstra-ctl/cmd-tail.sh +0 -92
- package/runtime/bin/lib/okstra-ctl/main.sh +0 -41
- package/runtime/bin/lib/okstra-ctl/prepare.sh +0 -31
- package/runtime/bin/lib/okstra-ctl/usage.sh +0 -23
- package/runtime/bin/okstra-central.sh +0 -152
- package/runtime/bin/okstra-incremental-carry.py +0 -10
- package/runtime/bin/okstra-incremental-scope.py +0 -10
- package/runtime/bin/okstra-team-reconcile.sh +0 -36
- package/runtime/python/okstra_ctl/agent_prompt_cli.py +0 -1156
- package/runtime/python/okstra_ctl/batch.py +0 -60
- package/runtime/python/okstra_ctl/clarification_items.py +0 -1050
- package/runtime/python/okstra_ctl/container_registry.py +0 -72
- package/runtime/python/okstra_ctl/improvement_assignment.py +0 -61
- package/runtime/python/okstra_ctl/resolver.py +0 -54
- package/runtime/python/okstra_ctl/team_reconcile.py +0 -275
- package/runtime/python/okstra_ctl/tmux.py +0 -134
- package/runtime/python/okstra_ctl/worktree.py +0 -1099
|
@@ -12,9 +12,10 @@ to be worth a default here — ``content_block_events``, whose events are keyed
|
|
|
12
12
|
provider, and an adapter that speaks something else says so in its own file.
|
|
13
13
|
|
|
14
14
|
Screen output folds what the log keeps in full — a tool call becomes one line, a
|
|
15
|
-
tool result becomes an outcome
|
|
16
|
-
|
|
17
|
-
rather than from log writes (see the
|
|
15
|
+
tool result becomes an outcome, a size, and the first few rows of what came
|
|
16
|
+
back. Thinking is dropped at normalisation, which is safe only because worker
|
|
17
|
+
liveness is measured from stream arrival rather than from log writes (see the
|
|
18
|
+
spec's 7.2).
|
|
18
19
|
|
|
19
20
|
Three projections of the same stream: ``format_live`` for the pane,
|
|
20
21
|
``format_log`` for the archive, and ``final_text`` for the caller that must
|
|
@@ -31,6 +32,14 @@ from typing import Any, Callable, Mapping
|
|
|
31
32
|
# previous one off the top of a short pane.
|
|
32
33
|
_MAX_SUMMARY = 120
|
|
33
34
|
|
|
35
|
+
# 화면이 받는 도구 결과 본문의 줄 수. 0 줄이던 동안 pane 에 남는 것은 성패와
|
|
36
|
+
# 바이트 수뿐이었다. 어떤 어댑터가 본문 대신 도구 이름표를 넘겨 모든 호출이
|
|
37
|
+
# 한 자릿수 바이트로 보이던 run 을, 화면만 보고는 아무도 판별하지 못했다.
|
|
38
|
+
# 결과 하나가 pane 을 다 차지하면 직전 호출이 위로 밀려 나가므로 앞부분만
|
|
39
|
+
# 보여주고, 나머지는 로그가 갖는다.
|
|
40
|
+
_LIVE_BODY_ROWS = 4
|
|
41
|
+
_BODY_INDENT = " "
|
|
42
|
+
|
|
34
43
|
|
|
35
44
|
@dataclass(frozen=True)
|
|
36
45
|
class Text:
|
|
@@ -58,11 +67,20 @@ class ToolResult:
|
|
|
58
67
|
``failed`` is None when the stream closed the tool step without reporting an
|
|
59
68
|
outcome at all. Reading that absence as success would put a confident "ok"
|
|
60
69
|
next to a command that failed.
|
|
70
|
+
|
|
71
|
+
``body_describes_result`` marks a tool that reported *about* its result
|
|
72
|
+
instead of returning it — a file read that answers ``54 lines, 4293 bytes``
|
|
73
|
+
rather than the 4293 bytes. Without the mark the two are the same shape and
|
|
74
|
+
the size reads as the payload, so a 4293-byte read is archived as
|
|
75
|
+
``← done (20 bytes)`` and a reader concludes the read came back nearly
|
|
76
|
+
empty. The provider that emits such a report says so; this layer only
|
|
77
|
+
renders it differently.
|
|
61
78
|
"""
|
|
62
79
|
|
|
63
80
|
body: str
|
|
64
81
|
size_bytes: int
|
|
65
82
|
failed: bool | None = None
|
|
83
|
+
body_describes_result: bool = False
|
|
66
84
|
|
|
67
85
|
|
|
68
86
|
@dataclass(frozen=True)
|
|
@@ -112,17 +130,6 @@ def host_event_row(
|
|
|
112
130
|
return row
|
|
113
131
|
|
|
114
132
|
|
|
115
|
-
def no_events(event: Mapping[str, Any]) -> tuple[StreamEvent, ...]:
|
|
116
|
-
"""The normaliser for a CLI that emits no events at all.
|
|
117
|
-
|
|
118
|
-
A text CLI's output is already what a person reads, so the runner forwards
|
|
119
|
-
it whole and never calls this. It exists so ``ExecCommand`` can default to
|
|
120
|
-
a truthful "there is nothing here to normalise" instead of to some
|
|
121
|
-
provider's schema.
|
|
122
|
-
"""
|
|
123
|
-
return ()
|
|
124
|
-
|
|
125
|
-
|
|
126
133
|
def content_block_events(event: Mapping[str, Any]) -> tuple[StreamEvent, ...]:
|
|
127
134
|
"""Normalise the stream shape keyed on ``type`` with ``message.content``.
|
|
128
135
|
|
|
@@ -157,7 +164,7 @@ def content_block_events(event: Mapping[str, Any]) -> tuple[StreamEvent, ...]:
|
|
|
157
164
|
|
|
158
165
|
|
|
159
166
|
def format_live(event: StreamEvent) -> list[str]:
|
|
160
|
-
return _rows(event, limit=_MAX_SUMMARY,
|
|
167
|
+
return _rows(event, limit=_MAX_SUMMARY, body_rows=_LIVE_BODY_ROWS)
|
|
161
168
|
|
|
162
169
|
|
|
163
170
|
def format_log(event: StreamEvent) -> list[str]:
|
|
@@ -167,7 +174,7 @@ def format_log(event: StreamEvent) -> list[str]:
|
|
|
167
174
|
the fact, by a person reconstructing why a worker failed and by
|
|
168
175
|
``okstra log-report``.
|
|
169
176
|
"""
|
|
170
|
-
return _rows(event, limit=None,
|
|
177
|
+
return _rows(event, limit=None, body_rows=None)
|
|
171
178
|
|
|
172
179
|
|
|
173
180
|
def final_text(event: StreamEvent) -> str | None:
|
|
@@ -175,17 +182,24 @@ def final_text(event: StreamEvent) -> str | None:
|
|
|
175
182
|
return event.text if isinstance(event, Result) else None
|
|
176
183
|
|
|
177
184
|
|
|
178
|
-
def _rows(event: StreamEvent, *, limit: int | None,
|
|
185
|
+
def _rows(event: StreamEvent, *, limit: int | None, body_rows: int | None) -> list[str]:
|
|
179
186
|
if isinstance(event, Text):
|
|
180
187
|
return _body_rows(event.body)
|
|
181
188
|
if isinstance(event, ToolCall):
|
|
182
189
|
head = f"→ {event.name}: {event.detail}" if event.detail else f"→ {event.name}"
|
|
183
190
|
return [_truncate(head, limit)]
|
|
184
191
|
if isinstance(event, ToolResult):
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
192
|
+
if event.body_describes_result:
|
|
193
|
+
# 크기를 싣지 않는다. 이 이벤트가 가진 숫자는 보고 문자열의 길이일
|
|
194
|
+
# 뿐이고(보고조차 없으면 0), 그것을 payload 자리에 놓는 것이 오독의
|
|
195
|
+
# 출처였다.
|
|
196
|
+
report = " ".join(event.body.split())
|
|
197
|
+
tail = (
|
|
198
|
+
f"the tool reported: {report}" if report else "the tool reported nothing"
|
|
199
|
+
)
|
|
200
|
+
return [_truncate(f" ← {_outcome(event.failed)} — no body returned; {tail}", limit)]
|
|
201
|
+
head = f" ← {_outcome(event.failed)} ({event.size_bytes} bytes)"
|
|
202
|
+
return [head, *_result_body(event.body, limit=limit, keep=body_rows)]
|
|
189
203
|
if isinstance(event, Denial):
|
|
190
204
|
return [_truncate(f"!! PERMISSION DENIED — {event.tool}: {event.reason}", limit)]
|
|
191
205
|
# A Result is printed by the runner at the point the run ends, not woven
|
|
@@ -193,6 +207,23 @@ def _rows(event: StreamEvent, *, limit: int | None, include_body: bool) -> list[
|
|
|
193
207
|
return []
|
|
194
208
|
|
|
195
209
|
|
|
210
|
+
def _result_body(body: str, *, limit: int | None, keep: int | None) -> list[str]:
|
|
211
|
+
"""결과 본문을 몇 줄 보여줄지 정한다.
|
|
212
|
+
|
|
213
|
+
`keep is None` 이 기록의 몫이다 — 전부 남긴다. 화면은 앞 몇 줄만 받고,
|
|
214
|
+
생략한 줄 수를 밝힌다. 밝히지 않으면 짧은 출력과 잘린 출력이 같은 모양이
|
|
215
|
+
되어, 읽는 사람이 로그를 열 이유를 알 수 없다.
|
|
216
|
+
"""
|
|
217
|
+
rows = _body_rows(body)
|
|
218
|
+
if keep is None:
|
|
219
|
+
return rows
|
|
220
|
+
shown = [_truncate(_BODY_INDENT + row, limit) for row in rows[:keep]]
|
|
221
|
+
dropped = len(rows) - keep
|
|
222
|
+
if dropped > 0:
|
|
223
|
+
shown.append(f"{_BODY_INDENT}… +{dropped} more line(s) — full body in the log")
|
|
224
|
+
return shown
|
|
225
|
+
|
|
226
|
+
|
|
196
227
|
def _outcome(failed: bool | None) -> str:
|
|
197
228
|
if failed is None:
|
|
198
229
|
return "done"
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"""쓰기 정책 값 타입 · 직렬화 · 검증.
|
|
2
|
+
|
|
3
|
+
`..write_policy`(623줄) 안에 있던 값 코어를 도메인으로 내렸다. 그 모듈은
|
|
4
|
+
git 을 실행하고 run manifest 를 읽는 응용 로직인데, `domain/worker_exec.py` 가
|
|
5
|
+
`WritePolicy` / `WriteEnforcement` 타입 하나 때문에 그 응용 모듈을 최상위
|
|
6
|
+
import 하고 있었다 — 도메인이 응용을 부르는 역전이고, 그 탓에
|
|
7
|
+
`write_policy → path_hints` 가 함수 본문 지연 import 로 밀려나 있었다.
|
|
8
|
+
|
|
9
|
+
값과 그 값의 정합성(직렬화·다이제스트·payload 검증)까지가 여기다.
|
|
10
|
+
정책을 **만들거나**(build_*) **유도하는**(derive_*) 일은 응용에 남는다.
|
|
11
|
+
`..write_policy` 가 이 이름들을 재노출하므로 기존 호출부는 바뀌지 않는다.
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import hashlib
|
|
16
|
+
import json
|
|
17
|
+
from collections.abc import Mapping, Sequence
|
|
18
|
+
from dataclasses import dataclass
|
|
19
|
+
from pathlib import Path, PurePosixPath
|
|
20
|
+
from typing import Any, Literal
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
BoundaryPrecision = Literal["exact-path", "directory-boundary", "none"]
|
|
24
|
+
|
|
25
|
+
_PRECISION_RANK = {"none": 0, "directory-boundary": 1, "exact-path": 2}
|
|
26
|
+
|
|
27
|
+
_POLICY_KEYS = {
|
|
28
|
+
"artifactPolicy",
|
|
29
|
+
"sourcePolicy",
|
|
30
|
+
"gitPolicy",
|
|
31
|
+
"auxiliaryPolicy",
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
_ENFORCEMENT_KEYS = {
|
|
35
|
+
"boundaryPrecision",
|
|
36
|
+
"mutationAudit",
|
|
37
|
+
"attribution",
|
|
38
|
+
"auditedRoots",
|
|
39
|
+
"observationCoverage",
|
|
40
|
+
"unobservedWriteSurfaces",
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
class WritePolicyError(ValueError):
|
|
44
|
+
"""Raised when a write policy cannot be made canonical or trustworthy."""
|
|
45
|
+
|
|
46
|
+
@dataclass(frozen=True)
|
|
47
|
+
class WritePolicy:
|
|
48
|
+
artifact_policy: Mapping[str, Any]
|
|
49
|
+
source_policy: Mapping[str, Any]
|
|
50
|
+
git_policy: Mapping[str, Any]
|
|
51
|
+
auxiliary_policy: Mapping[str, Any]
|
|
52
|
+
maximum_boundary_precision: BoundaryPrecision = "none"
|
|
53
|
+
|
|
54
|
+
def to_payload(self) -> dict[str, Any]:
|
|
55
|
+
return {
|
|
56
|
+
"artifactPolicy": dict(self.artifact_policy),
|
|
57
|
+
"sourcePolicy": dict(self.source_policy),
|
|
58
|
+
"gitPolicy": dict(self.git_policy),
|
|
59
|
+
"auxiliaryPolicy": dict(self.auxiliary_policy),
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def digest(self) -> str:
|
|
64
|
+
return write_policy_digest(self.to_payload())
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def source_mode(self) -> str:
|
|
68
|
+
return str(self.source_policy["mode"])
|
|
69
|
+
|
|
70
|
+
@dataclass(frozen=True)
|
|
71
|
+
class WriteEnforcement:
|
|
72
|
+
boundary_precision: BoundaryPrecision
|
|
73
|
+
mutation_audit: Literal["none", "batch"]
|
|
74
|
+
attribution: Literal["call", "batch-unattributed"]
|
|
75
|
+
audited_roots: tuple[Path, ...]
|
|
76
|
+
observation_coverage: Literal["complete", "scoped", "partial"]
|
|
77
|
+
unobserved_write_surfaces: tuple[str, ...]
|
|
78
|
+
|
|
79
|
+
def to_payload(self) -> dict[str, Any]:
|
|
80
|
+
return {
|
|
81
|
+
"boundaryPrecision": self.boundary_precision,
|
|
82
|
+
"mutationAudit": self.mutation_audit,
|
|
83
|
+
"attribution": self.attribution,
|
|
84
|
+
"auditedRoots": [str(path) for path in self.audited_roots],
|
|
85
|
+
"observationCoverage": self.observation_coverage,
|
|
86
|
+
"unobservedWriteSurfaces": list(self.unobserved_write_surfaces),
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
def write_policy_from_payload(payload: Mapping[str, Any]) -> WritePolicy:
|
|
90
|
+
validate_write_policy_payload(payload)
|
|
91
|
+
return WritePolicy(
|
|
92
|
+
artifact_policy=dict(payload["artifactPolicy"]),
|
|
93
|
+
source_policy=dict(payload["sourcePolicy"]),
|
|
94
|
+
git_policy=dict(payload["gitPolicy"]),
|
|
95
|
+
auxiliary_policy=dict(payload["auxiliaryPolicy"]),
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
def write_enforcement_from_payload(
|
|
99
|
+
payload: Mapping[str, Any],
|
|
100
|
+
) -> WriteEnforcement:
|
|
101
|
+
validate_write_enforcement_payload(payload)
|
|
102
|
+
return WriteEnforcement(
|
|
103
|
+
boundary_precision=payload["boundaryPrecision"],
|
|
104
|
+
mutation_audit=payload["mutationAudit"],
|
|
105
|
+
attribution=payload["attribution"],
|
|
106
|
+
audited_roots=tuple(Path(value) for value in payload["auditedRoots"]),
|
|
107
|
+
observation_coverage=payload["observationCoverage"],
|
|
108
|
+
unobserved_write_surfaces=tuple(payload["unobservedWriteSurfaces"]),
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
def write_policy_digest(payload: Mapping[str, Any]) -> str:
|
|
112
|
+
validate_write_policy_payload(payload)
|
|
113
|
+
encoded = json.dumps(
|
|
114
|
+
payload,
|
|
115
|
+
sort_keys=True,
|
|
116
|
+
separators=(",", ":"),
|
|
117
|
+
ensure_ascii=False,
|
|
118
|
+
).encode("utf-8")
|
|
119
|
+
return "sha256:" + hashlib.sha256(encoded).hexdigest()
|
|
120
|
+
|
|
121
|
+
def validate_write_policy_payload(payload: Mapping[str, Any]) -> None:
|
|
122
|
+
if set(payload) != _POLICY_KEYS:
|
|
123
|
+
raise WritePolicyError("writePolicy must contain four canonical policy sections")
|
|
124
|
+
artifact = _mapping(payload.get("artifactPolicy"), "artifactPolicy")
|
|
125
|
+
source = _mapping(payload.get("sourcePolicy"), "sourcePolicy")
|
|
126
|
+
git = _mapping(payload.get("gitPolicy"), "gitPolicy")
|
|
127
|
+
auxiliary = _mapping(payload.get("auxiliaryPolicy"), "auxiliaryPolicy")
|
|
128
|
+
if set(artifact) != {"allowedRoot", "allowedPaths"}:
|
|
129
|
+
raise WritePolicyError("artifactPolicy is incomplete")
|
|
130
|
+
_absolute_text(artifact.get("allowedRoot"), "artifactPolicy.allowedRoot")
|
|
131
|
+
_relative_paths(artifact.get("allowedPaths", ()))
|
|
132
|
+
if source.get("mode") not in {"source-readonly", "project-mutation"}:
|
|
133
|
+
raise WritePolicyError("sourcePolicy mode is invalid")
|
|
134
|
+
if set(source) != {"mode", "allowedRoot", "plannedPaths", "protectedPaths"}:
|
|
135
|
+
raise WritePolicyError("sourcePolicy is incomplete")
|
|
136
|
+
_absolute_text(source.get("allowedRoot"), "sourcePolicy.allowedRoot")
|
|
137
|
+
_relative_paths(source.get("plannedPaths", ()))
|
|
138
|
+
_relative_paths(source.get("protectedPaths", ()))
|
|
139
|
+
if git.get("mode") not in {"disabled", "fast-forward-descendant-chain"}:
|
|
140
|
+
raise WritePolicyError("gitPolicy mode is invalid")
|
|
141
|
+
if git.get("mode") == "disabled" and set(git) != {"mode"}:
|
|
142
|
+
raise WritePolicyError("disabled gitPolicy must not grant Git paths")
|
|
143
|
+
required_git = {
|
|
144
|
+
"mode", "worktreeGitDir", "gitCommonDir", "expectedBaseCommit",
|
|
145
|
+
"allowedBranchRef", "commitMode",
|
|
146
|
+
}
|
|
147
|
+
if git.get("mode") != "disabled" and set(git) != required_git:
|
|
148
|
+
raise WritePolicyError("project mutation gitPolicy is incomplete")
|
|
149
|
+
if set(auxiliary) != {"scratchRoots", "generatedPaths", "externalRoots"}:
|
|
150
|
+
raise WritePolicyError("auxiliaryPolicy is incomplete")
|
|
151
|
+
_relative_paths(auxiliary.get("generatedPaths", ()))
|
|
152
|
+
for key in ("scratchRoots", "externalRoots"):
|
|
153
|
+
for value in _text_sequence(auxiliary.get(key), f"auxiliaryPolicy.{key}"):
|
|
154
|
+
_absolute_text(value, f"auxiliaryPolicy.{key}")
|
|
155
|
+
|
|
156
|
+
def validate_write_enforcement_payload(payload: Mapping[str, Any]) -> None:
|
|
157
|
+
if set(payload) != _ENFORCEMENT_KEYS:
|
|
158
|
+
raise WritePolicyError("writeEnforcement is incomplete")
|
|
159
|
+
boundary = payload.get("boundaryPrecision")
|
|
160
|
+
mutation_audit = payload.get("mutationAudit")
|
|
161
|
+
attribution = payload.get("attribution")
|
|
162
|
+
coverage = payload.get("observationCoverage")
|
|
163
|
+
if boundary not in _PRECISION_RANK:
|
|
164
|
+
raise WritePolicyError("writeEnforcement boundaryPrecision is invalid")
|
|
165
|
+
if mutation_audit not in {"none", "batch"}:
|
|
166
|
+
raise WritePolicyError("writeEnforcement mutationAudit is invalid")
|
|
167
|
+
if attribution not in {"call", "batch-unattributed"}:
|
|
168
|
+
raise WritePolicyError("writeEnforcement attribution is invalid")
|
|
169
|
+
if coverage not in {"complete", "scoped", "partial"}:
|
|
170
|
+
raise WritePolicyError("writeEnforcement observationCoverage is invalid")
|
|
171
|
+
if (boundary, mutation_audit, attribution) == ("exact-path", "none", "call"):
|
|
172
|
+
if coverage != "complete":
|
|
173
|
+
raise WritePolicyError("exact enforcement must have complete coverage")
|
|
174
|
+
elif (boundary, mutation_audit, attribution) == (
|
|
175
|
+
"none",
|
|
176
|
+
"none",
|
|
177
|
+
"batch-unattributed",
|
|
178
|
+
):
|
|
179
|
+
if coverage != "partial":
|
|
180
|
+
raise WritePolicyError("host-session enforcement must be partial")
|
|
181
|
+
elif mutation_audit != "batch" or attribution != "batch-unattributed":
|
|
182
|
+
raise WritePolicyError("non-exact enforcement must use batch attribution")
|
|
183
|
+
elif boundary == "exact-path" or coverage == "complete":
|
|
184
|
+
raise WritePolicyError("batch enforcement cannot claim exact coverage")
|
|
185
|
+
for root in _text_sequence(payload.get("auditedRoots"), "auditedRoots"):
|
|
186
|
+
_absolute_text(root, "auditedRoots")
|
|
187
|
+
_text_sequence(payload.get("unobservedWriteSurfaces"), "unobservedWriteSurfaces")
|
|
188
|
+
|
|
189
|
+
def _relative_paths(value: object) -> tuple[str, ...]:
|
|
190
|
+
paths: list[str] = []
|
|
191
|
+
for raw in _text_sequence(value, "relative paths"):
|
|
192
|
+
candidate = PurePosixPath(raw)
|
|
193
|
+
if candidate.is_absolute() or not candidate.parts or ".." in candidate.parts:
|
|
194
|
+
raise WritePolicyError("policy paths must be normalized relative paths")
|
|
195
|
+
normalized = candidate.as_posix()
|
|
196
|
+
if normalized in {"", "."} or normalized != raw:
|
|
197
|
+
raise WritePolicyError("policy paths must be normalized relative paths")
|
|
198
|
+
paths.append(normalized)
|
|
199
|
+
if len(set(paths)) != len(paths):
|
|
200
|
+
raise WritePolicyError("policy paths must be unique")
|
|
201
|
+
return tuple(paths)
|
|
202
|
+
|
|
203
|
+
def _mapping(value: object, label: str) -> Mapping[str, Any]:
|
|
204
|
+
if not isinstance(value, Mapping):
|
|
205
|
+
raise WritePolicyError(f"{label} must be an object")
|
|
206
|
+
return value
|
|
207
|
+
|
|
208
|
+
def _text_sequence(value: object, label: str) -> tuple[str, ...]:
|
|
209
|
+
if not isinstance(value, Sequence) or isinstance(value, (str, bytes)):
|
|
210
|
+
raise WritePolicyError(f"{label} must be an array")
|
|
211
|
+
rows = tuple(value)
|
|
212
|
+
if any(not isinstance(row, str) or not row for row in rows):
|
|
213
|
+
raise WritePolicyError(f"{label} must contain non-empty strings")
|
|
214
|
+
return rows
|
|
215
|
+
|
|
216
|
+
def _absolute_text(value: object, label: str) -> str:
|
|
217
|
+
if not isinstance(value, str) or not value or not Path(value).is_absolute():
|
|
218
|
+
raise WritePolicyError(f"{label} must be an absolute path")
|
|
219
|
+
return value
|
|
@@ -9,7 +9,7 @@ from contextlib import contextmanager
|
|
|
9
9
|
from dataclasses import asdict
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
|
|
12
|
-
from ..
|
|
12
|
+
from ..agent.invocation import (
|
|
13
13
|
AgentInvocationError,
|
|
14
14
|
AgentModelAssignment,
|
|
15
15
|
agent_model_assignment_from_payload,
|
|
@@ -113,7 +113,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
113
113
|
resolve.add_argument(
|
|
114
114
|
"--capability",
|
|
115
115
|
action="append",
|
|
116
|
-
choices=("claude-skill-handoff",
|
|
116
|
+
choices=("claude-skill-handoff",),
|
|
117
117
|
default=[],
|
|
118
118
|
)
|
|
119
119
|
launch = commands.add_parser("launch-plan")
|
|
@@ -200,9 +200,16 @@ def _probe_payload(
|
|
|
200
200
|
status = "unknown" if "unavailable" in statuses else (
|
|
201
201
|
"ready" if readiness.ok else "blocked"
|
|
202
202
|
)
|
|
203
|
+
# A check may report that this session cannot host the lead while the run
|
|
204
|
+
# itself is fine. The caller needs the mode it must actually launch in, not
|
|
205
|
+
# the mode it asked about, so the probe answers with the resolved one.
|
|
206
|
+
entry_mode = (
|
|
207
|
+
"spawn-process" if "lead-must-spawn" in statuses else args.entry_mode
|
|
208
|
+
)
|
|
203
209
|
return {
|
|
204
210
|
"runtime": adapter.descriptor.id,
|
|
205
211
|
"status": status,
|
|
212
|
+
"entryMode": entry_mode,
|
|
206
213
|
"checks": list(readiness.checks),
|
|
207
214
|
"relayContract": adapter.descriptor.relay_contract,
|
|
208
215
|
}
|
|
@@ -210,8 +210,22 @@ def render_result_text(result: dict) -> str:
|
|
|
210
210
|
return "".join(parts)
|
|
211
211
|
|
|
212
212
|
|
|
213
|
+
_CLI_EPILOG = r"""Usage:
|
|
214
|
+
okstra error-report <task-root>
|
|
215
|
+
okstra error-report <task-key> --project-root <dir>
|
|
216
|
+
okstra error-report <task-key> --cwd <dir>
|
|
217
|
+
|
|
218
|
+
Writes a timestamped markdown report under <task-root>/error-reports/ and
|
|
219
|
+
prints a JSON summary (counts by errorType / source / phase / agent) to stdout.
|
|
220
|
+
This is read-only against task state; it never mutates task artifacts.
|
|
221
|
+
"""
|
|
222
|
+
|
|
223
|
+
|
|
213
224
|
def main(argv: list[str] | None = None) -> int:
|
|
214
225
|
parser = argparse.ArgumentParser(
|
|
226
|
+
prog="okstra error-report",
|
|
227
|
+
epilog=_CLI_EPILOG,
|
|
228
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
215
229
|
description="Aggregate okstra-run error logs into a task-level report."
|
|
216
230
|
)
|
|
217
231
|
parser.add_argument("target", help="task root path or task-key")
|
|
@@ -19,7 +19,11 @@ from okstra_ctl.error_log_core import aggregate, parse_records
|
|
|
19
19
|
from okstra_ctl.jsonl import read_jsonl
|
|
20
20
|
from okstra_ctl.locks import central_lock
|
|
21
21
|
from okstra_ctl.paths import okstra_home, resolve_under_root
|
|
22
|
-
from okstra_ctl.json_boundary import
|
|
22
|
+
from okstra_ctl.json_boundary import (
|
|
23
|
+
JsonBoundaryError,
|
|
24
|
+
load_owned_object,
|
|
25
|
+
write_owned_object_atomic,
|
|
26
|
+
)
|
|
23
27
|
|
|
24
28
|
|
|
25
29
|
def run_dirs(home: Path) -> list[tuple[str, Path, dict]]:
|
|
@@ -282,7 +286,7 @@ def last_output_path(home: Path) -> str:
|
|
|
282
286
|
"lastOutputPath", ""
|
|
283
287
|
)
|
|
284
288
|
)
|
|
285
|
-
except
|
|
289
|
+
except JsonBoundaryError:
|
|
286
290
|
return ""
|
|
287
291
|
|
|
288
292
|
|
|
@@ -335,8 +339,20 @@ def render_result_text(result: dict) -> str:
|
|
|
335
339
|
return "".join(lines)
|
|
336
340
|
|
|
337
341
|
|
|
342
|
+
_CLI_EPILOG = r"""Usage:
|
|
343
|
+
okstra error-zip --out <path>
|
|
344
|
+
|
|
345
|
+
Walks the global run-index (~/.okstra/recent.jsonl + active.jsonl), collects
|
|
346
|
+
every target project's runs/*/logs/errors-*.jsonl, anonymizes records, and
|
|
347
|
+
writes a .zip (report.md + errors/anonymized.jsonl) to <path>. Read-only
|
|
348
|
+
against every target's .okstra/. Prints a JSON summary to stdout.
|
|
349
|
+
"""
|
|
350
|
+
|
|
351
|
+
|
|
338
352
|
def main(argv: list[str] | None = None) -> int:
|
|
339
353
|
parser = argparse.ArgumentParser(
|
|
354
|
+
epilog=_CLI_EPILOG,
|
|
355
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
340
356
|
prog="okstra error-zip",
|
|
341
357
|
description="cross-project okstra 에러를 수집·익명화해 zip 으로 묶는다.",
|
|
342
358
|
)
|
|
@@ -6,7 +6,7 @@ import json
|
|
|
6
6
|
from collections.abc import Mapping
|
|
7
7
|
from dataclasses import dataclass, field
|
|
8
8
|
from pathlib import Path
|
|
9
|
-
from typing import Any
|
|
9
|
+
from typing import Any, Literal
|
|
10
10
|
|
|
11
11
|
from .domain.provider import HostModelBinding, ServedModelAttestation
|
|
12
12
|
from .domain.worker_exec import WorkerWriteCapability
|
|
@@ -116,9 +116,6 @@ class Invocation:
|
|
|
116
116
|
dispatch_kind: str
|
|
117
117
|
round: int
|
|
118
118
|
input_digest: str
|
|
119
|
-
write_policy: Mapping[str, Any]
|
|
120
|
-
write_policy_digest: str
|
|
121
|
-
write_enforcement: Mapping[str, Any]
|
|
122
119
|
|
|
123
120
|
def to_payload(self) -> dict[str, Any]:
|
|
124
121
|
return {
|
|
@@ -131,14 +128,19 @@ class Invocation:
|
|
|
131
128
|
"dispatchKind": self.dispatch_kind,
|
|
132
129
|
"round": self.round,
|
|
133
130
|
"inputDigest": self.input_digest,
|
|
134
|
-
"writePolicy": dict(self.write_policy),
|
|
135
|
-
"writePolicyDigest": self.write_policy_digest,
|
|
136
|
-
"writeEnforcement": dict(self.write_enforcement),
|
|
137
131
|
}
|
|
138
132
|
|
|
139
133
|
|
|
140
134
|
@dataclass(frozen=True)
|
|
141
135
|
class Attempt:
|
|
136
|
+
"""One dispatch of a logical invocation, with the write contract it ran under.
|
|
137
|
+
|
|
138
|
+
쓰기 계약이 invocation 이 아니라 여기 있는 이유: 계약의 artifactPolicy 는 그
|
|
139
|
+
시도가 실제로 쓰는 프롬프트 파생 파일(`...-attempt-2.log` 등)을 이름으로
|
|
140
|
+
담는다. attempt 마다 다른 값이므로 attempt-불변인 invocation 행에 두면 같은
|
|
141
|
+
invocationRef 의 2회차가 `invocationRef drift` 로 거절된다.
|
|
142
|
+
"""
|
|
143
|
+
|
|
142
144
|
invocation_ref: str
|
|
143
145
|
attempt: int
|
|
144
146
|
started_at: str
|
|
@@ -148,6 +150,9 @@ class Attempt:
|
|
|
148
150
|
error_path: str | None
|
|
149
151
|
change_summary: Mapping[str, Any]
|
|
150
152
|
evidence_seal_ref: str | None
|
|
153
|
+
write_policy: Mapping[str, Any]
|
|
154
|
+
write_policy_digest: str
|
|
155
|
+
write_enforcement: Mapping[str, Any]
|
|
151
156
|
|
|
152
157
|
def to_payload(self) -> dict[str, Any]:
|
|
153
158
|
return {
|
|
@@ -160,6 +165,9 @@ class Attempt:
|
|
|
160
165
|
"errorPath": self.error_path,
|
|
161
166
|
"changeSummary": dict(self.change_summary),
|
|
162
167
|
"evidenceSealRef": self.evidence_seal_ref,
|
|
168
|
+
"writePolicy": dict(self.write_policy),
|
|
169
|
+
"writePolicyDigest": self.write_policy_digest,
|
|
170
|
+
"writeEnforcement": dict(self.write_enforcement),
|
|
163
171
|
}
|
|
164
172
|
|
|
165
173
|
|
|
@@ -528,3 +536,88 @@ def _required_index_text(
|
|
|
528
536
|
def _optional_text(value: object) -> str | None:
|
|
529
537
|
text = str(value or "").strip()
|
|
530
538
|
return text or None
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
# ---- 무거운 모듈에서 옮겨 온 값 타입 ------------------------------------
|
|
542
|
+
# 아래 둘은 dispatch_state(2,092줄) 와 mutation_recovery 안에 있었다. 값 하나가
|
|
543
|
+
# 필요한 모듈이 그 모듈 전체를 끌어오게 되어, 반대 방향은 함수 본문 지연
|
|
544
|
+
# import 로 밀려나 순환이 됐다. 원래 소유 모듈이 이름을 재노출한다.
|
|
545
|
+
|
|
546
|
+
def build_dispatch_id(invocation_id: str, attempt: int) -> str:
|
|
547
|
+
"""The only place Python assembles a dispatch id.
|
|
548
|
+
|
|
549
|
+
Two generators drifted: this module pinned the attempt to 1 while
|
|
550
|
+
`dispatch_core` used the real one, so a re-dispatch took the first attempt's
|
|
551
|
+
id, team-state kept the same row twice, and `validate-run` failed that run
|
|
552
|
+
with `agent dispatch ID is duplicated`.
|
|
553
|
+
|
|
554
|
+
Prose mirrors of this shape live outside Python, where no guard reaches
|
|
555
|
+
them: `prompts/lead/convergence.md`, `prompts/lead/report-writer.md`,
|
|
556
|
+
`prompts/lead/plan-body-verification.md` and the five
|
|
557
|
+
`adapters/hosts/*/relay.md` each spell an `--dispatch-id` argument out for
|
|
558
|
+
the lead. They agree with this function only because
|
|
559
|
+
`record_verified_agent_dispatch` records the first attempt and no other;
|
|
560
|
+
changing that convention has to change them too.
|
|
561
|
+
"""
|
|
562
|
+
return f"{invocation_id}:attempt-{attempt}"
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
@dataclass(frozen=True)
|
|
566
|
+
class MutationRecoveryDecision:
|
|
567
|
+
recovery_ref: str
|
|
568
|
+
source_invocation_ref: str
|
|
569
|
+
source_attempt_ref: str
|
|
570
|
+
source_evidence_seal_ref: str | None
|
|
571
|
+
original_baseline_digest: str
|
|
572
|
+
terminal_source_diff_digest: str
|
|
573
|
+
terminal_git_chain_digest: str
|
|
574
|
+
verifier_role_execution_ref: str | None
|
|
575
|
+
verifier_invocation_ref: str | None
|
|
576
|
+
recovered_evidence_refs: tuple[Mapping[str, Any], ...]
|
|
577
|
+
recovered_out_of_plan_edits: tuple[Mapping[str, Any], ...]
|
|
578
|
+
unmet_obligations: tuple[str, ...]
|
|
579
|
+
decision: Literal["carry-forward", "reject", "cleanup-confirmed"]
|
|
580
|
+
reason: str = ""
|
|
581
|
+
|
|
582
|
+
def to_payload(self) -> dict[str, Any]:
|
|
583
|
+
return {
|
|
584
|
+
"recoveryRef": self.recovery_ref,
|
|
585
|
+
"sourceInvocationRef": self.source_invocation_ref,
|
|
586
|
+
"sourceAttemptRef": self.source_attempt_ref,
|
|
587
|
+
"sourceEvidenceSealRef": self.source_evidence_seal_ref,
|
|
588
|
+
"originalBaselineDigest": self.original_baseline_digest,
|
|
589
|
+
"terminalSourceDiffDigest": self.terminal_source_diff_digest,
|
|
590
|
+
"terminalGitChainDigest": self.terminal_git_chain_digest,
|
|
591
|
+
"verifierRoleExecutionRef": self.verifier_role_execution_ref,
|
|
592
|
+
"verifierInvocationRef": self.verifier_invocation_ref,
|
|
593
|
+
"recoveredEvidenceRefs": [dict(row) for row in self.recovered_evidence_refs],
|
|
594
|
+
"recoveredOutOfPlanEdits": [
|
|
595
|
+
dict(row) for row in self.recovered_out_of_plan_edits
|
|
596
|
+
],
|
|
597
|
+
"unmetObligations": list(self.unmet_obligations),
|
|
598
|
+
"decision": self.decision,
|
|
599
|
+
"reason": self.reason,
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
@classmethod
|
|
603
|
+
def from_payload(cls, payload: Mapping[str, Any]) -> "MutationRecoveryDecision":
|
|
604
|
+
return cls(
|
|
605
|
+
recovery_ref=str(payload["recoveryRef"]),
|
|
606
|
+
source_invocation_ref=str(payload["sourceInvocationRef"]),
|
|
607
|
+
source_attempt_ref=str(payload["sourceAttemptRef"]),
|
|
608
|
+
source_evidence_seal_ref=payload.get("sourceEvidenceSealRef"),
|
|
609
|
+
original_baseline_digest=str(payload.get("originalBaselineDigest") or ""),
|
|
610
|
+
terminal_source_diff_digest=str(
|
|
611
|
+
payload.get("terminalSourceDiffDigest") or ""
|
|
612
|
+
),
|
|
613
|
+
terminal_git_chain_digest=str(payload.get("terminalGitChainDigest") or ""),
|
|
614
|
+
verifier_role_execution_ref=payload.get("verifierRoleExecutionRef"),
|
|
615
|
+
verifier_invocation_ref=payload.get("verifierInvocationRef"),
|
|
616
|
+
recovered_evidence_refs=tuple(payload.get("recoveredEvidenceRefs") or ()),
|
|
617
|
+
recovered_out_of_plan_edits=tuple(
|
|
618
|
+
payload.get("recoveredOutOfPlanEdits") or ()
|
|
619
|
+
),
|
|
620
|
+
unmet_obligations=tuple(payload.get("unmetObligations") or ()),
|
|
621
|
+
decision=str(payload["decision"]),
|
|
622
|
+
reason=str(payload.get("reason") or ""),
|
|
623
|
+
)
|