okstra 0.201.3 → 0.202.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.
Files changed (41) hide show
  1. package/dist/commands/lifecycle/setup.mjs +15 -0
  2. package/dist/commands/lifecycle/setup.mjs.map +1 -1
  3. package/dist/lib/citation-guidance.d.mts +21 -0
  4. package/dist/lib/citation-guidance.mjs +79 -0
  5. package/dist/lib/citation-guidance.mjs.map +1 -0
  6. package/docs/architecture/storage-model.md +4 -0
  7. package/docs/architecture.md +1 -1
  8. package/docs/cli.md +2 -2
  9. package/docs/for-ai/skills/okstra-manager.md +21 -4
  10. package/docs/for-ai/skills/okstra-setup.md +9 -0
  11. package/docs/project-structure-overview.md +4 -1
  12. package/package.json +1 -1
  13. package/runtime/BUILD.json +2 -2
  14. package/runtime/prompts/launch.template.md +1 -1
  15. package/runtime/prompts/lead/okstra-lead-contract.md +2 -2
  16. package/runtime/prompts/profiles/_implementation-verifier.md +1 -1
  17. package/runtime/prompts/profiles/implementation-planning.md +2 -0
  18. package/runtime/python/okstra_ctl/convergence_critic_prompt.py +4 -6
  19. package/runtime/python/okstra_ctl/convergence_provenance.py +75 -18
  20. package/runtime/python/okstra_ctl/execution_mutation_audit.py +21 -21
  21. package/runtime/python/okstra_ctl/manager_cli.py +85 -12
  22. package/runtime/python/okstra_ctl/manager_launch.py +40 -18
  23. package/runtime/python/okstra_ctl/manager_paths.py +8 -0
  24. package/runtime/python/okstra_ctl/manager_split.py +474 -0
  25. package/runtime/python/okstra_ctl/manager_store.py +121 -18
  26. package/runtime/python/okstra_ctl/manager_sync.py +33 -15
  27. package/runtime/python/okstra_ctl/manager_view.py +216 -0
  28. package/runtime/python/okstra_ctl/plan_items_cli.py +6 -1
  29. package/runtime/python/okstra_ctl/qa_commands.py +15 -0
  30. package/runtime/python/okstra_ctl/report_finalize.py +13 -6
  31. package/runtime/python/okstra_ctl/report_html/view_models/final_verification.py +2 -21
  32. package/runtime/python/okstra_ctl/report_html/visualizations.py +0 -5
  33. package/runtime/python/okstra_ctl/verification_target.py +13 -2
  34. package/runtime/skills/okstra-manager/SKILL.md +53 -4
  35. package/runtime/skills/okstra-run/SKILL.md +1 -1
  36. package/runtime/skills/okstra-setup/SKILL.md +9 -0
  37. package/runtime/templates/manager/view.template.html +108 -0
  38. package/runtime/templates/reports/html/i18n/en.json +2 -0
  39. package/runtime/templates/reports/html/i18n/ko.json +2 -0
  40. package/runtime/templates/reports/html/tasks/final-verification.template.html +2 -2
  41. package/runtime/validators/validate-brief.py +7 -2
@@ -2,6 +2,7 @@ import { promises as fs } from "node:fs";
2
2
  import { createInterface } from "node:readline";
3
3
  import { homedir } from "node:os";
4
4
  import { join, resolve as resolvePath } from "node:path";
5
+ import { ensureCitationGuidance } from "../../lib/citation-guidance.mjs";
5
6
  import { buildPythonpath, resolvePaths } from "../../lib/paths.mjs";
6
7
  import { errorCode, errorMessage, fileExists, runProcess } from "../../lib/proc.mjs";
