okstra 0.50.0 → 0.51.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 +8 -7
- package/README.md +8 -7
- package/bin/okstra +2 -0
- package/docs/kr/architecture.md +15 -16
- package/docs/kr/cli.md +5 -5
- package/docs/project-structure-overview.md +10 -6
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/SKILL.md +15 -11
- package/runtime/agents/workers/claude-worker.md +3 -3
- package/runtime/agents/workers/codex-worker.md +2 -2
- package/runtime/agents/workers/gemini-worker.md +2 -2
- package/runtime/bin/lib/okstra/cli.sh +8 -1
- package/runtime/bin/lib/okstra/globals.sh +3 -0
- package/runtime/bin/lib/okstra/interactive.sh +14 -12
- package/runtime/bin/lib/okstra/usage.sh +6 -0
- package/runtime/bin/okstra-team-reconcile.sh +28 -0
- package/runtime/bin/okstra.sh +2 -0
- package/runtime/prompts/launch.template.md +3 -1
- package/runtime/prompts/profiles/_common-contract.md +4 -4
- package/runtime/prompts/profiles/_implementation-executor.md +2 -2
- package/runtime/prompts/profiles/_implementation-verifier.md +1 -1
- package/runtime/prompts/profiles/implementation-planning.md +1 -0
- package/runtime/prompts/profiles/implementation.md +1 -1
- package/runtime/python/okstra_ctl/analysis_packet.py +259 -0
- package/runtime/python/okstra_ctl/context_cost.py +308 -0
- package/runtime/python/okstra_ctl/migrate.py +2 -12
- package/runtime/python/okstra_ctl/paths.py +22 -0
- package/runtime/python/okstra_ctl/render.py +284 -125
- package/runtime/python/okstra_ctl/render_final_report.py +31 -0
- package/runtime/python/okstra_ctl/run.py +507 -245
- package/runtime/python/okstra_ctl/sequence.py +2 -5
- package/runtime/python/okstra_ctl/team_reconcile.py +131 -0
- package/runtime/python/okstra_ctl/wizard.py +129 -133
- package/runtime/python/okstra_ctl/worktree.py +13 -5
- package/runtime/schemas/final-report-v1.0.schema.json +4 -0
- package/runtime/skills/okstra-coding-preflight/SKILL.md +69 -0
- package/runtime/skills/okstra-coding-preflight/architecture/hexagonal.md +116 -0
- package/runtime/skills/okstra-coding-preflight/clean-code.md +254 -0
- package/runtime/skills/okstra-coding-preflight/languages/java.md +64 -0
- package/runtime/skills/okstra-coding-preflight/languages/javascript-typescript.md +87 -0
- package/runtime/skills/okstra-coding-preflight/languages/kotlin.md +69 -0
- package/runtime/skills/okstra-coding-preflight/languages/nodejs.md +66 -0
- package/runtime/skills/okstra-coding-preflight/languages/python.md +179 -0
- package/runtime/skills/okstra-coding-preflight/languages/rust.md +105 -0
- package/runtime/skills/okstra-coding-preflight/languages/sql.md +68 -0
- package/runtime/skills/okstra-context-loader/SKILL.md +12 -6
- package/runtime/skills/okstra-inspect/SKILL.md +100 -1
- package/runtime/skills/okstra-report-writer/SKILL.md +5 -1
- package/runtime/skills/okstra-run/SKILL.md +1 -1
- package/runtime/skills/okstra-team-contract/SKILL.md +7 -4
- package/runtime/templates/reports/final-report.template.md +1 -0
- package/runtime/templates/worker-prompt-preamble.md +3 -3
- package/src/_python-helper.mjs +3 -3
- package/src/context-cost.mjs +27 -0
- package/src/install.mjs +1 -0
- package/src/uninstall.mjs +1 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# Python Conventions
|
|
2
|
+
|
|
3
|
+
If a project-level Python style skill or repo-local `CONTRIBUTING.md` / `pyproject.toml` config exists, **it wins**. This file is the fallback.
|
|
4
|
+
|
|
5
|
+
## Core principles
|
|
6
|
+
|
|
7
|
+
- Write simple, explicit, readable Python. Prefer boring, maintainable code over clever abstractions.
|
|
8
|
+
- Optimize for correctness first, then clarity, then performance.
|
|
9
|
+
- Keep functions small and single-responsibility. Prefer composition over inheritance.
|
|
10
|
+
- Type-hint all public functions, class methods, and non-trivial internal functions.
|
|
11
|
+
- Use dataclasses or Pydantic models for structured data — never loose `dict`s for domain data.
|
|
12
|
+
- Make side effects explicit. Fail fast with clear errors. No hidden global state.
|
|
13
|
+
- Code must be testable without network, filesystem, database, or time dependencies.
|
|
14
|
+
|
|
15
|
+
## Python version
|
|
16
|
+
|
|
17
|
+
Target **Python 3.11+** unless told otherwise. Use modern syntax:
|
|
18
|
+
|
|
19
|
+
- `str | None`, not `Optional[str]`
|
|
20
|
+
- `list[str]` / `dict[str, int]`, not `List` / `Dict`
|
|
21
|
+
- `match` only when it improves clarity
|
|
22
|
+
- `pathlib.Path`, not string paths
|
|
23
|
+
|
|
24
|
+
## Style guide
|
|
25
|
+
|
|
26
|
+
PEP 8, enforced by `ruff format` (or `black`).
|
|
27
|
+
|
|
28
|
+
- Indent: **4 spaces**. Line length: **88** (ruff/black default) unless the project sets otherwise.
|
|
29
|
+
- `snake_case` functions/variables, `PascalCase` classes, `SCREAMING_SNAKE_CASE` constants, leading `_` for private.
|
|
30
|
+
|
|
31
|
+
## Function design
|
|
32
|
+
|
|
33
|
+
- One thing per function. Avoid bodies over ~40 lines without a strong reason.
|
|
34
|
+
- Explicit parameters over reading globals. Return values instead of mutating arguments.
|
|
35
|
+
- Avoid behavior-changing boolean flags — split into separate functions.
|
|
36
|
+
- Do not hide I/O inside functions that look pure. Do not catch broad exceptions unless re-raising with useful context.
|
|
37
|
+
|
|
38
|
+
Bad:
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
def process(data, save=True, notify=False):
|
|
42
|
+
...
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Better:
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
def build_invoice(data: InvoiceInput) -> Invoice: ...
|
|
49
|
+
def save_invoice(invoice: Invoice) -> None: ...
|
|
50
|
+
def notify_invoice_created(invoice: Invoice) -> None: ...
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Typing
|
|
54
|
+
|
|
55
|
+
- Type hints everywhere meaningful. Avoid `Any` unless unavoidable; never silence a type error without a one-line why.
|
|
56
|
+
- No untyped dicts for domain data — use `dataclass`, `Enum`, `TypedDict`, or Pydantic.
|
|
57
|
+
- `Protocol` for dependency inversion.
|
|
58
|
+
|
|
59
|
+
Bad:
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
def create_user(data: dict): ...
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Better:
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
@dataclass(frozen=True)
|
|
69
|
+
class CreateUserCommand:
|
|
70
|
+
email: str
|
|
71
|
+
name: str
|
|
72
|
+
|
|
73
|
+
def create_user(command: CreateUserCommand) -> User: ...
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Error handling
|
|
77
|
+
|
|
78
|
+
- Specific exception types with useful context. Never swallow exceptions silently.
|
|
79
|
+
- Do not use exceptions for normal control flow.
|
|
80
|
+
- Convert infrastructure errors into application/domain errors at boundaries.
|
|
81
|
+
- Never expose internal stack traces or secrets to users.
|
|
82
|
+
|
|
83
|
+
Bad:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
try:
|
|
87
|
+
send_email(user)
|
|
88
|
+
except Exception:
|
|
89
|
+
pass
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Better:
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
try:
|
|
96
|
+
send_email(user)
|
|
97
|
+
except EmailProviderError as exc:
|
|
98
|
+
raise NotificationFailedError(f"Failed to notify user_id={user.id}") from exc
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Async
|
|
102
|
+
|
|
103
|
+
- Use async only for real I/O concurrency. Never call sync-blocking I/O inside an async function.
|
|
104
|
+
- Always set timeouts on external calls. No fire-and-forget tasks without explicit lifecycle + error handling.
|
|
105
|
+
|
|
106
|
+
Bad:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
async def fetch():
|
|
110
|
+
requests.get(url) # blocking call inside async
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Better:
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
async def fetch(client: httpx.AsyncClient, url: str) -> Response:
|
|
117
|
+
return await client.get(url, timeout=10)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Project / module layout
|
|
121
|
+
|
|
122
|
+
Separate domain logic from infrastructure; keep business rules independent of frameworks, DBs, queues, and external APIs.
|
|
123
|
+
|
|
124
|
+
- `domain/` — entities, value objects, pure business logic
|
|
125
|
+
- `application/` — use cases, orchestration, commands, queries
|
|
126
|
+
- `infrastructure/` — DB, external APIs, filesystem, queues
|
|
127
|
+
- `interfaces/` — HTTP, CLI, workers, event handlers
|
|
128
|
+
- `tests/` — unit, integration, e2e
|
|
129
|
+
|
|
130
|
+
When the project is ports-and-adapters, also read [../architecture/hexagonal.md](../architecture/hexagonal.md).
|
|
131
|
+
|
|
132
|
+
## Security
|
|
133
|
+
|
|
134
|
+
- Never hardcode secrets — read from env vars or a secret manager.
|
|
135
|
+
- Parameterized SQL only; never build SQL via string interpolation / f-strings.
|
|
136
|
+
- Validate all external input. Treat file paths, URLs, headers, and serialized input as untrusted.
|
|
137
|
+
- No unsafe deserialization (arbitrary `pickle.load`).
|
|
138
|
+
|
|
139
|
+
## Database
|
|
140
|
+
|
|
141
|
+
- Explicit, reviewable SQL. Avoid N+1 queries. Wrap multi-step writes in transactions.
|
|
142
|
+
- Use repository interfaces (`Protocol`) when DB access should be decoupled from domain logic.
|
|
143
|
+
- Keep migrations backward-compatible when possible.
|
|
144
|
+
|
|
145
|
+
## Logging
|
|
146
|
+
|
|
147
|
+
- Structured logging — never `print()` for application logs.
|
|
148
|
+
- Include IDs/context (request, user, job, entity). Never log secrets, tokens, passwords, cookies, API keys, or sensitive PII.
|
|
149
|
+
|
|
150
|
+
## Tests
|
|
151
|
+
|
|
152
|
+
- Unit-test domain logic; integration-test DB, external-API wrappers, and framework wiring.
|
|
153
|
+
- Deterministic tests — no `sleep`, no execution-order dependence, no real external services unless marked integration/e2e.
|
|
154
|
+
- Mock only at boundaries. Use factories/builders for test data. Test behavior, not implementation.
|
|
155
|
+
- Every bug fix ships a regression test when feasible.
|
|
156
|
+
|
|
157
|
+
### Self-mock signals to refuse (rule from `clean-code.md` → Testing discipline)
|
|
158
|
+
|
|
159
|
+
- `unittest.mock.patch`-ing a method **on the class under test**, then asserting that method was called. Mock the collaborator it depends on, not the unit it *is*.
|
|
160
|
+
- Splitting out a helper *only so* the test can patch it, then asserting `helper.assert_called_once()` as the real check — that proves the SUT calls the helper, not that the behavior works.
|
|
161
|
+
- Reaching into privates (`obj._internal`) to assert on internal state instead of observable outcomes.
|
|
162
|
+
- A `MagicMock` standing in for the SUT itself with a `return_value` that mirrors the very thing under test.
|
|
163
|
+
|
|
164
|
+
What's fine: mocking injected dependencies (`Mock(spec=UserRepository)`, `httpx.MockTransport`), asserting on return values / raised exceptions / emitted events / boundary calls.
|
|
165
|
+
|
|
166
|
+
## Required tooling
|
|
167
|
+
|
|
168
|
+
Run before declaring a Python change complete:
|
|
169
|
+
|
|
170
|
+
- `ruff check .` — lint
|
|
171
|
+
- `ruff format --check .` — formatting (or `black --check .`)
|
|
172
|
+
- `mypy .` or `pyright` — type check (if configured)
|
|
173
|
+
- `pytest` — tests
|
|
174
|
+
|
|
175
|
+
Dependency/project management: `uv`, Poetry, or `pip-tools`. Pin dependencies in application projects; reach for the standard library before adding third-party deps, and avoid importing heavy deps at module-import time when unnecessary.
|
|
176
|
+
|
|
177
|
+
## Forbidden anti-patterns
|
|
178
|
+
|
|
179
|
+
God classes/functions, hidden global mutable state, circular imports, catch-all `except Exception` without re-raise, silent failure, untyped domain dicts, business logic in controllers/routes or coupled to ORM models, hardcoded secrets, string-formatted SQL, unbounded retries, missing timeouts on external calls, fire-and-forget async without error handling, order-dependent tests, abstractions before two concrete use cases, magic constants without names, copy-pasted logic, comments that restate obvious code, leftover `print()` debugging.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Rust Conventions
|
|
2
|
+
|
|
3
|
+
If a project-level `rust-guidelines` skill or repo-local `CONTRIBUTING.md` exists, **it wins**. This file is the fallback.
|
|
4
|
+
|
|
5
|
+
## Style guide
|
|
6
|
+
|
|
7
|
+
Official Rust Style Guide (rustwiki.org/en/style-guide/), enforced by `rustfmt`. Set the edition in `rustfmt.toml`:
|
|
8
|
+
|
|
9
|
+
```toml
|
|
10
|
+
style_edition = "2024"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Naming (RFC 430)
|
|
14
|
+
|
|
15
|
+
| Element | Convention | Example |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| Crate / module | `snake_case` | `my_crate`, `parser` |
|
|
18
|
+
| Type / trait / enum variant | `UpperCamelCase` | `HttpClient`, `Error::Timeout` |
|
|
19
|
+
| Function / method / variable | `snake_case` | `send_request`, `retry_count` |
|
|
20
|
+
| Const / static | `SCREAMING_SNAKE_CASE` | `MAX_RETRIES` |
|
|
21
|
+
| Lifetime | short lowercase | `'a`, `'src` |
|
|
22
|
+
| Type parameter | single uppercase | `T`, `E` |
|
|
23
|
+
|
|
24
|
+
## Formatting
|
|
25
|
+
|
|
26
|
+
- Indent: **4 spaces**.
|
|
27
|
+
- Max line length: **100** (`rustfmt` default).
|
|
28
|
+
- Always run `cargo fmt` before commit.
|
|
29
|
+
|
|
30
|
+
## Ownership & borrowing
|
|
31
|
+
|
|
32
|
+
- Prefer borrowing (`&T`) over cloning. `.clone()` is a code smell unless you can name the reason in one sentence.
|
|
33
|
+
- Return owned types from constructors and "convert" methods; accept borrowed slices (`&str`, `&[T]`) as parameters.
|
|
34
|
+
- `&mut` only when you must mutate. Two `&` borrows are usually better than one `&mut`.
|
|
35
|
+
- `Cow<'_, str>` when a function sometimes allocates and sometimes does not.
|
|
36
|
+
|
|
37
|
+
## Error handling
|
|
38
|
+
|
|
39
|
+
- **Library** crates: define a typed error with `thiserror`. One `Error` enum per crate, one variant per failure mode.
|
|
40
|
+
- **Application** crates: `anyhow::Result<T>` at the top level is fine; convert to typed errors at module boundaries.
|
|
41
|
+
- **No `unwrap()` / `expect()` in production paths.** Acceptable in:
|
|
42
|
+
- Tests.
|
|
43
|
+
- `main` for setup that genuinely cannot fail.
|
|
44
|
+
- `expect("invariant: ...")` when the message documents the invariant.
|
|
45
|
+
- Use the `?` operator. Do not write `match`-on-`Result` ladders.
|
|
46
|
+
|
|
47
|
+
## Idioms
|
|
48
|
+
|
|
49
|
+
- Iterators (`map`, `filter`, `collect`, `fold`, `find`) over indexed loops.
|
|
50
|
+
- `if let` / `let else` over `match` with a single arm.
|
|
51
|
+
- `#[derive(Debug, Clone, ...)]` aggressively. Add `PartialEq` / `Eq` / `Hash` when the type lands in a collection.
|
|
52
|
+
- Newtype small primitives that carry meaning: `struct UserId(u64);`, not raw `u64`.
|
|
53
|
+
- `mut` and `pub` only when needed. Start private, widen on demand.
|
|
54
|
+
- Use `From` / `TryFrom` for conversions, not `parse_x_from_y` helpers.
|
|
55
|
+
- Pattern-match deeply (`if let Some(User { id, .. }) = user`) rather than chained `.unwrap().unwrap()`.
|
|
56
|
+
|
|
57
|
+
## Async / Tokio
|
|
58
|
+
|
|
59
|
+
- Pick **one** runtime per binary (`tokio` is standard). Never mix `tokio` and `async-std`.
|
|
60
|
+
- Never `block_on` inside an async function.
|
|
61
|
+
- Spawn tasks deliberately; remember `JoinHandle`s and `await` them.
|
|
62
|
+
- `tokio::select!` for races; never poll futures by hand.
|
|
63
|
+
- Long CPU work goes in `tokio::task::spawn_blocking`.
|
|
64
|
+
- Cancellation: use `CancellationToken` (tokio-util) for cooperative shutdown.
|
|
65
|
+
|
|
66
|
+
## Unsafe
|
|
67
|
+
|
|
68
|
+
- Every `unsafe` block needs a comment documenting **every** invariant the caller must uphold.
|
|
69
|
+
- New `unsafe` requires a second pair of eyes on review.
|
|
70
|
+
- Default to safe abstractions (`bytes`, `parking_lot`, `crossbeam`) before reaching for `unsafe`.
|
|
71
|
+
|
|
72
|
+
## Module layout
|
|
73
|
+
|
|
74
|
+
- Public API at the crate root via `pub use`; implementation in private modules.
|
|
75
|
+
- One concept per file. Split a module before it passes ~500 lines.
|
|
76
|
+
- Unit tests in `mod tests { use super::*; ... }` at the bottom of the file.
|
|
77
|
+
- Integration tests in the `tests/` directory.
|
|
78
|
+
|
|
79
|
+
## Tests
|
|
80
|
+
|
|
81
|
+
- Unit: `#[test]` inside `mod tests`. Use `assert_eq!`, `assert!`, `assert_matches!`.
|
|
82
|
+
- Async: `#[tokio::test]` or `#[test]` with an explicit `tokio::runtime::Runtime` when you need control.
|
|
83
|
+
- Property: `proptest` or `quickcheck` for pure transformations.
|
|
84
|
+
- **Doc tests**: runnable examples in doc comments are tests — keep them green.
|
|
85
|
+
- Use `pretty_assertions::assert_eq!` for readable diffs on large structs.
|
|
86
|
+
|
|
87
|
+
### Self-mock signals to refuse (rule from `clean-code.md` → Testing discipline)
|
|
88
|
+
|
|
89
|
+
Rust's trait-based DI makes self-mocking rarer than in JVM/JS, but it still happens:
|
|
90
|
+
|
|
91
|
+
- Using `mockall::mock!` (or `automock`) to generate a mock of the **same struct under test**, then asserting on its own methods. The unit under test must be the real impl; mock the trait it depends on, not the trait it *is*.
|
|
92
|
+
- Splitting a behavior into a helper trait *only so* the test can stub it, then expecting `expect_helper().returning(...)` to be the real assertion. The test now proves the SUT calls the helper, not that the behavior works.
|
|
93
|
+
- Reaching into privates via `pub(crate)` widening, `#[cfg(test)] pub` shortcuts, or test-only modules that expose internal state to assert on.
|
|
94
|
+
- A test that constructs the SUT, replaces one of its trait-object dependencies with a mock whose `returning(...)` mirrors the very thing being tested.
|
|
95
|
+
|
|
96
|
+
What's fine: `mockall` mocks of injected trait dependencies (`MockHttpClient`, `MockUserRepository`), `unwrap()` in tests for setup that genuinely cannot fail, `assert_eq!` on returned values, `assert_matches!` on returned `Result` / `Option`.
|
|
97
|
+
|
|
98
|
+
## Required tooling
|
|
99
|
+
|
|
100
|
+
Run before any commit:
|
|
101
|
+
|
|
102
|
+
- `cargo fmt --all` — formatting.
|
|
103
|
+
- `cargo clippy --all-targets --all-features -- -D warnings` — lint (warnings are errors).
|
|
104
|
+
- `cargo check --all-targets` — fast type check.
|
|
105
|
+
- `cargo test --all` — tests.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# SQL Conventions
|
|
2
|
+
|
|
3
|
+
Defaults below target PostgreSQL. MySQL-specific notes are marked.
|
|
4
|
+
|
|
5
|
+
## Formatting / style
|
|
6
|
+
|
|
7
|
+
- Keywords **lowercase**: `select`, `from`, `where`, `join`. (Some teams prefer uppercase — match the file you are editing; never mix in one statement.)
|
|
8
|
+
- All identifiers `snake_case`: tables, columns, indexes, constraints.
|
|
9
|
+
- Always use explicit `as` for column aliases: `select count(*) as user_count`.
|
|
10
|
+
- Always state the join type: `inner join`, `left join`, `cross join`. **Never** a bare `join`.
|
|
11
|
+
- One column per line in `select`; one table or join per line in `from`.
|
|
12
|
+
- Prefer **CTEs** (`with foo as (...)`) over deeply nested subqueries.
|
|
13
|
+
- Dates / timestamps in ISO 8601: `'2026-05-17'`, `'2026-05-17T12:00:00Z'`.
|
|
14
|
+
|
|
15
|
+
## Schema design
|
|
16
|
+
|
|
17
|
+
- Every table has an `id` primary key.
|
|
18
|
+
- PostgreSQL: `id bigint generated always as identity primary key`.
|
|
19
|
+
- MySQL: `id bigint unsigned not null auto_increment primary key`.
|
|
20
|
+
- Foreign keys named `<referenced_table>_id`: `user_id`, `order_id`.
|
|
21
|
+
- Singular table names (`user`, `order`, `invoice_line`) unless the project already uses plural — match, do not mix.
|
|
22
|
+
- `comment on table ... is '...'` for every table; `comment on column ...` for non-obvious columns. (MySQL: `comment '...'` inline.)
|
|
23
|
+
- Timestamps: `created_at`, `updated_at`, both `timestamptz` in Postgres. Keep timezone discipline explicit — store UTC, render in the user's zone at the edge.
|
|
24
|
+
- Soft delete: `deleted_at timestamptz null`. Index it if you query on it. Add a partial index `where deleted_at is null` for hot reads.
|
|
25
|
+
- Use `not null` aggressively. `null` should mean "unknown", not "default".
|
|
26
|
+
- Use enum or `check` constraints over free-text status columns.
|
|
27
|
+
- Composite indexes: column order matches your `where` / `order by` patterns; left-most prefix wins.
|
|
28
|
+
|
|
29
|
+
## Migrations
|
|
30
|
+
|
|
31
|
+
- One change per migration file. Name: `<timestamp>_<verb>_<noun>.sql` (e.g. `20260517_120000_add_user_deleted_at.sql`).
|
|
32
|
+
- Migrations are **forward-only** in production. Write a "down" migration only if your tool requires it and you genuinely intend to run it.
|
|
33
|
+
- Splitting a destructive change:
|
|
34
|
+
1. Add nullable column.
|
|
35
|
+
2. Backfill (separate deploy).
|
|
36
|
+
3. Add `not null` / index `concurrently`.
|
|
37
|
+
4. Drop the old column.
|
|
38
|
+
- `create index concurrently` in Postgres for hot tables — avoids the write lock.
|
|
39
|
+
- Application-deploy migrations **never** destroy data. Destructive operations are a separate, explicit step gated on backups.
|
|
40
|
+
|
|
41
|
+
## Query practices
|
|
42
|
+
|
|
43
|
+
- Always filter on indexed columns for OLTP queries. Verify with `explain` / `explain analyze`.
|
|
44
|
+
- Never `select *` in application code (migrations and ad-hoc inspection are fine).
|
|
45
|
+
- Parameterised queries from the application layer. String concatenation is SQL injection.
|
|
46
|
+
- `limit` every query that could return an unbounded set.
|
|
47
|
+
- `returning *` (Postgres) on `insert` / `update` / `delete` instead of a follow-up `select`.
|
|
48
|
+
- For pagination, prefer keyset (`where id > $last_seen`) over offset on large tables.
|
|
49
|
+
|
|
50
|
+
## MySQL-specific
|
|
51
|
+
|
|
52
|
+
- Engine: **InnoDB** (default). Charset: `utf8mb4`, collation `utf8mb4_0900_ai_ci` (8.0+).
|
|
53
|
+
- Quote identifiers with backticks when they collide with reserved words.
|
|
54
|
+
- `select ... for update` only inside an explicit transaction.
|
|
55
|
+
- `on duplicate key update` for upserts; in Postgres use `on conflict (...) do update`.
|
|
56
|
+
|
|
57
|
+
## Tests
|
|
58
|
+
|
|
59
|
+
- Run query tests against a **real** database via `testcontainers` or a disposable schema. In-memory SQLite is not equivalent to Postgres / MySQL — different SQL dialect, different isolation, different `null` semantics.
|
|
60
|
+
- Migrations themselves must be tested: apply from an empty schema in CI; assert the resulting structure.
|
|
61
|
+
- Seed test data via factory functions (one per table), not raw `insert` statements copy-pasted into each test.
|
|
62
|
+
- Verify performance assumptions with `explain` in CI for queries flagged as hot.
|
|
63
|
+
|
|
64
|
+
## Tools
|
|
65
|
+
|
|
66
|
+
- Formatting: `pg_format`, `sqlfluff`, `sql-formatter`.
|
|
67
|
+
- Linting / safety: `squawk` (Postgres migration linter — catches missing `concurrently`, locking foot-guns, etc.).
|
|
68
|
+
- Schema diff: `migra` (Postgres), `mysqldiff` (MySQL).
|
|
@@ -56,7 +56,7 @@ user-invocable: false
|
|
|
56
56
|
| `workflow.awaitingApproval` | Approval wait marker |
|
|
57
57
|
| `workflow.routingStatus` | Routing decision status |
|
|
58
58
|
| `workflow.lastSafeCheckpoint` | Safe resume checkpoint metadata |
|
|
59
|
-
| `instructionSetPath` | Path to the `instruction-set/` **directory** containing `analysis-profile.md`, `analysis-material.md`, `reference-expectations.md`, `task-brief.md`, `final-report-template.md` (see Step 4). Not a single-file path. |
|
|
59
|
+
| `instructionSetPath` | Path to the `instruction-set/` **directory** containing `analysis-packet.md`, `analysis-profile.md`, `analysis-material.md`, `reference-expectations.md`, `task-brief.md`, `final-report-template.md` (see Step 4). Not a single-file path. |
|
|
60
60
|
| `referenceExpectationsPath` | config/deployment expectation artifact path |
|
|
61
61
|
| `latestRunPath` | latest run path |
|
|
62
62
|
| `latestRunStatus` | latest run status |
|
|
@@ -78,6 +78,7 @@ After identifying the task root in `task-manifest.json`, derive all paths accord
|
|
|
78
78
|
├── task-index.md (human-readable summary, non-canonical)
|
|
79
79
|
├── instruction-set/
|
|
80
80
|
│ ├── analysis-profile.md (analysis guide by task type)
|
|
81
|
+
│ ├── analysis-packet.md (primary compact input for analysis workers)
|
|
81
82
|
│ ├── analysis-material.md (analysis materials)
|
|
82
83
|
│ ├── reference-expectations.md (config/deployment expected values)
|
|
83
84
|
│ ├── task-brief.md (task brief)
|
|
@@ -116,13 +117,18 @@ After identifying the task root in `task-manifest.json`, derive all paths accord
|
|
|
116
117
|
|
|
117
118
|
## Step 4: Instruction Set Reading Order
|
|
118
119
|
|
|
119
|
-
After verifying `task-manifest.json`, read the
|
|
120
|
+
After verifying `task-manifest.json`, read only the compact intake files needed for the current action. Do not bulk-read the whole instruction-set directory.
|
|
120
121
|
|
|
121
122
|
1. `instruction-set/analysis-profile.md` (analysis guide by task type)
|
|
122
|
-
2. `instruction-set/analysis-
|
|
123
|
-
3. `
|
|
124
|
-
|
|
125
|
-
|
|
123
|
+
2. `instruction-set/analysis-packet.md` (primary compact input for analysis workers)
|
|
124
|
+
3. `runs/<task-type>/state/active-run-context-<task-type>-<seq>.json` if present (compact current-run path/worker snapshot)
|
|
125
|
+
|
|
126
|
+
Read source files lazily:
|
|
127
|
+
|
|
128
|
+
- `instruction-set/task-brief.md` only for reporter-confirmation checks, source verification, or report-writer synthesis.
|
|
129
|
+
- `instruction-set/analysis-material.md` only when packet content is insufficient or a source citation needs verification.
|
|
130
|
+
- `instruction-set/reference-expectations.md` for report-writer synthesis or when packet expectation extract is insufficient.
|
|
131
|
+
- `instruction-set/final-report-template.md` only for report-writer authoring.
|
|
126
132
|
|
|
127
133
|
### Brief Reporter-Confirmation Precondition (BLOCKING)
|
|
128
134
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: okstra-inspect
|
|
3
3
|
description: |
|
|
4
|
-
Use for any read-side okstra inspection or status mutation. Single skill dispatches by sub-command to
|
|
4
|
+
Use for any read-side okstra inspection or status mutation. Single skill dispatches by sub-command to six facets — status, history, report, time, logs, cost. Trigger words include "okstra status", "task status", "current phase", "next phase", "okstra status set", "okstra mark", "<task-id> done|in-progress|진행중|완료", "okstra history", "past runs", "re-run", "resume", "list tasks", "find report", "show report for", "read the okstra report", "continue from report", "작업 시간", "소요 시간", "time summary", "duration", "elapsed", "얼마나 걸렸", "시간 분석", "okstra logs", "로그 현황", "로그 파일", "log size", "log status", "로그 정리", "log cleanup", "okstra context-cost", "context cost", "context-cost", "컨텍스트 비용", "읽기 비용", "산출물 비용".
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# OKSTRA Inspect
|
|
@@ -15,6 +15,7 @@ Single read-side entry point for okstra runtime inspection plus the one write-si
|
|
|
15
15
|
| `report` | Resolve final-report path for a task-key. Optionally read it. |
|
|
16
16
|
| `time` | Per-task-type and per-worker duration breakdown for a task. |
|
|
17
17
|
| `logs` | Inventory codex/gemini wrapper `.log` sidecars; emit cleanup commands. |
|
|
18
|
+
| `cost` | Estimate file/read context cost for a task bundle. |
|
|
18
19
|
|
|
19
20
|
## Step 0: Verify okstra runtime + project setup (shared)
|
|
20
21
|
|
|
@@ -467,6 +468,104 @@ Never write `claude (claude)` — the parenthesized agent is shown only when it
|
|
|
467
468
|
|
|
468
469
|
---
|
|
469
470
|
|
|
471
|
+
## cost
|
|
472
|
+
|
|
473
|
+
Trigger phrases: "okstra context-cost", "context cost", "context-cost", "컨텍스트 비용", "읽기 비용", "산출물 비용", "task bundle cost", "agent read cost".
|
|
474
|
+
|
|
475
|
+
Read-only estimate of how much file/context surface a prepared task bundle asks the lead, analysis workers, and report-writer to absorb. This sub-command does **not** mutate task artifacts.
|
|
476
|
+
|
|
477
|
+
### cost.1 — Resolve target
|
|
478
|
+
|
|
479
|
+
Accepted target forms:
|
|
480
|
+
|
|
481
|
+
1. Full task-key: `<project-id>:<task-group>:<task-id>`.
|
|
482
|
+
2. Task id only, e.g. `DEV-9184`.
|
|
483
|
+
3. Task root path, e.g. `<projectRoot>/.okstra/tasks/<group>/<task-id>`.
|
|
484
|
+
|
|
485
|
+
If the user gives a task root path, run `okstra context-cost <absolute-or-user-provided-path>` directly.
|
|
486
|
+
|
|
487
|
+
If the user gives a full task-key, run:
|
|
488
|
+
|
|
489
|
+
```bash
|
|
490
|
+
okstra context-cost <task-key> --project-root <projectRoot>
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
If the user gives only a task id:
|
|
494
|
+
|
|
495
|
+
1. Read `.okstra/discovery/task-catalog.json`.
|
|
496
|
+
2. Match `taskId` case-insensitively.
|
|
497
|
+
3. Single match → use its `taskKey`.
|
|
498
|
+
4. Multiple matches → list candidates and ask the user to retry with a full task-key.
|
|
499
|
+
5. No match → report that the task cannot be found.
|
|
500
|
+
|
|
501
|
+
If the user asks generally ("컨텍스트 비용 보여줘") and does not name a task:
|
|
502
|
+
|
|
503
|
+
1. Read `.okstra/discovery/task-catalog.json`.
|
|
504
|
+
2. If exactly one task exists, use it.
|
|
505
|
+
3. If multiple tasks exist, show the latest 10 by `updatedAt` and ask which task to measure. Do not guess.
|
|
506
|
+
|
|
507
|
+
### cost.2 — Run estimator
|
|
508
|
+
|
|
509
|
+
Use the CLI output as the source of truth:
|
|
510
|
+
|
|
511
|
+
```bash
|
|
512
|
+
okstra context-cost <resolved-target> --project-root <projectRoot>
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
Do not re-count files manually unless the CLI fails and the user explicitly asks for manual fallback.
|
|
516
|
+
|
|
517
|
+
### cost.3 — Summarize output
|
|
518
|
+
|
|
519
|
+
Parse the JSON and report these fields:
|
|
520
|
+
|
|
521
|
+
| Field | Source |
|
|
522
|
+
|---|---|
|
|
523
|
+
| Task bundle | `totals.taskFileCount`, `totals.taskBytes` |
|
|
524
|
+
| Current run | `totals.currentRunFileCount`, `totals.currentRunBytes`, `currentRunPath` |
|
|
525
|
+
| Legacy timestamp artifacts | `totals.legacyTimestampFileCount` |
|
|
526
|
+
| Instruction set | `instructionSet.fileCount`, `instructionSet.bytes`, `instructionSet.analysisPacketBytes`, `instructionSet.legacyTaskPacketBytes` |
|
|
527
|
+
| Lead Phase 1 | `leadPhase1.mode`, `leadPhase1.fileCount`, `leadPhase1.bytes` |
|
|
528
|
+
| Analysis worker | `analysisWorker.mode`, `analysisWorker.fileCount`, `analysisWorker.bytesPerWorker`, `analysisWorker.legacyFullContractBytesPerWorker`, `analysisWorker.estimatedPacketModeBytesPerWorker`, `analysisWorker.estimatedReductionPercent` |
|
|
529
|
+
| Report writer | `reportWriter.fileCount`, `reportWriter.bytes` |
|
|
530
|
+
|
|
531
|
+
Format bytes as both raw bytes and rounded KB/MB where useful. Use `analysisWorker.estimatedReductionPercent` for the worker-input reduction. Do not recompute it from `bytesPerWorker` when `analysisWorker.mode == "analysis-packet-primary"` because `bytesPerWorker` is already the packet-primary cost.
|
|
532
|
+
|
|
533
|
+
### cost.4 — Output template
|
|
534
|
+
|
|
535
|
+
```markdown
|
|
536
|
+
## okstra Context Cost — <task-key>
|
|
537
|
+
|
|
538
|
+
| Surface | Files | Size |
|
|
539
|
+
|---|---:|---:|
|
|
540
|
+
| Task bundle | <N> | <bytes> (<human>) |
|
|
541
|
+
| Current run | <N> | <bytes> (<human>) |
|
|
542
|
+
| Instruction set | <N> | <bytes> (<human>) |
|
|
543
|
+
| Lead Phase 1 (`<mode>`) | <N> | <bytes> (<human>) |
|
|
544
|
+
| Analysis worker / worker (`<mode>`) | <N> | <bytes> (<human>) |
|
|
545
|
+
| Report writer synthesis | <N> | <bytes> (<human>) |
|
|
546
|
+
|
|
547
|
+
- Current run: `<currentRunPath-or-->`
|
|
548
|
+
- Legacy timestamp artifacts: `<N>`
|
|
549
|
+
- Legacy full worker contract: `<legacyFullContractBytesPerWorker>` bytes (`<human>`) per analysis worker
|
|
550
|
+
- Packet estimate: `<estimatedPacketModeBytesPerWorker>` bytes (`<human>`) per analysis worker
|
|
551
|
+
- Estimated worker-input reduction: `<percent>%`
|
|
552
|
+
|
|
553
|
+
### Reading
|
|
554
|
+
|
|
555
|
+
<One or two Korean sentences explaining the main bottleneck and the next likely optimization target.>
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
Interpretation rules:
|
|
559
|
+
|
|
560
|
+
- `leadPhase1.mode == "active-run-context"` means the compact lead intake file is present and should be treated as the primary lead read surface.
|
|
561
|
+
- `leadPhase1.mode == "legacy-five-file"` means this task was prepared before active-run-context, or the manifest does not reference it.
|
|
562
|
+
- `analysisWorker.mode == "analysis-packet-primary"` means new workers should read `analysis-packet.md` first and open full source inputs only for evidence checks or missing detail.
|
|
563
|
+
- If `analysisWorker.mode == "full-input-contract"` and `estimatedReductionPercent` is low, the next target is worker prompt/input contract slimming.
|
|
564
|
+
- If `reportWriter.bytes` dominates, the next target is a compact `synthesis-input` artifact.
|
|
565
|
+
- If `legacyTimestampFileCount` is high, recommend current-view/cold-artifact separation or retention cleanup, not destructive deletion by default.
|
|
566
|
+
|
|
567
|
+
---
|
|
568
|
+
|
|
470
569
|
## logs
|
|
471
570
|
|
|
472
571
|
Trigger phrases: "okstra logs", "로그 현황", "로그 파일", "log files", "log size", "log status", "로그 정리", "log cleanup".
|
|
@@ -12,6 +12,8 @@ The final-report **data.json** (JSON SSOT) at `runs/<task-type>/reports/final-re
|
|
|
12
12
|
|
|
13
13
|
The data.json schema is `schemas/final-report-v1.0.schema.json`. The renderer + the run-validator both consume that schema, so a data.json that validates is guaranteed to render into a markdown that passes the contract checks.
|
|
14
14
|
|
|
15
|
+
Two `frontmatter` approval fields are always emitted with their unset default — never pre-fill them: `frontmatter.approved` is emitted as `false`, and `frontmatter.implementationOption` is emitted as an empty string `""`. The user later flips `approved` to `true` (via `--approve` or manual edit) and fills `implementationOption` with the chosen Option Candidate name (via `--implementation-option <name>` or manual edit) to authorise and scope the next `implementation` run.
|
|
16
|
+
|
|
15
17
|
If you are reading this skill **as the report-writer-worker subagent**, YOU are the one calling the `Write` tool against the data.json path AND invoking the renderer via `Bash`. Do not return either artifact inline — the files on disk are the canonical record.
|
|
16
18
|
|
|
17
19
|
If you are reading this skill **as Claude lead**, your job in Phase 6 is to (a) prepare the report-writer prompt, (b) dispatch the Report writer worker per the Phase 6 dispatch template in SKILL.md, (c) review both files in Phase 7. Do not call `Write` against either path yourself when Report writer worker is in the roster.
|
|
@@ -33,11 +35,13 @@ Agent(
|
|
|
33
35
|
name: "report-writer",
|
|
34
36
|
subagent_type: "report-writer-worker",
|
|
35
37
|
team_name: "okstra-<task-key>", # omit if team is not alive — see Resume-safe dispatch
|
|
36
|
-
model: "
|
|
38
|
+
model: "<family token of Report writer worker's modelExecutionValue>", # opus/sonnet/haiku — NOT hardcoded; see below
|
|
37
39
|
mode: "auto"
|
|
38
40
|
)
|
|
39
41
|
```
|
|
40
42
|
|
|
43
|
+
The `model:` parameter is **derived from the Report writer worker's `modelExecutionValue`** in `task-manifest.json`, mapped to an Agent family token (`opus` / `sonnet` / `haiku`) per [okstra-team-contract](../okstra-team-contract/SKILL.md) "Model Assignment Rules" #3–#4. Do NOT hardcode it — the report-writer-worker definition is `model: inherit`, so without this explicit parameter the worker silently runs on the lead's model instead of its assignment. The same `modelExecutionValue` feeds the prompt header in item 6 below, so the spawn model and the recorded `**Model:**` header always agree.
|
|
44
|
+
|
|
41
45
|
The prompt MUST include, in this order at the top:
|
|
42
46
|
|
|
43
47
|
1. `**Project Root:** <absolute-path>`
|
|
@@ -186,7 +186,7 @@ You can delete the literal state-file path after this point — its job is done.
|
|
|
186
186
|
|
|
187
187
|
## Step 6: Take over as Claude lead
|
|
188
188
|
|
|
189
|
-
Read `<INSTRUCTION_SET_PATH>/claude-execution-prompt.md` verbatim and enter `Claude lead` mode. The lead prompt
|
|
189
|
+
Read `<INSTRUCTION_SET_PATH>/claude-execution-prompt.md` verbatim and enter `Claude lead` mode. The lead prompt now points to compact intake artifacts first (`active-run-context`, `analysis-profile.md`, and `analysis-packet.md`); full source files such as `analysis-material.md`, `reference-expectations.md`, and `final-report-template.md` are lazy/fallback inputs. Follow the rendered prompt order, do not preempt it.
|
|
190
190
|
|
|
191
191
|
Then proceed through the phases exactly as the lead prompt directs (Phase 1 context → Phase 2+ worker dispatch → final synthesis → final report).
|
|
192
192
|
|
|
@@ -37,6 +37,9 @@ okstra tasks are always operated using the `Claude lead` + required worker team
|
|
|
37
37
|
|
|
38
38
|
1. `resultContract.requiredWorkerRoles` in `task-manifest.json` (and the lead model metadata) is the canonical source. There is no role-level fallback — a missing assignment is a manifest defect, not a license to invent one.
|
|
39
39
|
2. If `modelExecutionValue` differs from `model`, use `modelExecutionValue` during execution.
|
|
40
|
+
3. **Spawn-time enforcement for in-process Claude subagents (BLOCKING).** `Claude worker` and `Report writer worker` are in-process Claude subagents whose agent definitions declare `model: inherit` (`agents/workers/claude-worker.md`, `agents/workers/report-writer-worker.md`). `inherit` follows the **lead's** runtime model, NOT the role's assignment — so an opus assignment silently runs on a sonnet lead. To make the assignment binding (not merely declared), lead MUST pass an explicit `model:` parameter on every `Agent(...)` dispatch for these two roles, derived from that role's `modelExecutionValue`. The dispatch `model:` parameter overrides the `inherit` frontmatter; the frontmatter remains only as the fallback when no parameter is supplied. Omitting `model:` on a Claude-side dispatch is a contract violation that reproduces the assigned-vs-actual model deviation.
|
|
41
|
+
4. **`modelExecutionValue` → Agent `model:` family token.** The Agent tool's `model` parameter accepts family tokens only — `opus` / `sonnet` / `haiku` (an exact version such as `claude-opus-4-7` is NOT a valid value). Map by prefix: a `modelExecutionValue` of `opus*` / `claude-opus*` → `"opus"`, `sonnet*` / `claude-sonnet*` → `"sonnet"`, `haiku*` / `claude-haiku*` → `"haiku"`. This enforces the assignment at **family granularity** (opus vs sonnet vs haiku); the exact version within a family is still inherited from the lead session and cannot be pinned via this parameter.
|
|
42
|
+
5. **Codex / Gemini wrappers are out of scope for the Agent `model:` rule.** `Codex worker` / `Gemini worker` subagents are Claude wrappers that shell out to an external CLI; the role's `modelExecutionValue` is already applied via the CLI's own `--model <modelExecutionValue>` argument (see `agents/workers/_cli-wrapper-template.md`). The Agent `model:` parameter for these wrappers would only set the wrapper's own orchestration model, not the external CLI's model — leave it at `inherit` and do NOT map it from `modelExecutionValue`.
|
|
40
43
|
|
|
41
44
|
### Dynamic Worker Role Determination
|
|
42
45
|
|
|
@@ -91,7 +94,7 @@ Send byte-identical dispatch prompts to every analysis worker (Claude / Codex /
|
|
|
91
94
|
The lead does NOT inline `[Required reading]` or `[Error reporting]` blocks into worker prompts. Both contracts live in a single canonical file at `~/.okstra/templates/worker-prompt-preamble.md` (source: `templates/worker-prompt-preamble.md`). The lead injects the path via the `**Worker Preamble Path:**` anchor header (header #5 above) and each worker Reads that file end-to-end before producing output.
|
|
92
95
|
|
|
93
96
|
What the lead MUST still do per dispatch:
|
|
94
|
-
- Inject the input file enumeration into the dispatch prompt body via an `## Inputs` section (or any heading the recipient agent expects), listing the actual project-relative
|
|
97
|
+
- Inject the input file enumeration into the dispatch prompt body via an `## Inputs` section (or any heading the recipient agent expects), listing the actual project-relative primary inputs derived from the run's `instruction-set/`. For analysis workers, list `analysis-packet.md` as the required primary input and list task-brief / analysis-profile / analysis-material / reference-expectations / clarification-response as source/fallback paths only when useful. The preamble describes the rules; the lead provides the specific paths for THIS run.
|
|
95
98
|
- Inject the absolute `**Errors log path:**` and `**Errors sidecar path:**` headers (#6 and #7 above) — workers cannot synthesize these paths.
|
|
96
99
|
- Omit the preamble pointer for reverify dispatches (Phase 5.5 lightweight mode) — see [okstra-convergence](../okstra-convergence/SKILL.md) "Reverify prompt: required-reading suppression".
|
|
97
100
|
|
|
@@ -99,8 +102,8 @@ Audience-scoped file enumeration (BLOCKING — performance optimization):
|
|
|
99
102
|
|
|
100
103
|
| Recipient | Files the lead lists under `## Inputs` |
|
|
101
104
|
|---|---|
|
|
102
|
-
| Claude / Codex / Gemini analysis workers |
|
|
103
|
-
| Report writer worker (Phase 6) |
|
|
105
|
+
| Claude / Codex / Gemini analysis workers | `analysis-packet.md` as primary input; source/fallback paths may be listed below it but are not automatic first-read files |
|
|
106
|
+
| Report writer worker (Phase 6) | task-brief, analysis-profile, analysis-material, reference-expectations, clarification-response (if carry-in), **plus** the instruction-set-local `final-report-template.md` (phase-stripped) and `final-report-schema.json` (per-task-type excerpt) — NOT the full `templates/reports/...` / `schemas/...` sources |
|
|
104
107
|
| Reverify dispatches | none — the lead provides only the items to reverify |
|
|
105
108
|
|
|
106
109
|
Asymmetry note: `claude-worker` runs in-process and the Agent SDK auto-loads its agent definition; lead's dispatch prompt body for claude-worker can therefore be shorter than for codex/gemini. The Worker Preamble pointer is still emitted for all three so the contract source is identical regardless of dispatch path.
|
|
@@ -147,7 +150,7 @@ After each worker subagent returns (regardless of role), Lead MUST verify the ca
|
|
|
147
150
|
|
|
148
151
|
### Result Frontmatter (mandatory, precedes Section 1)
|
|
149
152
|
|
|
150
|
-
Every worker result file MUST begin with a YAML frontmatter block.
|
|
153
|
+
Every worker result file MUST begin with a YAML frontmatter block. For analysis workers, values are sourced from `analysis-packet.md` frontmatter; fall back to `analysis-material.md` or `task-brief.md` only if the packet is missing a field. Report-writer can use `analysis-material.md` / `task-brief.md` as before. Copy values verbatim; do NOT regenerate them. Only `workerId` and `title` are worker-specific.
|
|
151
154
|
|
|
152
155
|
```yaml
|
|
153
156
|
---
|
|
@@ -18,6 +18,7 @@ project-id: {{ frontmatter.projectId | yaml_scalar }}
|
|
|
18
18
|
taskType: {{ frontmatter.taskType | yaml_scalar }}
|
|
19
19
|
workerId: {{ frontmatter.workerId | yaml_scalar }}
|
|
20
20
|
approved: {{ frontmatter.approved | yaml_scalar }}
|
|
21
|
+
implementation-option: {{ frontmatter.implementationOption | yaml_scalar }}
|
|
21
22
|
---
|
|
22
23
|
|
|
23
24
|
# {{ header.taskKey }} - Multi-Agent Cross Verification Final Report
|
|
@@ -8,7 +8,7 @@ It replaces the previous practice of inlining ~80 lines of identical boilerplate
|
|
|
8
8
|
|
|
9
9
|
## Required reading (analysis workers + report-writer worker)
|
|
10
10
|
|
|
11
|
-
You are required to read every input file enumerated by the dispatcher (the lead's prompt lists them under `[Required reading]`) from the very first character to the very last character before you produce any analysis output. Skimming, partial reads, jumping to a single section, or relying on prior knowledge of a similar file's structure is not acceptable.
|
|
11
|
+
You are required to read every primary input file enumerated by the dispatcher (the lead's prompt lists them under `[Required reading]`) from the very first character to the very last character before you produce any analysis output. Skimming, partial reads, jumping to a single section, or relying on prior knowledge of a similar file's structure is not acceptable. Source files listed as fallback/evidence paths are read on demand when you need to verify a citation, resolve ambiguity, or inspect material the packet says it omitted.
|
|
12
12
|
|
|
13
13
|
### Audience-scoped enumeration (BLOCKING — performance optimization)
|
|
14
14
|
|
|
@@ -16,7 +16,7 @@ Different recipients need different files. Do NOT include `final-report-template
|
|
|
16
16
|
|
|
17
17
|
| Recipient | Files included in `[Required reading]` |
|
|
18
18
|
|---|---|
|
|
19
|
-
| Claude / Codex / Gemini analysis workers | task-brief, analysis-profile, analysis-material
|
|
19
|
+
| Claude / Codex / Gemini analysis workers | analysis-packet.md as the primary compact input; task-brief, analysis-profile, analysis-material, reference-expectations, and clarification-response remain source/fallback paths, not automatic first-read files |
|
|
20
20
|
| Report writer worker (Phase 6) | all of the above **plus** the instruction-set-local `final-report-template.md` (phase-stripped) and `final-report-schema.json` (per-task-type excerpt) — NOT the full `templates/reports/...` / `schemas/...` sources |
|
|
21
21
|
| Reverify dispatches (Phase 5.5, lightweight mode) | **do NOT inject `[Required reading]` at all** — see [okstra-convergence](../skills/okstra-convergence/SKILL.md) "Reverify prompt: required-reading suppression". |
|
|
22
22
|
|
|
@@ -25,7 +25,7 @@ Different recipients need different files. Do NOT include `final-report-template
|
|
|
25
25
|
- Use a single `Read` tool call per file with no `offset` and no `limit`. If a file is genuinely too large for one read, page through with explicit `offset` / `limit` covering the entire file, and state the page boundaries in your Findings.
|
|
26
26
|
- For the carry-in clarification response, walk every row of `## 1. Clarification Items` (`C-001`, `C-002`, ...) in full, including rows whose `User input` cell is blank — a blank `User input` with `Status=open` is itself a signal you must surface. The structural similarity between the prior final report and the upcoming output is NOT a license to skim.
|
|
27
27
|
- Write the Reading Confirmation block to your **audit sidecar** at `runs/<task-type>/worker-results/<worker>-audit-<task-type>-<seq>.md` (sibling to the main worker-results file). One short line per input file confirming end-to-end reading. Do NOT include a `## 0. Reading Confirmation` heading in the main worker-results file — the validator fails worker-results that contain one. If you cannot truthfully confirm a file end-to-end, record a `tool-failure` in the errors sidecar instead of fabricating Findings.
|
|
28
|
-
-
|
|
28
|
+
- Treat `analysis-packet.md` as the canonical primary analysis input. It preserves the source files' frontmatter and extracts the task-specific brief, phase focus, reference expectations, and carry-in clarification rows. If the packet appears incomplete or a finding depends on a source citation, open the corresponding source file and cite it directly.
|
|
29
29
|
|
|
30
30
|
---
|
|
31
31
|
|