okstra 0.110.0 → 0.112.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.kr.md +3 -2
- package/README.md +3 -2
- package/bin/okstra +7 -1
- package/docs/for-ai/README.md +2 -2
- package/docs/for-ai/skills/okstra-brief.md +2 -3
- package/docs/for-ai/skills/okstra-container-build.md +2 -3
- package/docs/for-ai/skills/okstra-inspect.md +5 -12
- package/docs/for-ai/skills/okstra-rollup.md +3 -4
- package/docs/for-ai/skills/okstra-run.md +10 -10
- package/docs/for-ai/skills/okstra-schedule.md +2 -7
- package/docs/for-ai/skills/okstra-setup.md +1 -1
- package/docs/kr/architecture/storage-model.md +1 -2
- package/docs/kr/architecture.md +11 -12
- package/docs/kr/cli.md +6 -4
- package/docs/project-structure-overview.md +14 -12
- package/docs/task-process/README.md +4 -4
- package/docs/task-process/common-flow.md +8 -5
- package/docs/task-process/implementation.md +4 -5
- package/docs/task-process/release-handoff.md +3 -3
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/antigravity-worker.md +1 -0
- package/runtime/agents/workers/codex-worker.md +1 -0
- package/runtime/prompts/coding-preflight/overview.md +3 -1
- package/runtime/prompts/launch.template.md +1 -5
- package/runtime/prompts/lead/context-loader.md +2 -4
- package/runtime/prompts/lead/convergence.md +11 -240
- package/runtime/prompts/lead/okstra-lead-contract.md +70 -34
- package/runtime/prompts/lead/plan-body-verification.md +240 -0
- package/runtime/prompts/lead/report-writer.md +7 -7
- package/runtime/prompts/lead/team-contract.md +15 -17
- package/runtime/prompts/profiles/_common-contract.md +2 -38
- package/runtime/prompts/profiles/_implementation-diff-review.md +43 -0
- package/runtime/prompts/profiles/_implementation-executor.md +9 -11
- package/runtime/prompts/profiles/_implementation-self-check.md +11 -5
- package/runtime/prompts/profiles/_implementation-verifier.md +1 -1
- package/runtime/prompts/profiles/final-verification.md +1 -1
- package/runtime/prompts/profiles/implementation-planning.md +2 -2
- package/runtime/prompts/profiles/implementation.md +1 -1
- package/runtime/python/okstra_ctl/codex_dispatch.py +3 -0
- package/runtime/python/okstra_ctl/consumers.py +4 -0
- package/runtime/python/okstra_ctl/handoff.py +5 -23
- package/runtime/python/okstra_ctl/implementation_stage.py +11 -11
- package/runtime/python/okstra_ctl/path_hints.py +1 -0
- package/runtime/python/okstra_ctl/paths.py +3 -0
- package/runtime/python/okstra_ctl/render.py +8 -0
- package/runtime/python/okstra_ctl/report_views.py +76 -26
- package/runtime/python/okstra_ctl/set_work_status.py +147 -0
- package/runtime/python/okstra_ctl/stage_targets.py +152 -0
- package/runtime/python/okstra_ctl/team_reconcile.py +1 -1
- package/runtime/python/okstra_ctl/wizard.py +47 -0
- package/runtime/python/okstra_project/__init__.py +2 -0
- package/runtime/python/okstra_project/state.py +44 -2
- package/runtime/skills/okstra-brief/SKILL.md +32 -176
- package/runtime/skills/okstra-brief/references/reporter-confirmations.md +71 -0
- package/runtime/skills/okstra-brief/references/tracker-recursion.md +90 -0
- package/runtime/skills/okstra-container-build/SKILL.md +7 -20
- package/runtime/skills/okstra-graphify/SKILL.md +8 -8
- package/runtime/skills/okstra-inspect/SKILL.md +27 -43
- package/runtime/skills/okstra-rollup/SKILL.md +6 -6
- package/runtime/skills/okstra-run/SKILL.md +27 -32
- package/runtime/skills/okstra-schedule/SKILL.md +64 -419
- package/runtime/skills/okstra-setup/SKILL.md +25 -223
- package/runtime/skills/okstra-setup/references/project-config.md +188 -0
- package/runtime/templates/reports/schedule.template.md +2 -2
- package/runtime/templates/worker-prompt-preamble.md +1 -1
- package/runtime/validators/validate-run.py +7 -7
- package/src/cli-registry.mjs +14 -0
- package/src/commands/execute/wizard.mjs +3 -1
- package/src/commands/inspect/set-work-status.mjs +31 -0
- package/src/commands/inspect/task-show.mjs +11 -31
- package/src/commands/lifecycle/check-project.mjs +68 -56
- package/src/commands/lifecycle/install.mjs +1 -0
- package/src/commands/lifecycle/preflight.mjs +82 -0
|
@@ -6,168 +6,118 @@ model: opus
|
|
|
6
6
|
|
|
7
7
|
# OKSTRA Schedule
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
Generate a consolidated work schedule for all non-done tasks in a given `task-group`. The skill reads each task's `task-manifest.json` and `latestReport`, classifies tasks into phases by priority and risk, and writes a single Markdown plan file under `.okstra/tasks/<task-group>/schedule/`.
|
|
12
|
-
|
|
13
|
-
The skill runs as a single Claude lead synthesis (lightweight mode). A `--cross-verify` multi-agent variant was previously sketched here but never specified end-to-end; it has been dropped pre-1.0 and is tracked as a follow-up if multi-agent schedule verification is needed later.
|
|
9
|
+
Generate a consolidated work schedule for all non-done tasks in a given `task-group`. The skill reads each task's `task-manifest.json` and `latestReport`, classifies tasks into phases by priority and risk, and writes a single Markdown plan file under `.okstra/tasks/<task-group>/schedule/`. It runs as a single Claude lead synthesis (lightweight mode); the frontmatter `model: opus` switches supporting harnesses to Opus-class for the turn — cross-task synthesis needs that reasoning depth.
|
|
14
10
|
|
|
15
11
|
## When to Use
|
|
16
12
|
|
|
17
13
|
- User asks to generate a work schedule / plan / "일정" for an entire `task-group`
|
|
18
14
|
- User wants a single document that summarizes all non-done tasks with effort, risk, and dependencies
|
|
19
|
-
- A `task-group` exists in `.okstra/discovery/task-catalog.json` with at least one task whose `workStatus` is not `done`
|
|
20
15
|
|
|
21
|
-
**Do NOT use** for single-task analysis (use `okstra-inspect status`
|
|
16
|
+
**Do NOT use** for single-task analysis (use `okstra-inspect status`) or to execute one task (use `okstra-run`).
|
|
22
17
|
|
|
23
|
-
|
|
18
|
+
Explicit command form: `okstra schedule <task-group> [--title "<custom title>"] [--directive-file <abs-path>]`. If `--title` is omitted, derive a default from `task-group` (e.g. `uploadFont` → `uploadFont — Work Schedule`).
|
|
24
19
|
|
|
25
|
-
|
|
26
|
-
- "uploadFont 작업 일정 만들어줘"
|
|
27
|
-
- "uploadFont schedule 생성"
|
|
28
|
-
- "uploadFont 일정 계획표"
|
|
29
|
-
- "Generate schedule for uploadFont"
|
|
20
|
+
## Step 0: Preflight
|
|
30
21
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
22
|
+
Run one Bash tool call, starting with the literal token `okstra` (never wrapped in `if`/`eval`/`export`/`$(...)`/`VAR=...`/`||`/`&&`/`npx` — a non-literal leading token defeats the `Bash(okstra:*)` permission match):
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
okstra preflight --runtime claude-code --json
|
|
26
|
+
```
|
|
35
27
|
|
|
36
|
-
|
|
28
|
+
Parse the stdout JSON. `ok: true` → carry `projectRoot` as a literal string and use it to locate `.okstra/discovery/task-catalog.json` and the task-group directory. `ok: false` → tell the user to run `/okstra-setup` first, then stop. If the call fails with `unknown command: preflight`, the `okstra` binary on PATH predates this skill — tell the user to update it (`npm i -g okstra@latest`), then stop (`/okstra-setup` does not update the binary).
|
|
37
29
|
|
|
38
|
-
##
|
|
30
|
+
## Audience & authority (READ FIRST — drives everything below)
|
|
39
31
|
|
|
40
|
-
|
|
32
|
+
**The schedule is a client-facing work plan.** It assumes the team has all permissions and can proceed without further approval. Even when the underlying per-task reports flag blocking items, missing approvals, or "사용자 확인 필요 항목", **the schedule MUST NOT surface them** — those belong in the internal report. Never emit a decision checklist, a `#### 사용자 확인 필요 항목` sub-section, `Done`/`Ready?`/`Blocking Decisions` columns, or checkbox lists; "Status" reflects work phase only.
|
|
41
33
|
|
|
42
|
-
|
|
43
|
-
If this exits non-zero, tell the user: "okstra not installed — run `/okstra-setup` first." Then stop. Do **not** try to invoke `npx -y okstra@latest ...` as a fallback.
|
|
34
|
+
**Assume the user and their team hold full authority and every permission required.** External approvals, access grants, sign-off, and vendor coordination are treated as already satisfied unless a report names a concrete external dependency outside the user's control. Concretely:
|
|
44
35
|
|
|
45
|
-
|
|
46
|
-
|
|
36
|
+
- **Effort sizing & day totals** count engineering work only — strip approval-waiting / coordination buffers from source sizings (note the adjustment in `## Executive Summary` if material).
|
|
37
|
+
- **Gantt bars** represent engineering duration only; no dead-time gaps for approval cycles. `(after <TASK-ID>)` marks genuine engineering dependencies only.
|
|
38
|
+
- **Risk Mitigation Strategy** lists real engineering risks (data loss, regression surface, rollback path) — permission/coordination items are dropped.
|
|
39
|
+
- **Recommended Immediate Actions / Next Action** are concrete engineering steps; "권한 확인", "승인 요청", "이해관계자 정렬" 류는 출력 금지.
|
|
40
|
+
- **Cross-Task Dependencies** covers engineering coupling only (shared modules, release order, package versions).
|
|
47
41
|
|
|
48
|
-
|
|
49
|
-
- `ok: true` → carry `projectRoot` as a literal string and use it to locate `.okstra/discovery/task-catalog.json` and the task-group directory.
|
|
42
|
+
**The schedule must be self-contained.** Opaque codes pulled from internal reports (`FC-5`, `UC-12`, `M1`, decision-item letters, …) must not appear unresolved. Choose one per identifier: **Form A** (≤3 codes) — replace the code inline with a 5–20자 one-line description of the item; **Form B** (≥4 recurring codes) — keep the codes and emit a `## Glossary` table as the last section resolving every one. Decision-item letters (`A1`, `B2`, …) are approval items and may not appear at all. TASK-IDs listed in `## At a Glance` need neither.
|
|
50
43
|
|
|
51
|
-
|
|
44
|
+
## Contract SSOT — template + validator
|
|
52
45
|
|
|
53
|
-
|
|
46
|
+
The installed template `~/.okstra/templates/reports/schedule.template.md` is the **byte-for-byte SSOT** for the output shape: frontmatter, top header block, the mandatory `##` heading list and order, per-task `Item / Detail` field labels and sub-section order, table column shapes, the ASCII Gantt format (relative day axis, plain fence, `█`/`░`/`! crit`/`est` legend), the dependency-graph shapes, and the optional `## Glossary` gate. **Read the template before writing the schedule and follow it exactly** — do not re-derive section shapes from memory. Headings and field labels stay English literals regardless of the source-report language; body prose is Korean. When a section has no data, render its heading with `_없음_` — never delete or reorder headings. Never emit mermaid or any graph DSL.
|
|
54
47
|
|
|
55
|
-
|
|
48
|
+
`~/.okstra/lib/validators/validate-schedule.py` is the enforcement for all of the above (heading order, field labels, controlled vocabulary — e.g. `Med-High` is the canonical risk form — forbidden translations, checkbox bans, Gantt fence rules, unresolved-code detection). The Step 4 ambiguous-classification rationale line is the one rule the validator does not yet enforce — emit it yourself.
|
|
56
49
|
|
|
57
|
-
|
|
50
|
+
Two computation rules the template scaffold cannot carry inline:
|
|
58
51
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
3. If the active model is **Sonnet or Haiku-class**: STOP and output the following message verbatim, then wait for user response:
|
|
62
|
-
```
|
|
63
|
-
okstra-schedule는 Opus-class 모델에서 실행하는 것을 권장합니다 (현재: <active-model>).
|
|
64
|
-
/model opus 로 전환 후 다시 호출하시거나, 'sonnet으로 진행' 이라고 명시하시면 그대로 실행합니다.
|
|
65
|
-
```
|
|
66
|
-
4. If the user explicitly insists on the lower model ("sonnet으로 진행", "그대로 진행", "force", or similar): proceed to Step 1, but prepend a single-line warning at the top of the generated schedule file: `> ⚠️ Generated with <model> (not Opus). Cross-task synthesis quality may be reduced.`
|
|
52
|
+
- **Effort-to-Day mapping**: day ranges per size are defined once in the template's `### Effort Sizing 기준` table. For the At a Glance totals line, sum that table's lower bounds across in-scope tasks for the lower total and upper bounds for the upper total.
|
|
53
|
+
- **`[NEEDS-OKSTRA-RUN]` / `[PARSE-ERROR: <section>]` placement**: put the marker immediately under the per-task heading inside its Phase section and fill only the available fields — never relocate it to a sibling section.
|
|
67
54
|
|
|
68
|
-
|
|
55
|
+
## Procedure
|
|
69
56
|
|
|
70
57
|
### Step 1: Resolve task-group and collect tasks
|
|
71
58
|
|
|
72
59
|
1. Read `.okstra/discovery/task-catalog.json`.
|
|
73
|
-
2. **Normalise the user-supplied `<task-group>` argument:** lowercase it, then strip every character that is not `[a-z0-9]
|
|
60
|
+
2. **Normalise the user-supplied `<task-group>` argument:** lowercase it, then strip every character that is not `[a-z0-9]`. Apply the same transform to each entry's `taskGroupPathSegment`. Match on equality — this is the single comparison rule; do NOT also fall back to the raw `taskGroup` field.
|
|
74
61
|
3. If no tasks found, output `해당 task-group을 찾을 수 없습니다.` and stop.
|
|
75
62
|
4. For each matched task, read `.okstra/tasks/<task-group-segment>/<task-id-segment>/task-manifest.json` directly. Catalog data may be stale; the manifest is authoritative.
|
|
76
|
-
5. **Derive `<project-id>`** for the
|
|
63
|
+
5. **Derive `<project-id>`** for the header: prefer `task-catalog.json`'s top-level `projectId`, otherwise the first matched manifest's `projectId`. Do not invent a value.
|
|
77
64
|
|
|
78
65
|
### Step 2: Filter by workStatus
|
|
79
66
|
|
|
80
|
-
`workStatus` is
|
|
67
|
+
For inference when `workStatus` is missing or empty, defer to the inference table in `skills/okstra-inspect/SKILL.md` (`status.4` → "Default value convention") — do not duplicate it here. Then filter: resolved `done` → exclude; everything else (`todo` / `in-progress` / `blocked` / `phase-done` / inferred non-done) → include.
|
|
81
68
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
- If the resolved value is `done` (set by the user OR inferred via `currentStatus == "completed"` + terminal next-phase) → exclude.
|
|
85
|
-
- Otherwise (`todo` / `in-progress` / `blocked` / `phase-done` / explicit user value / inferred non-done) → include.
|
|
86
|
-
|
|
87
|
-
If after filtering 0 tasks remain, output:
|
|
88
|
-
```
|
|
89
|
-
해당 task-group의 모든 task가 done 상태입니다. 생성할 schedule이 없습니다.
|
|
90
|
-
```
|
|
91
|
-
Then stop without creating a file.
|
|
69
|
+
If 0 tasks remain, output `해당 task-group의 모든 task가 done 상태입니다. 생성할 schedule이 없습니다.` and stop **without creating a file**.
|
|
92
70
|
|
|
93
71
|
### Step 3: Per-task data extraction
|
|
94
72
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
**From `task-manifest.json`**:
|
|
98
|
-
- `taskId`, `taskGroup`, `taskKey`
|
|
99
|
-
- `workCategory`
|
|
100
|
-
- `workflow.currentPhase`, `workflow.currentPhaseState`
|
|
101
|
-
- `taskType`
|
|
102
|
-
- `workStatus`
|
|
103
|
-
- `latestReportPath`
|
|
104
|
-
|
|
105
|
-
**From the report file (`latestReportPath`)**, parse:
|
|
106
|
-
- Title / Problem statement
|
|
107
|
-
- Solution / Architecture
|
|
108
|
-
- Work Breakdown (table)
|
|
109
|
-
- Verification Commands
|
|
110
|
-
- Rollback strategy
|
|
111
|
-
- Effort, Risk, Priority, Scope, Repos
|
|
112
|
-
|
|
113
|
-
Note: per-task reports may include "사용자 확인 필요 항목" / blocking items / approval requests. **Do not extract or surface these in the schedule** — the schedule is a client-facing work plan. Internal blockers stay in the source report.
|
|
73
|
+
From `task-manifest.json`: `taskId`, `taskGroup`, `taskKey`, `workCategory`, `workflow.currentPhase`, `workflow.currentPhaseState`, `taskType`, `workStatus`, `latestReportPath`.
|
|
114
74
|
|
|
115
|
-
|
|
116
|
-
- **Before tagging `[NEEDS-OKSTRA-RUN]`, attempt the manifest-staleness fallback** (manifest pointer can become stale when an interleaved `--render-only` prep run advances `latestReportPath` to a path that will never be written):
|
|
117
|
-
1. Resolve `<task-root>` from `task-manifest.json` → `taskRootPath`.
|
|
118
|
-
2. List `<task-root>/runs/<taskType>/reports/final-report-*.md` and pick the **newest existing file by mtime** (NOT by filename timestamp — render-only prep can create entries whose timestamp is later than the last completed run's report). If none exists, also try `<task-root>/runs/*/reports/final-report-*.md` across all task-types as a last-resort.
|
|
119
|
-
3. If a candidate is found, parse it and proceed normally. Append a one-line note at the top of that task's per-task block in the schedule output:
|
|
120
|
-
`> _Report fallback: manifest pointed at non-existent <pointed-name>, used <actual-name> (mtime <ts>) instead. Manifest may be stale due to a render-only prep — see Phase 6 of okstra contract._`
|
|
121
|
-
4. If no candidate file exists either, only then fall through to `[NEEDS-OKSTRA-RUN]`.
|
|
122
|
-
- If still unresolvable: use only manifest metadata, mark the task entry with `[NEEDS-OKSTRA-RUN]`, and do not abort — continue with remaining tasks.
|
|
75
|
+
From the report file (`latestReportPath`): Title / Problem statement, Solution / Architecture, Work Breakdown table, Verification Commands, Rollback strategy, Effort, Risk, Priority, Scope, Repos. Blocking items / approval requests in the report are **not** extracted (see Audience).
|
|
123
76
|
|
|
124
|
-
If
|
|
125
|
-
- Mark the entry with `[PARSE-ERROR: <section>]` and continue.
|
|
77
|
+
If the report file does not exist or cannot be parsed, attempt the **manifest-staleness fallback** before tagging (`latestReportPath` can go stale when an interleaved `--render-only` prep advances it to a path that is never written):
|
|
126
78
|
|
|
127
|
-
|
|
79
|
+
1. Resolve `<task-root>` from the manifest's `taskRootPath`.
|
|
80
|
+
2. List `<task-root>/runs/<taskType>/reports/final-report-*.md` and pick the **newest existing file by mtime** (NOT by filename timestamp). If none, try `<task-root>/runs/*/reports/final-report-*.md` across all task-types.
|
|
81
|
+
3. If found, parse it and add one line at the top of that task's block: `> _Report fallback: manifest pointed at non-existent <pointed-name>, used <actual-name> (mtime <ts>) instead._`
|
|
82
|
+
4. Only if no candidate exists, tag the entry `[NEEDS-OKSTRA-RUN]`, use manifest metadata only, and continue with the remaining tasks. If parsing fails for one section, tag `[PARSE-ERROR: <section>]` and continue.
|
|
128
83
|
|
|
129
|
-
|
|
84
|
+
### Step 4: Phase classification
|
|
130
85
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
Classify each task into one of three phases based on report data.
|
|
134
|
-
|
|
135
|
-
**`workCategory` accepted values** — the category keys come from `scripts/okstra_ctl/worktree.py::_WORK_CATEGORY_PREFIX` (code source), plus the `unknown` fallback emitted by `render.py`. The phase mapping below is layered on top: when a category is added to `worktree.py`, add a row here too — otherwise the new category falls through to `unknown` → Phase 2.
|
|
86
|
+
`workCategory` keys come from `scripts/okstra_ctl/worktree.py::_WORK_CATEGORY_PREFIX` (code source) plus the `unknown` fallback from `render.py`. When a category is added there, add a row here — otherwise it falls through to `unknown` → Phase 2.
|
|
136
87
|
|
|
137
88
|
| workCategory | Default phase |
|
|
138
89
|
|--------------|---------------|
|
|
139
|
-
| `bugfix` | Phase 1
|
|
140
|
-
| `feature` | Phase 2 |
|
|
141
|
-
| `
|
|
142
|
-
| `
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
| `unknown` (or unmatched / missing) | **Phase 2**, with a one-line rationale `> _workCategory '<raw-value>' 미정의 — Phase 2로 기본 분류._` at the top of that phase section |
|
|
90
|
+
| `bugfix` | Phase 1 when risk is High/Med-High; otherwise Phase 2 |
|
|
91
|
+
| `feature` / `improvement` / `docs` / `doc` | Phase 2 |
|
|
92
|
+
| `refactor` / `ops` | Phase 3 |
|
|
93
|
+
| `unknown` (or unmatched / missing) | Phase 2, with rationale `> _workCategory '<raw-value>' 미정의 — Phase 2로 기본 분류._` at the top of that phase section |
|
|
94
|
+
|
|
95
|
+
Priority overrides category: `P0` → Phase 1; `P1`/`P2` → Phase 2; `P3` or multi-repo + infrastructure scope → Phase 3. When still ambiguous, place the task in the closest phase and add a one-line rationale at the top of that phase section (not validator-enforced — emit it yourself).
|
|
146
96
|
|
|
147
|
-
|
|
97
|
+
### Step 5: Gantt decision (render by default)
|
|
148
98
|
|
|
149
|
-
|
|
150
|
-
- **Phase 2 (개선/기능)**: priority `P1` or `P2`, OR `workCategory in {"feature", "improvement", "docs", "doc"}`, OR fallback per the table above
|
|
151
|
-
- **Phase 3 (확장/아키텍처)**: priority `P3`, OR `workCategory in {"refactor", "ops"}`, OR multi-repo + infrastructure scope
|
|
99
|
+
`## Gantt Chart` is **rendered by default** — skip ONLY when literally no day signal exists (every task is effort=XXL with no visible decomposition, or all tasks lack both effort sizing and decomposition). Render whenever any of these hold: 2+ tasks with effort sizing; 1 task whose effort yields a range (mid-point bar, or `lo`/`hi` two-bar form); 1 task with Part/Phase/Step decomposition in the source (bars at decomposition-unit level); total estimated effort ≥ 3 days. When per-unit day allocations aren't itemized, split the parent range across the visible units yourself and append the `est` annotation (or add `> 일별 배분은 추정치이며 차단 항목 해소 후 갱신 권장.`). "Range is wide", "single task", "user decisions pending" are NOT skip reasons — render an estimate-tagged chart instead.
|
|
152
100
|
|
|
153
|
-
When
|
|
101
|
+
When you do skip, insert in the section's position exactly: `> _Gantt Chart 생략: <concrete reason referencing the actual data>._`
|
|
154
102
|
|
|
155
|
-
|
|
103
|
+
**Directive override (highest priority).** Before applying the heuristic, check for a `## Directive` section, first hit wins: (1) the `--directive-file <abs-path>` argument; (2) `<PROJECT_ROOT>/.okstra/tasks/<task-group-segment>/schedule/instruction-set/analysis-material.md`; (3) none → apply the default heuristic silently. A found directive overrides the render/skip heuristic for the affected section — note it inline as `> _Per Directive directive: <verbatim short excerpt>._` — and its pre-supplied day allocations / phase weights are used verbatim as bar lengths. A directive file without a `## Directive` heading counts as "no directive".
|
|
156
104
|
|
|
157
105
|
### Step 6: Write the schedule file
|
|
158
106
|
|
|
159
|
-
Output path:
|
|
160
107
|
```
|
|
161
108
|
.okstra/tasks/<task-group-segment>/schedule/<task-group-segment>-plan-<YYYY-MM-DD_HH-MM-SS>.md
|
|
162
109
|
```
|
|
163
110
|
|
|
164
|
-
|
|
165
|
-
- Timestamp: current local time at generation, format `YYYY-MM-DD_HH-MM-SS`.
|
|
166
|
-
- Auto-create the parent directory if it does not exist.
|
|
111
|
+
`<task-group-segment>` comes from the manifest's `taskGroupPathSegment` verbatim. Timestamp is current local time. Auto-create the parent directory. Never overwrite an existing file — on a same-second collision append `-2`, `-3`, ….
|
|
167
112
|
|
|
168
|
-
### Step 7:
|
|
113
|
+
### Step 7: Self-validate before reporting completion
|
|
169
114
|
|
|
170
|
-
|
|
115
|
+
1. Re-read the file you just wrote.
|
|
116
|
+
2. Run `python3 ~/.okstra/lib/validators/validate-schedule.py <output-path>`.
|
|
117
|
+
3. If it exits non-zero, fix the file and re-validate. Do not print the Step 8 message until it passes.
|
|
118
|
+
4. If the validator is not installed, fall back to a manual check against the template: every template `##` heading present with exact spelling, title ends with `— Work Schedule`, `> Generated:` block present.
|
|
119
|
+
|
|
120
|
+
### Step 8: Completion message (Korean)
|
|
171
121
|
|
|
172
122
|
```
|
|
173
123
|
✓ Schedule 생성 완료: <relative-path>
|
|
@@ -177,325 +127,20 @@ After writing the file, reply briefly:
|
|
|
177
127
|
- 모드: lightweight
|
|
178
128
|
```
|
|
179
129
|
|
|
180
|
-
## Audience (READ FIRST — drives everything below)
|
|
181
|
-
|
|
182
|
-
**The schedule is a client-facing work plan.** It assumes the team has all permissions and can proceed without further approval. Even when the underlying per-task reports flag blocking items, missing approvals, or "사용자 확인 필요 항목", **the schedule MUST NOT surface them**. Those concerns belong in the internal report, not the deliverable.
|
|
183
|
-
|
|
184
|
-
### Authority & permissions assumption (schedule sizing)
|
|
185
|
-
|
|
186
|
-
**Assume the user (and their team) holds full authority and every permission required for every included task.** External approvals, third-party access grants, role/IAM permissions, organisational sign-off, legal/compliance review, vendor coordination, and "verify access exists" steps are treated as already satisfied unless the source per-task report explicitly identifies a concrete external dependency outside the user's control.
|
|
187
|
-
|
|
188
|
-
Concretely, when computing this schedule:
|
|
189
|
-
|
|
190
|
-
- **Effort sizing & day totals**: Count engineering work only. Do NOT inflate `S/M/L/XL` or the `<X.X> ~ <Y.Y> days` total for permission-checking, approval-waiting, stakeholder-coordination, or "권한 확인" buffer time. If a per-task report's effort sizing already bakes in such buffers, strip them when synthesising the schedule total and note the adjustment inside `## Executive Summary` if material.
|
|
191
|
-
- **Gantt Chart**: Bars represent engineering duration only. Do not insert dead-time gaps for approval cycles or coordination wait. Sequential `(after <TASK-ID>)` annotations remain valid only for genuine engineering dependencies.
|
|
192
|
-
- **Risk Mitigation Strategy**: Permission/authority/external-coordination items are NOT acceptable risk strategies — drop them. Real risks (data loss, regression surface, rollback path, performance regression, etc.) only.
|
|
193
|
-
- **Recommended Immediate Actions** and **Execution Priority Matrix → Next Action**: Every action is a concrete engineering step (write test, modify file, run command). "권한 확인", "승인 요청", "이해관계자 정렬" 같은 항목은 출력 금지.
|
|
194
|
-
- **Cross-Task Dependencies & Shared Concerns**: Only engineering coupling (shared modules, release order, package versions). Cross-team coordination notes inherited from per-task reports MUST be filtered out.
|
|
195
|
-
|
|
196
|
-
This rule is independent of the existing client-facing audience rule — even if a future variant of this skill chose to surface decision items, the authority assumption still suppresses external-permission accounting.
|
|
197
|
-
|
|
198
|
-
Concretely:
|
|
199
|
-
- No "Consolidated User Decision Checklist" section.
|
|
200
|
-
- No per-task "사용자 확인 필요 항목" sub-section.
|
|
201
|
-
- No `Done` / `Ready?` / `Blocking Decisions` columns anywhere.
|
|
202
|
-
- No checkboxes (`[ ]` / `[x]`) — bullet lists only.
|
|
203
|
-
- "Status" field reflects work phase only; never bubble up "blocked" rationale prose.
|
|
204
|
-
|
|
205
|
-
**The schedule must be self-contained.** Every identifier the client reads must be resolvable from the schedule itself. Cross-document opaque codes pulled from internal reports — `FC-5`, `UC-12`, `TC-3`, `RC-2`, `M1`, `A1`, `B2`, `C3`, decision-item letters, finding codes, milestone codes — **MUST NOT appear unresolved**. The client cannot look them up against the source report, and a bare code adds zero value to a delivery plan.
|
|
206
|
-
|
|
207
|
-
**Two acceptable forms — choose one per identifier:**
|
|
208
|
-
|
|
209
|
-
**Form A — inline replacement (preferred for ≤3 codes).** Replace the identifier with a brief description of that item's content (한 줄 요약, 5–20자 내외). Drop the code entirely; do not write code-and-content together.
|
|
210
|
-
|
|
211
|
-
| Source report | ❌ Forbidden | ✅ Form A |
|
|
212
|
-
|---------------|--------------|-----------|
|
|
213
|
-
| `FC-5: 결제 게이트웨이 타임아웃 처리 누락` | `FC-5 수정` / `FC-5 (결제 타임아웃)` | `결제 게이트웨이 타임아웃 처리` |
|
|
214
|
-
| `M2: 1차 베타 배포` | `M2 도달` | `1차 베타 배포` |
|
|
215
|
-
| `UC-3: 폰트 업로드 흐름` | `UC-3 검증` | `폰트 업로드 흐름 검증` |
|
|
216
|
-
|
|
217
|
-
**Form B — `## Glossary` at document bottom (preferred when ≥4 codes recur).** Keep the bare identifier in the body **only if** the document also emits a `## Glossary` section as the last `##` section (after `## Recommended Immediate Actions`). The glossary MUST resolve every opaque code that appears in the body. Format:
|
|
218
|
-
|
|
219
|
-
```markdown
|
|
220
|
-
## Glossary
|
|
221
|
-
|
|
222
|
-
| Code | Description |
|
|
223
|
-
|------|-------------|
|
|
224
|
-
| FC-5 | 결제 게이트웨이 타임아웃 처리 누락 |
|
|
225
|
-
| M2 | 1차 베타 배포 |
|
|
226
|
-
| UC-3 | 폰트 업로드 흐름 |
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
Rules for Form B:
|
|
230
|
-
- Header literal `| Code | Description |` is required.
|
|
231
|
-
- Every opaque code referenced anywhere in the body MUST have a glossary row. The validator flags any unresolved code.
|
|
232
|
-
- Decision-item letters (`A1`, `B2`, `C3`, `D4`) — these are blocking/approval items that MUST NOT appear in the schedule at all (see "client-facing" rule above). The glossary cannot whitewash them.
|
|
233
|
-
|
|
234
|
-
The only cross-reference that needs neither inlining nor a glossary entry is a TASK-ID that itself appears in the `## At a Glance` table.
|
|
235
|
-
|
|
236
|
-
The validator rejects any of these patterns.
|
|
237
|
-
|
|
238
|
-
## Section Contract (required)
|
|
239
|
-
|
|
240
|
-
The canonical template lives at `~/.okstra/templates/reports/schedule.template.md`. **Read it before writing the schedule** and follow it byte-for-byte for headings.
|
|
241
|
-
|
|
242
|
-
### MUST — exact ordered heading list
|
|
243
|
-
|
|
244
|
-
The output file MUST contain exactly these top-level (`##`) sections, in this order, with these exact English headings (verbatim, no translation, no rewording, no extra punctuation):
|
|
245
|
-
|
|
246
|
-
1. `## At a Glance`
|
|
247
|
-
2. `## Executive Summary` (with subsection `### Effort Sizing 기준`)
|
|
248
|
-
3. `## Task Dependency Graph`
|
|
249
|
-
4. `## Phase 1: Critical Fixes`
|
|
250
|
-
5. `## Phase 2: Enhancements`
|
|
251
|
-
6. `## Phase 3: Architecture`
|
|
252
|
-
7. `## Execution Priority Matrix`
|
|
253
|
-
8. `## Cross-Task Dependencies & Shared Concerns`
|
|
254
|
-
9. `## Risk Mitigation Strategy`
|
|
255
|
-
10. `## Recommended Immediate Actions`
|
|
256
|
-
|
|
257
|
-
**Optional sections** (allowed at fixed positions only):
|
|
258
|
-
- `## Gantt Chart` — between `## Task Dependency Graph` and `## Phase 1: Critical Fixes`.
|
|
259
|
-
- `## Glossary` — last `##` section, after `## Recommended Immediate Actions`. Required when the body contains any opaque code (FC-N, UC-N, M-N, …) using Form B; forbidden in any other position.
|
|
260
|
-
|
|
261
|
-
If a phase has zero tasks, keep its heading and write `_없음_` underneath. **Never delete a heading.** **Never reorder.**
|
|
262
|
-
|
|
263
|
-
### SHOULD — graphic section (English heading only)
|
|
264
|
-
|
|
265
|
-
The following section is the only graphic output and MUST appear in this position (between `## Task Dependency Graph` and `## Phase 1: Critical Fixes`), with this exact English heading literal:
|
|
266
|
-
|
|
267
|
-
- `## Gantt Chart` — render as a fenced **ASCII** chart inside a plain ```` ``` ```` block (no language tag, no `mermaid`). See "ASCII Gantt format" below.
|
|
268
|
-
|
|
269
|
-
#### ASCII Gantt format (REQUIRED — mermaid is forbidden)
|
|
270
|
-
|
|
271
|
-
Render the chart as a monospace text block. **The horizontal axis MUST be a relative day count starting at Day 1 (or J1) — never calendar dates from "today" or any other absolute date.** The schedule describes effort/duration in days, not a wall-clock plan; rendering `2026-05-04`, `Mon May 4`, etc. is a contract violation. Use this structure exactly:
|
|
272
|
-
|
|
273
|
-
````
|
|
274
|
-
```
|
|
275
|
-
Day: 1 5 10 15 20 25 30
|
|
276
|
-
| | | | | | |
|
|
277
|
-
Phase 1
|
|
278
|
-
<TASK-ID> (<S/M/L/XL>) ██████ ! crit
|
|
279
|
-
<TASK-ID> (<S/M/L/XL>) ████████
|
|
280
|
-
Phase 2
|
|
281
|
-
<TASK-ID> (<S/M/L/XL>) ██████░░ est
|
|
282
|
-
Phase 3
|
|
283
|
-
<TASK-ID> (<S/M/L/XL>) ████
|
|
284
|
-
```
|
|
285
|
-
````
|
|
286
|
-
|
|
287
|
-
Rules:
|
|
288
|
-
- Fence the block with plain ```` ``` ```` (NOT ```` ```mermaid ````, NOT ```` ```gantt ````, NOT ```` ```text ````). The fence MUST have no language hint so downstream validators can detect the format.
|
|
289
|
-
- The first line is a `Day:` axis with **relative day numbers only** (1, 2, 3, … or J1, J2, J3, …). Do NOT substitute calendar dates, weekdays, ISO timestamps, or "today + N" labels — even if the user's environment shows today's date. Choose a tick interval (1, 2, or 5 days) so the axis fits within ~80 columns; align tick labels with `|` markers on the second line.
|
|
290
|
-
- Day 1 is the start of Phase 1 (the first scheduled task). Subsequent task start columns are computed from cumulative durations, NOT from any external calendar.
|
|
291
|
-
- Group bars under `Phase 1` / `Phase 2` / `Phase 3` headings (omit a phase if it has no tasks — but keep the order). Indent task rows by two spaces.
|
|
292
|
-
- Each task row is ` <TASK-ID> (<size>)` left-aligned in a fixed-width label column (pad with spaces so all bars start in the same column), followed by spaces to position the bar at its start day, then the bar.
|
|
293
|
-
- Use `█` for solid (committed) duration and `░` for the upper-bound / uncertainty tail when the effort sizing has a range. A single bar at mid-point is also acceptable.
|
|
294
|
-
- Append annotations after the bar separated by spaces:
|
|
295
|
-
- `! crit` for critical-path items (replaces mermaid's `:crit,`).
|
|
296
|
-
- `est` when day allocations are estimated (replaces `:est,`).
|
|
297
|
-
- `(after <TASK-ID>)` to mark a sequential dependency when not visually obvious.
|
|
298
|
-
- Keep total width ≤ 100 columns. If span exceeds the axis, increase the tick interval rather than wrapping.
|
|
299
|
-
- When effort is XXL ("세분화 필요") and no decomposition exists, follow the skip-reason rule instead of inventing bars.
|
|
300
|
-
|
|
301
|
-
#### Render-by-default rule (REVERSED from prior contract)
|
|
302
|
-
|
|
303
|
-
These sections are **rendered by default**. Skip them ONLY when literally no usable day data exists anywhere in the source. Specifically:
|
|
304
|
-
|
|
305
|
-
**`## Gantt Chart` — render whenever ANY of these hold:**
|
|
306
|
-
- 2+ tasks with any effort sizing (S/M/L/XL — all map to day ranges via the Effort Sizing 기준 table)
|
|
307
|
-
- 1 task whose Effort sizing yields any range (use range mid-point as a single bar, or render two bars `lo` and `hi` for visible uncertainty)
|
|
308
|
-
- 1 task with explicit Part/Phase/Step decomposition in the source report (look for headings like "Part 1", "Phase 1", "Step N", "Quick Wins + CDN Architecture" etc.) — render bars at the **decomposition unit** level, even if internal day allocations are estimates
|
|
309
|
-
- Any case where total estimated effort is ≥ 3 days
|
|
310
|
-
|
|
311
|
-
When per-decomposition day allocations aren't crisply itemized, **estimate them yourself by splitting the parent effort range across the visible decomposition units** and append the `est` annotation after the bar (see ASCII Gantt format below) or add a one-line note `> 일별 배분은 추정치이며 차단 항목 해소 후 갱신 권장.` The reader benefits more from a rough visual than from no visual.
|
|
312
|
-
|
|
313
|
-
**Skip is permitted ONLY when:**
|
|
314
|
-
- Every task has effort=XXL ("세분화 필요") AND no decomposition is visible in the source — i.e. there is genuinely no day signal to plot
|
|
315
|
-
- All included tasks lack BOTH effort sizing AND any decomposition
|
|
316
|
-
|
|
317
|
-
When skipping, follow the skip-reason note rule below — but the skip should be rare. "Range is wide" or "user decisions pending" or "single task" are NOT acceptable skip reasons by themselves; render an estimate-tagged chart instead.
|
|
318
|
-
|
|
319
|
-
#### Directive override (highest priority)
|
|
320
|
-
|
|
321
|
-
Before applying the heuristics above, **check the schedule-level directive source** for a `## Directive` section.
|
|
322
|
-
|
|
323
|
-
**Resolution order (first hit wins):**
|
|
324
|
-
|
|
325
|
-
1. Absolute path passed via the `--directive-file <abs-path>` argument when invoking the skill.
|
|
326
|
-
2. `<PROJECT_ROOT>/.okstra/tasks/<task-group-segment>/schedule/instruction-set/analysis-material.md` (the canonical schedule-level instruction-set location — okstra writes here when a schedule run is dispatched with `--directive`).
|
|
327
|
-
3. **No directive file** — fall through and apply the default heuristic without any override. This is the normal case; do not warn, do not block.
|
|
328
|
-
|
|
329
|
-
If a directive source is found and contains a `## Directive` section that affects Gantt rendering — e.g. "render a Gantt even with single XL task", "no Gantt needed" — that directive **overrides the heuristic and the skip-reason rule** for the affected section. When following a Directive override that contradicts the default heuristic, append a one-line note inside the rendered (or skipped) section: `> _Per Directive directive: <verbatim short excerpt>._` so the reader can trace why the section appeared/disappeared against the default. The Directive may also pre-supply day allocations, phase weights, or sub-task decompositions — use those verbatim as bar lengths in the Gantt.
|
|
330
|
-
|
|
331
|
-
A directive file that exists but contains no `## Directive` heading is treated as "no directive" — fall through to the heuristic, no warning required.
|
|
332
|
-
|
|
333
|
-
`## Gantt Chart` is the only `##` section that MAY be added beyond the 10 mandatory ones. Any other extra `##` heading is forbidden.
|
|
334
|
-
|
|
335
|
-
#### MUST — emit a skip-reason note when omitting Gantt Chart (rare case)
|
|
336
|
-
|
|
337
|
-
Skipping should be **rare** under the render-by-default rule above. When you do skip — only when the strict skip-permitted conditions hold — insert a one-line blockquote in the section's position (between `## Task Dependency Graph` and `## Phase 1: Critical Fixes`), in this exact shape:
|
|
338
|
-
|
|
339
|
-
```
|
|
340
|
-
> _Gantt Chart 생략: <concrete reason referencing the actual data>._
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
The reason MUST reference the actual data and must be one of the legitimate skip cases. Acceptable example:
|
|
344
|
-
|
|
345
|
-
- `> _Gantt Chart 생략: 모든 task가 effort=XXL (세분화 필요), day 추정 산출 불가._`
|
|
346
|
-
|
|
347
|
-
**NOT acceptable as skip reasons** (these mean you should render an estimate-tagged chart instead):
|
|
348
|
-
- "단일 task" — render with the task's effort range as bars
|
|
349
|
-
- "effort range가 넓음 (XL 5-15d)" — render mid-point or `lo`/`hi` two-bar form
|
|
350
|
-
- "사용자 결정 전 확정 불가" — render with `est` annotation and a `> 일별 배분은 추정치` note
|
|
351
|
-
- "Part/Phase 내부 day 배분 미정" — split the parent range across visible decomposition units
|
|
352
|
-
|
|
353
|
-
This rule exists because rendering an estimated chart with a clear "estimate" tag is **always** more useful than no chart at all.
|
|
354
|
-
|
|
355
|
-
### MUST — top header (verbatim shape)
|
|
356
|
-
|
|
357
|
-
```markdown
|
|
358
|
-
# <Title> — Work Schedule
|
|
359
|
-
|
|
360
|
-
> Generated: <YYYY-MM-DD HH:MM> | Project: <project-id> | Task Group: <task-group>
|
|
361
|
-
> Source: okstra <mode> (<N> tasks included, <M> done excluded)
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
The title suffix MUST be `— Work Schedule` (em dash, English). Korean titles like `작업 일정 계획서` are forbidden.
|
|
365
|
-
|
|
366
|
-
### MUST — per-task block field set
|
|
367
|
-
|
|
368
|
-
Every per-task block MUST include the `Item / Detail` table with these field rows in this order: `**Category**`, `**Priority**`, `**Effort**`, `**Status**`, `**Risk**`, `**Scope**`, `**Repo**`. None may be omitted, renamed, or translated.
|
|
369
|
-
|
|
370
|
-
### MUST — per-task block sub-section order
|
|
371
|
-
|
|
372
|
-
After the `Item / Detail` table, every per-task block MUST emit these sub-sections in this exact order — no insertions, no reordering, no omissions (unless the block is tagged `[NEEDS-OKSTRA-RUN]` / `[PARSE-ERROR: …]`):
|
|
373
|
-
|
|
374
|
-
1. `**Problem**:`
|
|
375
|
-
2. `**Solution**:`
|
|
376
|
-
3. `**Work Breakdown**:` (followed by the `| Step | File | Action | Detail |` table)
|
|
377
|
-
4. `**Verification Commands**:` (followed by a fenced ` ```bash ` block)
|
|
378
|
-
5. `**Rollback**:`
|
|
379
|
-
|
|
380
|
-
The validator enforces order by scanning each `### N-i.` block. A missing section or an out-of-order section is a contract violation. **Never emit `#### 사용자 확인 필요 항목`** — this is a client-facing schedule (see "Audience" above).
|
|
381
|
-
|
|
382
|
-
### MUST — controlled vocabulary (enums)
|
|
383
|
-
|
|
384
|
-
The following columns/labels accept ONLY the listed values — anywhere they appear (At a Glance table, per-task `Item / Detail` table, Execution Priority Matrix). Free-text is forbidden; if the source data is missing, leave the cell empty (`–` is also accepted by the validator only inside per-task `Item / Detail`, not in `## At a Glance`).
|
|
385
|
-
|
|
386
|
-
| Field | Allowed values |
|
|
387
|
-
|-------|----------------|
|
|
388
|
-
| **Effort** | `S`, `M`, `L`, `XL`, `XXL` (leading token only — trailing scope hint like `L (5-15 files)` is allowed inside parens) |
|
|
389
|
-
| **Priority** | `P0`, `P1`, `P2`, `P3` |
|
|
390
|
-
| **Risk** | `Very Low`, `Low`, `Medium`, `Med-High`, `High` |
|
|
391
|
-
| **Phase** | `1`, `2`, `3` |
|
|
392
|
-
|
|
393
|
-
`Med-High` (hyphenated) is the canonical form — `Medium-High` / `중상` / `Moyen-Élevé` are all rejected.
|
|
394
|
-
|
|
395
|
-
### MUST — At a Glance totals line
|
|
396
|
-
|
|
397
|
-
The At a Glance section MUST contain exactly one totals line in this shape (single line, all bold):
|
|
398
|
-
|
|
399
|
-
```
|
|
400
|
-
**총 <N>개 task / 예상 소요: <X.X> ~ <Y.Y> days (Effort 합산)**
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
`<N>` is the included-task count, `<X.X>` and `<Y.Y>` are the lower/upper sums of the Effort-to-Day mapping. The validator checks the literal pattern.
|
|
404
|
-
|
|
405
|
-
### MUST — table & list shapes (no checkboxes anywhere)
|
|
406
|
-
|
|
407
|
-
The schedule is a client-facing deliverable, not an internal todo board. **No table or list may contain `[ ]` / `[x]` checkbox cells, and no `Done` / `Ready?` / `Blocking Decisions` columns are permitted.**
|
|
408
|
-
|
|
409
|
-
Required shapes:
|
|
410
|
-
|
|
411
|
-
- `## Execution Priority Matrix` — header `| Priority | Task | Effort | Risk | Next Action |`. No leading `Done` column, no `Ready?`, no `Blocking Decisions`.
|
|
412
|
-
- `## Recommended Immediate Actions` — markdown bullet list (`- <action>`). Numbered lists and checkbox lists are both rejected.
|
|
413
|
-
- `## Risk Mitigation Strategy` — numbered list (it states *strategies*, not actions to tick off).
|
|
414
|
-
|
|
415
|
-
### MUST NOT — forbidden patterns
|
|
416
|
-
|
|
417
|
-
| Pattern | Why forbidden |
|
|
418
|
-
|---------|---------------|
|
|
419
|
-
| Translating any `##` heading to Korean (`전체 개요`, `요약`, `위험 완화 전략`, `즉시 권장 액션`, etc.) or any other language | Heading literals are stable identifiers used by the validator and downstream tooling |
|
|
420
|
-
| Adding sections not in the contract (`## Effort-to-Day 매핑`, `## Référentiel …`, etc. — anything beyond the 10 mandatory + the 1 optional `## Gantt Chart`) | Sizing tables belong inside `### Effort Sizing 기준` (Executive Summary). All other graphic detail belongs inside per-phase prose |
|
|
421
|
-
| Translating the optional graphic section (`## Gantt 다이어그램`, `## Diagramme de Gantt`) | Use `## Gantt Chart` literally — translation is forbidden |
|
|
422
|
-
| Adding `## Cumulative Timeline` (or any translated form: `## 누적 일정표`, `## Calendrier Cumulé`) | The Cumulative Timeline section has been removed from the contract — never emit it |
|
|
423
|
-
| Using calendar dates / weekdays / "today + N" labels in the Gantt axis (e.g. `2026-05-04`, `Mon May 4`, `오늘 + 3일`) | The axis MUST be relative day-counts (`Day 1`, `J1`, …) — the schedule describes effort, not a wall-clock plan |
|
|
424
|
-
| Using French (`Charge estimée`, `Détail`, `Catégorie`, `Priorité`, `Risque`, `Dépôt`, `Vue d'Ensemble`, `Résumé Exécutif`, etc.) anywhere in headings or field labels | Body prose is Korean, identifiers/headings/field labels are English literals. No third language anywhere structural |
|
|
425
|
-
| **Mirroring the source-report language into headings** — e.g. source analyse-report is in French → headings become French; source is heavily Korean → headings become Korean | Body prose may match the source language (the SKILL allows Korean prose), but the 10 mandatory + 1 optional `##` heading literals and the 7 per-task field labels remain English ALWAYS, regardless of source-report language |
|
|
426
|
-
| Translating per-task field labels (`출처`, `상세`, `위험`, `Repo별 영향` already-translated label OK only as table column header in `At a Glance` rows) | Field labels are part of the contract |
|
|
427
|
-
| Emitting `## Consolidated User Decision Checklist` or `#### 사용자 확인 필요 항목` | Forbidden — schedule is a client-facing deliverable; blocking/approval/decision items belong in the internal report |
|
|
428
|
-
| Adding `Done` / `Ready?` / `Blocking Decisions` columns to any table, or `[ ]` / `[x]` checkbox cells in any list | Forbidden for the same reason — see "Audience" section |
|
|
429
|
-
| Replacing `Item / Detail` per-task table headers with translated versions | The literal `Item / Detail` is required |
|
|
430
|
-
| Silently omitting `## Gantt Chart` without inserting the `> _Gantt Chart 생략: …_` blockquote in its position | Without the skip-reason line the reader cannot tell whether the section was forgotten, suppressed by a bug, or correctly skipped — every output must either render the chart or explicitly account for the skip |
|
|
431
|
-
| Skipping `## Gantt Chart` because the data is "wide range / single task / part-day allocation pending" | Per the render-by-default rule, these are reasons to render an **estimate-tagged** chart, not to skip. Skip is only legitimate when day data literally does not exist (all-XXL or no effort sizing anywhere) |
|
|
432
|
-
| Rendering Gantt as a mermaid (`` ```mermaid `` / `gantt` block) or any other graph DSL (PlantUML, Graphviz, etc.) | This skill renders ASCII only. Mermaid output is forbidden — use the ASCII Gantt format described above. Validators may reject mermaid blocks under this heading |
|
|
433
|
-
|
|
434
|
-
## Known Validator Gaps (out of scope here)
|
|
435
|
-
|
|
436
|
-
- The ambiguous-classification rationale required by Step 5 (`> _workCategory '<raw>' 미정의 …_` / nearest-phase rationale) is **not** currently enforced by `validators/validate-schedule.py`. The skill is responsible for emitting it; closing the validator gap requires a validator change and is tracked as a follow-up.
|
|
437
|
-
|
|
438
|
-
## Self-Validation Before Reporting Completion
|
|
439
|
-
|
|
440
|
-
After writing the file and before printing the completion message in Step 7, you MUST:
|
|
441
|
-
|
|
442
|
-
1. **Re-read the file** you just wrote.
|
|
443
|
-
2. **Run the validator**:
|
|
444
|
-
```bash
|
|
445
|
-
python3 ~/.okstra/lib/validators/validate-schedule.py <output-path>
|
|
446
|
-
```
|
|
447
|
-
3. If the validator exits non-zero, **fix the file and re-validate**. Do not print the completion message until the validator passes.
|
|
448
|
-
4. If `~/.okstra/lib/validators/validate-schedule.py` is not present, fall back to a manual checklist: confirm each of the 10 mandatory headings from `### MUST — exact ordered heading list` (above) appears in the file with that exact spelling, the title ends with `— Work Schedule`, and the metadata `> Generated:` block is present.
|
|
449
|
-
|
|
450
|
-
## Schedule Document Template
|
|
451
|
-
|
|
452
|
-
The installed template `~/.okstra/templates/reports/schedule.template.md` is the byte-for-byte SSOT for section ordering, heading spelling, table columns, and per-section HTML-comment guidance (Dependency Graph Shape A/B, Gantt rules, optional Glossary gate). Do not omit sections; if data is unavailable, render the section with `_없음_` rather than skipping it.
|
|
453
|
-
|
|
454
|
-
The two rules below complement the template — they encode COMPUTATION that the template scaffold cannot carry inline.
|
|
455
|
-
|
|
456
|
-
### Effort-to-Day mapping (At a Glance total)
|
|
457
|
-
|
|
458
|
-
Day-range values per size are defined once in the template's `### Effort Sizing 기준` table (`~/.okstra/templates/reports/schedule.template.md`) — that table is the SSOT. To compute the At a Glance total, read its `Day(s)` column and sum the lower bounds across all in-scope tasks for the lower total, the upper bounds for the upper total.
|
|
459
|
-
|
|
460
|
-
### `[NEEDS-OKSTRA-RUN]` / `[PARSE-ERROR: <section>]` placement
|
|
461
|
-
|
|
462
|
-
When a task entry is tagged with one of these markers, place the marker immediately under the per-task heading inside the corresponding Phase section and fill only the available fields. Do NOT relocate it to a sibling section.
|
|
463
|
-
|
|
464
130
|
## Edge Cases
|
|
465
131
|
|
|
466
132
|
| Case | Handling |
|
|
467
133
|
|------|----------|
|
|
468
|
-
| `workStatus`
|
|
134
|
+
| `workStatus` absent or empty | Resolve via the `okstra-inspect status.4` inference table; include unless resolved `done` |
|
|
469
135
|
| Filtered task count is 0 | Emit "모든 task가 done" message; do NOT create a file |
|
|
470
|
-
| `latestReportPath` missing or unreadable |
|
|
471
|
-
| Report parsing fails for
|
|
472
|
-
| `task-group`
|
|
136
|
+
| `latestReportPath` missing or unreadable | Staleness fallback, then `[NEEDS-OKSTRA-RUN]` with manifest metadata only |
|
|
137
|
+
| Report parsing fails for one section | `[PARSE-ERROR: <section>]`; continue with the rest |
|
|
138
|
+
| `task-group` matches no tasks | "해당 task-group을 찾을 수 없습니다." and stop |
|
|
473
139
|
| Catalog and manifest disagree on `workStatus` | Manifest wins (catalog may be stale) |
|
|
474
|
-
|
|
|
140
|
+
| task-group casing / punctuation variants | Normalise both sides (lowercase + strip non-`[a-z0-9]`), compare against `taskGroupPathSegment` only; use the manifest's segment verbatim for path output |
|
|
475
141
|
|
|
476
142
|
## Output Rules
|
|
477
143
|
|
|
478
|
-
- All user-facing messages in Korean.
|
|
479
|
-
- Schedule file body uses Korean for prose, English for technical identifiers.
|
|
144
|
+
- All user-facing messages in Korean; schedule body prose Korean, identifiers/headings/field labels English (template literals).
|
|
480
145
|
- Use project-relative paths in completion messages.
|
|
481
|
-
-
|
|
482
|
-
|
|
483
|
-
## Common Mistakes
|
|
484
|
-
|
|
485
|
-
| Mistake | Fix |
|
|
486
|
-
|---------|-----|
|
|
487
|
-
| Reading only `task-catalog.json` (stale data) | Always re-read each `task-manifest.json` directly |
|
|
488
|
-
| Skipping a task because its report cannot be parsed | Tag it `[NEEDS-OKSTRA-RUN]` or `[PARSE-ERROR]` and continue |
|
|
489
|
-
| Omitting the At a Glance section | This section is mandatory; place it immediately after the header |
|
|
490
|
-
| Using `workStatus` for the At a Glance status column | Use `taskType` instead — it carries lifecycle phase information |
|
|
491
|
-
| Creating a file when 0 tasks are included | Do not create any file in this case; just print the message |
|
|
492
|
-
| Skipping the Effort-to-Day total computation | Always compute and surface `<X.X> ~ <Y.Y> days` |
|
|
493
|
-
| Translating `## Risk Mitigation Strategy` → `## 위험 완화 전략` / `## Stratégie de Mitigation des Risques` (or similar) | Heading literals are part of the Section Contract — keep English |
|
|
494
|
-
| Translating the optional Gantt heading (`## Gantt 다이어그램`, `## Diagramme de Gantt`) | Use `## Gantt Chart` literally |
|
|
495
|
-
| Adding `## Cumulative Timeline` (or any translated form) | Removed from the contract — do not emit |
|
|
496
|
-
| Inventing extra top-level sections (`## Effort-to-Day 매핑`, `## Référentiel …`) when source data is rich | Sizing tables belong in `### Effort Sizing 기준`; `## Gantt Chart` is the only allowed extra `##` section (English heading) |
|
|
497
|
-
| Rendering the Gantt axis with calendar dates / today-anchored labels | Axis MUST be relative day-counts (`Day 1`, `J1`, …); never `2026-05-04` or `오늘 + 3일` |
|
|
498
|
-
| Mixing French (`Charge estimée`, `Catégorie`, `Risque`, `Dépôt`) into per-task blocks | Use `**Category**`/`**Risk**`/`**Repo**` etc. — English field labels only |
|
|
499
|
-
| Mirroring source-report language into headings (French source → French headings, Korean source → Korean headings) | Headings + per-task field labels are English literals regardless of source language |
|
|
500
|
-
| Emitting a Consolidated User Decision Checklist or per-task 사용자 확인 필요 항목 from old templates | Forbidden — schedule is client-facing; surface those items only in internal reports |
|
|
501
|
-
| Title written as `작업 일정 계획서` instead of `— Work Schedule` | The English suffix is part of the contract — fix and re-run validator |
|
|
146
|
+
- Use `taskType` (not `workStatus`) for the At a Glance status column — it carries lifecycle phase information.
|