7
8
  const USAGE = `okstra setup — register the current project with okstra
@@ -20,6 +21,9 @@ Usage:
20
21
  on the command line
21
22
 
22
23
  Behavior:
24
+ - If <PROJECT_ROOT>/CLAUDE.md or AGENTS.md exists, an okstra-managed block is
25
+ appended (or refreshed) telling agents not to cite okstra-internal ids and
26
+ .okstra/ paths outside okstra reports. Neither file is created.
23
27
  - If project.json already exists, the projectId must match (okstra refuses
24
28
  to silently rename a project). Delete the file manually if you really
25
29
  want to change projectId.
@@ -229,11 +233,22 @@ export async function run(args) {
229
233
  process.stderr.write(`warning: failed to provision .claude/settings.local.json symlink — ` +
230
234
  `host Claude Code sessions in this project may need to add wrapper permissions manually. (${errorMessage(err)})\n`);
231
235
  }
236
+ // 프로젝트에 host 지침 문서(CLAUDE.md / AGENTS.md)가 이미 있으면, okstra 산출물
237
+ // 인용 규율 블록을 그 끝에 심는다. 없는 파일은 만들지 않는다.
238
+ let citationGuidance = [];
239
+ try {
240
+ citationGuidance = await ensureCitationGuidance(projectRoot);
241
+ }
242
+ catch (err) {
243
+ process.stderr.write(`warning: failed to update okstra citation guidance in CLAUDE.md / AGENTS.md — ` +
244
+ `agents in this project may quote okstra-internal ids in non-okstra writing. (${errorMessage(err)})\n`);
245
+ }
232
246
  process.stdout.write(JSON.stringify({
233
247
  ok: true,
234
248
  ...result,
235
249
  projectJsonPath,
236
250
  settingsLocalJson: settingsSymlink,
251
+ citationGuidance,
237
252
  }, null, 2) + "\n");
238
253
  return 0;
239
254
  }
@@ -1 +1 @@
1
- {"version":3,"file":"setup.mjs","sourceRoot":"","sources":["../../../src/commands/lifecycle/setup.mts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"setup.mjs","sourceRoot":"","sources":["../../../src/commands/lifecycle/setup.mts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export declare const GUIDANCE_BEGIN = "<!-- okstra:citation-guidance:begin -->";
2
+ export declare const GUIDANCE_END = "<!-- okstra:citation-guidance:end -->";
3
+ /** 관리 대상 host 지침 문서. 존재하는 것만 갱신한다. */
4
+ export declare const GUIDANCE_TARGET_FILES: readonly ["CLAUDE.md", "AGENTS.md"];
5
+ /** 마커로 감싼 블록 전문. 앞뒤 개행은 붙이는 쪽에서 관리한다. */
6
+ export declare function renderGuidanceBlock(): string;
7
+ /**
8
+ * 문서 본문에 블록을 반영한 결과를 돌려준다. 기존 블록이 있으면 그 자리에서
9
+ * 교체하고(문안이 바뀌어도 사용자가 쓴 앞부분은 그대로), 없으면 문서 끝에
10
+ * 붙인다. 내용이 이미 같으면 `changed: false` 로 파일을 건드리지 않는다.
11
+ */
12
+ export declare function applyGuidance(content: string): {
13
+ content: string;
14
+ changed: boolean;
15
+ };
16
+ /**
17
+ * 프로젝트 루트의 host 지침 문서를 갱신하고, 실제로 쓴 파일 경로를 돌려준다.
18
+ * 없는 파일은 건너뛴다. `AGENTS.md` 가 `CLAUDE.md` 심링크인 흔한 배치에서는
19
+ * 같은 실파일을 두 번 쓰지 않도록 realpath 로 중복을 제거한다.
20
+ */
21
+ export declare function ensureCitationGuidance(projectRoot: string): Promise<string[]>;
@@ -0,0 +1,79 @@
1
+ // okstra 산출물 인용 규율 블록을 대상 프로젝트의 host 지침 문서에 심는다.
2
+ //
3
+ // 배경: okstra 리포트는 `.okstra/` 안의 독자를 전제로 내부 식별자(리포트 절
4
+ // 번호, `C-001` 같은 clarification id, run/stage id, `.okstra/...` 경로)를
5
+ // 쓴다. 에이전트가 같은 식별자를 리포트 밖 글(대화 답변, 커밋/PR 본문,
6
+ // 프로젝트 문서)에 그대로 옮기면 독자는 그 참조를 해석할 수 없다.
7
+ //
8
+ // 이 모듈은 `okstra setup` 이 프로젝트 루트에 **이미 있는** `CLAUDE.md` /
9
+ // `AGENTS.md` 끝에 붙이는 관리 블록을 렌더하고 적용한다. 두 파일을 새로
10
+ // 만들지는 않는다 — 없는 프로젝트는 host 지침 문서를 쓰지 않는다는 뜻이다.
11
+ // 마커 규약은 `scripts/okstra_ctl/group_context.py` 의 task-memory 영역과 같다.
12
+ import { promises as fs } from "node:fs";
13
+ import { join } from "node:path";
14
+ export const GUIDANCE_BEGIN = "<!-- okstra:citation-guidance:begin -->";
15
+ export const GUIDANCE_END = "<!-- okstra:citation-guidance:end -->";
16
+ /** 관리 대상 host 지침 문서. 존재하는 것만 갱신한다. */
17
+ export const GUIDANCE_TARGET_FILES = ["CLAUDE.md", "AGENTS.md"];
18
+ const GUIDANCE_BODY = [
19
+ "<!-- Managed by `okstra setup`. Edit above this block; this region is rewritten on each setup run. -->",
20
+ "",
21
+ "## Citing okstra artifacts",
22
+ "",
23
+ "okstra keeps its reports, decisions, and ledgers under `.okstra/`, written for readers of those reports.",
24
+ "Outside an okstra report — chat answers, commit messages, PR bodies, project docs, issue comments — do not",
25
+ "cite okstra-internal references (report section numbers, finding or clarification ids such as `C-001`,",
26
+ "run and stage ids, `.okstra/...` paths) as if the reader could resolve them. State the finding itself and",
27
+ "cite source code as `path:line`; name an okstra file only when the reader has been pointed to it.",
28
+ ].join("\n");
29
+ /** 마커로 감싼 블록 전문. 앞뒤 개행은 붙이는 쪽에서 관리한다. */
30
+ export function renderGuidanceBlock() {
31
+ return `${GUIDANCE_BEGIN}\n${GUIDANCE_BODY}\n${GUIDANCE_END}`;
32
+ }
33
+ /**
34
+ * 문서 본문에 블록을 반영한 결과를 돌려준다. 기존 블록이 있으면 그 자리에서
35
+ * 교체하고(문안이 바뀌어도 사용자가 쓴 앞부분은 그대로), 없으면 문서 끝에
36
+ * 붙인다. 내용이 이미 같으면 `changed: false` 로 파일을 건드리지 않는다.
37
+ */
38
+ export function applyGuidance(content) {
39
+ const block = renderGuidanceBlock();
40
+ const begin = content.indexOf(GUIDANCE_BEGIN);
41
+ const end = content.indexOf(GUIDANCE_END);
42
+ if (begin !== -1 && end > begin) {
43
+ const next = content.slice(0, begin) + block + content.slice(end + GUIDANCE_END.length);
44
+ return { content: next, changed: next !== content };
45
+ }
46
+ const base = content.replace(/\s*$/, "");
47
+ const next = base.length === 0 ? `${block}\n` : `${base}\n\n${block}\n`;
48
+ return { content: next, changed: true };
49
+ }
50
+ /**
51
+ * 프로젝트 루트의 host 지침 문서를 갱신하고, 실제로 쓴 파일 경로를 돌려준다.
52
+ * 없는 파일은 건너뛴다. `AGENTS.md` 가 `CLAUDE.md` 심링크인 흔한 배치에서는
53
+ * 같은 실파일을 두 번 쓰지 않도록 realpath 로 중복을 제거한다.
54
+ */
55
+ export async function ensureCitationGuidance(projectRoot) {
56
+ const written = [];
57
+ const seen = new Set();
58
+ for (const name of GUIDANCE_TARGET_FILES) {
59
+ const target = join(projectRoot, name);
60
+ let real;
61
+ try {
62
+ real = await fs.realpath(target);
63
+ }
64
+ catch {
65
+ continue; // 파일이 없거나 끊어진 심링크 — okstra 가 새로 만들지는 않는다.
66
+ }
67
+ if (seen.has(real))
68
+ continue;
69
+ seen.add(real);
70
+ const content = await fs.readFile(target, "utf8");
71
+ const applied = applyGuidance(content);
72
+ if (!applied.changed)
73
+ continue;
74
+ await fs.writeFile(target, applied.content, "utf8");
75
+ written.push(target);
76
+ }
77
+ return written;
78
+ }
79
+ //# sourceMappingURL=citation-guidance.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"citation-guidance.mjs","sourceRoot":"","sources":["../../src/lib/citation-guidance.mts"],"names":[],"mappings":"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"}
@@ -220,11 +220,13 @@ The following former files are no longer generated by okstra.
220
220
  ~/.okstra/managers/<manager-id>/
221
221
  ├── manager.json
222
222
  ├── projects.json
223
+ ├── view/index.html
223
224
  └── task-groups/<safe-task-group>/<safe-task-id>/
224
225
  ├── manifest.json
225
226
  ├── children.json
226
227
  ├── directives.jsonl
227
228
  ├── snapshots.json
229
+ ├── split-plan.json
228
230
  ├── events.jsonl
229
231
  └── child-context/<safe-project-id>-<safe-child-task-id>.md
230
232
  ```
