okstra 0.189.0 → 0.189.1
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/dist/cli-registry.mjs +6 -0
- package/dist/cli-registry.mjs.map +1 -1
- package/docs/architecture/storage-model.md +9 -0
- package/docs/cli.md +3 -0
- package/docs/for-ai/skills/okstra-brief-gen.md +2 -0
- package/docs/project-structure-overview.md +3 -1
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/prompts/profiles/_common-contract.md +1 -0
- package/runtime/python/okstra_ctl/analysis_packet.py +38 -0
- package/runtime/python/okstra_ctl/group_context.py +223 -0
- package/runtime/python/okstra_ctl/model_io/renderers.py +12 -7
- package/runtime/python/okstra_ctl/recap.py +7 -1
- package/runtime/python/okstra_ctl/run.py +28 -0
- package/runtime/python/okstra_ctl/timeline_runs.py +71 -0
- package/runtime/python/okstra_ctl/wizard.py +2 -1
- package/runtime/skills/okstra-brief-gen/SKILL.md +29 -1
- package/runtime/skills/okstra-inspect/facets/history.md +1 -0
- package/runtime/skills/okstra-inspect/facets/recap.md +1 -1
- package/runtime/templates/reports/group-context.template.md +31 -0
- package/runtime/validators/validate-brief.py +9 -0
package/dist/cli-registry.mjs
CHANGED
|
@@ -244,6 +244,12 @@ export const COMMAND_REGISTRY = [
|
|
|
244
244
|
category: "introspection",
|
|
245
245
|
summary: ["Assemble a task's run-to-run phase recap or append a recap log entry"],
|
|
246
246
|
},
|
|
247
|
+
{
|
|
248
|
+
name: "group-context",
|
|
249
|
+
python: { target: { module: "okstra_ctl.group_context" } },
|
|
250
|
+
category: "introspection",
|
|
251
|
+
summary: ["Create a task-group context skeleton beside the group's briefs"],
|
|
252
|
+
},
|
|
247
253
|
{
|
|
248
254
|
name: "user-response",
|
|
249
255
|
python: { target: { module: "okstra_ctl.user_response" } },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-registry.mjs","sourceRoot":"","sources":["../src/cli-registry.mts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli-registry.mjs","sourceRoot":"","sources":["../src/cli-registry.mts"],"names":[],"mappings":"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"}
|
|
@@ -367,8 +367,17 @@ The history generally includes the following.
|
|
|
367
367
|
- related tasks
|
|
368
368
|
- workflow snapshot
|
|
369
369
|
- `fixCycleId` *(only when attached to a fix cycle; field omitted otherwise)*
|
|
370
|
+
|
|
371
|
+
An entry is written once, when the run is prepared (`render.render_timeline`, called only from `prepare_task_bundle`). Its `status`, `workflowSnapshot`, and `reportRecordPath` are therefore the values at preparation time: `status` is `prepared` or `in-progress`, the snapshot is the workflow as it stood before the run, and the report path is the run's *reserved* record path. The run's current facts live in its own `run-manifest-<task-type>-<seq>.json`, which `validators/validate-run.py` updates when the run ends (`status`, `validation`, `workflowSnapshot`); task-level current facts (`currentStatus`, `latestRunStatus`, `workflow.*`, `latestReportRecordPath`) live in `task-manifest.json`. Read-side projections (`okstra model-io history-input` / `recap-input`, `okstra recap assemble`) overlay each entry with its run-manifest through `okstra_ctl.timeline_runs.current_run_facts`, and a run whose `validation.status` is still `not-run` projects no report path — the report sequence is allocated from files on disk, so a prepared-but-never-run entry's reservation is reused by the next run and would otherwise point at that later run's report.
|
|
372
|
+
|
|
370
373
|
Reruns of the same task type reuse the same resolved run directory family. Non-stage runs use `runs/<task-type>/`, while `implementation` and single-stage `final-verification` runs use `runs/<task-type>/stage-<N>/`. Sequence-specific artifacts live beneath that resolved run directory, and each execution accumulates as a separate history entry because `run-manifest-<task-type>-<seq>.json` and related artifact paths are separated by per-category sequence suffixes (`<task-type>-<seq>`). The cross-category identifier is the manifest's `runDateTimeSegment` ISO timestamp field.
|
|
371
374
|
|
|
375
|
+
## Task-group context contract
|
|
376
|
+
|
|
377
|
+
`.okstra/briefs/<task-group>/group-context.md` is the one document a task-group shares: why the group exists, how its result is measured (with the denominator named), group-wide constraints, and ticket relations. It is optional — a group without it prepares as before. The skeleton comes from `okstra group-context init` (`templates/reports/group-context.template.md`; frontmatter `type: group-context`, `task-group`, `created`, `generator`) and the user fills the four sections `Why This Group Exists`, `Definition of Better`, `Group-Wide Constraints`, `Ticket Relations` (the last two accept `_(none)_`). `validators/validate-brief.py` dispatches on the frontmatter `type`, so the group's directory validation covers briefs and the context together (`okstra_ctl.group_context.validate_group_context`).
|
|
378
|
+
|
|
379
|
+
Preparation validates the file before any side effect and refuses one that still carries a `<...>` placeholder line (`run._validate_group_context_preflight`), then copies it to `instruction-set/task-group-context.md` and the analysis packet carries it as `## Task-Group Context` between `## Source Files` and `## Task-Specific Brief Extract`, behind a fixed preface that separates the group's measure and constraints from the brief's scope. The wizard's brief suggestions skip the file.
|
|
380
|
+
|
|
372
381
|
## Lead operating contract
|
|
373
382
|
|
|
374
383
|
After `okstra` prepares a run, the host-native Okstra lead follows this default sequence when reading the current task.
|
package/docs/cli.md
CHANGED
|
@@ -201,6 +201,8 @@ Examples:
|
|
|
201
201
|
- `.project-docs/linear/feature/8858/okstra-task-brief.md`
|
|
202
202
|
- `.project-docs/tasks/8852/BUG_REPORT.md`
|
|
203
203
|
|
|
204
|
+
When the task-group directory beside the brief holds `group-context.md` (`.okstra/briefs/<task-group>/group-context.md`, skeleton from `okstra group-context init`), preparation validates it, copies it to `instruction-set/task-group-context.md`, and the analysis packet carries it as `## Task-Group Context` ahead of `## Task-Specific Brief Extract`. A file that still carries a template placeholder line fails preparation; delete it if the group needs no context.
|
|
205
|
+
|
|
204
206
|
### `--yes`
|
|
205
207
|
|
|
206
208
|
Skips interactive prompts and confirmation.
|
|
@@ -792,6 +794,7 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
|
|
|
792
794
|
| `okstra convergence finalize --work-state <path> --output <path>` | Materialize the terminal schema v1.3 convergence state |
|
|
793
795
|
| `okstra convergence validate --state <path> --kind <working\|final>` | Validate replayable working state or a terminal final state |
|
|
794
796
|
| `okstra convergence example --kind <groups\|round-results\|critic-results\|coverage-batch>` | Print one deterministic valid input example as JSON. Each kind feeds one command: `groups` → `seed --groups`, `round-results` → `apply-round --results`, `coverage-batch` → `apply-critic-gaps --results`. `critic-results` feeds nothing — it is the critic worker's own result document, and feeding it to `apply-critic-gaps` is rejected by design; that reducer takes the coverage batch the lead assembles from those candidates plus each analyser's vote, which is what `--kind coverage-batch` prints |
|
|
797
|
+
| `okstra group-context init --project-root <root> --task-group <group>` | Write the task-group context skeleton `.okstra/briefs/<task-group>/group-context.md` from `templates/reports/group-context.template.md` and print the sections to fill. Exits 2 when the file already exists. The filled document is validated by `validators/validate-brief.py` (frontmatter `type: group-context`), copied by preparation into `instruction-set/task-group-context.md`, and carried in the analysis packet's `## Task-Group Context` section ahead of the brief extract; preparation refuses a file that still carries a `<...>` placeholder line, and a task-group without the file prepares as before |
|
|
795
798
|
| `okstra plan-items extract (--narrative <report-narrative.md>\|--data <historical-data.json>) --output <items.json>` | Deterministically extract the complete implementation-planning `P-*` queue. Contract v3 reads the report-writer narrative before publication; `--data` is the historical v2 reader. |
|
|
796
799
|
| `okstra plan-items validate (--narrative <report-narrative.md>\|--data <historical-data.json>) --items <items.json>` | Require the persisted `P-*` queue to match a fresh deterministic extraction exactly. |
|
|
797
800
|
| `okstra plan-items derivations --data <data.json> --response <user-response sidecar> [--clarification C-NNN]` | List the plan statements an answered clarification may have falsified. Extracts the symbols, paths, and ids the answer names (backticked spans plus `R-001` / `DEV-10174`-style ids) and reports every string in the plan body that mentions one, as a JSON pointer plus excerpt. Advisory: it says where a decision's subject is mentioned, never which mentions are now wrong — the supersession rule (`prompts/profiles/_common-contract.md`) requires the author to enumerate before editing, and this supplies the enumeration |
|
|
@@ -249,6 +249,8 @@ briefs saved (N):
|
|
|
249
249
|
next: /okstra-run
|
|
250
250
|
```
|
|
251
251
|
|
|
252
|
+
Before the hand-off block, once per task-group (Step 7a): if `<PROJECT_ROOT>/.okstra/briefs/<task-group>/group-context.md` is absent, ask whether to create the skeleton (`okstra group-context init --project-root <PROJECT_ROOT> --task-group <task-group>`; recommended for a new group) or skip. Never fill it from the tickets. When created, add `group context skeleton: <abs>/<task-group>/group-context.md (fill before /okstra-run)` to the block — preparation refuses the group's tasks while a `<...>` placeholder line remains.
|
|
253
|
+
|
|
252
254
|
## Forbidden patterns
|
|
253
255
|
|
|
254
256
|
- Summarizing or tidying Source Material before inserting it.
|
|
@@ -262,8 +262,10 @@ Important modules:
|
|
|
262
262
|
| `consumers.py` | Append-only `consumers.jsonl` writer + reader — records which `implementation` runs consumed which `implementation-planning` stage |
|
|
263
263
|
| `implementation_outcome.py` | Artifact-derived reconstruction of the implementation phase outcome — reads `runs/implementation/carry/stage-<N>.json` + `consumers.jsonl` + the approved Stage Map to derive `phaseOutcome.implementation`, and when every stage has pass-grade carry evidence it raises `workflow.nextRecommendedPhase.status` to `ready` (keeping the `contract-violated` audit information). It never picks the phase — `phase` is left as the last stage's report routing settled it, and the status is raised only while `phase` is non-empty |
|
|
264
264
|
| `paths.py` | Path/sequence computation for task/run artifacts (including recap directory/log paths) |
|
|
265
|
-
| `recap.py` | deterministic backend for the okstra-inspect `recap` facet — `assemble` builds the cross-run phase transitions from the timeline, `record` append-only writes a summary/Q&A to `<task-root>/recap/recap-log.jsonl` (other task artifacts unchanged) |
|
|
265
|
+
| `recap.py` | deterministic backend for the okstra-inspect `recap` facet — `assemble` builds the cross-run phase transitions from the timeline overlaid with each run-manifest's current facts (`timeline_runs.py`), `record` append-only writes a summary/Q&A to `<task-root>/recap/recap-log.jsonl` (other task artifacts unchanged) |
|
|
266
|
+
| `timeline_runs.py` | read-side overlay of a `history/timeline.json` entry with its run-manifest's current facts (`current_run_facts`) — the entry is a prepare-time snapshot (`status`, `workflowSnapshot`, reserved `reportRecordPath`) and `validate-run` writes the end state to the run-manifest only; a run whose `validation.status` is `not-run` projects no report path. Shared by `recap.py` and the `history-input` / overview projections in `model_io/renderers.py` |
|
|
266
267
|
| `render.py` | task manifest, run manifest, timeline, task index, discovery, team-state, prompt/template render |
|
|
268
|
+
| `group_context.py` | task-group context document (`.okstra/briefs/<task-group>/group-context.md`): the skeleton writer behind `okstra group-context init` (template `templates/reports/group-context.template.md`), `validate_group_context` (four required sections, no template placeholder left, directory slug matches the frontmatter `task-group`) that `validators/validate-brief.py` dispatches to on frontmatter `type: group-context`, and the path helpers `run.py` uses to validate the file at preflight and copy it to `instruction-set/task-group-context.md` for the analysis packet's `## Task-Group Context` section |
|
|
267
269
|
| `workflow.py` | Phase sequence (`PHASE_SEQUENCE`), per-phase allowed outputs, forbidden actions. It does not decide the next phase — that is `next_phase.py` |
|
|
268
270
|
| `next_phase.py` | `workflow.nextRecommendedPhase` SSOT — the pointer's shape (`make` / `is_pointer` over `{phase, status, rationale}`, `status` ∈ `ready`/`pending`/`blocked`/`terminal`), the promotion of a legacy string pointer (`promote`), the projection of one report's routing field into a pointer (`project`), and the `ready`-only read the shell and wizard autofill share (`autofill_task_type`). There is no static phase table and no sequence walk: the next phase comes from what the report authored, and nothing else may compute one |
|
|
269
271
|
| `workers.py`, `models.py` | Worker roster; `models.py` is the model catalog SSOT (`ModelSpec` per alias + `ROLE_DEFAULTS`) — add-a-model single reference point from which picker options, codex pricing, and role defaults all derive |
|
package/package.json
CHANGED
package/runtime/BUILD.json
CHANGED
|
@@ -43,6 +43,7 @@ profile document.
|
|
|
43
43
|
- A legacy brief with no `reporter-confirmations` field is not reinterpreted as `pending`; it keeps the compatibility path and proceeds without this reporter-confirmation gate.
|
|
44
44
|
`[CONFIRMED <YYYY-MM-DD> → RC-N]` markers on `Open Questions` rows are the per-row signal that the reporter has answered; their answers live verbatim under `## Reporter Confirmations` in the brief.
|
|
45
45
|
- `Source Material` is reporter-verbatim. Do NOT paraphrase, summarize, reorder, or restructure it. Quote it directly when needed.
|
|
46
|
+
- `## Task-Group Context` (present in the analysis packet only when the task-group has `.okstra/briefs/<task-group>/group-context.md`, copied to `instruction-set/task-group-context.md`) is background shared by every task in the group — why the group exists, how the result is measured, group-wide constraints, ticket relations. It is not this task's requirement ledger: the brief decides this run's scope, the group context decides the measure and what no task may break. Reason from the group's measure (its stated denominator) rather than from a quantity only this ticket exposes, and where the brief and the group context conflict, raise a `Clarification Items` row instead of resolving the conflict silently in either direction.
|
|
46
47
|
- `Related Task Graph` is the structured task-topology handoff. If the section is present and not `_(none)_`, read it before classification, diagnosis, candidate discovery, fan-out, or next-step routing. Preserve the edge direction exactly as written: `From` → `To` is load-bearing for `depends-on`, `blocks`, parent/child, follow-up, and split relations.
|
|
47
48
|
- Valid relations are `parent-of`, `child-of`, `depends-on`, `blocks`, `blocked-by`, `follow-up-of`, `split-from`, `duplicates`, and `related-to`. `duplicates` / `related-to` are undirected; every other relation is directed.
|
|
48
49
|
- Treat `Source` as the edge provenance. Do not invent graph edges from filename similarity, topic overlap, or worker preference. If a needed edge is missing or contradictory, raise a `Clarification Items` row instead of silently reordering tasks.
|
|
@@ -99,6 +99,7 @@ def build_analysis_packet(
|
|
|
99
99
|
clarification_response_path: Path | None,
|
|
100
100
|
directive: str,
|
|
101
101
|
instruction_set_relative_path: str,
|
|
102
|
+
group_context_path: Path | None = None,
|
|
102
103
|
fix_history_text: str = "",
|
|
103
104
|
stage_ledger_json: str = "",
|
|
104
105
|
stage_ledger_notice: str = "",
|
|
@@ -112,8 +113,13 @@ def build_analysis_packet(
|
|
|
112
113
|
from disk state this file does not own. Each arrives already narrowed, and
|
|
113
114
|
an empty string means the caller found nothing to carry — the matching
|
|
114
115
|
block is then omitted rather than rendered saying "none".
|
|
116
|
+
|
|
117
|
+
`group_context_path` is the task-group context prepare copied into the
|
|
118
|
+
instruction set (`task-group-context.md`); `None` means the group has no
|
|
119
|
+
such document and the packet carries no `## Task-Group Context` section.
|
|
115
120
|
"""
|
|
116
121
|
brief_text = task_brief_path.read_text(encoding="utf-8")
|
|
122
|
+
group_context_text = _read_optional(group_context_path) if group_context_path else ""
|
|
117
123
|
profile_text = analysis_profile_path.read_text(encoding="utf-8")
|
|
118
124
|
reference_text = _read_optional(reference_expectations_path)
|
|
119
125
|
clarification_text = (
|
|
@@ -127,8 +133,12 @@ def build_analysis_packet(
|
|
|
127
133
|
task_type,
|
|
128
134
|
instruction_set_relative_path,
|
|
129
135
|
bool(clarification_response_path),
|
|
136
|
+
bool(group_context_text),
|
|
130
137
|
)
|
|
131
138
|
)
|
|
139
|
+
# 그룹 맥락은 브리프 발췌보다 앞에 둔다: 짧고 "왜" 를 담으며, 46KB 에서 잘리는
|
|
140
|
+
# 읽기(agy view_file)에서도 도착해야 하는 절이다.
|
|
141
|
+
parts.extend(_group_context_block(group_context_text))
|
|
132
142
|
parts.extend(_brief_block(brief_text))
|
|
133
143
|
parts.extend(_profile_block(task_type, profile_text))
|
|
134
144
|
parts.extend(_reference_block(reference_text))
|
|
@@ -243,6 +253,7 @@ def _intro_block(
|
|
|
243
253
|
task_type: str,
|
|
244
254
|
instruction_set: str,
|
|
245
255
|
has_clarification: bool,
|
|
256
|
+
has_group_context: bool = False,
|
|
246
257
|
) -> list[str]:
|
|
247
258
|
lines = [
|
|
248
259
|
f"# OKSTRA Analysis Packet - {task_key}",
|
|
@@ -268,9 +279,36 @@ def _intro_block(
|
|
|
268
279
|
lines.append(
|
|
269
280
|
f"- Clarification response: `{instruction_set}/clarification-response.md`"
|
|
270
281
|
)
|
|
282
|
+
if has_group_context:
|
|
283
|
+
lines.append(
|
|
284
|
+
f"- Task-group context: `{instruction_set}/task-group-context.md`"
|
|
285
|
+
)
|
|
271
286
|
return lines
|
|
272
287
|
|
|
273
288
|
|
|
289
|
+
GROUP_CONTEXT_PREFACE = (
|
|
290
|
+
"Background shared by every task in this task-group, copied from the group's "
|
|
291
|
+
"`group-context.md`. It is not this task's requirement ledger: the "
|
|
292
|
+
"`## Task-Specific Brief Extract` below decides what this run must deliver, "
|
|
293
|
+
"while this section decides how the result is measured and what no task in the "
|
|
294
|
+
"group may break. Where the two conflict, raise a `Clarification Items` row; "
|
|
295
|
+
"never resolve the conflict silently in either direction."
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def _group_context_block(group_context_text: str) -> list[str]:
|
|
300
|
+
if not group_context_text.strip():
|
|
301
|
+
return []
|
|
302
|
+
return [
|
|
303
|
+
"",
|
|
304
|
+
"## Task-Group Context",
|
|
305
|
+
"",
|
|
306
|
+
GROUP_CONTEXT_PREFACE,
|
|
307
|
+
"",
|
|
308
|
+
_strip_frontmatter(group_context_text).strip(),
|
|
309
|
+
]
|
|
310
|
+
|
|
311
|
+
|
|
274
312
|
def _brief_block(brief_text: str) -> list[str]:
|
|
275
313
|
return [
|
|
276
314
|
"",
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"""task-group 맥락 문서 — 그룹의 모든 task 가 공유하는 배경을 워커 입력에 싣는다.
|
|
2
|
+
|
|
3
|
+
`.okstra/briefs/<task-group>/group-context.md` 한 파일이 그룹이 존재하는 이유,
|
|
4
|
+
성과 척도, 그룹 전체 금지선, 티켓 간 관계를 담는다. 브리프는 티켓 하나의 범위를
|
|
5
|
+
말하므로 그룹 단위의 "왜" 는 어느 브리프에도 없다(2026-09-04 실측, fontsninja
|
|
6
|
+
`cache` 그룹: 브리프 15개 중 가용성 사고를 말한 것이 0개였고 option-selection 이
|
|
7
|
+
분모를 페이지당 요청 수로 바꿔 판단했다).
|
|
8
|
+
|
|
9
|
+
세 소비자가 이 모듈 하나를 쓴다.
|
|
10
|
+
|
|
11
|
+
- `okstra group-context init` — 템플릿에서 뼈대를 쓴다(있으면 거절).
|
|
12
|
+
- `validators/validate-brief.py` — 프론트매터 `type: group-context` 를 만나면
|
|
13
|
+
`validate_group_context` 로 검사한다.
|
|
14
|
+
- prepare(`run.py`) — 파일이 있으면 같은 검사를 통과해야 진행하고, 통과하면
|
|
15
|
+
`instruction-set/task-group-context.md` 로 복사해 analysis packet 에 싣는다.
|
|
16
|
+
"""
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import argparse
|
|
20
|
+
import datetime as dt
|
|
21
|
+
import re
|
|
22
|
+
import sys
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
from .brief_frontmatter import read_brief_frontmatter
|
|
26
|
+
from .ids import slugify_task_segment
|
|
27
|
+
from .paths import find_asset_root
|
|
28
|
+
|
|
29
|
+
GROUP_CONTEXT_FILENAME = "group-context.md"
|
|
30
|
+
GROUP_CONTEXT_TYPE = "group-context"
|
|
31
|
+
GROUP_CONTEXT_GENERATOR = "okstra-brief-gen"
|
|
32
|
+
INSTRUCTION_SET_FILENAME = "task-group-context.md"
|
|
33
|
+
REQUIRED_FRONTMATTER_KEYS = ("type", "task-group", "created", "generator")
|
|
34
|
+
SECTIONS = (
|
|
35
|
+
"Why This Group Exists",
|
|
36
|
+
"Definition of Better",
|
|
37
|
+
"Group-Wide Constraints",
|
|
38
|
+
"Ticket Relations",
|
|
39
|
+
)
|
|
40
|
+
# 나머지 두 절은 `_(none)_` 이 허용된다 — 금지선이나 관계가 없는 그룹도 있다.
|
|
41
|
+
MUST_BE_FILLED = SECTIONS[:2]
|
|
42
|
+
TEMPLATE_RELATIVE = ("templates", "reports", "group-context.template.md")
|
|
43
|
+
|
|
44
|
+
_HTML_COMMENT_RE = re.compile(r"<!--.*?-->", re.DOTALL)
|
|
45
|
+
_NONE_MARKERS = {"_(none)_", ""}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def briefs_root(project_root: Path) -> Path:
|
|
49
|
+
return Path(project_root) / ".okstra" / "briefs"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def group_context_file(project_root: Path, task_group: str) -> Path:
|
|
53
|
+
"""그룹 맥락 문서의 정본 경로. 디렉터리는 브리프와 같은 slug 를 쓴다."""
|
|
54
|
+
return briefs_root(project_root) / slugify_task_segment(task_group) / GROUP_CONTEXT_FILENAME
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def is_group_context_file(path: Path) -> bool:
|
|
58
|
+
return path.name == GROUP_CONTEXT_FILENAME
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def validate_group_context(path: Path, root: Path) -> list[str]:
|
|
62
|
+
"""결함 목록. 비어 있으면 통과. 결함마다 사람이 고칠 자리를 이름한다."""
|
|
63
|
+
text = _HTML_COMMENT_RE.sub("", path.read_text(encoding="utf-8"))
|
|
64
|
+
errors: list[str] = []
|
|
65
|
+
frontmatter = read_brief_frontmatter(path)
|
|
66
|
+
if not frontmatter:
|
|
67
|
+
return ["frontmatter: missing or malformed (a `---` block must open line 1)"]
|
|
68
|
+
missing = [key for key in REQUIRED_FRONTMATTER_KEYS if key not in frontmatter]
|
|
69
|
+
if missing:
|
|
70
|
+
errors.append(f"frontmatter missing keys: {missing}")
|
|
71
|
+
if frontmatter.get("type") != GROUP_CONTEXT_TYPE:
|
|
72
|
+
errors.append(
|
|
73
|
+
f"frontmatter type must be {GROUP_CONTEXT_TYPE!r}, got {frontmatter.get('type')!r}"
|
|
74
|
+
)
|
|
75
|
+
if frontmatter.get("generator") != GROUP_CONTEXT_GENERATOR:
|
|
76
|
+
errors.append(
|
|
77
|
+
f"frontmatter generator must be {GROUP_CONTEXT_GENERATOR!r}, "
|
|
78
|
+
f"got {frontmatter.get('generator')!r}"
|
|
79
|
+
)
|
|
80
|
+
errors.extend(_path_errors(path, root, frontmatter.get("task-group", "")))
|
|
81
|
+
errors.extend(_section_errors(text))
|
|
82
|
+
return errors
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _path_errors(path: Path, root: Path, task_group: str) -> list[str]:
|
|
86
|
+
errors: list[str] = []
|
|
87
|
+
if path.name != GROUP_CONTEXT_FILENAME:
|
|
88
|
+
errors.append(f"file must be named {GROUP_CONTEXT_FILENAME!r}, got {path.name!r}")
|
|
89
|
+
try:
|
|
90
|
+
relative = path.resolve().relative_to(Path(root).resolve())
|
|
91
|
+
except ValueError:
|
|
92
|
+
return errors + [f"file is not under the briefs root {root}"]
|
|
93
|
+
if len(relative.parts) != 2:
|
|
94
|
+
errors.append(
|
|
95
|
+
"file must sit directly under its task-group directory "
|
|
96
|
+
f"(`<briefs>/<task-group>/{GROUP_CONTEXT_FILENAME}`), got {relative}"
|
|
97
|
+
)
|
|
98
|
+
return errors
|
|
99
|
+
expected = slugify_task_segment(task_group)
|
|
100
|
+
if task_group and relative.parts[0] != expected:
|
|
101
|
+
errors.append(
|
|
102
|
+
f"task-group directory segment {relative.parts[0]!r} does not match the "
|
|
103
|
+
f"slugified frontmatter task-group {expected!r}"
|
|
104
|
+
)
|
|
105
|
+
return errors
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _section_errors(text: str) -> list[str]:
|
|
109
|
+
bodies = _section_bodies(text)
|
|
110
|
+
errors: list[str] = []
|
|
111
|
+
for heading in SECTIONS:
|
|
112
|
+
if heading not in bodies:
|
|
113
|
+
errors.append(f"missing section `## {heading}`")
|
|
114
|
+
continue
|
|
115
|
+
lines = [line.strip() for line in bodies[heading].splitlines() if line.strip()]
|
|
116
|
+
placeholders = [line for line in lines if _is_template_placeholder(line)]
|
|
117
|
+
if placeholders:
|
|
118
|
+
errors.append(
|
|
119
|
+
f"section `## {heading}` still carries a template placeholder "
|
|
120
|
+
f"({placeholders[0][:40]}...); fill it or delete the file"
|
|
121
|
+
)
|
|
122
|
+
continue
|
|
123
|
+
if heading in MUST_BE_FILLED and all(line in _NONE_MARKERS for line in lines):
|
|
124
|
+
errors.append(f"section `## {heading}` must be filled; `_(none)_` is not accepted here")
|
|
125
|
+
return errors
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _section_bodies(text: str) -> dict[str, str]:
|
|
129
|
+
"""`## ` 제목 → 본문. `## ` 만 절을 닫는다(validate-brief `section_body` 와 같은 규칙)."""
|
|
130
|
+
bodies: dict[str, str] = {}
|
|
131
|
+
current: str | None = None
|
|
132
|
+
buffer: list[str] = []
|
|
133
|
+
for line in text.splitlines():
|
|
134
|
+
if line.startswith("## "):
|
|
135
|
+
if current is not None:
|
|
136
|
+
bodies[current] = "\n".join(buffer)
|
|
137
|
+
current = line[3:].strip()
|
|
138
|
+
buffer = []
|
|
139
|
+
elif current is not None:
|
|
140
|
+
buffer.append(line)
|
|
141
|
+
if current is not None:
|
|
142
|
+
bodies[current] = "\n".join(buffer)
|
|
143
|
+
return bodies
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _is_template_placeholder(line: str) -> bool:
|
|
147
|
+
bare = line.lstrip("-").strip()
|
|
148
|
+
return bare.startswith("<") and bare.endswith(">")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def render_skeleton(task_group: str, created: str) -> str:
|
|
152
|
+
root = find_asset_root(TEMPLATE_RELATIVE)
|
|
153
|
+
if root is None:
|
|
154
|
+
raise FileNotFoundError(
|
|
155
|
+
"group-context template not found in any okstra asset root: "
|
|
156
|
+
+ "/".join(TEMPLATE_RELATIVE)
|
|
157
|
+
)
|
|
158
|
+
template = root.joinpath(*TEMPLATE_RELATIVE).read_text(encoding="utf-8")
|
|
159
|
+
slug = slugify_task_segment(task_group)
|
|
160
|
+
return template.replace("<task-group>", slug).replace("<YYYY-MM-DD>", created)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def init_group_context(project_root: Path, task_group: str, *, today: dt.date) -> Path:
|
|
164
|
+
"""뼈대를 쓴다. 이미 있으면 `FileExistsError` — 채운 문서를 덮어쓰지 않는다."""
|
|
165
|
+
target = group_context_file(project_root, task_group)
|
|
166
|
+
if target.exists():
|
|
167
|
+
raise FileExistsError(str(target))
|
|
168
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
169
|
+
target.write_text(render_skeleton(task_group, today.isoformat()), encoding="utf-8")
|
|
170
|
+
return target
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _init_command(args: argparse.Namespace) -> int:
|
|
174
|
+
project_root = Path(args.project_root).resolve()
|
|
175
|
+
try:
|
|
176
|
+
target = init_group_context(project_root, args.task_group, today=dt.date.today())
|
|
177
|
+
except FileExistsError as exc:
|
|
178
|
+
print(
|
|
179
|
+
f"group-context: already exists: {exc}\n"
|
|
180
|
+
"Edit that file instead; delete it first if you want a fresh skeleton.",
|
|
181
|
+
file=sys.stderr,
|
|
182
|
+
)
|
|
183
|
+
return 2
|
|
184
|
+
print(f"group context skeleton: {target}")
|
|
185
|
+
print("Fill these sections (one `<...>` placeholder line each):")
|
|
186
|
+
for heading in SECTIONS:
|
|
187
|
+
note = "required" if heading in MUST_BE_FILLED else "`_(none)_` allowed"
|
|
188
|
+
print(f" - ## {heading} ({note})")
|
|
189
|
+
print(
|
|
190
|
+
"Validate with: python3 ~/.okstra/lib/validators/validate-brief.py "
|
|
191
|
+
f"{target} --briefs-root {briefs_root(project_root)}"
|
|
192
|
+
)
|
|
193
|
+
print(
|
|
194
|
+
"Every run of task-group "
|
|
195
|
+
f"`{slugify_task_segment(args.task_group)}` refuses to prepare while a placeholder "
|
|
196
|
+
"line remains; delete the file if the group needs no context."
|
|
197
|
+
)
|
|
198
|
+
return 0
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
202
|
+
parser = argparse.ArgumentParser(
|
|
203
|
+
prog="okstra group-context",
|
|
204
|
+
description=(
|
|
205
|
+
"Create the task-group context skeleton beside the group's briefs "
|
|
206
|
+
"(`.okstra/briefs/<task-group>/group-context.md`)."
|
|
207
|
+
),
|
|
208
|
+
)
|
|
209
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
210
|
+
init = sub.add_parser("init", help="write the skeleton from the template; refuses an existing file")
|
|
211
|
+
init.add_argument("--project-root", required=True, help="project root that holds `.okstra/`")
|
|
212
|
+
init.add_argument("--task-group", required=True, help="task-group name; slugified for the directory")
|
|
213
|
+
init.set_defaults(func=_init_command)
|
|
214
|
+
return parser
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def main(argv: list[str] | None = None) -> int:
|
|
218
|
+
args = build_parser().parse_args(argv)
|
|
219
|
+
return args.func(args)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
if __name__ == "__main__":
|
|
223
|
+
sys.exit(main())
|
|
@@ -20,6 +20,7 @@ from ..fixed_text import line as _line, scalar as _value
|
|
|
20
20
|
from ..json_boundary import JsonBoundaryError, load_owned_object
|
|
21
21
|
from ..paths import okstra_home
|
|
22
22
|
from ..recap import assemble_recap
|
|
23
|
+
from ..timeline_runs import current_run_facts
|
|
23
24
|
from ..worker_artifacts import worker_provider_id
|
|
24
25
|
from .lines import (
|
|
25
26
|
_assignment_line,
|
|
@@ -51,7 +52,7 @@ from .references import (
|
|
|
51
52
|
)
|
|
52
53
|
|
|
53
54
|
|
|
54
|
-
def _latest_timeline_run(manifest_path: Path) -> Mapping[str, Any]:
|
|
55
|
+
def _latest_timeline_run(project_root: Path, manifest_path: Path) -> Mapping[str, Any]:
|
|
55
56
|
timeline_path = manifest_path.parent / "history" / "timeline.json"
|
|
56
57
|
if not timeline_path.is_file():
|
|
57
58
|
return {}
|
|
@@ -59,10 +60,11 @@ def _latest_timeline_run(manifest_path: Path) -> Mapping[str, Any]:
|
|
|
59
60
|
runs = timeline.get("runs")
|
|
60
61
|
if not isinstance(runs, list):
|
|
61
62
|
return {}
|
|
62
|
-
|
|
63
|
+
latest = next(
|
|
63
64
|
(run for run in reversed(runs) if isinstance(run, Mapping)),
|
|
64
|
-
|
|
65
|
+
None,
|
|
65
66
|
)
|
|
67
|
+
return current_run_facts(project_root, latest) if latest is not None else {}
|
|
66
68
|
|
|
67
69
|
|
|
68
70
|
def _overview_rows(
|
|
@@ -79,15 +81,18 @@ def _overview_rows(
|
|
|
79
81
|
project_root, manifest_path, expected_task_key=task_key, artifact="task catalog"
|
|
80
82
|
)
|
|
81
83
|
manifest = load_owned_object(manifest_path, artifact="task manifest")
|
|
82
|
-
latest_run = _latest_timeline_run(manifest_path)
|
|
84
|
+
latest_run = _latest_timeline_run(project_root, manifest_path)
|
|
83
85
|
_, group, _ = parse_task_key(task_key)
|
|
84
86
|
workflow = _mapping(manifest, "workflow")
|
|
85
87
|
next_phase = _mapping(workflow, "nextRecommendedPhase")
|
|
88
|
+
# task 단위 현재 사실은 task-manifest 가 권위다(validate-run 이 run 종료
|
|
89
|
+
# 시 거기에 쓴다). timeline 의 마지막 run 은 task-manifest 에 그 필드가
|
|
90
|
+
# 없을 때의 폴백이고, 그 값도 run-manifest 로 덮어쓴 현재 사실이다.
|
|
86
91
|
row = {
|
|
87
92
|
"taskKey": task_key,
|
|
88
93
|
"taskGroup": manifest.get("taskGroup") or task.get("taskGroup") or group,
|
|
89
94
|
"taskType": manifest.get("taskType") or latest_run.get("taskType"),
|
|
90
|
-
"latestRunStatus":
|
|
95
|
+
"latestRunStatus": manifest.get("latestRunStatus") or latest_run.get("status"),
|
|
91
96
|
"updatedAt": manifest.get("updatedAt") or task.get("updatedAt") or latest_run.get("runTimestamp"),
|
|
92
97
|
"latestRunManifestPath": pointer.get("latestRunManifestPath"),
|
|
93
98
|
"workCategory": manifest.get("workCategory"),
|
|
@@ -98,7 +103,7 @@ def _overview_rows(
|
|
|
98
103
|
"nextPhaseStatus": next_phase.get("status"),
|
|
99
104
|
"nextPhaseRationale": next_phase.get("rationale"),
|
|
100
105
|
"awaitingApproval": workflow.get("awaitingApproval"),
|
|
101
|
-
"latestReportRecordPath":
|
|
106
|
+
"latestReportRecordPath": manifest.get("latestReportRecordPath") or latest_run.get("reportRecordPath"),
|
|
102
107
|
"latestResumeCommandPath": latest_run.get("resumeCommandPath") or manifest.get("latestResumeCommandPath"),
|
|
103
108
|
"workStatus": manifest.get("workStatus"),
|
|
104
109
|
"lastRun": latest_run.get("runTimestamp"),
|
|
@@ -336,7 +341,7 @@ def render_history_input(
|
|
|
336
341
|
)
|
|
337
342
|
manifest, runs = _selected_task_data(project_root, task_ref)
|
|
338
343
|
blocks: list[str] = []
|
|
339
|
-
for index, run in enumerate(runs, 1):
|
|
344
|
+
for index, run in enumerate((current_run_facts(project_root, run) for run in runs), 1):
|
|
340
345
|
blocks.append(
|
|
341
346
|
f"\n## Run {index}\n\n"
|
|
342
347
|
+ _line("Run timestamp", run.get("runTimestamp"))
|
|
@@ -22,6 +22,7 @@ from okstra_project import read_task_key
|
|
|
22
22
|
from okstra_ctl.run_context import dir_flock
|
|
23
23
|
from okstra_ctl.final_report_paths import timeline_report_record_rel
|
|
24
24
|
from okstra_ctl.task_target import resolve_task_root, project_rel
|
|
25
|
+
from okstra_ctl.timeline_runs import current_run_facts
|
|
25
26
|
|
|
26
27
|
NOTE_KINDS = ("verification-evidence", "decision-draft", "analysis-note")
|
|
27
28
|
|
|
@@ -97,7 +98,12 @@ def rerun_readiness(project_root: Path, runs: list[dict]) -> dict | None:
|
|
|
97
98
|
|
|
98
99
|
|
|
99
100
|
def assemble_recap(task_root: Path, project_root: Path) -> dict:
|
|
100
|
-
|
|
101
|
+
# timeline 항목의 status / workflowSnapshot / reportRecordPath 는 준비 시점
|
|
102
|
+
# 값이다. 각 run 의 종료 상태는 그 run 의 run-manifest 에서 덮어쓴다.
|
|
103
|
+
runs = [
|
|
104
|
+
current_run_facts(project_root, run) if isinstance(run, dict) else run
|
|
105
|
+
for run in _load_timeline(task_root)
|
|
106
|
+
]
|
|
101
107
|
transitions = []
|
|
102
108
|
prev_phase = ""
|
|
103
109
|
latest_states: dict = {}
|
|
@@ -38,6 +38,7 @@ from okstra_project import project_json_path, upsert_project_json
|
|
|
38
38
|
from okstra_project.slug import slugify
|
|
39
39
|
from . import fix_cycles
|
|
40
40
|
from .analysis_packet import build_analysis_packet
|
|
41
|
+
from . import group_context
|
|
41
42
|
from .stage_ledger import (
|
|
42
43
|
build_stage_ledger,
|
|
43
44
|
render_stage_ledger,
|
|
@@ -1363,6 +1364,23 @@ def _validate_task_brief_preflight(
|
|
|
1363
1364
|
)
|
|
1364
1365
|
|
|
1365
1366
|
|
|
1367
|
+
def _validate_group_context_preflight(project_root: Path, task_group: str) -> None:
|
|
1368
|
+
"""그룹 맥락 문서가 있으면 검증한다. 없으면 선택적 입력이라 아무 일도 없다.
|
|
1369
|
+
|
|
1370
|
+
채우지 않은 뼈대가 워커에 닿으면 자리표시자를 배경으로 읽으므로, 있는데 결함이면
|
|
1371
|
+
prepare 를 멈추고 채우거나 지우라고 말한다."""
|
|
1372
|
+
path = group_context.group_context_file(project_root, task_group)
|
|
1373
|
+
if not path.is_file():
|
|
1374
|
+
return
|
|
1375
|
+
errors = group_context.validate_group_context(path, group_context.briefs_root(project_root))
|
|
1376
|
+
if errors:
|
|
1377
|
+
raise PrepareError(
|
|
1378
|
+
f"task-group context failed validation ({path}): "
|
|
1379
|
+
+ "; ".join(errors)
|
|
1380
|
+
+ " — fill the file, or delete it if the group needs no context"
|
|
1381
|
+
)
|
|
1382
|
+
|
|
1383
|
+
|
|
1366
1384
|
def _validate_prepare_inputs(project_root: Path, inp: PrepareInputs) -> list:
|
|
1367
1385
|
"""Validate pure prepare inputs and return a final-verification stage map."""
|
|
1368
1386
|
if not project_root.is_dir():
|
|
@@ -3599,6 +3617,14 @@ def _write_instruction_set_sources(
|
|
|
3599
3617
|
)
|
|
3600
3618
|
(instruction_set / "analysis-material.md").write_text(review_material, encoding="utf-8")
|
|
3601
3619
|
shutil.copyfile(inp.brief_path, instruction_set / "task-brief.md")
|
|
3620
|
+
# 그룹 맥락은 preflight 를 통과한 파일만 여기 온다(`_validate_group_context_preflight`).
|
|
3621
|
+
group_context_source = group_context.group_context_file(
|
|
3622
|
+
Path(inp.project_root), inp.task_group
|
|
3623
|
+
)
|
|
3624
|
+
group_context_path: Path | None = None
|
|
3625
|
+
if group_context_source.is_file():
|
|
3626
|
+
group_context_path = instruction_set / group_context.INSTRUCTION_SET_FILENAME
|
|
3627
|
+
shutil.copyfile(group_context_source, group_context_path)
|
|
3602
3628
|
# A rule that lives only in the conversation is one compaction away from
|
|
3603
3629
|
# gone, with no signal that it went. On disk it survives, and the session
|
|
3604
3630
|
# conformance check can ask afterwards whether it was read. The token is
|
|
@@ -3664,6 +3690,7 @@ def _write_instruction_set_sources(
|
|
|
3664
3690
|
task_key=ctx["TASK_KEY"],
|
|
3665
3691
|
task_type=ctx["TASK_TYPE"],
|
|
3666
3692
|
task_brief_path=instruction_set / "task-brief.md",
|
|
3693
|
+
group_context_path=group_context_path,
|
|
3667
3694
|
analysis_profile_path=instruction_set / "analysis-profile.md",
|
|
3668
3695
|
reference_expectations_path=instruction_set / "reference-expectations.md",
|
|
3669
3696
|
clarification_response_path=(
|
|
@@ -4547,6 +4574,7 @@ def prepare_task_bundle(inp: PrepareInputs) -> PrepareOutputs:
|
|
|
4547
4574
|
inp.brief_path,
|
|
4548
4575
|
assets.brief_validator,
|
|
4549
4576
|
)
|
|
4577
|
+
_validate_group_context_preflight(project_root, inp.task_group)
|
|
4550
4578
|
selected_direction = _resolve_planning_direction(inp)
|
|
4551
4579
|
if inp.task_type == "implementation":
|
|
4552
4580
|
ctx_stage_map = _prepare_implementation_approved_plan(inp)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""timeline.json 의 run 항목을 그 run 의 현재 사실로 읽는 read-side 투영.
|
|
2
|
+
|
|
3
|
+
timeline 항목은 prepare 가 한 번 쓴다 — `render.render_timeline` 의 호출자는
|
|
4
|
+
`run._finalize_status_and_render_manifests` 뿐이다. run 이 끝날 때 상태를 쓰는
|
|
5
|
+
곳은 `validators/validate-run.py` 이고, 그 코드는 run-manifest(`status`,
|
|
6
|
+
`validation`, `workflowSnapshot`)와 task-manifest 만 고친다. 그래서 timeline
|
|
7
|
+
항목의 `status` 는 언제나 준비 시점 값(`prepared` / `in-progress`)이고
|
|
8
|
+
`workflowSnapshot` 은 준비 시점 스냅샷이다(2026-09-04 실측, dev-10626: 항목
|
|
9
|
+
6개 전부 `prepared`, 같은 run 의 run-manifest 4개는 `completed`). 같은 run 의
|
|
10
|
+
현재 사실은 그 run 의 run-manifest 가 가지므로, 읽는 쪽은 그것을 권위로 삼는다.
|
|
11
|
+
|
|
12
|
+
`reportRecordPath` 도 예약이다. 항목이 적는 값은 이번 run 의 기대 리포트 경로인데
|
|
13
|
+
리포트 seq 는 파일 존재로 배정되므로, 준비만 되고 돌지 않은 run 의 seq 를 다음
|
|
14
|
+
run 이 이어받는다(같은 실측: error-analysis run 001·002 가 같은
|
|
15
|
+
`final-report-error-analysis-001.data.json` 을 적었고 파일은 002 가 썼다).
|
|
16
|
+
validate-run 이 그 run 의 리포트를 검증했을 때(`validation.status` 가 `not-run`
|
|
17
|
+
이 아닐 때)만 그 경로가 그 run 의 리포트다.
|
|
18
|
+
|
|
19
|
+
task 단위 현재 사실(`currentStatus`, `latestRunStatus`, `workflow.*`,
|
|
20
|
+
`latestReportRecordPath`)은 task-manifest 가 권위다. 이 모듈은 run 단위만 다룬다.
|
|
21
|
+
"""
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from typing import Any, Mapping
|
|
26
|
+
|
|
27
|
+
from .json_boundary import JsonBoundaryError, load_owned_object
|
|
28
|
+
from .paths import resolve_under_root
|
|
29
|
+
|
|
30
|
+
VALIDATION_NOT_RUN = "not-run"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def current_run_facts(project_root: Path, run: Mapping[str, Any]) -> dict[str, Any]:
|
|
34
|
+
"""timeline 항목에 그 run 의 run-manifest 가 기록한 현재 사실을 덮어쓴 사본.
|
|
35
|
+
|
|
36
|
+
- `status`, `workflowSnapshot`: run-manifest 값. 키가 없으면 항목 값 그대로.
|
|
37
|
+
- `reportRecordPath` / `reportPath`: run-manifest 의 `validation.status` 가
|
|
38
|
+
`not-run` 이면 비운다 — 그 run 은 리포트를 낸 적이 없고 경로는 예약이다.
|
|
39
|
+
`validation` 블록이 없는 매니페스트는 판정 근거가 없으므로 그대로 둔다.
|
|
40
|
+
|
|
41
|
+
run-manifest 가 없으면(`runManifestPath` 가 비었거나 파일이 없으면) 항목을
|
|
42
|
+
그대로 돌려준다. 있는데 읽을 수 없으면 `JsonBoundaryError` 가 그대로 올라간다
|
|
43
|
+
— 투영이 잘못된 파일을 조용히 건너뛰면 그 run 만 준비 시점 값으로 남는다.
|
|
44
|
+
"""
|
|
45
|
+
entry = dict(run)
|
|
46
|
+
manifest = _run_manifest(project_root, run)
|
|
47
|
+
if manifest is None:
|
|
48
|
+
return entry
|
|
49
|
+
status = manifest.get("status")
|
|
50
|
+
if isinstance(status, str) and status:
|
|
51
|
+
entry["status"] = status
|
|
52
|
+
snapshot = manifest.get("workflowSnapshot")
|
|
53
|
+
if isinstance(snapshot, Mapping):
|
|
54
|
+
entry["workflowSnapshot"] = dict(snapshot)
|
|
55
|
+
validation = manifest.get("validation")
|
|
56
|
+
if isinstance(validation, Mapping) and validation.get("status") == VALIDATION_NOT_RUN:
|
|
57
|
+
entry["reportRecordPath"] = ""
|
|
58
|
+
entry["reportPath"] = ""
|
|
59
|
+
return entry
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _run_manifest(project_root: Path, run: Mapping[str, Any]) -> Mapping[str, Any] | None:
|
|
63
|
+
relative = run.get("runManifestPath")
|
|
64
|
+
if not isinstance(relative, str) or not relative:
|
|
65
|
+
return None
|
|
66
|
+
path = resolve_under_root(project_root, relative)
|
|
67
|
+
if path is None:
|
|
68
|
+
raise JsonBoundaryError(Path(relative), "run manifest", "outside this project")
|
|
69
|
+
if not path.is_file():
|
|
70
|
+
return None
|
|
71
|
+
return load_owned_object(path, artifact="run manifest")
|
|
@@ -70,6 +70,7 @@ from okstra_ctl.role_requirements import (
|
|
|
70
70
|
)
|
|
71
71
|
from okstra_ctl.ids import slugify_task_segment
|
|
72
72
|
from okstra_ctl.brief_frontmatter import read_brief_frontmatter
|
|
73
|
+
from okstra_ctl.group_context import is_group_context_file
|
|
73
74
|
from okstra_ctl.analysis_inputs import (
|
|
74
75
|
ANALYSIS_TASK_TYPES,
|
|
75
76
|
AnalysisInputError,
|
|
@@ -2525,7 +2526,7 @@ def _suggest_group_briefs(state: WizardState, limit: int = 6) -> list[str]:
|
|
|
2525
2526
|
used_at_by_relpath = _recently_used_brief_times(state)
|
|
2526
2527
|
candidates: list[tuple[float, str]] = []
|
|
2527
2528
|
for path in root.rglob("*.md"):
|
|
2528
|
-
if not path.is_file():
|
|
2529
|
+
if not path.is_file() or is_group_context_file(path):
|
|
2529
2530
|
continue
|
|
2530
2531
|
tg_suggestion, _ = _brief_suggestions(path)
|
|
2531
2532
|
if tg_suggestion:
|
|
@@ -993,10 +993,38 @@ briefs saved (N):
|
|
|
993
993
|
next: /okstra-run (run a separate task-key per brief — use the filename stem as task-id)
|
|
994
994
|
```
|
|
995
995
|
|
|
996
|
+
### 7a. Task-group context (once per task-group)
|
|
997
|
+
|
|
998
|
+
Before printing the hand-off block, check whether
|
|
999
|
+
`<PROJECT_ROOT>/.okstra/briefs/<task-group>/group-context.md` exists. That
|
|
1000
|
+
file is the one document every task in the group shares — why the group
|
|
1001
|
+
exists, how its result is measured (with the denominator named), group-wide
|
|
1002
|
+
constraints, ticket relations — and no single brief can recover it
|
|
1003
|
+
(observed: a 15-brief group whose reason, "the origin keeps going down under
|
|
1004
|
+
attack traffic", appeared in none of them, so option selection measured a
|
|
1005
|
+
per-page ratio instead of origin load). If the file is absent, ask once via
|
|
1006
|
+
`AskUserQuestion`:
|
|
1007
|
+
|
|
1008
|
+
- `Create the group context skeleton now (Recommended for a new task-group)`
|
|
1009
|
+
→ run `okstra group-context init --project-root <PROJECT_ROOT> --task-group <task-group>`
|
|
1010
|
+
and echo its output verbatim. The skeleton carries one `<...>` placeholder
|
|
1011
|
+
line per section; the user fills it. `/okstra-run` refuses to prepare any
|
|
1012
|
+
task in the group while a placeholder line remains.
|
|
1013
|
+
- `Skip — this group needs no shared context`.
|
|
1014
|
+
|
|
1015
|
+
Never fill the skeleton yourself from the tickets: a ticket summary decides
|
|
1016
|
+
nothing, and the sections ask for what the tickets do not say. If the file
|
|
1017
|
+
exists, leave it untouched and mention its path in the hand-off block.
|
|
1018
|
+
|
|
996
1019
|
Then stop. Do not invoke `okstra-run` directly — the user chooses when to
|
|
997
1020
|
proceed, and they may want to edit the brief externally first. In the
|
|
998
1021
|
multi-brief case the user also decides the order in which tasks are
|
|
999
|
-
started.
|
|
1022
|
+
started. When a skeleton was created in 7a, add one line to the hand-off
|
|
1023
|
+
block:
|
|
1024
|
+
|
|
1025
|
+
```
|
|
1026
|
+
group context skeleton: <abs>/<task-group>/group-context.md (fill before /okstra-run)
|
|
1027
|
+
```
|
|
1000
1028
|
|
|
1001
1029
|
## Output Rules
|
|
1002
1030
|
|
|
@@ -36,6 +36,7 @@ When a user selects a specific task:
|
|
|
36
36
|
|
|
37
37
|
1. Run `okstra model-io history-input --project-root <projectRoot> --task-ref <task-key>`.
|
|
38
38
|
2. Use each numbered run block for chronological status, report, run-manifest, and resume paths.
|
|
39
|
+
`Status` is the run's current status from its own run-manifest (the timeline entry itself only records the prepare-time value). `Report` is `-` for a run that never validated a report — a prepared run that was superseded before it ran — so two runs never share one report in this list.
|
|
39
40
|
|
|
40
41
|
```markdown
|
|
41
42
|
## Runs for <task-key>
|
|
@@ -22,7 +22,7 @@ Use the CLI output as the source of truth:
|
|
|
22
22
|
okstra model-io recap-input --project-root <projectRoot> --task-ref <resolved-target>
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
Read the fixed-text `Run count` and repeated `Transition` blocks. Narrate each block's `From phase → To phase`, `Status`, `Last completed phase`, `Next phase`, and `Report` in the emitted chronological order. If `Run count: 0`, answer only "This task has no recorded runs." and do not claim to have read any file.
|
|
25
|
+
Read the fixed-text `Run count` and repeated `Transition` blocks. Narrate each block's `From phase → To phase`, `Status`, `Last completed phase`, `Next phase`, and `Report` in the emitted chronological order. `Status`, `Last completed phase`, and `Next phase` are each run's end state from its own run-manifest, so a `prepared` transition is a run that was prepared and never ran, and it carries no `Report`. If `Run count: 0`, answer only "This task has no recorded runs." and do not claim to have read any file.
|
|
26
26
|
|
|
27
27
|
`Next phase` is already a fixed scalar projection. Narrate it when non-empty, and otherwise use `Next phase status`: `pending` means that run did not settle the route, `blocked` means it stopped on something outside the run, and `terminal` means the lifecycle ended there.
|
|
28
28
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: group-context
|
|
3
|
+
task-group: <task-group>
|
|
4
|
+
created: <YYYY-MM-DD>
|
|
5
|
+
generator: okstra-brief-gen
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Task-Group Context: <task-group>
|
|
9
|
+
|
|
10
|
+
> Shared by every task in this task-group. okstra copies it into each run's
|
|
11
|
+
> `instruction-set/task-group-context.md` and carries it in the analysis
|
|
12
|
+
> packet's `## Task-Group Context` section, ahead of the brief extract.
|
|
13
|
+
> Write only what no single ticket can recover — a summary of the tickets
|
|
14
|
+
> decides nothing. Preparation refuses this file while any `<...>`
|
|
15
|
+
> placeholder line remains; delete the file instead if the group needs none.
|
|
16
|
+
|
|
17
|
+
## Why This Group Exists
|
|
18
|
+
|
|
19
|
+
<The situation that created this group: what keeps happening, to whom, and why it takes a group of tickets rather than one. Not a summary of the tickets.>
|
|
20
|
+
|
|
21
|
+
## Definition of Better
|
|
22
|
+
|
|
23
|
+
<The measure the whole group is judged by, as a quantity and its direction. Name the denominator explicitly: a per-page ratio and a fleet-wide count are different measures, and a run that has only one of them will reason from it.>
|
|
24
|
+
|
|
25
|
+
## Group-Wide Constraints
|
|
26
|
+
|
|
27
|
+
<Rules every task in the group must respect, one bullet each, so no brief has to repeat them. Write `_(none)_` when there are none.>
|
|
28
|
+
|
|
29
|
+
## Ticket Relations
|
|
30
|
+
|
|
31
|
+
<Which tickets are causes, which are observation means, which depend on which. Write `_(none)_` when the briefs' Related Task Graph already says it all.>
|
|
@@ -42,6 +42,11 @@ Checks performed per brief file:
|
|
|
42
42
|
3-digit id and an `— verify: <how>` observation method, EB/EO are rejected
|
|
43
43
|
in the codebase-scan variant, and `## External Gates` — the destination for
|
|
44
44
|
an item with no observation method — is required in every variant.
|
|
45
|
+
15. A file whose frontmatter `type` is `group-context` is the task-group's
|
|
46
|
+
context document (`<briefs>/<task-group>/group-context.md`), not a brief:
|
|
47
|
+
it is checked by `okstra_ctl.group_context.validate_group_context` (four
|
|
48
|
+
required sections, no template placeholder left, directory slug matches
|
|
49
|
+
the frontmatter `task-group`). Any other `type` is a failure.
|
|
45
50
|
|
|
46
51
|
Exit code 0 on PASS, 1 on FAIL.
|
|
47
52
|
"""
|
|
@@ -66,6 +71,7 @@ from okstra_ctl.improvement_lenses import (
|
|
|
66
71
|
MAX_PRIORITY_LENSES,
|
|
67
72
|
MIN_PRIORITY_LENSES,
|
|
68
73
|
)
|
|
74
|
+
from okstra_ctl.group_context import GROUP_CONTEXT_TYPE, validate_group_context
|
|
69
75
|
from okstra_ctl.ids import slugify_task_segment
|
|
70
76
|
|
|
71
77
|
REQUIRED_FRONTMATTER_KEYS = {
|
|
@@ -677,6 +683,9 @@ def validate_brief(path: Path, briefs_root: Path) -> list[str]:
|
|
|
677
683
|
except ValueError as exc:
|
|
678
684
|
return [f"frontmatter: {exc}"]
|
|
679
685
|
|
|
686
|
+
if fm.get("type") == GROUP_CONTEXT_TYPE:
|
|
687
|
+
return validate_group_context(path, briefs_root)
|
|
688
|
+
|
|
680
689
|
missing = REQUIRED_FRONTMATTER_KEYS - fm.keys()
|
|
681
690
|
if missing:
|
|
682
691
|
errors.append(f"frontmatter missing keys: {sorted(missing)}")
|