okstra 0.151.1 → 0.153.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/okstra +7 -0
- package/docs/cli.md +5 -1
- package/docs/for-ai/skills/okstra-schedule-gen.md +152 -232
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/bin/okstra-antigravity-exec.sh +11 -6
- package/runtime/bin/okstra-wrapper-agy-stream.py +61 -0
- package/runtime/prompts/lead/convergence.md +3 -2
- package/runtime/prompts/lead/plan-body-verification.md +30 -1
- package/runtime/prompts/profiles/implementation-planning.md +6 -2
- package/runtime/python/okstra_ctl/container.py +9 -10
- package/runtime/python/okstra_ctl/convergence_engine.py +2 -1
- package/runtime/python/okstra_ctl/handoff.py +4 -8
- package/runtime/python/okstra_ctl/implementation_outcome.py +10 -56
- package/runtime/python/okstra_ctl/model_discovery.py +22 -1
- package/runtime/python/okstra_ctl/plan_run_root.py +15 -8
- package/runtime/python/okstra_ctl/run.py +8 -54
- package/runtime/python/okstra_ctl/schedule_semantics.py +1249 -0
- package/runtime/python/okstra_ctl/stage_map.py +288 -0
- package/runtime/python/okstra_ctl/wizard.py +24 -35
- package/runtime/python/okstra_project/state.py +19 -5
- package/runtime/skills/okstra-schedule-gen/SKILL.md +75 -35
- package/runtime/templates/reports/schedule.template.md +9 -9
- package/runtime/validators/validate-implementation-plan-stages.py +173 -70
- package/runtime/validators/validate-run.py +136 -0
- package/runtime/validators/validate-schedule.py +78 -10
- package/src/commands/inspect/stage-map.mjs +1 -1
package/README.md
CHANGED
|
@@ -184,7 +184,7 @@ Use these slash commands inside a Claude Code session:
|
|
|
184
184
|
| `/okstra-inspect` | Unified read side. Subcommands: `status` (phase/state and workStatus updates), `history` (past tasks, reruns, resumes), `report` (find/read final reports), `time` (elapsed-time breakdown), `logs` (wrapper log sidecar inventory and cleanup suggestions), `cost` (task bundle context/read cost), `errors` (aggregate run error logs into a report), `error-zip` (collect cross-project error logs into an anonymized zip and summarize clusters), and `recap` (run-to-run before/after summary plus free-form Q&A over a task's `.okstra` artifacts) |
|
|
185
185
|
| `/okstra-rollup` | Aggregate every task run in a task group or project, including per-task run counts, duration, errors, group totals, and a cross-task report digest |
|
|
186
186
|
| `/okstra-usage` | Show the current project's recent run coverage, raw and billable-equivalent tokens, known USD cost, CPU time, and wall-clock time grouped by task type (default: last 30 days) |
|
|
187
|
-
| `/okstra-schedule-gen` |
|
|
187
|
+
| `/okstra-schedule-gen` | Invoke as `/okstra-schedule-gen [task-group]` to generate a work schedule for an entire task group. Each non-done task is resolved through the source-aware `stage-map` response; your unfinished-stage choices are captured in a temporary selection contract, and only the same draft that passes deterministic selection validation followed by independent narrative verification is published |
|
|
188
188
|
| `/okstra-container-build` | Deploy a verified task's code as a local Docker Compose group and monitor per-container logs (subcommands: `up` / `status` / `logs` / `stop-watcher` / `down`) |
|
|
189
189
|
| `/okstra-manager` | Coordinate cross-project okstra tasks through manager-owned plans, assignments, one-way project sync snapshots, status, and child launch context packets |
|
|
190
190
|
| `/okstra-pr-gen` | Register PR body templates under `~/.okstra/template/pr/` and generate a PR description from a branch diff (subcommands: `template` / `branches` / `gen`). Global skill—needs a Git repo, not a registered okstra project |
|
package/bin/okstra
CHANGED
|
@@ -18,6 +18,13 @@ async function main(argv) {
|
|
|
18
18
|
const [cmd, ...rest] = args;
|
|
19
19
|
const loader = COMMANDS.get(cmd);
|
|
20
20
|
if (!loader) {
|
|
21
|
+
if (cmd === "schedule") {
|
|
22
|
+
process.stderr.write(
|
|
23
|
+
"unknown command: schedule\n" +
|
|
24
|
+
"Schedule generation runs in an agent host: /okstra-schedule-gen [task-group]\n",
|
|
25
|
+
);
|
|
26
|
+
return 2;
|
|
27
|
+
}
|
|
21
28
|
process.stderr.write(
|
|
22
29
|
`unknown command: ${cmd}\n` +
|
|
23
30
|
"hint: this okstra binary may predate the skill calling it — update it " +
|
package/docs/cli.md
CHANGED
|
@@ -324,6 +324,10 @@ Example:
|
|
|
324
324
|
scripts/okstra.sh --task-type error-analysis --project-id jobs --project-root /Volumes/Workspaces/workspace/projects/jobs ...
|
|
325
325
|
```
|
|
326
326
|
|
|
327
|
+
### Schedule generation skill
|
|
328
|
+
|
|
329
|
+
The public schedule entry point is the host skill `/okstra-schedule-gen [task-group]`; `stage-map` and `validate-schedule.py` are its backend contracts, not an additional schedule-generation shell command. For each candidate task, the skill branches on the `stage-map` `state` and `sourcePlanPath`, records the selected, completed, and full stage sets in a temporary `.selection.json`, and runs deterministic `--selection-json` validation before an independent narrative verifier. Only the same draft that passes both gates is promoted, and the temporary selection contract is removed after final validation.
|
|
330
|
+
|
|
327
331
|
### `--directive`
|
|
328
332
|
|
|
329
333
|
A free-text channel for passing user intent to the lead, workers, and downstream skills. The value is embedded in a `## Directive` section at the end of `instruction-set/analysis-material.md` and in `instruction-set/analysis-packet.md`, the analysis workers' primary input. It is also backed up to `instruction-set/directive.txt`.
|
|
@@ -737,7 +741,7 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
|
|
|
737
741
|
| `okstra migrate [--apply] [--cwd <dir>] [--quiet]` | One-time migration of the project artifact root from `.project-docs/okstra/` to `.okstra/`. It is a dry run by default; `--apply` performs the move with `git mv` in a Git worktree, removes an empty `.project-docs/`, and synchronizes the `<PROJECT>/CLAUDE.md` import line, `.gitignore`, the project's rows in `~/.okstra/{recent,active}.jsonl`, and `~/.okstra/worktrees/registry.json`. It exits 1 if `.okstra/` already exists or the legacy directory is absent. Scheduled for removal by the end of v0.x |
|
|
738
742
|
| `okstra task-list [--project-root <path>]` | Combine `list_project_tasks` and `read_latest_task` into JSON containing the task catalog and latest task |
|
|
739
743
|
| `okstra task-show <task-key> [--project-root <path>]` | Summarize workflow, phase, status, and artifacts from the Task Read-Side Snapshot |
|
|
740
|
-
| `okstra stage-map <task-key> [--cwd <dir>\|--project <dir>]` | Dump the task's implementation-planning Stage Map as JSON: `{ ok, taskKey, taskRoot, stages:[{stage_number,title,depends_on,step_count}], doneStages:[int] }`. `
|
|
744
|
+
| `okstra stage-map <task-key> [--cwd <dir>\|--project <dir>]` | Dump the task's implementation-planning Stage Map as JSON: `{ ok, taskKey, taskRoot, state, sourcePlanPath, stages:[{stage_number,title,depends_on,step_count}], doneStages:[int] }`. `state` is `ready` for one resolved source and `missing` when no Stage Map exists; corrupt or conflicting sources return structured non-zero errors instead of silently selecting another report. `doneStages` is read from the implementation-planning stage consumer state (with carry recovery). This is the read-side source `/okstra-schedule-gen [task-group]` uses to derive selectable unfinished stages and their completed dependency closure |
|
|
741
745
|
| `okstra incremental-scope <args…>` | Decide re-verify vs carry-forward scope for an `implementation-planning` clarification re-run. Thin shim into `scripts/okstra_ctl/incremental_scope.py` (deterministic pure function): it reads the dependency graph from the prior run `data.json`'s `implementationPlanning.stageMap` and returns `mode:"incremental"` only when the base-ref SHA is unchanged and the affected stages' `downstream_stage_closure` covers at most half of all stages; otherwise it signals a full re-run. Used to bound the cost of a clarification re-run |
|
|
742
746
|
| `okstra incremental-carry <args…>` | Merge carried-forward plan-item verdicts into an incremental re-run. Thin shim into `scripts/okstra_ctl/incremental_carry.py`: it takes the prior run's plan-item verdicts that the current run does not re-verify and merges them into the current `data.json` tagged with `carriedForwardFromSeq`. A `schemaVersion` drift raises `CarryError` and exits non-zero to force a full fallback. Runs after `incremental-scope` returns `mode:"incremental"` |
|
|
743
747
|
| `okstra code-review target --task-key <k> --stage <N> [--project-root <dir>] [--cwd <dir>] [--json]` / `okstra code-review target --branch <name> [--base <ref>] [--date <YYYY-MM-DD>] [--project-root <dir>] [--cwd <dir>] [--json]` | Resolve what a code review reads and where its result file goes. Output is always JSON, so `--json` only makes that explicit. `--project-root` and `--cwd` are shared pre-dispatch arguments and apply to both modes; `--cwd` is only consulted when `--project-root` is absent. Both modes return `{ ok, projectRoot, mode, worktreePath, branch, baseCommit, headCommit, reviewPath, round }`; stage mode additionally returns `taskKey`, `taskRoot`, and `stage`. Stage mode takes the diff base from the `base_ref` recorded on that stage's worktree-registry row when it was provisioned — not from a rule re-applied at review time — and names the result `.okstra/tasks/<task-group>/<task-id>/code-reviews/stage-<NN>.md`, where a re-review of the same stage becomes `-r2`, `-r3`, … (the `round` field). Only a legacy row provisioned before `base_ref` was recorded falls back to re-deriving the base through `stage_targets`, and a failure there is reported as `stage_base_unresolved`. `worktreePath` comes back empty whenever the stage worktree is not usable as a live checkout — the registry row is no longer `active` (whole-task final-verification released it), the row never carried a path, or the recorded directory is gone — and the review then reads the `branch` ref instead. Branch mode uses `--base` when given, otherwise the merge-base with the default branch (`refs/remotes/origin/HEAD`, else `main`/`master`), and names the result `.project-docs/code-reviews/<branch>/<YYYY-MM-DD>-<NN>.md`, where `<NN>` (the `round` field) is the next sequence number for that date — the highest already on disk plus one. Read-only: it resolves paths and creates no directory and no file, so the review directory does not exist until the caller writes the report. Backend for the okstra-code-review skill |
|
|
@@ -3,318 +3,238 @@
|
|
|
3
3
|
## Source
|
|
4
4
|
|
|
5
5
|
- Skill source: [`skills/okstra-schedule-gen/SKILL.md`](../../../skills/okstra-schedule-gen/SKILL.md)
|
|
6
|
-
-
|
|
7
|
-
-
|
|
6
|
+
- Schedule template: [`templates/reports/schedule.template.md`](../../../templates/reports/schedule.template.md)
|
|
7
|
+
- Schedule validator: [`validators/validate-schedule.py`](../../../validators/validate-schedule.py)
|
|
8
|
+
- Stage Map read side: [`scripts/okstra_project/state.py`](../../../scripts/okstra_project/state.py)
|
|
9
|
+
- Selection semantics: [`scripts/okstra_ctl/schedule_semantics.py`](../../../scripts/okstra_ctl/schedule_semantics.py)
|
|
10
|
+
- Work-category source of truth: [`scripts/okstra_ctl/work_categories.py`](../../../scripts/okstra_ctl/work_categories.py)
|
|
8
11
|
- workStatus inference reference: [`skills/okstra-inspect/SKILL.md`](../../../skills/okstra-inspect/SKILL.md)
|
|
9
12
|
|
|
10
|
-
## Purpose
|
|
13
|
+
## Purpose and invocation
|
|
11
14
|
|
|
12
|
-
`okstra-schedule-gen` gathers
|
|
15
|
+
`okstra-schedule-gen` gathers non-done tasks in a task group and produces one client-facing work schedule from user-selected unfinished implementation stages.
|
|
13
16
|
|
|
14
|
-
|
|
17
|
+
Public invocation:
|
|
15
18
|
|
|
16
19
|
```text
|
|
17
|
-
|
|
20
|
+
/okstra-schedule-gen [task-group]
|
|
18
21
|
```
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
This is a host skill, not a schedule-generation shell command. Use `stage-map` and `validate-schedule.py` only as backend contracts inside the skill.
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
- The user requests a "schedule", "work plan", or work-schedule table for an entire task-group.
|
|
25
|
-
- `.okstra/discovery/task-catalog.json` contains that task-group and it has at least one task that is not `done`.
|
|
25
|
+
Output location:
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
```text
|
|
28
|
+
<PROJECT_ROOT>/.okstra/tasks/<task-group-segment>/schedule/<task-group-segment>-plan-<YYYY-MM-DD_HH-MM-SS>.md
|
|
29
|
+
```
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
- Actual phase execution: `okstra-run`
|
|
31
|
-
- An already-completed task-group: do not create a file; state that all tasks are done.
|
|
31
|
+
Do not use it for single-task status analysis or phase execution. Use `okstra-inspect status` and `okstra-run` for those jobs.
|
|
32
32
|
|
|
33
|
-
## Preflight
|
|
33
|
+
## Preflight and task-group resolution
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
Run one literal-token preflight call:
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
38
|
okstra preflight --runtime claude-code --json
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
## Resolving the task-group
|
|
41
|
+
On `ok: false`, point the user to `/okstra-setup` and stop. Otherwise:
|
|
44
42
|
|
|
45
43
|
1. Read `.okstra/discovery/task-catalog.json`.
|
|
46
|
-
2.
|
|
47
|
-
3.
|
|
48
|
-
4.
|
|
49
|
-
5. Read each matched
|
|
44
|
+
2. Resolve an explicit task-group from the invocation or host request. If none is unambiguous, ask the user to choose; never guess.
|
|
45
|
+
3. Lowercase the token and strip characters outside `[a-z0-9]`.
|
|
46
|
+
4. Apply the same transform to each catalog `taskGroupPathSegment` and compare only those normalized values.
|
|
47
|
+
5. Read each matched `task-manifest.json`; it is authoritative when the catalog is stale.
|
|
50
48
|
|
|
51
|
-
On zero matches,
|
|
49
|
+
On zero matches, report that the task group was not found and do not create a file.
|
|
52
50
|
|
|
53
|
-
##
|
|
51
|
+
## Candidate filter
|
|
54
52
|
|
|
55
|
-
|
|
53
|
+
`workStatus` is used only to decide which tasks are candidates. When it is missing or empty, use the `okstra-inspect` `status.4` inference table.
|
|
56
54
|
|
|
57
|
-
Exclude
|
|
55
|
+
- Exclude resolved `done` tasks.
|
|
56
|
+
- Include every other resolved state.
|
|
57
|
+
- If no task remains, report that all tasks are done and do not create a file.
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
- inferred `done`
|
|
59
|
+
Do not render `workStatus` as the detailed task status. The per-task `Status` value is `<taskType> / <currentPhase>`.
|
|
61
60
|
|
|
62
|
-
|
|
61
|
+
## Source-aware Stage Map resolution
|
|
63
62
|
|
|
64
|
-
|
|
65
|
-
- `in-progress`
|
|
66
|
-
- `blocked`
|
|
67
|
-
- `phase-done`
|
|
68
|
-
- other non-done inferred/display states
|
|
63
|
+
For every candidate task, call:
|
|
69
64
|
|
|
70
|
-
|
|
65
|
+
```bash
|
|
66
|
+
okstra stage-map <task-key> --json
|
|
67
|
+
```
|
|
71
68
|
|
|
72
|
-
|
|
69
|
+
The successful response has this boundary shape:
|
|
70
|
+
|
|
71
|
+
```text
|
|
72
|
+
{ ok, taskKey, taskRoot, state, sourcePlanPath,
|
|
73
|
+
stages:[{stage_number,title,depends_on,step_count}], doneStages:[int] }
|
|
74
|
+
```
|
|
73
75
|
|
|
74
|
-
|
|
76
|
+
Handle each result explicitly:
|
|
75
77
|
|
|
76
|
-
- `
|
|
77
|
-
- `
|
|
78
|
-
- `
|
|
79
|
-
- `workflow.currentPhaseState`
|
|
80
|
-
- `taskType`
|
|
81
|
-
- `workStatus`
|
|
82
|
-
- `latestReportPath`
|
|
78
|
+
- `state: ready`: use exactly `sourcePlanPath`; do not pick a report by mtime or `latestReportPath`. Select only `stages − doneStages`.
|
|
79
|
+
- `state: missing`: record an empty source and empty stage sets, mark the task `[NEEDS-PLANNING]`, and emit no forward Work Breakdown, Gantt, or day total for it.
|
|
80
|
+
- `ok: false` or another state: stop before drafting and report the structured `stage` and `reason`. A corrupt or conflicting source must never fall back to a guessed report.
|
|
83
81
|
|
|
84
|
-
|
|
82
|
+
A valid selected set is dependency-closed: every transitive prerequisite of a selected stage is either also selected or present in `doneStages`. Completed prerequisites remain evidence only and are never scheduled forward.
|
|
85
83
|
|
|
86
|
-
|
|
87
|
-
- Solution / Architecture
|
|
88
|
-
- Work Breakdown
|
|
89
|
-
- Verification Commands
|
|
90
|
-
- Rollback strategy
|
|
91
|
-
- Effort, Risk, Priority, Scope, Repos
|
|
84
|
+
If a ready task has no unfinished stages, render `_Complete — no remaining stage_` and omit forward effort.
|
|
92
85
|
|
|
93
|
-
|
|
86
|
+
## Stage selection
|
|
94
87
|
|
|
95
|
-
|
|
96
|
-
2. If none, also look at `runs/*/reports/final-report-*.md`.
|
|
97
|
-
3. If found, parse it and put a fallback note in the schedule task block.
|
|
98
|
-
4. If still nothing, mark it `[NEEDS-OKSTRA-RUN]` and use only the manifest metadata.
|
|
88
|
+
Offer up to three dependency-closed cumulative bundles in topological order, plus all remaining stages. A custom set is accepted only after closing it over unfinished prerequisites; completed prerequisites are preserved separately.
|
|
99
89
|
|
|
100
|
-
|
|
90
|
+
Skip the picker when the remaining work has only one possible bundle and use all unfinished stages. Record the final stage numbers as `selectedStages`.
|
|
101
91
|
|
|
102
|
-
##
|
|
92
|
+
## Temporary selection contract
|
|
103
93
|
|
|
104
|
-
|
|
94
|
+
Write a paired draft and selection input with one timestamp:
|
|
105
95
|
|
|
106
|
-
|
|
96
|
+
```text
|
|
97
|
+
.okstra/tasks/<task-group-segment>/schedule/.draft/<timestamp>.md
|
|
98
|
+
.okstra/tasks/<task-group-segment>/schedule/.draft/<timestamp>.selection.json
|
|
99
|
+
```
|
|
107
100
|
|
|
108
|
-
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
101
|
+
The selection file is a temporary verification input. It freezes the exact source, full stage map, completed stages, and user-selected forward work so both validators judge the same facts instead of re-resolving mutable task state.
|
|
102
|
+
|
|
103
|
+
Schema version 1:
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"schemaVersion": 1,
|
|
108
|
+
"tasks": [
|
|
109
|
+
{
|
|
110
|
+
"taskKey": "demo:group:DEV-1",
|
|
111
|
+
"taskId": "DEV-1",
|
|
112
|
+
"state": "ready",
|
|
113
|
+
"sourcePlanPath": "/absolute/path/final-report-implementation-planning-001.md",
|
|
114
|
+
"selectedStages": [2, 3],
|
|
115
|
+
"doneStages": [1],
|
|
116
|
+
"stages": [
|
|
117
|
+
{
|
|
118
|
+
"stageNumber": 1,
|
|
119
|
+
"title": "Prepare port",
|
|
120
|
+
"dependsOn": [],
|
|
121
|
+
"stepCount": 2
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"stageNumber": 2,
|
|
125
|
+
"title": "Build adapter",
|
|
126
|
+
"dependsOn": [1],
|
|
127
|
+
"stepCount": 3
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"stageNumber": 3,
|
|
131
|
+
"title": "Wire consumer",
|
|
132
|
+
"dependsOn": [2],
|
|
133
|
+
"stepCount": 2
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
]
|
|
138
|
+
}
|
|
139
|
+
```
|
|
116
140
|
|
|
117
|
-
|
|
141
|
+
Include every candidate task. A `missing` task has an empty `sourcePlanPath`, `selectedStages`, `doneStages`, and `stages`. Convert the CLI stage-row keys to the camel-case selection boundary exactly as shown.
|
|
118
142
|
|
|
119
|
-
##
|
|
143
|
+
## Phase classification
|
|
120
144
|
|
|
121
|
-
|
|
145
|
+
Only these canonical categories are valid:
|
|
122
146
|
|
|
123
|
-
| workCategory | phase |
|
|
147
|
+
| workCategory | Default phase |
|
|
124
148
|
|---|---|
|
|
125
|
-
| `bugfix` | Phase 1
|
|
149
|
+
| `bugfix` | Phase 1 for High or Med-High risk; otherwise Phase 2 |
|
|
126
150
|
| `feature` | Phase 2 |
|
|
127
151
|
| `improvement` | Phase 2 |
|
|
128
152
|
| `refactor` | Phase 3 |
|
|
129
153
|
| `ops` | Phase 3 |
|
|
130
|
-
| `docs` / `doc` | Phase 2 |
|
|
131
|
-
| `unknown` or undefined | Phase 2, add a rationale note |
|
|
132
154
|
|
|
133
|
-
|
|
155
|
+
Priority overrides category: P0 maps to Phase 1, P1/P2 to Phase 2, and P3 to Phase 3. An unknown or missing raw category falls back to Phase 2 with a one-line rationale naming the raw value. Do not invent another category.
|
|
134
156
|
|
|
135
|
-
|
|
136
|
-
- `P1`, `P2`: Phase 2
|
|
137
|
-
- `P3`: Phase 3
|
|
157
|
+
## Template contract
|
|
138
158
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
## section contract
|
|
142
|
-
|
|
143
|
-
Follow the template's heading order and spelling. `validate-schedule.py` checks section order, title suffix, metadata, field labels, enum, Gantt axis, and more.
|
|
144
|
-
|
|
145
|
-
top-level contract sections:
|
|
159
|
+
Follow `schedule.template.md` exactly. The required top-level order is:
|
|
146
160
|
|
|
147
161
|
1. `## At a Glance`
|
|
148
|
-
2. `## Executive Summary`
|
|
162
|
+
2. `## Executive Summary`
|
|
149
163
|
3. `## Task Dependency Graph`
|
|
150
|
-
4. `##
|
|
151
|
-
5. `## Phase
|
|
152
|
-
6. `## Phase
|
|
153
|
-
7. `##
|
|
154
|
-
8. `##
|
|
155
|
-
9. `##
|
|
156
|
-
10. `##
|
|
157
|
-
|
|
158
|
-
optional
|
|
159
|
-
|
|
160
|
-
- `## Gantt Chart`: between `Task Dependency Graph` and `Phase 1`.
|
|
161
|
-
- `## Glossary`: last section. Use only when opaque codes remain in the body.
|
|
162
|
-
|
|
163
|
-
Keep the heading even when a phase has no task, and write `_none_`.
|
|
164
|
-
|
|
165
|
-
## top header
|
|
166
|
-
|
|
167
|
-
Shape:
|
|
168
|
-
|
|
169
|
-
```markdown
|
|
170
|
-
# <Title> — Work Schedule
|
|
171
|
-
|
|
172
|
-
> Generated: <YYYY-MM-DD HH:MM> | Project: <project-id> | Task Group: <task-group>
|
|
173
|
-
> Source: okstra <mode> (<N> tasks included, <M> done excluded)
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
The validator checks the title suffix `— Work Schedule`. For `<project-id>`, prefer `task-catalog.json`'s top-level `projectId`, and if absent use the first matched manifest's `projectId`. Do not invent a value.
|
|
177
|
-
|
|
178
|
-
## At a Glance
|
|
179
|
-
|
|
180
|
-
This totals line must be present exactly.
|
|
181
|
-
|
|
182
|
-
```markdown
|
|
183
|
-
**<N> tasks total / estimated effort: <X.X> ~ <Y.Y> days (Effort sum)**
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
The Effort-to-day mapping's SSOT is the template's `### Effort Sizing Criteria` table. Build the total day range by summing the lower/upper bounds.
|
|
187
|
-
|
|
188
|
-
enum values:
|
|
189
|
-
|
|
190
|
-
| Field | value |
|
|
191
|
-
|---|---|
|
|
192
|
-
| Effort | `S`, `M`, `L`, `XL`, `XXL` |
|
|
193
|
-
| Priority | `P0`, `P1`, `P2`, `P3` |
|
|
194
|
-
| Risk | `Very Low`, `Low`, `Medium`, `Med-High`, `High` |
|
|
195
|
-
| Phase | `1`, `2`, `3` |
|
|
196
|
-
|
|
197
|
-
`Med-High` is canonical.
|
|
198
|
-
|
|
199
|
-
## per-task block
|
|
164
|
+
4. optional `## Gantt Chart`
|
|
165
|
+
5. `## Phase 1: Critical Fixes`
|
|
166
|
+
6. `## Phase 2: Enhancements`
|
|
167
|
+
7. `## Phase 3: Architecture`
|
|
168
|
+
8. `## Execution Priority Matrix`
|
|
169
|
+
9. `## Cross-Task Dependencies & Shared Concerns`
|
|
170
|
+
10. `## Risk Mitigation Strategy`
|
|
171
|
+
11. `## Recommended Immediate Actions`
|
|
172
|
+
12. optional final `## Glossary`
|
|
200
173
|
|
|
201
|
-
|
|
174
|
+
Keep an empty required section and render `_none_`. Headings and field labels stay as English template literals; body prose is Korean.
|
|
202
175
|
|
|
203
|
-
|
|
204
|
-
2. `**Priority**`
|
|
205
|
-
3. `**Effort**`
|
|
206
|
-
4. `**Status**`
|
|
207
|
-
5. `**Risk**`
|
|
208
|
-
6. `**Scope**`
|
|
209
|
-
7. `**Repo**`
|
|
210
|
-
|
|
211
|
-
Then the subsection order:
|
|
212
|
-
|
|
213
|
-
1. `**Problem**:`
|
|
214
|
-
2. `**Solution**:`
|
|
215
|
-
3. `**Work Breakdown**:` — followed by a `| Step | File | Action | Detail |` table
|
|
216
|
-
4. `**Verification Commands**:` — followed by a ` ```bash ` fenced block
|
|
217
|
-
5. `**Rollback**:`
|
|
218
|
-
|
|
219
|
-
For a `[NEEDS-OKSTRA-RUN]` or `[PARSE-ERROR: <section>]` task, fill only the available fields but place the marker right below the task heading.
|
|
220
|
-
|
|
221
|
-
## Task Dependency Graph
|
|
222
|
-
|
|
223
|
-
When there is no dependency, literal:
|
|
176
|
+
Each scheduled task uses this stage-level Work Breakdown shape:
|
|
224
177
|
|
|
225
178
|
```markdown
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
````
|
|
179
|
+
| Stage | Title | Steps | Depends On | Days |
|
|
180
|
+
|---:|---|---:|---|---:|
|
|
181
|
+
| 2 | Build adapter | 3 | 1 (done) | 2.0 ~ 3.0 |
|
|
182
|
+
| 3 | Wire consumer | 2 | 2 | 1.0 ~ 2.0 |
|
|
232
183
|
```
|
|
233
|
-
DEV-1 -> DEV-2, DEV-3
|
|
234
|
-
DEV-2 -> DEV-4
|
|
235
|
-
```
|
|
236
|
-
````
|
|
237
|
-
|
|
238
|
-
Use only the ASCII arrow `->`.
|
|
239
|
-
|
|
240
|
-
## Gantt Chart
|
|
241
|
-
|
|
242
|
-
**directive override (highest priority):** before applying the heuristic below, first check the directive source's `## Directive` section. Resolution order (first hit): (1) the `--directive-file <abs-path>` argument, (2) `<PROJECT_ROOT>/.okstra/tasks/<task-group-segment>/schedule/instruction-set/analysis-material.md`, (3) if none, the heuristic as-is (normal path — no warning·stop). When the directive instructs Gantt render/skip, it overrides the heuristic·skip rules, and leave one line in that section: `> _Per Directive directive: <verbatim short excerpt>._`. When the directive supplies day allocation·phase weight·sub-task decomposition, reflect it verbatim in bar length.
|
|
243
184
|
|
|
244
|
-
|
|
185
|
+
Use the template's Effort Sizing Criteria values without redefining them. Allocate a task's range across selected stages in `stepCount` proportion: round every stage except the last to 0.5 day and let the last absorb the remainder. The stage ranges must sum to the task range, and finite task ranges must sum to the displayed total. XXL, missing, and complete tasks contribute no forward total.
|
|
245
186
|
|
|
246
|
-
|
|
187
|
+
An unrepresentable half-day allocation is a validation error. Do not substitute a fallback allocation algorithm; revise the task sizing or selected-stage scope.
|
|
247
188
|
|
|
248
|
-
|
|
249
|
-
- Even 1 task has an effort range.
|
|
250
|
-
- The source report has Part/Phase/Step decomposition.
|
|
251
|
-
- Total effort is 3 days or more.
|
|
252
|
-
|
|
253
|
-
Skip only when every task is XXL with no decomposition, or when all tasks lack both effort and decomposition. On skip, place the following blockquote at the `Gantt Chart` position.
|
|
254
|
-
|
|
255
|
-
```markdown
|
|
256
|
-
> _Gantt Chart skipped: <concrete reason referencing the actual data>._
|
|
257
|
-
```
|
|
189
|
+
## Gantt contract
|
|
258
190
|
|
|
259
|
-
|
|
191
|
+
Render a plain fenced relative-day Gantt when the selected stages have finite day ranges. Every forward row is identified by stage and repeats its Work Breakdown range:
|
|
260
192
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
| | | | |
|
|
265
|
-
Phase 1
|
|
266
|
-
DEV-1 (M) ██████ ! crit
|
|
267
|
-
Phase 2
|
|
268
|
-
DEV-2 (L) ██████░░ est
|
|
193
|
+
```text
|
|
194
|
+
DEV-1/S2 ████ days=2.0~3.0
|
|
195
|
+
DEV-1/S3 ████ days=1.0~2.0
|
|
269
196
|
```
|
|
270
|
-
````
|
|
271
197
|
|
|
272
|
-
The
|
|
198
|
+
The identifier format is `<TASK-ID>/S<stage-number>` and the annotation is `days=<lower>~<upper>`. Do not emit a row for a completed, unselected, missing, or unknown stage. Bar length is illustrative; `days=` is the validated duration contract.
|
|
273
199
|
|
|
274
|
-
|
|
200
|
+
Skip the chart only when no forward task has a finite day signal, and state the concrete reason. Do not use calendar dates, Mermaid, PlantUML, Graphviz, or another graph language.
|
|
275
201
|
|
|
276
|
-
|
|
202
|
+
A host-supplied directive or the first `## Directive` in the configured analysis material may override the render/skip heuristic, but it cannot override stage selection, dependency closure, or validated day arithmetic.
|
|
277
203
|
|
|
278
|
-
|
|
204
|
+
## Client-facing boundary
|
|
279
205
|
|
|
280
|
-
|
|
206
|
+
Assume the team has the required authority. Exclude approval waits, permission checks, stakeholder coordination, decision checklists, and internal blocker codes from forward engineering work. Gantt duration and totals represent engineering work only.
|
|
281
207
|
|
|
282
|
-
|
|
208
|
+
Resolve opaque source-report codes inline or in the optional final Glossary. Decision-item codes do not belong in the schedule.
|
|
283
209
|
|
|
284
|
-
## validation
|
|
210
|
+
## Two validation gates
|
|
285
211
|
|
|
286
|
-
|
|
212
|
+
Run both gates against the same draft and temporary selection contract.
|
|
287
213
|
|
|
288
|
-
|
|
289
|
-
python3 ~/.okstra/lib/validators/validate-schedule.py <output-path>
|
|
290
|
-
```
|
|
214
|
+
1. Deterministic gate:
|
|
291
215
|
|
|
292
|
-
|
|
216
|
+
```bash
|
|
217
|
+
python3 ~/.okstra/lib/validators/validate-schedule.py <draft> --selection-json <selection>
|
|
218
|
+
```
|
|
293
219
|
|
|
294
|
-
|
|
295
|
-
python3 validators/validate-schedule.py <output-path>
|
|
296
|
-
```
|
|
220
|
+
2. Only after that command passes, dispatch an independent LLM verifier with the draft and selection JSON, but not the lead's reasoning. It checks narrative coherence, phase rationale, executable order, engineering-only scope, and contradictions with the structured rows.
|
|
297
221
|
|
|
298
|
-
|
|
222
|
+
If either gate finds a defect, revise the same draft in place and restart from the deterministic gate. Allow at most two revision rounds across both gates. Never publish a draft that has not passed both gates in that order.
|
|
299
223
|
|
|
300
|
-
|
|
224
|
+
After both gates pass:
|
|
301
225
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
- Estimated effort: X.X ~ Y.Y days (Effort sum)
|
|
307
|
-
- Mode: lightweight
|
|
308
|
-
```
|
|
226
|
+
1. Move the same draft content to the collision-safe final path; do not re-render it.
|
|
227
|
+
2. Re-read it and run the installed format validator on the final path, falling back to the repository validator only when needed.
|
|
228
|
+
3. Delete the temporary selection file only after final validation passes.
|
|
229
|
+
4. Report completion in Korean with the output path, included/excluded counts, finite total range, and lead-plus-verifier mode.
|
|
309
230
|
|
|
310
231
|
## Forbidden patterns
|
|
311
232
|
|
|
312
|
-
-
|
|
313
|
-
-
|
|
314
|
-
-
|
|
315
|
-
-
|
|
316
|
-
-
|
|
317
|
-
-
|
|
318
|
-
-
|
|
319
|
-
-
|
|
320
|
-
- Overwriting an existing file on a timestamp collision. Append a `-2`, `-3` suffix.
|
|
233
|
+
- Guessing a planning report after `stage-map` reports a structured error.
|
|
234
|
+
- Treating `workStatus` as the detailed schedule status.
|
|
235
|
+
- Scheduling completed or non-selected stages.
|
|
236
|
+
- Publishing a task-level Gantt row without the `/S<stage-number>` suffix and `days=` range.
|
|
237
|
+
- Dispatching narrative validation before deterministic `--selection-json` validation.
|
|
238
|
+
- Re-rendering after validation instead of promoting the same draft.
|
|
239
|
+
- Deleting the selection contract before final validation.
|
|
240
|
+
- Publishing after more than two unsuccessful revision rounds.
|
package/package.json
CHANGED
package/runtime/BUILD.json
CHANGED
|
@@ -245,11 +245,15 @@ fi
|
|
|
245
245
|
# non-interactive dispatch from blocking on tool-permission prompts (the worker
|
|
246
246
|
# is sandboxed to the supplied `--add-dir` workspace).
|
|
247
247
|
#
|
|
248
|
-
# stdout:
|
|
249
|
-
#
|
|
250
|
-
#
|
|
251
|
-
#
|
|
252
|
-
#
|
|
248
|
+
# stdout: agy runs in `stream-json` so the live log records the tool calls it
|
|
249
|
+
# made — in the default `text` format agy prints only its closing
|
|
250
|
+
# summary, leaving ~2KB of self-report where codex leaves ~487KB of
|
|
251
|
+
# trace, and no way to check from outside whether the worker opened the
|
|
252
|
+
# evidence it was asked to verify. `okstra-wrapper-agy-stream.py`
|
|
253
|
+
# appends every event to the log and forwards ONLY the final response
|
|
254
|
+
# text to the wrapper's own stdout, so what the subagent's `BashOutput`
|
|
255
|
+
# captures for Phase 5 synthesis is unchanged by the format switch.
|
|
256
|
+
# agy stays a single addressable PID we can SIGTERM from the watchdog.
|
|
253
257
|
# stderr: appended to the live log only — keeps the wrapper's stderr clean.
|
|
254
258
|
# exit: agy's own exit code is preserved by `wait`.
|
|
255
259
|
# stdout mirror via a named FIFO instead of a `> >(tee …)` process substitution:
|
|
@@ -261,7 +265,7 @@ fi
|
|
|
261
265
|
stdout_fifo="${log_path}.stdout.fifo"
|
|
262
266
|
rm -f "$stdout_fifo"
|
|
263
267
|
mkfifo "$stdout_fifo"
|
|
264
|
-
|
|
268
|
+
python3 "$script_dir/okstra-wrapper-agy-stream.py" "$log_path" < "$stdout_fifo" &
|
|
265
269
|
stdout_tee_pid=$!
|
|
266
270
|
|
|
267
271
|
# Disable git's fsmonitor for every git command agy runs in this process tree —
|
|
@@ -275,6 +279,7 @@ export "GIT_CONFIG_VALUE_${_gc_idx}=false"
|
|
|
275
279
|
export GIT_CONFIG_COUNT="$(( _gc_idx + 1 ))"
|
|
276
280
|
|
|
277
281
|
agy --print "$(cat "$prompt_path")" --model "$model" "${add_dir_args[@]}" \
|
|
282
|
+
--output-format stream-json \
|
|
278
283
|
--print-timeout "$PRINT_TIMEOUT" --dangerously-skip-permissions \
|
|
279
284
|
2>> "$log_path" \
|
|
280
285
|
> "$stdout_fifo" &
|