@@ -234,9 +236,11 @@ Storage authority:
234
236
  - `manager.json`: manager identity and schema version.
235
237
  - `projects.json`: the projectId / projectRoot / role / tags registered with the manager. `projectRoot` must be an existing directory, and setup-equivalent registration is performed only when project-local `.okstra/project.json` is absent.
236
238
  - `manifest.json`, `children.json`, `directives.jsonl`: manager-owned plan, child assignment, and shared/project directives.
239
+ - `split-plan.json`: the last tracker split plan `task split` applied. The briefs it produced live in each child project's `.okstra/briefs/`, and the children it registered carry `ticketId`, `briefPath`, `scope` and `recommendedPhase` in `children.json`.
237
240
  - `snapshots.json`: a read-side snapshot that `task sync` imports from the child project's `.okstra`. It is not the source of truth for project state.
238
241
  - `events.jsonl`: manager events such as `task-created` and `child-launch-prepared`.
239
242
  - `child-context/*.md`: child lead context prepared by `task run`. Sibling project reports/snapshots are passed only as read-side source material.
243
+ - `view/index.html`: the page `okstra manager view` writes from the files above. It is a derived view, rewritten on every run; it does not read child projects, so it shows each task as of its last `task sync`.
240
244
 
241
245
  Path segments are normalized into slugs. If a slug would be empty, as can happen with non-ASCII values, a `u-<sha1-prefix>` fallback segment is used. However, `manifest.json` and the child `taskKey` preserve the original input values (`project-id:task-group:task-id`).
242
246
 
@@ -128,7 +128,7 @@ Runtime entry points are consolidated in Python packages. Bash and skills only c
128
128
  - [`okstra_ctl.session`](../scripts/okstra_ctl/session.py) · [`okstra_ctl.seeding`](../scripts/okstra_ctl/seeding.py) — Claude session ID / resume command / installation validation / runtime settings.
129
129
  - [`okstra_ctl.{ids,index,invocation,jsonl,project_meta,reconcile,sequence,backfill,listing,locks}`](../scripts/okstra_ctl/) — existing central-index (`~/.okstra`) modules.
130
130
  - [`okstra_project.{resolver,state}`](../scripts/okstra_project/) — PROJECT_ROOT resolution + project.json upsert + task-catalog/manifest reader.
131
- - [`okstra_ctl.manager_cli`](../scripts/okstra_ctl/manager_cli.py), [`manager_store`](../scripts/okstra_ctl/manager_store.py), [`manager_sync`](../scripts/okstra_ctl/manager_sync.py), [`manager_launch`](../scripts/okstra_ctl/manager_launch.py), [`manager_paths`](../scripts/okstra_ctl/manager_paths.py) — cross-project manager state, one-way project snapshot sync, and child launch packet/context creation for `okstra manager`.
131
+ - [`okstra_ctl.manager_cli`](../scripts/okstra_ctl/manager_cli.py), [`manager_store`](../scripts/okstra_ctl/manager_store.py), [`manager_sync`](../scripts/okstra_ctl/manager_sync.py), [`manager_launch`](../scripts/okstra_ctl/manager_launch.py), [`manager_paths`](../scripts/okstra_ctl/manager_paths.py), [`manager_view`](../scripts/okstra_ctl/manager_view.py), [`manager_split`](../scripts/okstra_ctl/manager_split.py) — cross-project manager state, one-way project snapshot sync, child launch packet/context creation, the HTML overview page, and tracker split into per-project scoped briefs for `okstra manager`.
132
132
 
133
133
  ### Bash entry points (thin)
134
134
 
package/docs/cli.md CHANGED
@@ -823,7 +823,7 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
823
823
  | `okstra doctor [--runtime claude-code\|codex\|antigravity\|external\|all] [--phase <phase>] [--json]` | Diagnose the runtime, Python imports, skill/agent installation, and model-pool state. The JSON `modelPool` object reports pool errors, default errors, binding precision, observed model, max write boundary, and invocation downgrade reason. It never sends an inference call. The `codex`, `antigravity`, and `external` runtimes omit Claude skill checks. `--phase` adds readiness checks for `implementation`, `final-verification`, `release-handoff`, or `improvement-discovery` |
824
824
  | `okstra model list [--role <role>] [--host <host>] [--json]` | List catalog models for a host and optional role. Unselectable exact bindings report `exact binding unavailable`. No inference call |
825
825
  | `okstra model default set\|unset <role> ... --scope project\|global [--cwd <dir>]` | Atomically write or remove `modelDefaults` for one canonical role |
826
- | `okstra setup --project-id <id>` | Create or update `.okstra/project.json` in the current project |
826
+ | `okstra setup --project-id <id>` | Create or update `.okstra/project.json` in the current project. When `<PROJECT_ROOT>/CLAUDE.md` or `AGENTS.md` already exists, it also appends — or refreshes in place — an okstra-managed block between `<!-- okstra:citation-guidance:begin -->` / `end` telling agents not to cite okstra-internal references (report section numbers, `C-NNN` ids, run/stage ids, `.okstra/...` paths) outside an okstra report. Neither file is created, and a failure is a warning, not an error |
827
827
  | `okstra check-project [--json]` | Verify that the current project is registered |
828
828
  | `okstra preflight [--runtime <name>] [--cwd <dir>] [--machine]` | Single skill-preflight call combining `ensure-installed`, with silent reinstall when stale, `check-project`, and host-specific `runtimeReadiness`. It defaults to a fixed text projection. `--machine` returns the automation JSON contract, and `--json` is a deprecated one-release alias. A `claude-code` host checks project workspace trust. A `codex` current-session host verifies write access to `~/.okstra/worktrees/registry.lock`; a sandbox denial blocks before the wizard with the `switch-codex-to-full-access-and-rerun` action. `antigravity` and `external` hosts return ready without reading Claude Code state. Step 0 of every project-scoped skill converges on this command |
829
829
  | `okstra convergence seed --groups <path> --work-state <path> --final-state <path> --migration-dir <dir> [--restart-from-round0]` | Create, resume, reuse, or explicitly recover deterministic convergence state |
