okstra 0.114.0 → 0.116.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/docs/kr/architecture.md +2 -2
- package/docs/kr/follow-ups/2026-07-10-final-report-option-3.md +51 -0
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/report-writer-worker.md +1 -0
- package/runtime/prompts/launch.template.md +34 -0
- package/runtime/prompts/lead/convergence.md +2 -0
- package/runtime/prompts/lead/okstra-lead-contract.md +1 -1
- package/runtime/prompts/lead/report-writer.md +1 -1
- package/runtime/prompts/profiles/implementation-planning.md +1 -0
- package/runtime/python/okstra_ctl/implementation_stage.py +46 -39
- package/runtime/python/okstra_ctl/incremental_carry.py +70 -0
- package/runtime/python/okstra_ctl/incremental_scope.py +89 -0
- package/runtime/python/okstra_ctl/report_views.py +151 -12
- package/runtime/python/okstra_ctl/run.py +24 -24
- package/runtime/python/okstra_ctl/stage_targets.py +26 -0
- package/runtime/python/okstra_ctl/worktree.py +1 -1
- package/runtime/python/okstra_token_usage/claude.py +58 -19
- package/runtime/python/okstra_token_usage/collect.py +3 -1
- package/runtime/python/okstra_vendor/__init__.py +3 -0
- package/runtime/schemas/final-report-v1.0.schema.json +39 -0
- package/runtime/templates/reports/final-report.template.md +27 -0
- package/runtime/templates/reports/i18n/en.json +23 -12
- package/runtime/templates/reports/i18n/ko.json +23 -12
- package/runtime/templates/reports/report.css +55 -0
- package/runtime/templates/reports/report.js +53 -1
- package/runtime/validators/validate-run.py +50 -0
- package/src/cli-registry.mjs +14 -0
- package/src/commands/execute/incremental-carry.mjs +20 -0
- package/src/commands/execute/incremental-scope.mjs +20 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_approx_clust_coeff.py +0 -41
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_clique.py +0 -112
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_connectivity.py +0 -199
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_density.py +0 -146
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_distance_measures.py +0 -59
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_dominating_set.py +0 -78
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_kcomponents.py +0 -303
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_matching.py +0 -8
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_maxcut.py +0 -94
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_ramsey.py +0 -31
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_steinertree.py +0 -306
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_traveling_salesman.py +0 -1014
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_treewidth.py +0 -274
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_vertex_cover.py +0 -68
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/base_test.py +0 -81
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_connectivity.py +0 -143
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_correlation.py +0 -122
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_mixing.py +0 -174
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_neighbor_degree.py +0 -107
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_pairs.py +0 -87
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_basic.py +0 -125
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_centrality.py +0 -192
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_cluster.py +0 -84
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_covering.py +0 -33
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_edgelist.py +0 -240
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_extendability.py +0 -334
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_generators.py +0 -407
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_link_analysis.py +0 -218
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_matching.py +0 -327
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_matrix.py +0 -138
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_project.py +0 -409
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_redundancy.py +0 -35
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_spectral_bipartivity.py +0 -80
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_betweenness_centrality.py +0 -923
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_betweenness_centrality_subset.py +0 -354
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_closeness_centrality.py +0 -274
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality.py +0 -259
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality_subset.py +0 -147
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_closeness.py +0 -43
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_degree_centrality.py +0 -144
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_dispersion.py +0 -73
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_eigenvector_centrality.py +0 -186
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_group.py +0 -277
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_harmonic_centrality.py +0 -122
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_katz_centrality.py +0 -345
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_laplacian_centrality.py +0 -220
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_load_centrality.py +0 -344
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_percolation_centrality.py +0 -87
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_reaching.py +0 -140
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_second_order_centrality.py +0 -82
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_subgraph.py +0 -110
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_trophic.py +0 -302
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_voterank.py +0 -64
- package/runtime/python/okstra_vendor/networkx/algorithms/coloring/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/coloring/tests/test_coloring.py +0 -863
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_asyn_fluid.py +0 -147
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_bipartitions.py +0 -157
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_centrality.py +0 -85
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_divisive.py +0 -106
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_kclique.py +0 -91
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_label_propagation.py +0 -241
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_leiden.py +0 -138
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_local.py +0 -76
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_louvain.py +0 -264
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_lukes.py +0 -152
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_modularity_max.py +0 -340
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_quality.py +0 -139
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_utils.py +0 -26
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_attracting.py +0 -70
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_biconnected.py +0 -248
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_connected.py +0 -138
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_semiconnected.py +0 -55
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_strongly_connected.py +0 -193
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_weakly_connected.py +0 -96
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_connectivity.py +0 -421
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_cuts.py +0 -309
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_disjoint_paths.py +0 -249
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_edge_augmentation.py +0 -502
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_edge_kcomponents.py +0 -488
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_kcomponents.py +0 -323
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_kcutsets.py +0 -280
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_stoer_wagner.py +0 -102
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/gl1.gpickle.bz2 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/gw1.gpickle.bz2 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/netgen-2.gpickle.bz2 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_gomory_hu.py +0 -128
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_maxflow.py +0 -573
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_maxflow_large_graph.py +0 -155
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_mincost.py +0 -475
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_networksimplex.py +0 -481
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/wlm3.gpickle.bz2 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/iso_r01_s80.A99 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/iso_r01_s80.B99 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/si2_b06_m200.A99 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/si2_b06_m200.B99 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_ismags.py +0 -719
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_isomorphism.py +0 -103
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_isomorphvf2.py +0 -490
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_match_helpers.py +0 -64
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_temporalisomorphvf2.py +0 -212
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_tree_isomorphism.py +0 -202
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2pp.py +0 -1655
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2pp_helpers.py +0 -3118
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2userfunc.py +0 -196
- package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/test_hits.py +0 -77
- package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/test_pagerank.py +0 -213
- package/runtime/python/okstra_vendor/networkx/algorithms/minors/tests/test_contraction.py +0 -544
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_all.py +0 -328
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_binary.py +0 -451
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_product.py +0 -491
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_unary.py +0 -55
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_astar.py +0 -254
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_dense.py +0 -212
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_dense_numpy.py +0 -88
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_generic.py +0 -511
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_unweighted.py +0 -149
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_weighted.py +0 -983
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_asteroidal.py +0 -23
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_boundary.py +0 -154
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_bridges.py +0 -144
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_broadcasting.py +0 -109
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_chains.py +0 -136
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_chordal.py +0 -129
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_clique.py +0 -300
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cluster.py +0 -678
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_communicability.py +0 -80
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_core.py +0 -266
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_covering.py +0 -85
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cuts.py +0 -171
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cycles.py +0 -984
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_d_separation.py +0 -340
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dag.py +0 -835
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_distance_measures.py +0 -831
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_distance_regular.py +0 -85
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dominance.py +0 -299
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dominating.py +0 -115
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_efficiency.py +0 -58
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_euler.py +0 -314
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_graph_hashing.py +0 -872
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_graphical.py +0 -163
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_hierarchy.py +0 -46
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_hybrid.py +0 -24
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_isolate.py +0 -26
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_link_prediction.py +0 -615
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_lowest_common_ancestors.py +0 -459
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_matching.py +0 -556
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_max_weight_clique.py +0 -179
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_mis.py +0 -62
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_moral.py +0 -15
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_node_classification.py +0 -140
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_non_randomness.py +0 -60
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_perfect_graph.py +0 -27
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_planar_drawing.py +0 -274
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_planarity.py +0 -556
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_polynomials.py +0 -57
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_reciprocity.py +0 -37
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_regular.py +0 -88
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_richclub.py +0 -149
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_similarity.py +0 -1158
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_simple_paths.py +0 -803
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_smallworld.py +0 -76
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_smetric.py +0 -8
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_sparsifiers.py +0 -138
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_structuralholes.py +0 -191
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_summarization.py +0 -642
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_swap.py +0 -179
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_threshold.py +0 -270
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_time_dependent.py +0 -431
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_tournament.py +0 -161
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_triads.py +0 -248
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_vitality.py +0 -41
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_voronoi.py +0 -103
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_walks.py +0 -54
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_wiener.py +0 -157
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_beamsearch.py +0 -25
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_bfs.py +0 -203
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_dfs.py +0 -307
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_edgebfs.py +0 -147
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_edgedfs.py +0 -131
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_branchings.py +0 -624
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_coding.py +0 -114
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_decomposition.py +0 -79
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_distance_measures.py +0 -99
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_mst.py +0 -934
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_operations.py +0 -53
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_recognition.py +0 -174
- package/runtime/python/okstra_vendor/networkx/classes/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/classes/tests/dispatch_interface.py +0 -192
- package/runtime/python/okstra_vendor/networkx/classes/tests/historical_tests.py +0 -476
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_coreviews.py +0 -362
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_digraph.py +0 -331
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_digraph_historical.py +0 -110
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_filters.py +0 -177
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_function.py +0 -1045
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_graph.py +0 -950
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_graph_historical.py +0 -12
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_graphviews.py +0 -349
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_multidigraph.py +0 -459
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_multigraph.py +0 -528
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_reportviews.py +0 -1421
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_special.py +0 -131
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_subgraphviews.py +0 -371
- package/runtime/python/okstra_vendor/networkx/conftest.py +0 -261
- package/runtime/python/okstra_vendor/networkx/drawing/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_complex.png +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_empty_graph.png +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_house_with_colors.png +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_labels_and_colors.png +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_shortest_path.png +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_house_with_colors.png +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/test_agraph.py +0 -237
- package/runtime/python/okstra_vendor/networkx/drawing/tests/test_image_comparison_pylab_mpl.py +0 -229
- package/runtime/python/okstra_vendor/networkx/drawing/tests/test_latex.py +0 -285
- package/runtime/python/okstra_vendor/networkx/drawing/tests/test_layout.py +0 -631
- package/runtime/python/okstra_vendor/networkx/drawing/tests/test_pydot.py +0 -146
- package/runtime/python/okstra_vendor/networkx/drawing/tests/test_pylab.py +0 -1582
- package/runtime/python/okstra_vendor/networkx/generators/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_atlas.py +0 -75
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_classic.py +0 -642
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_cographs.py +0 -20
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_community.py +0 -362
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_degree_seq.py +0 -224
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_directed.py +0 -189
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_duplication.py +0 -103
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_ego.py +0 -39
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_expanders.py +0 -182
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_geometric.py +0 -488
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_harary_graph.py +0 -133
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_internet_as_graphs.py +0 -221
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_intersection.py +0 -28
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_interval_graph.py +0 -144
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_joint_degree_seq.py +0 -125
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_lattice.py +0 -264
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_line.py +0 -316
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_mycielski.py +0 -30
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_nonisomorphic_trees.py +0 -82
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_random_clustered.py +0 -33
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_random_graphs.py +0 -495
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_small.py +0 -220
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_spectral_graph_forge.py +0 -49
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_stochastic.py +0 -72
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_sudoku.py +0 -92
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_time_series.py +0 -64
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_trees.py +0 -195
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_triads.py +0 -15
- package/runtime/python/okstra_vendor/networkx/linalg/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_algebraic_connectivity.py +0 -400
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_attrmatrix.py +0 -108
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_bethehessian.py +0 -40
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_graphmatrix.py +0 -275
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_laplacian.py +0 -334
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_modularity.py +0 -86
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_spectrum.py +0 -70
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_adjacency.py +0 -78
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_cytoscape.py +0 -78
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_node_link.py +0 -109
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_tree.py +0 -48
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_adjlist.py +0 -354
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_edgelist.py +0 -318
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_gexf.py +0 -612
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_gml.py +0 -744
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_graph6.py +0 -181
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_graphml.py +0 -1531
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_leda.py +0 -30
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_p2g.py +0 -63
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_pajek.py +0 -128
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_sparse6.py +0 -166
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_text.py +0 -1742
- package/runtime/python/okstra_vendor/networkx/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/tests/test_all_random_functions.py +0 -248
- package/runtime/python/okstra_vendor/networkx/tests/test_convert.py +0 -321
- package/runtime/python/okstra_vendor/networkx/tests/test_convert_numpy.py +0 -531
- package/runtime/python/okstra_vendor/networkx/tests/test_convert_pandas.py +0 -349
- package/runtime/python/okstra_vendor/networkx/tests/test_convert_scipy.py +0 -281
- package/runtime/python/okstra_vendor/networkx/tests/test_exceptions.py +0 -40
- package/runtime/python/okstra_vendor/networkx/tests/test_import.py +0 -11
- package/runtime/python/okstra_vendor/networkx/tests/test_lazy_imports.py +0 -96
- package/runtime/python/okstra_vendor/networkx/tests/test_relabel.py +0 -349
- package/runtime/python/okstra_vendor/networkx/tests/test_removed_functions_exception_messages.py +0 -8
- package/runtime/python/okstra_vendor/networkx/utils/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/utils/tests/test__init.py +0 -11
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_backends.py +0 -225
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_config.py +0 -263
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_decorators.py +0 -510
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_heaps.py +0 -131
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_mapped_queue.py +0 -268
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_misc.py +0 -393
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_random_sequence.py +0 -53
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_rcm.py +0 -63
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_unionfind.py +0 -55
package/docs/kr/architecture.md
CHANGED
|
@@ -235,7 +235,7 @@ per-process 환경 변수에 task 정체성·경로·workflow 상태를 보관
|
|
|
235
235
|
- standard workflow의 기본 worker role은 `Claude worker`, `Codex worker`, `Report writer worker`이며, `Antigravity worker`는 `--workers` 또는 프로필에서 명시할 때만 포함되는 옵션입니다.
|
|
236
236
|
- worker 역할 분담과 최종 판단은 Claude가 task bundle을 읽고 수행합니다.
|
|
237
237
|
- 사용자 홈에 설치된 okstra Claude assets(`~/.claude/skills`, `~/.claude/agents`) 는 `Agent(name: ...)` 로 워커를 dispatch 하도록 Claude 를 유도합니다 — 워커는 세션의 implicit team 에 자동 합류합니다.
|
|
238
|
-
- **팀 lifecycle (Claude Code v2.1.178+)**: v2.1.178 이 `TeamCreate` / `TeamDelete` 도구와 `Agent(...)` 의 `team_name` 파라미터를 제거했습니다. `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`(`okstra install` 이 `settings.json` 에 시드) 이면 세션마다 implicit team 1개가 시작 시점에 자동 생성됩니다. lead 는 Phase 3 에서 팀을 만드는 도구를 호출하지 않고, `teamName` audit 라벨과 `teamCreate: { attempted: false, status: "implicit", splitPane: <$TMUX 유무> }` 만 기록한 뒤 워커를 `Agent(name: "<role>-worker", run_in_background: true)`(team_name 없음)로 dispatch 합니다. split-pane teammate 는 `$TMUX` 가 설정돼 있고 `teammateMode: auto` 일 때 나타나며, tmux 밖이면 in-process 로 돕니다(둘 다 정상). run 종료 시 Phase 7 토큰 집계 이후 잔여 tmux pane 정리를 확인하고, split-pane run 에서만 worker teammate 를 정리할지 확인합니다. 승인 시 `okstra-team-reconcile.sh` 로 dead-pane stale-active 멤버를 inactive 로 정리하고 각 완료 teammate 에 `SendMessage` shutdown_request 를 보냅니다 — implicit team 자체를 지우는 도구는 없으며, 팀은 세션 종료와 함께 사라집니다. 사용자가 유지하면 teammate 는 FleetView roster 에 남고, lead 는 Teams/FleetView 에서 제거하라고 안내합니다 (`prompts/profiles/_common-contract.md` 의 *Run-end teammate teardown*). Phase 7 토큰 집계는 `teamCreate.status` 가 `implicit`/`skipped`/`error` 일 때 `agentName`
|
|
238
|
+
- **팀 lifecycle (Claude Code v2.1.178+)**: v2.1.178 이 `TeamCreate` / `TeamDelete` 도구와 `Agent(...)` 의 `team_name` 파라미터를 제거했습니다. `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`(`okstra install` 이 `settings.json` 에 시드) 이면 세션마다 implicit team 1개가 시작 시점에 자동 생성됩니다. lead 는 Phase 3 에서 팀을 만드는 도구를 호출하지 않고, `teamName` audit 라벨과 `teamCreate: { attempted: false, status: "implicit", splitPane: <$TMUX 유무> }` 만 기록한 뒤 워커를 `Agent(name: "<role>-worker", run_in_background: true)`(team_name 없음)로 dispatch 합니다. split-pane teammate 는 `$TMUX` 가 설정돼 있고 `teammateMode: auto` 일 때 나타나며, tmux 밖이면 in-process 로 돕니다(둘 다 정상). run 종료 시 Phase 7 토큰 집계 이후 잔여 tmux pane 정리를 확인하고, split-pane run 에서만 worker teammate 를 정리할지 확인합니다. 승인 시 `okstra-team-reconcile.sh` 로 dead-pane stale-active 멤버를 inactive 로 정리하고 각 완료 teammate 에 `SendMessage` shutdown_request 를 보냅니다 — implicit team 자체를 지우는 도구는 없으며, 팀은 세션 종료와 함께 사라집니다. 사용자가 유지하면 teammate 는 FleetView roster 에 남고, lead 는 Teams/FleetView 에서 제거하라고 안내합니다 (`prompts/profiles/_common-contract.md` 의 *Run-end teammate teardown*). Phase 7 토큰 집계는 `teamCreate.status` 가 `implicit`/`skipped`/`error` 일 때 top-level `agentName` 또는 nested `subagents/agent-a<name>-<hash>.jsonl` 파일명 기반으로 워커 세션을 찾습니다.
|
|
239
239
|
|
|
240
240
|
## Claude prompt contract
|
|
241
241
|
|
|
@@ -698,7 +698,7 @@ Phase 7 step 1.5 가 final-report MD 한 본을 입력으로 self-contained HTML
|
|
|
698
698
|
|
|
699
699
|
- Helper CLI: `scripts/okstra-token-usage.py`
|
|
700
700
|
- 수집 소스:
|
|
701
|
-
- Claude lead/workers: `~/.claude/projects/<cwd-as-dashes>/<sessionId>.jsonl
|
|
701
|
+
- Claude lead/workers: `~/.claude/projects/<cwd-as-dashes>/<sessionId>.jsonl` 또는 `~/.claude/projects/<cwd-as-dashes>/<lead-session>/subagents/agent-a<worker-name>-<hash>.jsonl` 의 per-message `message.usage`. nested subagent 파일은 파일명에서 worker name 을 복원하고, 현재 run 의 `team-state.lead.sessionId` 디렉터리 아래만 집계합니다.
|
|
702
702
|
- Codex CLI: `~/.agent/sessions/Y/M/D/rollout-*.jsonl`의 마지막 `total_token_usage.total_tokens`
|
|
703
703
|
- Antigravity CLI: `~/.antigravity/tmp/*/chats/session-*.json`의 per-message `tokens.total`
|
|
704
704
|
- billable-equivalent token math와 USD cost estimation을 함께 기록합니다. Anthropic billing ratio(`cache_creation_5m=1.25x`, `cache_creation_1h=2.0x`, `cache_read=0.1x`, `output=5x`)를 반영합니다. transcript 의 `usage.cache_creation.ephemeral_5m_input_tokens` / `ephemeral_1h_input_tokens` 분해가 있으면 분리 집계합니다.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Final Report 가독성 후속: 3안 재검토
|
|
2
|
+
|
|
3
|
+
상태: 보류
|
|
4
|
+
작성일: 2026-07-10
|
|
5
|
+
|
|
6
|
+
## 배경
|
|
7
|
+
|
|
8
|
+
이번 1차 가독성 개선은 범위를 좁게 유지했다.
|
|
9
|
+
|
|
10
|
+
- `readerSummary`로 Markdown final-report 앞부분에 사람이 먼저 읽을 요약 진입점을 둔다.
|
|
11
|
+
- HTML report view에 Reader Summary dashboard와 reader mode를 추가한다.
|
|
12
|
+
- 기존 `final-report` data는 `verdictCard` fallback으로 계속 호환한다.
|
|
13
|
+
|
|
14
|
+
이 문서는 더 큰 3안을 현재 변경에 섞지 않고, 나중에 별도 판단할 재검토 후보로 남긴다.
|
|
15
|
+
|
|
16
|
+
## 보류한 3안
|
|
17
|
+
|
|
18
|
+
`final-report` 산출물 자체를 목적별로 분리할지 재검토한다.
|
|
19
|
+
|
|
20
|
+
현재 구조는 하나의 canonical Markdown 문서와 그 문서에서 생성되는 view를 유지한다. 3안은 요약 블록이나 HTML 필터링만으로 충분한지, 아니면 report를 목적별 artifact로 나누는 편이 더 나은지 비교하는 작업이다.
|
|
21
|
+
|
|
22
|
+
비교 후보:
|
|
23
|
+
|
|
24
|
+
- 짧은 human handoff report와 별도 audit appendix.
|
|
25
|
+
- 같은 `data.json`에서 생성되는 `summary` view와 `audit` view.
|
|
26
|
+
- 사람이 먼저 행동하는 섹션만 남기는 phase별 slim report template.
|
|
27
|
+
- reporter handoff, implementer handoff, verifier audit, release handoff 같은 role별 view set.
|
|
28
|
+
|
|
29
|
+
## 재검토 트리거
|
|
30
|
+
|
|
31
|
+
아래 중 하나가 반복되면 이 문서를 다시 연다.
|
|
32
|
+
|
|
33
|
+
- `readerSummary`와 HTML reader mode 배포 후에도 사용자가 `final-report`를 읽기 어렵다고 말한다.
|
|
34
|
+
- 리뷰어가 항상 같은 audit 섹션을 건너뛰거나 더 작은 handoff artifact를 요구한다.
|
|
35
|
+
- `final-report` 생성에서 같은 evidence가 여러 섹션에 반복된다.
|
|
36
|
+
- 향후 schema migration에서 report artifact 계약을 어차피 건드려야 한다.
|
|
37
|
+
|
|
38
|
+
## 결정할 질문
|
|
39
|
+
|
|
40
|
+
- Markdown이 계속 primary human artifact인가, 아니면 `data.json`만 canonical source로 두고 view를 생성할 것인가?
|
|
41
|
+
- follow-up task에 기본 첨부할 artifact는 무엇인가?
|
|
42
|
+
- 어떤 섹션이 human-action material이고, 어떤 섹션이 audit-only material인가?
|
|
43
|
+
- 분리를 validator가 강제해야 하는가, renderer convention으로 둘 것인가?
|
|
44
|
+
- 분리가 기존 `render-views`, follow-up spawning, approval sidecar에 어떤 영향을 주는가?
|
|
45
|
+
|
|
46
|
+
## 참조
|
|
47
|
+
|
|
48
|
+
- 현재 schema: `schemas/final-report-v1.0.schema.json`
|
|
49
|
+
- 현재 Markdown template: `templates/reports/final-report.template.md`
|
|
50
|
+
- 현재 HTML renderer: `scripts/okstra_ctl/report_views.py`
|
|
51
|
+
- 현재 report UI assets: `templates/reports/report.css`, `templates/reports/report.js`
|
package/package.json
CHANGED
package/runtime/BUILD.json
CHANGED
|
@@ -88,6 +88,7 @@ Rules (the schema enforces most of these — they are listed here so you know *w
|
|
|
88
88
|
- `header.reportAuthor` is `"Report writer worker"`; `header.reportOwner` is `"Claude lead"`. Set author to `"Claude lead"` only for `release-handoff` runs (single-lead by design) or a recorded report-writer dispatch failure fallback.
|
|
89
89
|
- **Source items (worker:item) preservation.** Every `consensus[].sourceItems`, `differences[].workersPosition[].itemId`, and `evidence.primary[].sourceItems` entry MUST carry the worker:item-id pair (e.g. `claude:F-001`, `codex:1.1`, `antigravity:F-3`, or `lead:mcp-1` for lead-only evidence). The schema enforces this via the `SourceItem` regex; bare worker-name lists no longer parse.
|
|
90
90
|
- **Verdict Card consistency.** `verdictCard.verdictToken` / `.direction` / `.nextStep` MUST byte-match `finalVerdict.verdictToken` / `.direction` / `.nextStep` and `recommendedNextSteps[0].text`. The renderer pulls both from the same data structure — duplicating values across `verdictCard` and `finalVerdict` is intentional so the validator can diff them.
|
|
91
|
+
- **Reader Summary.** Populate `readerSummary` when the schema excerpt exposes it. It is the human-first entrypoint for both Markdown and HTML: one sentence for the decision, one for the human action required, one for blockers, one for audit sections safe to skip on first read, and one runnable recommended command. Do not duplicate raw evidence tables here.
|
|
91
92
|
- **§7 phase-continuation row (mandatory for non-terminal task-types).** When `header.taskType` is one of `requirements-discovery` / `implementation-planning` / `error-analysis` / `implementation` / `final-verification`, `followUpTasks` MUST contain at least one row whose `origin` is `phase-continuation`, `suggestedTaskType` equals the next phase (byte-identical to `finalVerdict.nextStep`'s referenced phase), `newTaskId` reuses the current task-id, `autoSpawn` is `"no"`, and `priority` is `"P0"`. For `release-handoff` runs, omit the phase-continuation row. Schema `allOf` clause enforces this via `contains`.
|
|
92
93
|
- **No deprecated sections.** The schema has no `4.5.8 User Approval Request` body field, no `4.5.9 Open Questions`, no `5.1 추가 자료 요청`, no `5.2 사용자 확인 질문` — clarifications go under the unified `clarificationItems[]` array.
|
|
93
94
|
- **Optional Section 0.** Include `clarificationCarryIn` ONLY when the lead's prompt provides a non-empty carry-in path. Omit the key entirely otherwise (do NOT set it to `null` or an empty object).
|
|
@@ -85,3 +85,37 @@ Emit one `PROGRESS: <phase-id> <verb-phrase>` line as plain user-facing text at
|
|
|
85
85
|
- Source path: `{{CLARIFICATION_RESPONSE_RELATIVE_PATH}}`
|
|
86
86
|
- If the source path above is empty, no prior clarification response was attached to this run.
|
|
87
87
|
- If the source path is set, a copy is staged at `{{INSTRUCTION_SET_RELATIVE_PATH}}/clarification-response.md`. Read it before running workers; reconcile each `C-*` row in section 1 (`## 1. Clarification Items`) of the prior report against new evidence and record the outcome in the conditional `## 0. Clarification Response Carried In From Previous Run` section of this run's final report (render that heading only when carry-in is non-empty — the validator fails empty Section 0 stubs).
|
|
88
|
+
|
|
89
|
+
### Incremental re-verification (implementation-planning clarification re-runs only)
|
|
90
|
+
|
|
91
|
+
The **default is full re-verification**. Only narrow this re-run to the impacted stages when the deterministic `okstra incremental-scope` CLI returns `mode == "incremental"`; on any doubt, stay full. This procedure fires ONLY when this run's task-type is `implementation-planning` AND a prior final report exists for this task-key (its data.json at `runs/implementation-planning/reports/final-report-implementation-planning-<prev-seq>.data.json`, where `<prev-seq>` is the most recent prior implementation-planning run's seq). For every other task-type, ignore this block and re-verify normally. This branches on the CLI's `mode` output only — it does NOT re-implement the safety logic in the prompt.
|
|
92
|
+
|
|
93
|
+
1. **Resolve the impacted stage set (safety condition C2 — your discretionary judgement).** For each answered `C-*` row you reconciled in §1, decide which **Stage Map stage numbers** (from the prior plan's `## 5.5 Stage Map`) the answer touches. Rules:
|
|
94
|
+
- Pass ONLY stage numbers that appear in that Stage Map. Never invent or guess a stage number — a number absent from the graph must never enter `--impacted` (it would leak into `reverify_stages`).
|
|
95
|
+
- If you cannot map a touched item to a real stage with confidence, leave the impacted set **EMPTY** — an empty set forces `mode == "full"`. Widening to full is always the safe choice; guessing is not.
|
|
96
|
+
- If any answer overturns the selected Option, restructures the stages, or changes the recommended approach (rather than a localized detail), also leave the impacted set **EMPTY**.
|
|
97
|
+
2. **Resolve the two base SHAs (safety condition C1 — code-unchanged, decided by the CLI, not by you).**
|
|
98
|
+
- Current base SHA: `{{EXECUTOR_WORKTREE_BASE_REF}}` (this run's resolved worktree base commit).
|
|
99
|
+
- Prior base SHA: read the prior run's active-run-context at `runs/implementation-planning/state/active-run-context-implementation-planning-<prev-seq>.json`, field `executorWorktree.baseRef` (a resolved commit SHA). The run-manifest does NOT carry this field — use the active-run-context. If that file or field cannot be located, treat the run as **full** and skip the rest of this procedure.
|
|
100
|
+
3. **Call the CLI** (it is pure — same inputs always yield the same decision):
|
|
101
|
+
```
|
|
102
|
+
okstra incremental-scope \
|
|
103
|
+
--prev-data runs/implementation-planning/reports/final-report-implementation-planning-<prev-seq>.data.json \
|
|
104
|
+
--cur-base-sha {{EXECUTOR_WORKTREE_BASE_REF}} \
|
|
105
|
+
--prev-base-sha <prior baseRef from step 2> \
|
|
106
|
+
--impacted <csv of impacted stage numbers, empty for full>
|
|
107
|
+
```
|
|
108
|
+
The CLI reads the plan's dependency graph from the top-level `## 5.5 Stage Map` (`implementationPlanning.stageMap`), which is authoritative for the impacted stage numbers — there is no per-option stage graph. The CLI prints JSON `{mode, reverify_stages, carry_stages, reason}`. Instruct the report-writer to record this JSON verbatim into this run's data.json as `implementationPlanning.incrementalDecision` (keys `mode`, `reverifyStages`, `carryStages`, `reason`) — the renderer turns it into the `### 0.1 Incremental Re-Verification Scope` audit block, and the validator fails an `incremental`-mode run whose Section 0 omits that block.
|
|
109
|
+
4. **`mode == "full"`** → run the existing full re-verification path unchanged; ignore `reverify_stages` / `carry_stages`.
|
|
110
|
+
5. **`mode == "incremental"`** → scope every worker dispatch prompt to `reverify_stages` only (the downstream closure of the impacted stages). Do NOT re-analyze `carry_stages` — their prior plan-item verdicts are carried forward verbatim (see `prompts/profiles/implementation-planning.md` "Cross-verification mode" and `prompts/lead/convergence.md` "Convergence scope").
|
|
111
|
+
6. **Merge carried-forward verdicts.** In `incremental` mode, after this run's report-writer authors its data.json, instruct it to merge the prior plan-item verdicts for `carry_stages` into it:
|
|
112
|
+
```
|
|
113
|
+
okstra incremental-carry \
|
|
114
|
+
--prev-data runs/implementation-planning/reports/final-report-implementation-planning-<prev-seq>.data.json \
|
|
115
|
+
--cur-data <this run's data.json> \
|
|
116
|
+
--prev-seq <prev-seq> \
|
|
117
|
+
--out <this run's data.json>
|
|
118
|
+
```
|
|
119
|
+
A non-zero exit (`CarryError` — schema drift between the two runs) means the carry is unsafe: fall back to **full** — discard the incremental result and re-verify every stage. Note: `verdictCard` / `finalVerdict` are NEVER carried — this run re-computes them from the re-verified plus carried plan items.
|
|
120
|
+
|
|
121
|
+
**Carry completeness (BLOCKING).** In incremental mode, this run's `planItems` MUST contain every plan-item id from the re-verified stages, each carried forward with its updated verdict. If re-verification concludes a plan item should be REMOVED, that is a signal the answer's blast radius is NOT local — abandon incremental and re-route to a FULL re-verification. The carry merge only ever ADDS prior items whose id is absent from this run; it cannot distinguish a legitimate deletion from an untouched carry, so it would resurrect a stale verdict.
|
|
@@ -66,6 +66,8 @@ Read the worker result files generated in Phase 4/5 and extract individual findi
|
|
|
66
66
|
|
|
67
67
|
**Convergence scope.** Convergence operates on sections 1–5 of the worker output (the common core, see `team-contract` "Worker Output Contract"). Section 6 ("Specialization Lens") is additive worker-specific depth and MUST NOT be fed into the consensus grouping, the verification queue, or the round-N reverify prompts. Carry Section 6 forward into the final report verbatim through the report-writer worker — do not let it inflate `unique` counts or trigger spurious `verification-error` statuses.
|
|
68
68
|
|
|
69
|
+
**Incremental re-verification scope (implementation-planning clarification re-runs).** When the lead's `okstra incremental-scope` decision is `mode == "incremental"` (procedure in `prompts/launch.template.md` §"Clarification Response Carried In"), only findings the lead attributes to a stage in `reverify_stages` enter the verification queue. Findings and plan-item verdicts carried forward for `carry_stages` are NOT re-queued — they skip the re-verification rounds entirely and are merged verbatim into this run's data.json via `okstra incremental-carry`. When the decision is `mode == "full"` (the default), every finding enters the queue as usual.
|
|
70
|
+
|
|
69
71
|
1. In the "Findings" section of each worker's results, identify individual items by number (F-001, F-002, ...) and parse the ticket identifier attached to each item:
|
|
70
72
|
- For table-form findings, read the `Ticket ID` column.
|
|
71
73
|
- For bullet/numbered findings, parse `[TICKETID: <id>]` from the item title.
|
|
@@ -366,7 +366,7 @@ jq -s 'group_by(.errorType) | map({type: .[0].errorType, count: length})' <runDi
|
|
|
366
366
|
|
|
367
367
|
The errors log is informational. Its presence/absence does not affect the final verdict. Do not block report writing on it.
|
|
368
368
|
|
|
369
|
-
After persistence, reply briefly in the resolved Report Language with: completion status, final report path, team-state path, validator result, resume command path, any remaining blocker.
|
|
369
|
+
After persistence, reply briefly in the resolved Report Language with: completion status, final report path, team-state path, validator result, resume command path, any remaining blocker. **Lead this reply with the run's task identity** — state `<task-group>/<task-id>` (or the full `taskKey`) first, so the reader knows which task the reply is about. **Every run-artifact path in this reply MUST be task-qualified** — report the final report as `.okstra/tasks/<task-group>/<task-id>/runs/<task-type>/reports/final-report-<task-type>-<seq>.md` (the full path rooted at the task bundle), NOT the bare `runs/<task-type>/reports/...` form. The bare `runs/...` prefix is byte-for-byte identical across every task-group / task-id of the same task-type, so it cannot tell one task's report from another's — always emit the `.okstra/tasks/<task-group>/<task-id>/` prefix. The same task-qualified rule applies to the team-state path, resume command path, and any other run-artifact path this reply cites.
|
|
370
370
|
|
|
371
371
|
## Run-scoped pane & teammate lifecycle
|
|
372
372
|
|
|
@@ -281,7 +281,7 @@ Every field MUST anchor its claim with at least one evidence reference — a `pa
|
|
|
281
281
|
|
|
282
282
|
**Reader-facing prose MUST NOT cite a bare brief/worker-internal ID that this report never surfaces** — `RC-*` (reporter confirmations, defined in the brief), `RF-*` / `F-*` (findings, defined in worker-results) have no anchor in the final report, so a reader hits an opaque token with nothing to click. Either expand it inline (`the confirmed version target 1.27.47→1.27.48`) or, for an audit trail, namespace it (`claude:F-005`). **Enforced:** `_validate_no_opaque_id_references` fails a bare `RC-*` / `RF-*` / non-namespaced `F-*` appearing in `verdictCard` / `finalVerdict` / `rationale` / `clarificationItems[].statement`. (The renderer anchors + links in-report IDs of any digit width, so a surfaced `RC-4`-style id does resolve.) Do NOT restate the Verdict Card or the §5.4 trade-off matrix verbatim — this section is the *why*, in connected prose, that those tables compress.
|
|
283
283
|
|
|
284
|
-
0. **Clarification Response Carried In** — render this `## 0.` heading ONLY when `{{CLARIFICATION_RESPONSE_RELATIVE_PATH}}` is non-empty. Walk every `C-*` row of the prior report's `## 1. Clarification Items` table, reconcile against new evidence, and record the outcome (`resolved` / `obsolete`) with citation before drafting the verdict. When no carry-in path was provided, OMIT the `## 0.` heading entirely — the validator fails an empty Section 0 stub.
|
|
284
|
+
0. **Clarification Response Carried In** — render this `## 0.` heading ONLY when `{{CLARIFICATION_RESPONSE_RELATIVE_PATH}}` is non-empty. Walk every `C-*` row of the prior report's `## 1. Clarification Items` table, reconcile against new evidence, and record the outcome (`resolved` / `obsolete`) with citation before drafting the verdict. When no carry-in path was provided, OMIT the `## 0.` heading entirely — the validator fails an empty Section 0 stub. When the lead ran `okstra incremental-scope` for this re-run, record its JSON verbatim into `implementationPlanning.incrementalDecision` (`mode`, `reverifyStages`, `carryStages`, `reason`); the renderer emits the `### 0.1 Incremental Re-Verification Scope` audit block from it, and the validator fails an `incremental`-mode run whose Section 0 omits that block. In `incremental` mode this run's `planItems` MUST carry every plan-item id from the re-verified stages forward with its updated verdict; if re-verification concludes a plan item should be REMOVED, that is a signal the answer's blast radius is not local — do not drop it here, tell the lead to abandon incremental and re-route to a FULL re-verification, because the carry merge only adds prior items and would resurrect the removed item's stale verdict.
|
|
285
285
|
1. **Cross Verification Results** — 4 categories (Full / Partial / Contested / Worker-Unique) when convergence is enabled, per `convergence`. Prepend the Round History sub-table (columns: `Round | inputQueueSize | resolvedCount | carriedForwardCount | dispatches | skippedWorkers`) plus a `round2SkippedReason: <value>` note, pulled verbatim from `convergence-<task-type>-<seq>.json`. Empty contested list renders as `- 합의 미달 항목 없음.`. Convergence-disabled runs use the legacy Consensus/Differences format and omit the round table.
|
|
286
286
|
2. **Final Verdict** — `Direction` ∈ `continue-investigation` / `begin-implementation` / `approve` / `reject` / `hold`. **Verdict Token** is `not-applicable` for every task-type except `final-verification` — see "Final-verification verdict token contract" below for that case.
|
|
287
287
|
3. **Evidence and Detailed Analysis** — primary evidence rows (file path, line, snippet); secondary evidence / alternate interpretations. If `reference-expectations.md` lists explicit expected values, record match/gap per row.
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
- Cross-verification mode:
|
|
44
44
|
- Phase 5.5 finding convergence runs in **adversarial mode** for this phase (`convergence.adversarial=true`). Verifiers actively try to refute each worker finding (requirement gap / risk / option) by re-inspecting its cited evidence; the burden of proof sits on the claim. See `prompts/lead/convergence.md` §"Adversarial Verification Mode".
|
|
45
45
|
- §5.5.9 plan-body verification runs with an **adversarial posture** (`prompts/lead/plan-body-verification.md` §"Adversarial plan-body posture"): verifiers open and confirm every cited path / command and put the burden of proof on the plan. The gate threshold is majority-based for kinds `b`/`c`/`e`, but a single `DISAGREE` blocks on its own for the concrete, safety-critical kinds `a` (path/symbol mismatch) / `d` (rollback order) — and `f` on `P-Req-*` items. A majority also needs ≥2 participating votes, so a lone dissent whose peer returned a non-result does not block on a majority-gated kind (see that contract's §"Adversarial plan-body posture").
|
|
46
|
+
- **Incremental re-verification scope (clarification re-runs):** when the lead's `okstra incremental-scope` decision is `mode == "incremental"` (procedure in `prompts/launch.template.md` §"Clarification Response Carried In"), workers re-analyze ONLY the stages listed in `reverify_stages` (the downstream closure of the impacted stages). Workers MUST NOT re-open, re-score, or re-judge any stage in `carry_stages` — those stages' prior plan-item verdicts are carried forward verbatim, and a worker never overwrites a carried verdict with its own judgement. When the decision is `mode == "full"` (the default), every stage is re-analyzed as usual.
|
|
46
47
|
{{INCLUDE:_coverage-critic.md}}
|
|
47
48
|
- Non-goals:
|
|
48
49
|
- code-level micro-optimization unless it changes the implementation approach
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""Implementation stage run orchestration.
|
|
2
2
|
|
|
3
|
-
This module owns the
|
|
4
|
-
consumer state, select an available Stage Map entry, provision the
|
|
5
|
-
stage worktree, and
|
|
3
|
+
This module owns the Stage Run Claim for one ``implementation`` stage run:
|
|
4
|
+
recover consumer state, select an available Stage Map entry, provision the
|
|
5
|
+
isolated stage worktree, and record the started event.
|
|
6
6
|
"""
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
@@ -18,12 +18,12 @@ from .stage_reconcile import auto_reconcile_best_effort
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
class ImplementationStageError(Exception):
|
|
21
|
-
"""Implementation stage
|
|
21
|
+
"""Implementation stage claim or provisioning failed."""
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
@dataclass
|
|
25
|
-
class
|
|
26
|
-
"""
|
|
25
|
+
class StageRunClaim:
|
|
26
|
+
"""Claim over one Stage Map stage and its isolated worktree coordinates."""
|
|
27
27
|
|
|
28
28
|
stage: int
|
|
29
29
|
worktree_path: str
|
|
@@ -50,22 +50,20 @@ def _as_implementation_stage_error(exc: Exception) -> ImplementationStageError:
|
|
|
50
50
|
return ImplementationStageError(str(exc))
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
def
|
|
53
|
+
def claim_implementation_stage_run(
|
|
54
54
|
inp: Any,
|
|
55
55
|
ctx_stage_map: list[dict[str, Any]],
|
|
56
56
|
task_group_segment: str,
|
|
57
57
|
task_id_segment: str,
|
|
58
58
|
task_key: str,
|
|
59
59
|
executor_worktree_status: str,
|
|
60
|
-
) ->
|
|
61
|
-
"""
|
|
60
|
+
) -> StageRunClaim:
|
|
61
|
+
"""Claim a ready implementation stage for one run.
|
|
62
62
|
|
|
63
|
-
The returned
|
|
63
|
+
The returned claim is path-independent with respect to run artifacts:
|
|
64
64
|
callers can compute stage-specific run paths after this function resolves
|
|
65
65
|
the selected stage.
|
|
66
66
|
"""
|
|
67
|
-
del task_key # The registry uses the split identity fields.
|
|
68
|
-
|
|
69
67
|
from .consumers import backfill_done_from_carry
|
|
70
68
|
from . import worktree as _worktree
|
|
71
69
|
from . import worktree_registry as _reg
|
|
@@ -95,7 +93,7 @@ def select_and_provision_implementation_stage(
|
|
|
95
93
|
|
|
96
94
|
if executor_worktree_status.startswith("skipped"):
|
|
97
95
|
head = _git_out(inp.project_root, "rev-parse", "HEAD")
|
|
98
|
-
|
|
96
|
+
claim = StageRunClaim(
|
|
99
97
|
stage=selected,
|
|
100
98
|
worktree_path="",
|
|
101
99
|
worktree_branch="",
|
|
@@ -105,6 +103,8 @@ def select_and_provision_implementation_stage(
|
|
|
105
103
|
started_head_commit=head,
|
|
106
104
|
concurrent_stages=concurrent_stages,
|
|
107
105
|
)
|
|
106
|
+
_record_stage_run_claim_started(task_key, plan_run_root, claim)
|
|
107
|
+
return claim
|
|
108
108
|
|
|
109
109
|
# The anchor and multi-dep candidate base must come from the task-key
|
|
110
110
|
# worktree HEAD (where stage work accumulates), not from inp.project_root
|
|
@@ -166,7 +166,7 @@ def select_and_provision_implementation_stage(
|
|
|
166
166
|
f"stage worktree provisioning failed: {exc}\n{hint}"
|
|
167
167
|
) from exc
|
|
168
168
|
|
|
169
|
-
|
|
169
|
+
claim = StageRunClaim(
|
|
170
170
|
stage=selected,
|
|
171
171
|
worktree_path=prov.path,
|
|
172
172
|
worktree_branch=prov.branch,
|
|
@@ -176,22 +176,40 @@ def select_and_provision_implementation_stage(
|
|
|
176
176
|
started_head_commit=prov.base_ref,
|
|
177
177
|
concurrent_stages=concurrent_stages,
|
|
178
178
|
)
|
|
179
|
+
_record_stage_run_claim_started(task_key, plan_run_root, claim)
|
|
180
|
+
return claim
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _record_stage_run_claim_started(
|
|
184
|
+
task_key: str,
|
|
185
|
+
plan_run_root: Path,
|
|
186
|
+
claim: StageRunClaim,
|
|
187
|
+
) -> None:
|
|
188
|
+
from .consumers import append_consumer
|
|
179
189
|
|
|
190
|
+
now = _dt.datetime.now(_dt.timezone.utc).isoformat()
|
|
191
|
+
append_consumer(
|
|
192
|
+
plan_run_root,
|
|
193
|
+
impl_task_key=task_key,
|
|
194
|
+
stage=claim.stage,
|
|
195
|
+
status="started",
|
|
196
|
+
started_at=now,
|
|
197
|
+
head_commit=claim.started_head_commit,
|
|
198
|
+
)
|
|
180
199
|
|
|
181
|
-
|
|
200
|
+
|
|
201
|
+
def publish_stage_run_claim(
|
|
182
202
|
inp: Any,
|
|
183
203
|
ctx: dict[str, Any],
|
|
184
204
|
ctx_stage_map: list[dict[str, Any]],
|
|
185
|
-
|
|
205
|
+
claim: StageRunClaim,
|
|
186
206
|
) -> None:
|
|
187
|
-
"""Publish a
|
|
188
|
-
from .consumers import append_consumer
|
|
189
|
-
|
|
207
|
+
"""Publish a Stage Run Claim into run context."""
|
|
190
208
|
ctx["parsed_stage_map"] = ctx_stage_map
|
|
191
|
-
ctx["effective_stages"] = [
|
|
192
|
-
csv = str(
|
|
209
|
+
ctx["effective_stages"] = [claim.stage]
|
|
210
|
+
csv = str(claim.stage)
|
|
193
211
|
ctx["EFFECTIVE_STAGES"] = csv
|
|
194
|
-
ctx["CONCURRENT_RUN_STAGES"] = ",".join(str(s) for s in
|
|
212
|
+
ctx["CONCURRENT_RUN_STAGES"] = ",".join(str(s) for s in claim.concurrent_stages)
|
|
195
213
|
ctx["STAGE_BATCH_DIRECTIVE"] = (
|
|
196
214
|
f"- **Stage for this implementation run:** `{csv}`. "
|
|
197
215
|
"Execute exactly this Stage Map stage — this is the authoritative scope. "
|
|
@@ -201,20 +219,9 @@ def apply_implementation_stage(
|
|
|
201
219
|
inp.stage = csv
|
|
202
220
|
print(f"selected stages: {csv}", file=sys.stdout)
|
|
203
221
|
|
|
204
|
-
if
|
|
205
|
-
ctx["EXECUTOR_WORKTREE_PATH"] =
|
|
206
|
-
ctx["EXECUTOR_WORKTREE_BRANCH"] =
|
|
207
|
-
ctx["EXECUTOR_WORKTREE_BASE_REF"] =
|
|
208
|
-
ctx["EXECUTOR_WORKTREE_STATUS"] =
|
|
209
|
-
ctx["EXECUTOR_WORKTREE_NOTE"] =
|
|
210
|
-
|
|
211
|
-
now = _dt.datetime.now(_dt.timezone.utc).isoformat()
|
|
212
|
-
plan_run_root = Path(inp.approved_plan_path).resolve().parents[1]
|
|
213
|
-
append_consumer(
|
|
214
|
-
plan_run_root,
|
|
215
|
-
impl_task_key=ctx["TASK_KEY"],
|
|
216
|
-
stage=sel.stage,
|
|
217
|
-
status="started",
|
|
218
|
-
started_at=now,
|
|
219
|
-
head_commit=sel.started_head_commit,
|
|
220
|
-
)
|
|
222
|
+
if claim.worktree_status and not claim.worktree_status.startswith("skipped"):
|
|
223
|
+
ctx["EXECUTOR_WORKTREE_PATH"] = claim.worktree_path
|
|
224
|
+
ctx["EXECUTOR_WORKTREE_BRANCH"] = claim.worktree_branch
|
|
225
|
+
ctx["EXECUTOR_WORKTREE_BASE_REF"] = claim.worktree_base_ref
|
|
226
|
+
ctx["EXECUTOR_WORKTREE_STATUS"] = claim.worktree_status
|
|
227
|
+
ctx["EXECUTOR_WORKTREE_NOTE"] = claim.worktree_note
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Merge carried-forward plan-item verdicts from the prior run into the
|
|
2
|
+
current incremental re-run's data.json. Plan items the current run did not
|
|
3
|
+
re-verify keep their prior verdict, tagged so the report shows they are
|
|
4
|
+
carried forward and unchanged.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import argparse
|
|
9
|
+
import json
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class CarryError(Exception):
|
|
15
|
+
"""Carry merge refused — schema drift or structural mismatch."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def merge_carried_forward(prev: dict, cur: dict, prev_seq: str = "previous") -> dict:
|
|
19
|
+
if prev.get("schemaVersion") != cur.get("schemaVersion"):
|
|
20
|
+
raise CarryError(
|
|
21
|
+
f"schemaVersion drift {prev.get('schemaVersion')!r} != {cur.get('schemaVersion')!r}; "
|
|
22
|
+
"cannot carry forward — caller must fall back to full"
|
|
23
|
+
)
|
|
24
|
+
prev_pbv = prev.get("implementationPlanning", {}).get("planBodyVerification", {})
|
|
25
|
+
cur_ip = cur.setdefault("implementationPlanning", {})
|
|
26
|
+
cur_pbv = cur_ip.setdefault("planBodyVerification", {})
|
|
27
|
+
cur_items = cur_pbv.setdefault("planItems", [])
|
|
28
|
+
reverified_ids = {i["id"] for i in cur_items}
|
|
29
|
+
for item in prev_pbv.get("planItems", []):
|
|
30
|
+
if item["id"] in reverified_ids:
|
|
31
|
+
continue
|
|
32
|
+
carried = dict(item)
|
|
33
|
+
carried["carriedForwardFromSeq"] = str(prev_seq)
|
|
34
|
+
cur_items.append(carried)
|
|
35
|
+
cur_items.sort(key=lambda i: i["id"])
|
|
36
|
+
return cur
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def main(argv: list[str]) -> int:
|
|
40
|
+
ap = argparse.ArgumentParser(prog="okstra incremental-carry")
|
|
41
|
+
ap.add_argument("--prev-data", required=True, help="prior run final-report data.json")
|
|
42
|
+
ap.add_argument("--cur-data", required=True, help="current incremental re-run data.json")
|
|
43
|
+
ap.add_argument("--prev-seq", required=True, help="prior run seq, tagged onto carried items")
|
|
44
|
+
ap.add_argument("--out", required=True, help="path to write the merged data.json")
|
|
45
|
+
args = ap.parse_args(argv)
|
|
46
|
+
|
|
47
|
+
prev = json.loads(Path(args.prev_data).read_text(encoding="utf-8"))
|
|
48
|
+
cur = json.loads(Path(args.cur_data).read_text(encoding="utf-8"))
|
|
49
|
+
try:
|
|
50
|
+
merged = merge_carried_forward(prev, cur, prev_seq=args.prev_seq)
|
|
51
|
+
except CarryError as exc:
|
|
52
|
+
print(f"carry refused: {exc}", file=sys.stderr)
|
|
53
|
+
return 1
|
|
54
|
+
|
|
55
|
+
Path(args.out).write_text(
|
|
56
|
+
json.dumps(merged, ensure_ascii=False, indent=2) + "\n", encoding="utf-8"
|
|
57
|
+
)
|
|
58
|
+
carried = sum(
|
|
59
|
+
1
|
|
60
|
+
for i in merged.get("implementationPlanning", {})
|
|
61
|
+
.get("planBodyVerification", {})
|
|
62
|
+
.get("planItems", [])
|
|
63
|
+
if i.get("carriedForwardFromSeq") == str(args.prev_seq)
|
|
64
|
+
)
|
|
65
|
+
print(f"merged {carried} carried-forward plan item(s) from seq {args.prev_seq} -> {args.out}")
|
|
66
|
+
return 0
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
if __name__ == "__main__":
|
|
70
|
+
raise SystemExit(main(sys.argv[1:]))
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""Decide whether an implementation-planning clarification re-run can be
|
|
2
|
+
incremental, and if so which stages to re-verify vs carry forward.
|
|
3
|
+
|
|
4
|
+
Deterministic half of the incremental-reverification feature: the lead
|
|
5
|
+
prompt supplies the impacted-stage set (its discretionary C2 judgement) and
|
|
6
|
+
the base SHAs; everything here is pure so the same inputs always yield the
|
|
7
|
+
same decision. See docs/superpowers/specs/2026-07-09-incremental-clarification-reverification-design.md.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import argparse
|
|
12
|
+
import json
|
|
13
|
+
import sys
|
|
14
|
+
from dataclasses import asdict, dataclass
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
from okstra_ctl.stage_targets import downstream_stage_closure
|
|
18
|
+
|
|
19
|
+
CUTOFF_RATIO = 0.5
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class IncrementalDecision:
|
|
24
|
+
mode: str # "incremental" | "full"
|
|
25
|
+
reverify_stages: list[int]
|
|
26
|
+
carry_stages: list[int]
|
|
27
|
+
reason: str
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _parse_depends_on(cell: str) -> list[int]:
|
|
31
|
+
text = (cell or "").strip()
|
|
32
|
+
if not text or text == "(none)":
|
|
33
|
+
return []
|
|
34
|
+
return [int(tok.strip()) for tok in text.split(",") if tok.strip()]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def parse_stage_graph(data: dict) -> list[tuple[int, list[int]]]:
|
|
38
|
+
stage_map = data.get("implementationPlanning", {}).get("stageMap", [])
|
|
39
|
+
return [(int(row["stage"]), _parse_depends_on(row.get("dependsOn", ""))) for row in stage_map]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def decide_scope(
|
|
43
|
+
*,
|
|
44
|
+
stages: list[tuple[int, list[int]]],
|
|
45
|
+
impacted_stages: set[int],
|
|
46
|
+
prev_base_sha: str,
|
|
47
|
+
cur_base_sha: str,
|
|
48
|
+
cutoff_ratio: float = CUTOFF_RATIO,
|
|
49
|
+
) -> IncrementalDecision:
|
|
50
|
+
if not prev_base_sha or prev_base_sha != cur_base_sha:
|
|
51
|
+
return IncrementalDecision(
|
|
52
|
+
"full", [], [],
|
|
53
|
+
f"base-ref changed ({prev_base_sha!r} -> {cur_base_sha!r}); prior analysis invalid",
|
|
54
|
+
)
|
|
55
|
+
if not impacted_stages:
|
|
56
|
+
return IncrementalDecision("full", [], [], "no impacted stages resolved; falling back to full")
|
|
57
|
+
all_stages = {num for num, _ in stages}
|
|
58
|
+
closure = downstream_stage_closure(stages, set(impacted_stages))
|
|
59
|
+
if len(closure) * 2 > len(all_stages):
|
|
60
|
+
return IncrementalDecision(
|
|
61
|
+
"full", [], [],
|
|
62
|
+
f"closure {len(closure)}/{len(all_stages)} exceeds {int(cutoff_ratio * 100)}% cutoff",
|
|
63
|
+
)
|
|
64
|
+
reverify = sorted(closure)
|
|
65
|
+
carry = sorted(all_stages - closure)
|
|
66
|
+
return IncrementalDecision("incremental", reverify, carry, f"closure {reverify} within cutoff")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def main(argv: list[str]) -> int:
|
|
70
|
+
ap = argparse.ArgumentParser(prog="okstra incremental-scope")
|
|
71
|
+
ap.add_argument("--prev-data", required=True, help="prior run final-report data.json")
|
|
72
|
+
ap.add_argument("--cur-base-sha", required=True)
|
|
73
|
+
ap.add_argument("--prev-base-sha", required=True)
|
|
74
|
+
ap.add_argument("--impacted", default="", help="comma-separated impacted stage numbers")
|
|
75
|
+
args = ap.parse_args(argv)
|
|
76
|
+
|
|
77
|
+
data = json.loads(Path(args.prev_data).read_text(encoding="utf-8"))
|
|
78
|
+
stages = parse_stage_graph(data)
|
|
79
|
+
impacted = {int(t.strip()) for t in args.impacted.split(",") if t.strip()}
|
|
80
|
+
decision = decide_scope(
|
|
81
|
+
stages=stages, impacted_stages=impacted,
|
|
82
|
+
prev_base_sha=args.prev_base_sha, cur_base_sha=args.cur_base_sha,
|
|
83
|
+
)
|
|
84
|
+
print(json.dumps(asdict(decision), ensure_ascii=False))
|
|
85
|
+
return 0
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
if __name__ == "__main__":
|
|
89
|
+
raise SystemExit(main(sys.argv[1:]))
|