okstra 0.172.0 → 0.174.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 +8 -6
- package/docs/architecture/storage-model.md +24 -3
- package/docs/architecture.md +21 -35
- package/docs/cli.md +39 -7
- package/docs/container.md +1 -1
- package/docs/contributor-change-matrix.md +1 -1
- package/docs/performance-improvement-plan-v2.md +6 -5
- package/docs/project-structure-overview.md +33 -25
- package/docs/task-process/README.md +6 -4
- package/docs/task-process/error-analysis.md +2 -2
- package/docs/task-process/final-verification.md +2 -2
- package/docs/task-process/implementation-option-selection.md +70 -0
- package/docs/task-process/implementation-planning.md +24 -16
- package/docs/task-process/requirements-discovery.md +2 -2
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/claude-worker.md +1 -1
- package/runtime/agents/workers/report-writer-worker.md +30 -6
- package/runtime/bin/lib/okstra/cli.sh +5 -1
- package/runtime/bin/lib/okstra/globals.sh +2 -1
- package/runtime/bin/lib/okstra/usage.sh +3 -0
- package/runtime/bin/okstra-provider-exec.py +29 -12
- package/runtime/bin/okstra-trace-cleanup.sh +58 -129
- package/runtime/bin/okstra.sh +2 -0
- package/runtime/prompts/duties/direction-selection-worker.md +44 -0
- package/runtime/prompts/duties/planning-worker.md +12 -4
- package/runtime/prompts/lead/adapters/cmux.md +2 -0
- package/runtime/prompts/lead/context-loader.md +1 -1
- package/runtime/prompts/lead/convergence.md +5 -5
- package/runtime/prompts/lead/okstra-lead-contract.md +7 -6
- package/runtime/prompts/lead/plan-body-verification.md +23 -6
- package/runtime/prompts/lead/report-writer.md +33 -11
- package/runtime/prompts/profiles/_common-contract.md +3 -3
- package/runtime/prompts/profiles/_implementation-deliverable.md +2 -2
- package/runtime/prompts/profiles/_implementation-executor.md +2 -0
- package/runtime/prompts/profiles/_implementation-verifier.md +2 -2
- package/runtime/prompts/profiles/error-analysis.md +4 -4
- package/runtime/prompts/profiles/final-verification.md +3 -3
- package/runtime/prompts/profiles/forbidden-actions.json +7 -0
- package/runtime/prompts/profiles/implementation-option-selection.md +35 -0
- package/runtime/prompts/profiles/implementation-planning.md +61 -46
- package/runtime/prompts/profiles/implementation.md +4 -2
- package/runtime/prompts/profiles/improvement-discovery.md +1 -1
- package/runtime/prompts/profiles/release-handoff.md +1 -1
- package/runtime/prompts/profiles/requirements-discovery.md +3 -3
- package/runtime/prompts/wizard/prompts.ko.json +9 -1
- package/runtime/python/okstra_ctl/adapters/dispatch/__init__.py +1 -6
- package/runtime/python/okstra_ctl/adapters/hosts/external/relay.md +4 -4
- package/runtime/python/okstra_ctl/adapters/providers/claude/adapter.py +5 -0
- package/runtime/python/okstra_ctl/agent_invocation.py +1 -0
- package/runtime/python/okstra_ctl/analysis_packet.py +6 -0
- package/runtime/python/okstra_ctl/conformance.py +68 -0
- package/runtime/python/okstra_ctl/dispatch_core.py +89 -39
- package/runtime/python/okstra_ctl/dispatch_state.py +142 -14
- package/runtime/python/okstra_ctl/doctor.py +2 -2
- package/runtime/python/okstra_ctl/domain/worker_exec.py +5 -0
- package/runtime/python/okstra_ctl/exact_coverage.py +128 -0
- package/runtime/python/okstra_ctl/final_report_schema.py +5 -4
- package/runtime/python/okstra_ctl/fix_cycles.py +3 -1
- package/runtime/python/okstra_ctl/implementation_direction.py +836 -0
- package/runtime/python/okstra_ctl/implementation_options.py +479 -0
- package/runtime/python/okstra_ctl/pane_reclaim.py +13 -22
- package/runtime/python/okstra_ctl/plan_items.py +51 -3
- package/runtime/python/okstra_ctl/render.py +1 -0
- package/runtime/python/okstra_ctl/render_final_report.py +16 -19
- package/runtime/python/okstra_ctl/report_contract.py +45 -14
- package/runtime/python/okstra_ctl/report_finalize.py +68 -9
- package/runtime/python/okstra_ctl/report_html/render.py +4 -2
- package/runtime/python/okstra_ctl/report_html/router.py +4 -0
- package/runtime/python/okstra_ctl/report_html/view_models/implementation_option_selection.py +32 -0
- package/runtime/python/okstra_ctl/report_html/view_models/implementation_planning.py +25 -10
- package/runtime/python/okstra_ctl/report_views.py +148 -12
- package/runtime/python/okstra_ctl/run.py +393 -4
- package/runtime/python/okstra_ctl/schema_excerpt.py +1 -1
- package/runtime/python/okstra_ctl/scope_provenance.py +16 -10
- package/runtime/python/okstra_ctl/session.py +69 -12
- package/runtime/python/okstra_ctl/team.py +51 -25
- package/runtime/python/okstra_ctl/tmux.py +19 -149
- package/runtime/python/okstra_ctl/user_response.py +75 -0
- package/runtime/python/okstra_ctl/wizard.py +144 -0
- package/runtime/python/okstra_ctl/worker_prompt_policy.py +2 -0
- package/runtime/python/okstra_ctl/worker_request.py +2 -0
- package/runtime/python/okstra_ctl/workflow.py +29 -7
- package/runtime/python/okstra_ctl/worktree.py +69 -3
- package/runtime/python/okstra_token_usage/cli.py +1 -1
- package/runtime/python/okstra_token_usage/collect.py +66 -6
- package/runtime/schemas/final-report-v2.0.schema.json +1428 -137
- package/runtime/skills/okstra-setup/references/project-config.md +11 -0
- package/runtime/templates/reports/final-report-v2.template.md +4 -0
- package/runtime/templates/reports/final-verification-input.template.md +1 -1
- package/runtime/templates/reports/html/base.template.html +3 -2
- package/runtime/templates/reports/html/i18n/en.json +21 -1
- package/runtime/templates/reports/html/i18n/ko.json +21 -1
- package/runtime/templates/reports/html/macros/forms.html +21 -2
- package/runtime/templates/reports/html/tasks/implementation-option-selection.template.html +49 -0
- package/runtime/templates/reports/html/tasks/implementation-planning.template.html +36 -2
- package/runtime/templates/reports/i18n/en.json +13 -0
- package/runtime/templates/reports/implementation-input.template.md +4 -2
- package/runtime/templates/reports/implementation-planning-input.template.md +18 -4
- package/runtime/templates/reports/improvement-discovery-input.template.md +1 -1
- package/runtime/templates/reports/md/tasks/implementation-option-selection.template.md +13 -0
- package/runtime/templates/reports/md/tasks/implementation-planning.template.md +17 -0
- package/runtime/templates/reports/report.js +111 -4
- package/runtime/templates/reports/settings.template.json +0 -24
- package/runtime/templates/reports/task-brief.template.md +9 -3
- package/runtime/templates/reports/user-response.template.md +25 -4
- package/runtime/templates/worker-prompt-preamble.md +8 -0
- package/runtime/validators/lib/fixtures.sh +49 -17
- package/runtime/validators/validate-implementation-plan-stages.py +169 -4
- package/runtime/validators/validate-report-views.py +2 -2
- package/runtime/validators/validate-run.py +149 -498
- package/runtime/validators/validate_improvement_report.py +5 -1
- package/runtime/validators/validate_session_conformance.py +1 -1
- package/src/cli-registry.mjs +8 -1
- package/src/commands/execute/codex-run.mjs +1 -0
- package/src/commands/execute/render-bundle.mjs +1 -0
- package/src/commands/execute/team.mjs +3 -3
- package/src/commands/execute/worktree-status.mjs +109 -0
- package/src/commands/lifecycle/install.mjs +0 -2
- package/src/commands/report/finalize.mjs +13 -6
- package/runtime/bin/okstra-subagent-reclaim.sh +0 -26
- package/runtime/schemas/final-report-v1.0.schema.json +0 -6366
- package/runtime/templates/reports/final-report.template.md +0 -1258
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""Pure exact requirement coverage calculation."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Mapping, Sequence
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from typing import Literal
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ExactCoverageError(ValueError):
|
|
11
|
+
"""Raised when coverage input cannot define a valid comparison."""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(frozen=True)
|
|
15
|
+
class ExactCoverageResult:
|
|
16
|
+
coverage_percent: float
|
|
17
|
+
scope_precision_percent: float
|
|
18
|
+
covered_count: int
|
|
19
|
+
total_count: int
|
|
20
|
+
unmapped_commitments: tuple[str, ...]
|
|
21
|
+
contradicted_requirements: tuple[str, ...]
|
|
22
|
+
verdict: Literal["exact", "under", "over", "contradicted"]
|
|
23
|
+
|
|
24
|
+
def as_report_summary(self) -> dict[str, object]:
|
|
25
|
+
return {
|
|
26
|
+
"coveragePercent": self.coverage_percent,
|
|
27
|
+
"scopePrecisionPercent": self.scope_precision_percent,
|
|
28
|
+
"coveredCount": self.covered_count,
|
|
29
|
+
"totalCount": self.total_count,
|
|
30
|
+
"unmappedCommitments": list(self.unmapped_commitments),
|
|
31
|
+
"contradictedRequirements": list(self.contradicted_requirements),
|
|
32
|
+
"coverageVerdict": self.verdict,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def calculate_exact_coverage(
|
|
37
|
+
original_requirement_ids: Sequence[str],
|
|
38
|
+
coverage_status_by_id: Mapping[str, str],
|
|
39
|
+
commitment_requirement_ids: Mapping[str, Sequence[str]],
|
|
40
|
+
) -> ExactCoverageResult:
|
|
41
|
+
original_ids = tuple(original_requirement_ids)
|
|
42
|
+
if not original_ids:
|
|
43
|
+
raise ExactCoverageError("original requirement denominator is empty")
|
|
44
|
+
if len(set(original_ids)) != len(original_ids):
|
|
45
|
+
raise ExactCoverageError("original requirement ids contain duplicates")
|
|
46
|
+
|
|
47
|
+
original_id_set = set(original_ids)
|
|
48
|
+
if set(coverage_status_by_id) != original_id_set:
|
|
49
|
+
raise ExactCoverageError("coverage rows must match original requirement ids")
|
|
50
|
+
allowed_statuses = {"covered", "not-covered", "contradicted"}
|
|
51
|
+
if any(status not in allowed_statuses for status in coverage_status_by_id.values()):
|
|
52
|
+
raise ExactCoverageError("coverage status is invalid")
|
|
53
|
+
if not commitment_requirement_ids:
|
|
54
|
+
raise ExactCoverageError("implementation commitment denominator is empty")
|
|
55
|
+
|
|
56
|
+
unmapped = tuple(
|
|
57
|
+
commitment_id
|
|
58
|
+
for commitment_id, requirement_ids in commitment_requirement_ids.items()
|
|
59
|
+
if not requirement_ids
|
|
60
|
+
or any(requirement_id not in original_id_set for requirement_id in requirement_ids)
|
|
61
|
+
)
|
|
62
|
+
contradicted = tuple(
|
|
63
|
+
requirement_id
|
|
64
|
+
for requirement_id in original_ids
|
|
65
|
+
if coverage_status_by_id[requirement_id] == "contradicted"
|
|
66
|
+
)
|
|
67
|
+
covered_count = sum(
|
|
68
|
+
coverage_status_by_id[requirement_id] == "covered"
|
|
69
|
+
for requirement_id in original_ids
|
|
70
|
+
)
|
|
71
|
+
coverage_percent = round(covered_count / len(original_ids) * 100, 2)
|
|
72
|
+
traceable_count = len(commitment_requirement_ids) - len(unmapped)
|
|
73
|
+
scope_precision_percent = round(
|
|
74
|
+
traceable_count / len(commitment_requirement_ids) * 100,
|
|
75
|
+
2,
|
|
76
|
+
)
|
|
77
|
+
verdict: Literal["exact", "under", "over", "contradicted"]
|
|
78
|
+
if contradicted:
|
|
79
|
+
verdict = "contradicted"
|
|
80
|
+
elif covered_count != len(original_ids):
|
|
81
|
+
verdict = "under"
|
|
82
|
+
elif unmapped:
|
|
83
|
+
verdict = "over"
|
|
84
|
+
else:
|
|
85
|
+
verdict = "exact"
|
|
86
|
+
|
|
87
|
+
return ExactCoverageResult(
|
|
88
|
+
coverage_percent=coverage_percent,
|
|
89
|
+
scope_precision_percent=scope_precision_percent,
|
|
90
|
+
covered_count=covered_count,
|
|
91
|
+
total_count=len(original_ids),
|
|
92
|
+
unmapped_commitments=unmapped,
|
|
93
|
+
contradicted_requirements=contradicted,
|
|
94
|
+
verdict=verdict,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def calculate_plan_exact_coverage(
|
|
99
|
+
original_requirement_ids: Sequence[str],
|
|
100
|
+
coverage_status_by_id: Mapping[str, str],
|
|
101
|
+
stage_requirement_ids: Mapping[int, Sequence[str]],
|
|
102
|
+
file_requirement_ids: Mapping[str, Sequence[str]],
|
|
103
|
+
) -> tuple[ExactCoverageResult, tuple[int, ...], tuple[str, ...]]:
|
|
104
|
+
"""Apply exact coverage to the executable stage and file-change scope."""
|
|
105
|
+
commitments = {
|
|
106
|
+
**{
|
|
107
|
+
f"stage:{stage}": requirement_ids
|
|
108
|
+
for stage, requirement_ids in stage_requirement_ids.items()
|
|
109
|
+
},
|
|
110
|
+
**{
|
|
111
|
+
f"file:{path}": requirement_ids
|
|
112
|
+
for path, requirement_ids in file_requirement_ids.items()
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
result = calculate_exact_coverage(
|
|
116
|
+
original_requirement_ids,
|
|
117
|
+
coverage_status_by_id,
|
|
118
|
+
commitments,
|
|
119
|
+
)
|
|
120
|
+
unmapped_stages = tuple(
|
|
121
|
+
stage for stage, requirement_ids in stage_requirement_ids.items()
|
|
122
|
+
if not requirement_ids
|
|
123
|
+
)
|
|
124
|
+
unmapped_files = tuple(
|
|
125
|
+
path for path, requirement_ids in file_requirement_ids.items()
|
|
126
|
+
if not requirement_ids
|
|
127
|
+
)
|
|
128
|
+
return result, unmapped_stages, unmapped_files
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Mini JSON Schema validator for the final-report data.json.
|
|
2
2
|
|
|
3
3
|
This is a deliberately narrow JSON Schema implementation that supports
|
|
4
|
-
exactly the keywords used by ``schemas/final-report-
|
|
4
|
+
exactly the keywords used by ``schemas/final-report-v2.0.schema.json``:
|
|
5
5
|
|
|
6
6
|
type, required, properties, additionalProperties, enum, const, pattern,
|
|
7
7
|
minLength, minItems, maxItems, uniqueItems, items, minimum, maximum, $ref ($defs),
|
|
@@ -23,6 +23,8 @@ import re
|
|
|
23
23
|
from pathlib import Path
|
|
24
24
|
from typing import Any
|
|
25
25
|
|
|
26
|
+
from okstra_ctl.report_contract import CURRENT_REPORT_SCHEMA_VERSION
|
|
27
|
+
|
|
26
28
|
|
|
27
29
|
class SchemaError(ValueError):
|
|
28
30
|
"""Raised when a schema itself is malformed (e.g. a $ref points
|
|
@@ -260,7 +262,6 @@ def validate(data: Any, schema: dict) -> list[str]:
|
|
|
260
262
|
|
|
261
263
|
|
|
262
264
|
SCHEMA_FILENAMES = {
|
|
263
|
-
"1.0": "final-report-v1.0.schema.json",
|
|
264
265
|
"2.0": "final-report-v2.0.schema.json",
|
|
265
266
|
}
|
|
266
267
|
|
|
@@ -295,9 +296,9 @@ def load_schema_for_data(data: dict, start: Path | None = None) -> dict:
|
|
|
295
296
|
|
|
296
297
|
def load_schema(schema_path: Path | None = None) -> dict:
|
|
297
298
|
"""Load the final-report schema. If ``schema_path`` is None, locate
|
|
298
|
-
``schemas/final-report-
|
|
299
|
+
``schemas/final-report-v2.0.schema.json`` relative to this file's
|
|
299
300
|
repo root.
|
|
300
301
|
"""
|
|
301
302
|
if schema_path is not None:
|
|
302
303
|
return json.loads(Path(schema_path).read_text(encoding="utf-8"))
|
|
303
|
-
return load_schema_version(
|
|
304
|
+
return load_schema_version(CURRENT_REPORT_SCHEMA_VERSION)
|
|
@@ -27,7 +27,9 @@ _LOCK_FILENAME = ".fix-cycles.lock"
|
|
|
27
27
|
# 완료(release-handoff) task 에 fix-cycle 로 재진입할 수 있는 entry phase 들.
|
|
28
28
|
# prepare(run.py) 의 게이트와 wizard 의 감지 술어가 공유하는 SSOT.
|
|
29
29
|
FIX_CYCLE_ENTRY_PHASES = (
|
|
30
|
-
"requirements-discovery", "error-analysis", "implementation-
|
|
30
|
+
"requirements-discovery", "error-analysis", "implementation-option-selection",
|
|
31
|
+
"implementation-planning",
|
|
32
|
+
)
|
|
31
33
|
|
|
32
34
|
|
|
33
35
|
def fix_cycles_path(task_root: Path) -> Path:
|