@@ -856,7 +856,7 @@ The `okstra` Node CLI (`bin/okstra`) provides both installer/admin commands and
856
856
  | `okstra model-io active-context-input --project-root <dir> --run-manifest <path>` | Resolve the prior implementation-planning active context only through the current project and run authority, then emit fixed fields such as the executor base ref. Caller-supplied active-context paths are not accepted. |
857
857
  | `okstra report-translate <source\|write\|check-data> --run-manifest <path> …` | Resolve the report data and translation sidecar from the run manifest. `source` emits a source digest with the fixed translation queue; `write` requires that digest and rejects a stale report; `check-data` verifies the derived sidecar. Models never choose the data or sidecar path. |
858
858
  | `okstra convergence prepare-groups --run-manifest <path> --input <grouping.md>` | Parse fixed grouping Markdown, validate distinct per-worker evidence and group semantics against the run authority, then publish the schema-valid groups artifact at the run-owned path. |
859
- | `okstra manager <init\|discover-projects\|new\|task> [--json]` | Public CLI for grouping cross-project okstra tasks into manager-owned context. The default is purpose-specific fixed text for model use; `--json` preserves the machine contract and exit codes. `new project --project-root` accepts only existing directories and performs setup-equivalent registration only if `.okstra/project.json` is absent. |
859
+ | `okstra manager <init\|discover-projects\|new\|task\|list\|view> [--json]` | Public CLI for grouping cross-project okstra tasks into manager-owned context. The default is purpose-specific fixed text for model use; `--json` preserves the machine contract and exit codes. `new project --project-root` accepts only existing directories and performs setup-equivalent registration only if `.okstra/project.json` is absent. `list managers`, `list projects --manager-id <id>` and `list tasks --manager-id <id>` enumerate manager state; `view --manager-id <id>` writes `~/.okstra/managers/<id>/view/index.html` and prints its path and `file://` URL. `task split --plan <json>` writes one validated brief with a `## Project Scope` section into each project an issue is assigned to and registers those children; `task run` then passes `--task-brief`. |
860
860
  | `okstra rollup [--task-group <group>] [--project-root <dir>] [--cwd <dir>] [--text\|--json]` | Read-only backend for the okstra-rollup skill. `--text` emits ordered fixed labels for model use. The default and `--json` preserve the full machine JSON contract and exit codes. Omitting `--task-group` targets the whole project catalog. |
861
861
  | `okstra usage-report [--days <positive-int>] [--project-root <dir>] [--cwd <dir>] [--text\|--json]` | Read-only backend for the okstra-usage skill. `--text` emits ordered fixed labels for model use. The default and `--json` preserve the full machine JSON contract and exit codes. Defaults to the current project's last 30 days. |
862
862
  | `okstra worker-state transition --team-state <path> --worker <id> --status <in-progress\|completed\|timeout\|error\|not-run> [--reason <text>] [--model <execution-value>]` | Atomically update one persisted worker row. `in-progress` records the authoritative `startedAt` and clears `endedAt`; terminal states record `endedAt`; `timeout`, `error`, and `not-run` require a reason. Dispatch adapters use this same transition path, so CLI-backed and in-process orchestration share the status timestamp contract |
@@ -33,8 +33,19 @@ okstra manager task note --manager-id <manager-id> --task-group <task-group> --t
33
33
  okstra manager task sync --manager-id <manager-id> --task-group <task-group> --task-id <task-id>
34
34
  okstra manager task status --manager-id <manager-id> --task-group <task-group> --task-id <task-id>
35
35
  okstra manager task run --manager-id <manager-id> --project-id <project-id> --task-group <task-group> --task-id <task-id> [--child-task-id <child-task-id>]
36
+ okstra manager task split --manager-id <manager-id> --task-group <task-group> --task-id <task-id> --plan <split-plan.json> [--overwrite]
37
+ okstra manager list managers
38
+ okstra manager list projects --manager-id <manager-id>
39
+ okstra manager list tasks --manager-id <manager-id>
40
+ okstra manager view --manager-id <manager-id>
36
41
  ```
37
42
 
43
+ - `list managers`: every manager in this home with its project count and manager-task count.
44
+ - `list projects`: the manager's registered projects with root, role, tags and link time.
45
+ - `list tasks`: the manager's tasks by task-group and task-id with objective, progress mode and child count.
46
+ - `task split`: reads a tracker split plan (one Linear project or parent issue, each issue assigned to one or more projects with a scope), writes one brief per (issue, project) pair to `<projectRoot>/.okstra/briefs/<task-group>/<ticketId>-<file-title>.md` with a `## Project Scope` section, and registers each pair as child `<project-id>:<task-group>:<slug(ticketId)>`. Every brief passes the brief validator before any file is written; an existing brief with different content stops the run unless `--overwrite` is given. The skill's Tracker Split section defines the plan JSON and the fetch/confirm procedure.
47
+ - `view`: writes `view/index.html` (summary tiles, project table, one panel per task with child rows, directives and events) and returns `View path` and `View URL`. It does not sync; each panel shows its last sync time and the sync command.
48
+
38
49
  ## Storage Model
39
50
 
40
51
  Manager state is stored under `~/.okstra/managers/<manager-id>/`, split into two layers: the manager root and the task directory.
@@ -47,11 +58,13 @@ Directly under the manager root:
47
58
  Under the task directory `task-groups/<safe-group>/<safe-task>/`:
48
59
 
49
60
  - `manifest.json`: manager task objective, common brief, progress mode
50
- - `children.json`: child task plan, assignment, launch metadata
61
+ - `children.json`: child task plan, assignment, launch metadata; children made by `task split` also carry `ticketId`, `briefPath`, `scope` and `recommendedPhase`
62
+ - `split-plan.json`: the last plan `task split` applied
51
63
  - `directives.jsonl`: shared/project directive rows
52
64
  - `snapshots.json`: the read-side snapshot `task sync` read from the project-local `.okstra`
53
- - `events.jsonl`: manager events such as `task-created` and `child-launch-prepared`
65
+ - `events.jsonl`: manager events such as `task-created`, `task-split` and `child-launch-prepared`
54
66
  - `child-context/<safe-project>-<safe-task>.md`: the child lead context `task run` produced
67
+ - `view/index.html` (under the manager root): the overview page `view` writes; rewritten on every run
55
68
 
56
69
  A segment whose slug is empty (e.g. a non-ASCII task-group/task-id) uses a `u-<sha1-prefix>` path segment, but the manifest and the child `taskKey` preserve the original input value.
57
70
 
@@ -60,10 +73,14 @@ A segment whose slug is empty (e.g. a non-ASCII task-group/task-id) uses a `u-<s
60
73
  `task run` does not run the child work directly; it prepares a launch packet. The key fixed fields of the returned packet:
61
74
 
62
75
  - `Task key`: the child's `project-id:task-group:task-id` (the public child-identity key — also recorded on the `child-launch-prepared` event)
63
- - `Backend`: always `subagent-child-lead`
76
+ - `Backend`: always `spawn-process` — the child lead runs as a separate host process started by the installed launcher
64
77
  - `Worker dispatch backend`: always `subagent` in v1
65
78
  - `Project root`: the child project root
66
79
  - `Context path`: the manager child context markdown
67
- - every numbered `Run arg N`: the ordered `okstra run ... --directive "Read manager child context: ..."` arguments for the host launcher to use
80
+ - `Run command`: the installed launcher, `~/.okstra/bin/okstra.sh`
81
+ - every numbered `Run arg N`: the ordered launcher arguments `--project-root … --project-id … --task-group … --task-id … --directive "Read manager child context: …"`. A child made by `task split` also gets `--task-brief <briefPath>`, and `--task-type <recommendedPhase>` while the child task does not exist yet in its project
82
+ - `Shell command`: `Run command` plus every `Run arg N`, shell-quoted; the skill hands this line to the user to run in a new terminal
83
+
84
+ The launcher fills the task type and brief from the child task manifest when it exists and asks for the rest, then prepares the run and starts the lead with the directive in its prompt. `okstra run` is not a substitute: for a lead host it adds `--launch-only`, which drops the task inputs and the directive.
68
85
 
69
86
  When packet creation succeeds, that child launch's status in `children.json` is updated to `prepared`, and a `child-launch-prepared` is appended to `events.jsonl`. On failure it does not modify the project-local task state.
@@ -91,6 +91,15 @@ Create command:
91
91
  okstra setup --yes --project-root /abs/project --project-id my-project
92
92
  ```
93
93
 
94
+ `okstra setup` also refreshes the okstra-managed citation-guidance block in
95
+ `<PROJECT_ROOT>/CLAUDE.md` and `AGENTS.md` when those files already exist (it never
96
+ creates them). The block tells agents not to carry okstra-internal references — report
97
+ section numbers, `C-NNN` clarification ids, run/stage ids, `.okstra/...` paths — into
98
+ writing that is not an okstra report, where the reader cannot resolve them. The command
99
+ reports the files it touched in its JSON `citationGuidance` array; a failure there is a
100
+ `warning:` line, not a non-zero exit. Tell the user which guidance files were updated so
101
+ they can review the appended block.
102
+
94
103
  ## Optional configuration
95
104
 
96
105
  Per the source, Step 3.5 is optional configuration performed only when the user explicitly wants it — read `references/project-config.md` in the skill directory for the detailed procedure. If the defaults are enough, skip it and go to doctor.
@@ -327,10 +327,13 @@ Important modules:
327
327
  | `plan_run_root.py` | shared helper deriving `approved_plan_path` → `plan_run_root` and back-tracing the task-key |
328
328
  | `manager_cli.py` | `okstra manager` Python entrypoint — purpose-specific fixed text by default, machine JSON with `--json` |
329
329
  | `manager_paths.py` | Manager state path SSOT under `~/.okstra/managers/<manager-id>/`; slug fallback uses `u-<sha1-prefix>` when a safe segment would be empty |
330
- | `manager_store.py` | Manager-owned state mutation — project membership, task planning, assignment, directives, event append |
330
+ | `manager_store.py` | Manager-owned state mutation — project membership, task planning, assignment, directives, event append — plus the `list managers/projects/tasks` readers |
331
331
  | `manager_sync.py` | One-way child project `.okstra` snapshot reader; corrupt child state becomes row-level `error` so other children continue |
332
332
  | `manager_launch.py` | Child launch packet and manager child context renderer; records `prepared` launch metadata/events without changing project-local task state |
333
+ | `manager_view.py` | `okstra manager view` — renders one manager's projects, tasks, child summaries, directives and events into `view/index.html` from `templates/manager/view.template.html`; reads manager-owned files only |
334
+ | `manager_split.py` | `okstra manager task split` — validates a tracker split plan, renders one brief per (issue, project) with a `## Project Scope` section, checks each with `validators/validate-brief.py` before writing, and registers the children |
333
335
  | `agent/invocation.py` | Deep invocation-contract module — composes model assignment, common/functional duty, and task instructions; publishes immutable prompt/metadata pairs; verifies five digests; owns standalone result/completion envelopes |
336
+ | `agent/evidence_recovery.py` | Issues a same-model, same-role evidence-recovery invocation over a terminal-state attempt — verifies the source invocation metadata and existing result, then republishes a suffixed prompt/metadata/result triple (`-evidence-recovery-<attempt>`) that preserves the original model assignment while confining the child to preserving the earlier result's evidence rather than re-running the completed work (`prepare_evidence_recovery`, driven from `dispatch_core`) |
334
337
  | `agent/prompt_cli/` | CLI boundary for run-backed and standalone materialization/verification plus host-native dispatch and result-link records. `inputs` resolves the path arguments this model-facing surface cannot trust and `emit` writes the result; above them `run_identity` refuses a role the run never issued and `dynamic_verifier` reserves a re-verification slot only after that role qualifies; `materialize` authors the specification (every report-writer prompt gets the okstra-rendered `## Output`; with `--corrections` it runs the ledger check in `corrections` and prepends `## Corrections`; without one it refuses a corrective dispatch over a parsing narrative), `results` links what came back, and `cli` is the argparse surface with the command's canonical USAGE epilog (`check-corrections` runs the ledger check without materializing; `apply-corrections` writes a mechanical ledger to the narrative and records the `lead-correction-applied` activity row via `corrections.run_corrections_apply`) |
335
338
  | `dispatch_state.py` | Provider-neutral `WorkerJob`, invocation metadata validation, immutable host-native dispatch/result-link recording, and shared team-state mutation helpers |
336
339
  | `dispatch_core.py` | Backend-neutral worker dispatch core — verifies invocation metadata immediately before worker execution, then records and collects code-owned process/pane attempts shared by every lead runtime |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "okstra",
3
- "version": "0.201.3",
3
+ "version": "0.202.0",
4
4
  "description": "Host-aware multi-provider cross-verification orchestrator runtime and agent skills.",
5
5
  "license": "MIT",
6
6
  "author": "devonshin",
@@ -1,5 +1,5 @@
1
1
  {
2
- "package": "0.201.3",
3
- "builtAt": "2026-09-14T12:27:48.872Z",
2
+ "package": "0.202.0",
3
+ "builtAt": "2026-09-19T06:41:23.090Z",
4
4
  "repoRoot": "/home/runner/work/okstra/okstra"
5
5
  }
@@ -76,7 +76,7 @@ For every other task type:
76
76
  - Pointer `status: pending` with a `rationale` → the user's own input is what comes next. Quote the `rationale` and issue the command it names. Do not re-run the phase that just completed, and do not send the user to `/okstra-inspect`: a finished phase has nothing to inspect, and re-running it discards the result the user is being asked to act on.
77
77
  - Otherwise → `/okstra-inspect status` for this task.
78
78
 
79
- For file links in progress updates and closeout, use a short descriptive label in the Report Language, such as `[<선택 언어> 보고서 열기](<actual-report-path>)`, replacing `<선택 언어>` with the run's selected report language name. Put each link on its own line. Keep the complete destination on one source line without inserted newlines or spaces; never abbreviate the destination or repeat the long path beside the label. Use the verified destination from `reportPaths.markdown` or the launch prompt's run paths, changing only the display label. Commands stay in backticks.
79
+ For file links in progress updates and closeout, use a short descriptive label in the Report Language, such as `[<선택 언어> 보고서 열기](<absolute-report-path>)`, replacing `<선택 언어>` with the run's selected report language name. The destination is always an absolute path: a project-relative destination does not open when the host's working directory differs or the user opens the file in an external program. `reportPaths.markdown` destinations are already absolute; for a project-relative path from this prompt, prefix `{{PROJECT_ROOT}}/`. Wrap a destination that contains spaces in `<...>`. Put each link on its own line. Keep the complete destination on one source line without inserted newlines; never abbreviate the destination or repeat the long path beside the label. Change only the display label. Commands stay in backticks.
80
80
 
81
81
  Some terminal hosts expand Markdown links into visible paths. If that happens, provide a copyable file-opening command for the verified host OS in a code block, on one source line with the actual path safely shell-quoted (for example, `open` on macOS). Do not execute it unless asked. Do not promise that Markdown prevents visual wrapping, or create a shortened copy or symlink merely for display. This is presentation guidance, not runtime validation of the emitted message.
82
82
 
@@ -106,7 +106,7 @@ User-utterance interpretation rule:
106
106
 
107
107
  At each phase or implementation-stage boundary, at task completion, and before a controlled session pause or handoff, follow the launch prompt's "Progress, remaining work, and recommendation" guidance. Include the result and evidence, unfinished work and blockers, and the next action with its reason. During an authorized continuous run, deliver this update beside the checkpoint and continue; do not turn the update into an approval gate. The same guidance applies to the final reply after persistence below.
108
108
 
109
- Apply the launch prompt's file-link presentation guidance to these updates as well: short localized labels, one link per line, an intact verified destination, and a copyable file-opening command when the terminal expands links. Keep file links separate from the raw progress checkpoint line.
109
+ Apply the launch prompt's file-link presentation guidance to these updates as well: short localized labels, one link per line, an intact absolute destination, and a copyable file-opening command when the terminal expands links. Keep file links separate from the raw progress checkpoint line.
110
110
 
111
111
  Follow the launch prompt's operation-level progress guidance: name the actual prepared artifact or executed check, distinguish preparation from execution and results, and cite the observed error when blocked. Apply its existing-authorization guidance before asking about provider data transfer again; reuse approval for the same recipients and material while respecting separate host execution permission.
112
112
 
@@ -529,7 +529,7 @@ When the host native picker is available and two of those rows could apply, ask
529
529
 
530
530
  **Cite run-artifact paths, do not assemble them.** The `report-finalize` result's `reportPaths` carries this run's `humanReport`, `reportRecord`, `teamState`, and `renderFullCopy` command, each already rooted at the project (`.okstra/tasks/<task-group>/<task-id>/runs/...`). Every other run-artifact path the reply cites — the resume command among them — comes from the launch prompt's `## Manifests` / `## Run Paths` lists, which are rooted the same way. A path you compose from a `runs/<task-type>/...` pattern instead is identical across every task of that task-type, so it names no task and does not resolve from the project root either.
531
531
 
532
- Write file references as Markdown links with short labels in the Report Language, following the launch prompt's file-link presentation guidance. `reportPaths.markdown` supplies verified destinations for the report, report record, and team state; preserve those destinations and shorten only their display labels. Put each link on its own line without repeating the path in prose or inserting a line break inside the destination. Apply the same format to worker results, error logs, and briefs, using the project-rooted paths from `## Manifests` / `## Run Paths`. If the terminal expands links into long paths, offer the host-appropriate copyable file-opening command described in the launch prompt. Markdown alone does not guarantee clickable links in every terminal.
532
+ Write file references as Markdown links with short labels in the Report Language, following the launch prompt's file-link presentation guidance. `reportPaths.markdown` supplies absolute destinations for the report, report record, and team state; preserve those destinations and shorten only their display labels. Put each link on its own line without repeating the path in prose or inserting a line break inside the destination. Apply the same format to worker results, error logs, and briefs: take the project-rooted path from `## Manifests` / `## Run Paths` and prefix the absolute project root, so every link destination is absolute. Relative paths stay in commands, not in link destinations. If the terminal expands links into long paths, offer the host-appropriate copyable file-opening command described in the launch prompt. Markdown alone does not guarantee clickable links in every terminal.
533
533
 
534
534
  **Enforced:** `scripts/okstra_ctl/report_finalize.py` `_closeout_report_paths` builds the task-qualified paths and `closeout_command` builds the close, so neither is re-derived; `validators/validate_session_conformance.py` `_check_progress_checkpoints` requires the `phase-7-persist` checkpoint this phase opens with.
535
535
 
@@ -23,7 +23,7 @@ Every verifier acts as a QA gate, not just a diff reviewer. Trusting the executo
23
23
 
24
24
  ### Record the verification target
25
25
 
26
- Before each declared check, run `okstra verification-target --project-root <project-root> --run-manifest <run-manifest> --expected-head <executor-head> --command <exact-declared-command>` and preserve its JSON output under this run's artifact directory. This tool reads the active run's recorded worktree and checks its HEAD and source fingerprint; it never executes the command. Execute the declared command through the host's authorized tool with that worktree as its separate working-directory argument. Repeat the target check with `--baseline <saved-json>` after execution. Include both target-check results and the actual command outcome in `readOnlyCommandLog`.
26
+ Before each declared check, run `okstra verification-target --project-root <project-root> --run-manifest <run-manifest> --expected-head <executor-head> --command <exact-declared-command>` and preserve its JSON output under this run's artifact directory. This tool reads the active run's recorded worktree and checks its HEAD and source fingerprint; it never executes the command. Execute exactly the returned `target.command` through the host's authorized tool with `target.cwd` as its separate working-directory argument. The tool separates a legacy trailing `; existing helper: <file>:<lines>` annotation and removes a leading `cd` only when it names that exact worktree. Preserve `declaredCommand` and `commandAnnotation` when returned; never independently trim prose or rewrite shell syntax. Repeat the target check with the same original declaration and `--baseline <saved-json>` after execution. Include both target-check results and the actual command outcome in `readOnlyCommandLog`. Enforcement: `capture_verification_target` and `test_verification_target_returns_one_command_without_executing_it`.
27
27
 
28
28
  A target mismatch or changed fingerprint invalidates this check's evidence. Record it as an execution-target problem, preserve the source, and rerun only the affected verification after the lead resolves it. An unavailable environment or a check that never ran is not a code rejection. A matching target fingerprint proves source stability at the two observations; it does not prove the command ran or that the test covers the requirement. Keep the independent command outcome and coverage assessment.
29
29
 
@@ -1,5 +1,7 @@
1
1
  # Implementation Planning Profile
2
2
 
3
+ Keep `commandOrObservation` executable when the checklist calls for a command. Put explanations and existing-helper citations in the checklist's `check` text, outside the command. Do not append prose after a semicolon. The plan-item renderer separates legacy `existing helper: <file>:<lines>` suffixes, and `verification-target` supplies the same executable command to every verifier.
4
+
3
5
  Validation commands are executable inputs: preserve their newlines, quotes, and code bodies. Use frozen dependency installation (`npm ci`, `pnpm install --frozen-lockfile`, or the package manager's equivalent). Name QA scripts with absolute task-artifact paths when a command runs from a stage worktree; `.okstra/tasks/...` relative to that worktree does not point to the project task. `stage_validation_executability_errors` enforces command restrictions at planning validation, implementation entry, and report preflight, including advisory plan-body runs.
4
6
 
5
7
  Plan for the actual worktree layout before approval. Shared documentation directories can be links to the main checkout. Choose a build command compatible with those links (for example, an installed Next.js version may provide `next build --webpack`); verify the available option rather than assuming it. Do not plan for a verifier to move links or repair its environment. Compare negative-case assertions with the brief and the script body: a requirement to cache existing assets does not establish that missing assets should be cached. Record any changed expectation in a new plan revision; preserve the earlier approved plan.
@@ -28,7 +28,7 @@ from dataclasses import dataclass
28
28
  from pathlib import Path
29
29
  from typing import Any, Mapping, Sequence
30
30
 
31
- from .convergence_provenance import worker_result_suffix
31
+ from .convergence_provenance import worker_result_paths, worker_result_suffix
32
32
  from .fixed_text import line
33
33
  from .json_boundary import JsonBoundaryError, load_owned_object
34
34
  from .paths import RunRef
@@ -132,9 +132,7 @@ def analyser_results(
132
132
  ) -> list[AnalyserResult]:
133
133
  """분석 audience 워커마다 결과 파일 경로와 finding id 를 짝지어 돌려준다.
134
134
 
135
- 결과 파일명은 `convergence_provenance` 가 이미 소유한 규칙을 그대로 쓴다 —
136
- `<worker>-worker-<task-type>-<workerResults seq>.md`. state 시퀀스와 다른
137
- 카운터라 그룹 파일명에서 접미사를 빌려 오면 빗나간다.
135
+ 출처 검사와 같은 실행 원장을 사용해야 교정 전 결과를 재검증하지 않는다.
138
136
  """
139
137
  suffix = worker_result_suffix(Path(run_dir), groups)
140
138
  if suffix is None:
@@ -142,13 +140,13 @@ def analyser_results(
142
140
  "cannot resolve the worker-result suffix from the grouping's "
143
141
  "runManifestPath"
144
142
  )
145
- results_dir = Path(run_dir) / "worker-results"
143
+ paths = worker_result_paths(Path(run_dir), groups, suffix)
146
144
  by_worker = _findings_by_worker(groups)
147
145
  return [
148
146
  AnalyserResult(
149
147
  worker_id=worker,
150
148
  result_path=_project_relative(
151
- project_root, results_dir / f"{worker}-worker-{suffix}.md"
149
+ project_root, paths[worker]
152
150
  ),
153
151
  finding_ids=tuple(by_worker.get(worker, ())),
154
152
  )
@@ -21,6 +21,8 @@ from pathlib import Path
21
21
  from typing import Mapping
22
22
 
23
23
  from okstra_ctl.convergence_engine import grouped_input_digest
24
+ from okstra_ctl.execution_identity import Attempt, ExecutionManifest
25
+ from okstra_ctl.execution_manifest import read_execution_manifest_view
24
26
  from okstra_ctl.json_boundary import (
25
27
  load_owned_object,
26
28
  )
@@ -97,6 +99,66 @@ def groups_digest_ok(state_dir: Path, suffix: str, document: dict) -> bool:
97
99
  return grouped_input_digest(document) == recorded
98
100
 
99
101
 
102
+ def discovery_attempts(manifest: ExecutionManifest) -> dict[str, list[Attempt]]:
103
+ """교정 실행은 발견 결과를 대체하지만 재검증 투표는 발견 출처가 아니다."""
104
+ latest: dict[str, Attempt] = {}
105
+ for attempt in manifest.attempts:
106
+ current = latest.get(attempt.invocation_ref)
107
+ if current is None or attempt.attempt > current.attempt:
108
+ latest[attempt.invocation_ref] = attempt
109
+ by_role: dict[str, list[Attempt]] = {}
110
+ for invocation in manifest.invocations:
111
+ if invocation.dispatch_kind not in {"initial", "correction"}:
112
+ continue
113
+ attempt = latest.get(invocation.invocation_ref)
114
+ if attempt is not None:
115
+ by_role.setdefault(invocation.role_execution_ref, []).append(attempt)
116
+ return by_role
117
+
118
+
119
+ def worker_result_paths(
120
+ run_dir: Path, document: Mapping, suffix: str
121
+ ) -> dict[str, Path]:
122
+ """실행 원장의 채택된 발견 결과를 고른다. 구형 원장은 파일명 규칙을 쓴다."""
123
+ results_dir = run_dir / "worker-results"
124
+ workers = document.get("workers") or []
125
+ paths = {
126
+ row["workerId"]: results_dir / f"{row['workerId']}-worker-{suffix}.md"
127
+ for row in workers if isinstance(row, Mapping) and row.get("workerId")
128
+ }
129
+ if document.get("schemaVersion") != "2.0":
130
+ return paths
131
+ recorded = document.get("runManifestPath")
132
+ if not _nonempty_string(recorded):
133
+ return paths
134
+ manifest_path = run_dir / "manifests" / Path(recorded).name
135
+ manifest, authority = read_execution_manifest_view(manifest_path)
136
+ if manifest.legacy:
137
+ return paths
138
+ attempts = discovery_attempts(manifest)
139
+ for row in workers:
140
+ if not isinstance(row, Mapping) or not row.get("workerId"):
141
+ continue
142
+ accepted = [
143
+ attempt for attempt in attempts.get(row.get("sourceRoleExecutionRef"), [])
144
+ if attempt.status == "ok" and attempt.result_path
145
+ ]
146
+ if not accepted:
147
+ continue
148
+ candidate = Path(accepted[-1].result_path)
149
+ if not candidate.is_absolute():
150
+ project_root = authority.get("projectRoot")
151
+ if not _nonempty_string(project_root):
152
+ raise ValueError("relative accepted resultPath requires projectRoot")
153
+ candidate = Path(project_root) / candidate
154
+ if candidate.resolve().parent != results_dir.resolve():
155
+ raise ValueError(f"accepted resultPath is outside worker-results: {candidate}")
156
+ if not candidate.is_file():
157
+ raise ValueError(f"accepted resultPath is missing: {candidate}")
158
+ paths[row["workerId"]] = candidate
159
+ return paths
160
+
161
+
100
162
  def read_canonical_worker_result(
101
163
  worker_results_dir: Path, worker: str, suffix: str
102
164
  ) -> str | None:
@@ -140,20 +202,25 @@ def provenance_errors(
140
202
  claims = group_claims(document)
141
203
  if claims is None:
142
204
  return []
205
+ paths = worker_result_paths(worker_results_dir.parent, document, suffix)
143
206
  contents: dict[str, str | None] = {}
144
207
  errors: list[str] = []
145
208
  for finding_id, worker, item_id in claims:
146
209
  if worker not in contents:
147
- contents[worker] = read_canonical_worker_result(
148
- worker_results_dir, worker, suffix
149
- )
210
+ candidate = paths.get(worker)
211
+ if candidate is not None and candidate.name != f"{worker}-worker-{suffix}.md":
212
+ contents[worker] = candidate.read_text(encoding="utf-8")
213
+ else:
214
+ contents[worker] = read_canonical_worker_result(
215
+ worker_results_dir, worker, suffix
216
+ )
150
217
  text = contents[worker]
151
218
  if text is None or id_occurs_wordbounded(text, item_id):
152
219
  continue
153
220
  errors.append(
154
221
  f"convergence groups `{groups_label}` group {finding_id} "
155
222
  f"cites source item `{worker}:{item_id}`, but that ID does not "
156
- f"occur in the worker's result file `{worker}-worker-{suffix}.md` — a "
223
+ f"occur in the worker's result file `{paths.get(worker, Path(f'{worker}-worker-{suffix}.md')).name}` — a "
157
224
  "grouping may not invent a provenance link to an item the "
158
225
  "worker never reported."
159
226
  )
@@ -243,10 +310,10 @@ DISCARDED_ATTEMPT_STATUSES = frozenset(
243
310
 
244
311
 
245
312
  def discarded_workers(document: object, execution_manifest: object) -> dict[str, str]:
246
- """``{workerId: "<invocationRef>#<attempt> <status>"}`` — 초기 attempt 가 전부
313
+ """``{workerId: "<invocationRef>#<attempt> <status>"}`` — 발견 attempt 가 전부
247
314
  폐기돼 채택할 결과가 없는 분석 워커.
248
315
 
249
- 한 워커의 초기 invocation 이 둘 이상이면(교정 디스패치는 새 invocation 이다)
316
+ 한 워커의 발견 invocation 이 둘 이상이면(교정 디스패치는 새 invocation 이다)
250
317
  그중 하나라도 마지막 attempt 가 ``ok`` 면 채택 가능한 결과가 있는 것이므로
251
318
  폐기로 보지 않는다. legacy 매니페스트나 v1 roster 는 판정하지 않는다.
252
319
  """
@@ -254,17 +321,7 @@ def discarded_workers(document: object, execution_manifest: object) -> dict[str,
254
321
  return {}
255
322
  if execution_manifest is None or getattr(execution_manifest, "legacy", False):
256
323
  return {}
257
- initial_refs: dict[str, set[str]] = {}
258
- for invocation in getattr(execution_manifest, "invocations", ()):
259
- if invocation.dispatch_kind == "initial":
260
- initial_refs.setdefault(invocation.role_execution_ref, set()).add(
261
- invocation.invocation_ref
262
- )
263
- latest: dict[str, object] = {}
264
- for attempt in getattr(execution_manifest, "attempts", ()):
265
- current = latest.get(attempt.invocation_ref)
266
- if current is None or attempt.attempt > current.attempt:
267
- latest[attempt.invocation_ref] = attempt
324
+ attempts = discovery_attempts(execution_manifest)
268
325
  result: dict[str, str] = {}
269
326
  for row in document["workers"]:
270
327
  if not isinstance(row, dict):
@@ -273,7 +330,7 @@ def discarded_workers(document: object, execution_manifest: object) -> dict[str,
273
330
  role_ref = row.get("sourceRoleExecutionRef")
274
331
  if not _nonempty_string(worker) or not _nonempty_string(role_ref):
275
332
  continue
276
- rows = [latest[ref] for ref in sorted(initial_refs.get(role_ref, ())) if ref in latest]
333
+ rows = attempts.get(role_ref, [])
277
334
  if not rows or any(item.status == "ok" for item in rows):
278
335
  continue
279
336
  discarded = [item for item in rows if item.status in DISCARDED_ATTEMPT_STATUSES]