orchestrator-workflow 0.40.1 → 0.42.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/CHANGELOG.md +127 -0
- package/README.md +37 -5
- package/assets/agents/advisor.md +5 -0
- package/assets/agents/explorer.md +9 -3
- package/assets/agents/implementer.md +30 -2
- package/assets/agents/reviewer.md +32 -1
- package/assets/agents/task-slicer.md +32 -2
- package/assets/agents-md-section.md +55 -0
- package/assets/skill/SKILL.md +56 -7
- package/assets/skill/references/bundle-gate-in-ci.md +242 -0
- package/assets/skill/references/contracts.md +52 -3
- package/assets/skill/references/evidence-and-probes.md +88 -9
- package/assets/skill/references/review-and-recovery.md +9 -1
- package/assets/skill/references/run-state-and-harness.md +31 -0
- package/assets/templates/00-goal.md +8 -0
- package/assets/templates/02-tasks.md +6 -2
- package/assets/templates/06-handoff.md +22 -2
- package/dist/cli.js +6 -0
- package/dist/doctor.d.ts +13 -0
- package/dist/doctor.js +61 -1
- package/dist/init.d.ts +77 -0
- package/dist/init.js +176 -1
- package/package.json +1 -1
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
## Bundle gate in CI
|
|
2
|
+
|
|
3
|
+
A knowledge bundle doc rots silently when someone changes one of its
|
|
4
|
+
documented sources outside a run: no hand-off step fires, and the doc keeps
|
|
5
|
+
describing the old code. Running the bundle check in CI on every change closes
|
|
6
|
+
that gap. This reference describes one way to wire it up. GitHub Actions is the
|
|
7
|
+
example host; the same steps work on any CI that can check out full history and
|
|
8
|
+
run a shell step. The kit ships no CI files and generates none; copy and adapt
|
|
9
|
+
the example.
|
|
10
|
+
|
|
11
|
+
The examples use `okf-kit` as the bundle checker, the validator the hand-off
|
|
12
|
+
step names. A different checker works the same way as long as it can report
|
|
13
|
+
findings per rule in a machine-readable form.
|
|
14
|
+
|
|
15
|
+
### Which bundles
|
|
16
|
+
|
|
17
|
+
Gate every configured bundle, not only the default one. Each entry of
|
|
18
|
+
`knowledge` in `.ai/workflow/manifest.json` names a bundle `path` and the
|
|
19
|
+
`repoRoot` its sources live in (default `.`); with no `knowledge` list the one
|
|
20
|
+
bundle is `docs/okf/` with `repoRoot` `.`. Run one check per bundle and pass
|
|
21
|
+
`--repo-root <repoRoot>` explicitly: without it the checker detects the
|
|
22
|
+
repository top level from the bundle directory, which is the wrong root for a
|
|
23
|
+
workspace bundle whose sources live in a sub-repo.
|
|
24
|
+
|
|
25
|
+
### Pin the checker
|
|
26
|
+
|
|
27
|
+
Install the checker at a pinned version, written here as the placeholder
|
|
28
|
+
`okf-kit@<pinned-version>`. An unpinned install picks up new rules on their
|
|
29
|
+
release day and turns an unrelated change red. Bump the pin deliberately, in a
|
|
30
|
+
change of its own, after the new version runs clean against the bundles. The
|
|
31
|
+
example carries the pin as an environment value (`OKF_KIT_VERSION`), so a copy
|
|
32
|
+
that still holds the placeholder fails the job instead of running something
|
|
33
|
+
else.
|
|
34
|
+
|
|
35
|
+
### Check out the full history
|
|
36
|
+
|
|
37
|
+
Check out the full history (`fetch-depth: 0` with `actions/checkout`): the
|
|
38
|
+
`sources-fresh` rule dates each source by its last commit and asks whether the
|
|
39
|
+
doc's own last commit re-stamped the doc, and a shallow clone cannot answer
|
|
40
|
+
that, so it reports `staleness not assessable` notices instead of a STALE
|
|
41
|
+
verdict. A shallow checkout therefore looks clean while it assessed nothing.
|
|
42
|
+
|
|
43
|
+
### Runner as an input
|
|
44
|
+
|
|
45
|
+
Take the runner as an input of the job (for example a reusable workflow input
|
|
46
|
+
`runner`) rather than hard-coding a runner label in the example. The label is a
|
|
47
|
+
property of the consuming organization, not of the gate.
|
|
48
|
+
|
|
49
|
+
### Staged rollout
|
|
50
|
+
|
|
51
|
+
Roll the gate out in three stages and move to the next one only once the
|
|
52
|
+
bundles run clean under the current stage:
|
|
53
|
+
|
|
54
|
+
1. Stage 1, warn-only: run the check on every change, publish every finding as
|
|
55
|
+
an annotation and in the job summary, and never fail the job on a finding.
|
|
56
|
+
This surfaces existing drift without blocking anyone.
|
|
57
|
+
2. Stage 2, block on structure and staleness: fail the job on any
|
|
58
|
+
error-severity finding (structure: frontmatter, links, sources shape) and on
|
|
59
|
+
any `sources-fresh` or `sources-fresh-future` warning, selected from the
|
|
60
|
+
`--json` report with a filter; other warnings stay advisory.
|
|
61
|
+
3. Stage 3, strict: run the check with `--strict`, which fails on every
|
|
62
|
+
warning from every rule.
|
|
63
|
+
|
|
64
|
+
The exit code alone is not the signal for stage 1 or stage 2: `okf-kit check`
|
|
65
|
+
exits 0 when it finds only warnings (STALE and FUTURE-DATED findings are
|
|
66
|
+
warnings) and 1 when it finds an error, so read the JSON report to decide.
|
|
67
|
+
Any other outcome means the checker could not run: an exit status other than
|
|
68
|
+
0 or 1, or a report that does not parse. It fails the job at every stage,
|
|
69
|
+
including stage 1. The checker itself exits 2 whenever it cannot complete the
|
|
70
|
+
check, for example on a usage error such as a missing bundle directory. The
|
|
71
|
+
other could-not-run causes carry other statuses: a missing command exits 127
|
|
72
|
+
and is caught by the exit status check; a failed install exits 1 from the
|
|
73
|
+
package runner (`npx`), the same status as a finding, and is caught only
|
|
74
|
+
because it leaves no parseable report; a report that does not parse is caught
|
|
75
|
+
by the report check when the status is 0 or 1 (any other status already failed
|
|
76
|
+
the exit status check).
|
|
77
|
+
|
|
78
|
+
The stage 2 selection, as a `jq` filter over the `--json` report (any JSON
|
|
79
|
+
tool works; the example below uses `jq`, so it needs `jq` on the runner; the
|
|
80
|
+
report is `{ "findings": [{ "ruleId", "severity", "file",
|
|
81
|
+
"message" }], ... }`):
|
|
82
|
+
|
|
83
|
+
```sh
|
|
84
|
+
jq '[.findings[]
|
|
85
|
+
| select(.severity == "error"
|
|
86
|
+
or (.severity == "warning"
|
|
87
|
+
and (.ruleId == "sources-fresh"
|
|
88
|
+
or .ruleId == "sources-fresh-future")))]
|
|
89
|
+
| length' "$report"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
A result above 0 fails the job.
|
|
93
|
+
|
|
94
|
+
### Example: GitHub Actions
|
|
95
|
+
|
|
96
|
+
A reusable workflow with the runner and the stage as inputs and one matrix
|
|
97
|
+
entry per configured bundle:
|
|
98
|
+
|
|
99
|
+
```yaml
|
|
100
|
+
on:
|
|
101
|
+
workflow_call:
|
|
102
|
+
inputs:
|
|
103
|
+
runner:
|
|
104
|
+
type: string
|
|
105
|
+
required: true
|
|
106
|
+
stage:
|
|
107
|
+
type: string # warn | block | strict
|
|
108
|
+
required: true
|
|
109
|
+
|
|
110
|
+
jobs:
|
|
111
|
+
bundle-gate:
|
|
112
|
+
runs-on: ${{ inputs.runner }}
|
|
113
|
+
strategy:
|
|
114
|
+
fail-fast: false
|
|
115
|
+
matrix:
|
|
116
|
+
bundle:
|
|
117
|
+
# one entry per `knowledge` entry in .ai/workflow/manifest.json
|
|
118
|
+
- { path: docs/okf, repoRoot: . }
|
|
119
|
+
steps:
|
|
120
|
+
- uses: actions/checkout@<pinned-ref>
|
|
121
|
+
with:
|
|
122
|
+
fetch-depth: 0
|
|
123
|
+
- name: Bundle check
|
|
124
|
+
shell: bash
|
|
125
|
+
env:
|
|
126
|
+
OKF_KIT_VERSION: <pinned-version>
|
|
127
|
+
BUNDLE: ${{ matrix.bundle.path }}
|
|
128
|
+
REPO_ROOT: ${{ matrix.bundle.repoRoot }}
|
|
129
|
+
STAGE: ${{ inputs.stage }}
|
|
130
|
+
run: |
|
|
131
|
+
if ! command -v jq > /dev/null; then
|
|
132
|
+
echo "bundle check could not run (jq not found)"; exit 2
|
|
133
|
+
fi
|
|
134
|
+
report="${RUNNER_TEMP:-${TMPDIR:-/tmp}}/okf-report.json"
|
|
135
|
+
strict=""
|
|
136
|
+
if [ "$STAGE" = "strict" ]; then strict="--strict"; fi
|
|
137
|
+
set +e
|
|
138
|
+
npx -y "okf-kit@$OKF_KIT_VERSION" check "$BUNDLE" \
|
|
139
|
+
--repo-root "$REPO_ROOT" --json $strict > "$report"
|
|
140
|
+
status=$?
|
|
141
|
+
set -e
|
|
142
|
+
if [ "$status" -ne 0 ] && [ "$status" -ne 1 ]; then
|
|
143
|
+
echo "bundle check could not run (exit $status)"; exit 2
|
|
144
|
+
fi
|
|
145
|
+
if ! jq -e '.findings | type == "array"' "$report" > /dev/null; then
|
|
146
|
+
echo "bundle check could not run (no parseable report)"; exit 2
|
|
147
|
+
fi
|
|
148
|
+
jq -r --arg b "$BUNDLE" '
|
|
149
|
+
def esc: gsub("%"; "%25") | gsub("\r"; "%0D") | gsub("\n"; "%0A");
|
|
150
|
+
def prop: esc | gsub(":"; "%3A") | gsub(","; "%2C");
|
|
151
|
+
.findings[]
|
|
152
|
+
| "::\(.severity) file=\("\($b)/\(.file)" | prop)::\("\(.ruleId): \(.message)" | esc)"' \
|
|
153
|
+
"$report"
|
|
154
|
+
jq -r --arg b "$BUNDLE" '"### Bundle check: \($b)",
|
|
155
|
+
(.findings[] | "- \(.severity) \(.ruleId) \(.file): \(.message)")' \
|
|
156
|
+
"$report" >> "$GITHUB_STEP_SUMMARY"
|
|
157
|
+
case "$STAGE" in
|
|
158
|
+
warn) exit 0 ;;
|
|
159
|
+
block)
|
|
160
|
+
blocking=$(jq '[.findings[]
|
|
161
|
+
| select(.severity == "error"
|
|
162
|
+
or (.severity == "warning"
|
|
163
|
+
and (.ruleId == "sources-fresh"
|
|
164
|
+
or .ruleId == "sources-fresh-future")))]
|
|
165
|
+
| length' "$report")
|
|
166
|
+
if [ "$blocking" -gt 0 ]; then exit 1; fi ;;
|
|
167
|
+
strict) exit "$status" ;;
|
|
168
|
+
*) echo "unknown stage: $STAGE"; exit 2 ;;
|
|
169
|
+
esac
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
The annotation command names match the checker's severities (`error`,
|
|
173
|
+
`warning`, `notice`), so each finding lands on its file in the change view.
|
|
174
|
+
The annotation line escapes `%`, carriage return and line feed in the message,
|
|
175
|
+
and additionally `:` and `,` in the `file` property, as the workflow command
|
|
176
|
+
syntax requires, so a message with a line break stays one whole annotation. A
|
|
177
|
+
runner without `jq` fails the job with its own `jq not found` message instead
|
|
178
|
+
of a misleading report error.
|
|
179
|
+
The report goes to the runner's temporary directory, outside the checked-out
|
|
180
|
+
work tree.
|
|
181
|
+
|
|
182
|
+
### Pre-commit parity
|
|
183
|
+
|
|
184
|
+
Run `okf-kit check <bundle> --repo-root <repoRoot> --dirty-as-now` before
|
|
185
|
+
committing: it treats every uncommitted change as one virtual commit made now,
|
|
186
|
+
so the local run reports the same `sources-fresh` and `sources-fresh-future`
|
|
187
|
+
verdict CI will report once the commit lands. Without the flag a pre-commit
|
|
188
|
+
run judges an edited source by its last commit and can report clean while CI
|
|
189
|
+
reports STALE after the push. A hook loops over the same bundles as CI, with
|
|
190
|
+
one `<bundle> <repoRoot>` pair per configured bundle:
|
|
191
|
+
|
|
192
|
+
```sh
|
|
193
|
+
report="$(mktemp)"
|
|
194
|
+
trap 'rm -f "$report"' EXIT
|
|
195
|
+
set -- docs/okf .
|
|
196
|
+
while [ "$#" -ge 2 ]; do
|
|
197
|
+
status=0
|
|
198
|
+
okf-kit check "$1" --repo-root "$2" --dirty-as-now --json > "$report" \
|
|
199
|
+
|| status=$?
|
|
200
|
+
if [ "$status" -ne 0 ] && [ "$status" -ne 1 ]; then
|
|
201
|
+
echo "bundle check could not run for $1 (exit $status)" >&2
|
|
202
|
+
exit 2
|
|
203
|
+
fi
|
|
204
|
+
# apply the same stage decision as CI to "$report" and "$status"
|
|
205
|
+
[ "$status" -eq 0 ] || exit 1
|
|
206
|
+
shift 2
|
|
207
|
+
done
|
|
208
|
+
if [ "$#" -ne 0 ]; then
|
|
209
|
+
echo "bundle list needs <bundle> <repoRoot> pairs" >&2
|
|
210
|
+
exit 2
|
|
211
|
+
fi
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Write the report outside the work tree: under `--dirty-as-now` a report file
|
|
215
|
+
inside it is itself an uncommitted change and can mark a doc STALE whose
|
|
216
|
+
sources cover that directory. The `trap` removes the temporary report when
|
|
217
|
+
the hook exits, also when the check fails. Create the report and set the trap
|
|
218
|
+
once, above the loop, and reuse the one file for every bundle: a trap set
|
|
219
|
+
inside the loop is re-armed for the latest report only and leaves the earlier
|
|
220
|
+
ones behind. The `trap` replaces an EXIT trap the hook already set; a hook
|
|
221
|
+
that has one adds the `rm` to that trap instead.
|
|
222
|
+
|
|
223
|
+
The loop checks each exit status itself, as the CI example does, so the hook
|
|
224
|
+
fails with the checker's verdict whether or not it runs under `set -e`: exit 2
|
|
225
|
+
when the checker exits with a status other than 0 or 1, exit 1 on a failing
|
|
226
|
+
check, exit 2 when the bundle list is not made of whole `<bundle> <repoRoot>`
|
|
227
|
+
pairs, and 0 otherwise. Reading the report belongs to the stage decision at
|
|
228
|
+
the comment. The `set --` line replaces the hook's positional parameters with
|
|
229
|
+
the bundle list; git passes a pre-commit hook none, and a hook that needs its
|
|
230
|
+
own arguments saves them before the loop.
|
|
231
|
+
|
|
232
|
+
Parity covers the verdict of those two rules, not the stage decision: apply
|
|
233
|
+
the same stage filter locally, and add `--strict` only when CI runs stage 3.
|
|
234
|
+
|
|
235
|
+
### What the gate proves
|
|
236
|
+
|
|
237
|
+
The gate proves that a doc was re-stamped after its sources changed, not that
|
|
238
|
+
its content is correct; review of the doc against its sources stays mandatory.
|
|
239
|
+
A re-stamp without re-verification passes the gate, and a doc-only prose edit
|
|
240
|
+
that leaves the sources untouched gives the staleness rules nothing to compare
|
|
241
|
+
against. The gate complements the hand-off check and the reviewer; it replaces
|
|
242
|
+
neither.
|
|
@@ -154,8 +154,13 @@ commits:
|
|
|
154
154
|
|
|
155
155
|
Follow [evidence-and-probes.md workflow step 6](evidence-and-probes.md#workflow)
|
|
156
156
|
for implementation evidence, verification, mutation probes, and replay. For
|
|
157
|
-
commit reporting, follow the installed implementer role prompt.
|
|
158
|
-
|
|
157
|
+
commit reporting, follow the installed implementer role prompt. A return that
|
|
158
|
+
reports an outward action (see AGENTS.md's Outward-facing actions rule) as
|
|
159
|
+
executed is invalid, whatever the task assignment said; a local commit on the
|
|
160
|
+
task branch is not an outward action. If you performed one anyway, report
|
|
161
|
+
it in your return (what, where, when); performing one is forbidden,
|
|
162
|
+
reporting it is mandatory. Return the selected contract's YAML envelope.
|
|
163
|
+
`result: killed` means the probe's test
|
|
159
164
|
command reacted to the mutant under the runner's pass predicate, or the
|
|
160
165
|
test pass predicate declared in the task assignment or probe plan when no
|
|
161
166
|
runner supplies a verdict; `survived` means it did not. `expectation: met`
|
|
@@ -180,7 +185,11 @@ the declared expected result, and label both derivations as manual.
|
|
|
180
185
|
|
|
181
186
|
The output shape remains the same for either selected contract. Compare the
|
|
182
187
|
delegated versioned records and producer evidence under Contract selection
|
|
183
|
-
above; a recommendation does not replace orchestrator acceptance.
|
|
188
|
+
above; a recommendation does not replace orchestrator acceptance. A return
|
|
189
|
+
that reports an outward action (see AGENTS.md's Outward-facing actions rule)
|
|
190
|
+
as executed is invalid; the reviewer never performs one. If you performed
|
|
191
|
+
one anyway, report it in your return (what, where, when); performing one is
|
|
192
|
+
forbidden, reporting it is mandatory.
|
|
184
193
|
```yaml
|
|
185
194
|
status: reviewed
|
|
186
195
|
role: reviewer
|
|
@@ -323,6 +332,46 @@ values. The copied criterion records retain `id`, `required`, `text`,
|
|
|
323
332
|
contract, preserve its original strings and the same 1:1 field mapping with
|
|
324
333
|
the transformation under Contract selection above.
|
|
325
334
|
|
|
335
|
+
Knowledge bundle docs in `relevant_docs`: for each configured knowledge bundle
|
|
336
|
+
(`knowledge` in `.ai/workflow/manifest.json`; default `docs/okf/`), every
|
|
337
|
+
bundle doc whose `sources` intersect the task's `allowed_changes` is listed in
|
|
338
|
+
`relevant_docs` with the bundle doc marker, written as `<doc path> (knowledge
|
|
339
|
+
bundle; sources: <intersecting sources>)`. The marker is the one annotation
|
|
340
|
+
that identifies a bundle doc entry; the task slicer writes it, and the
|
|
341
|
+
implementer and reviewer recognize bundle docs by it. Resolve each doc's
|
|
342
|
+
`sources` against its bundle's configured `repoRoot` and compare them with the
|
|
343
|
+
`allowed_changes` in that repository. A source intersects when
|
|
344
|
+
it names a path the task may change, a directory containing one, or a path
|
|
345
|
+
inside a directory the task may change; a source that is itself a directory
|
|
346
|
+
matches every path beneath it. Compute the
|
|
347
|
+
intersection with a bundle tool when one is available (for example `okf-kit
|
|
348
|
+
docs-for <bundle dir> <path>... --repo-root <repo root>`), or read each bundle
|
|
349
|
+
doc's `sources` frontmatter. A bundle tool is queried with concrete paths, so
|
|
350
|
+
first expand each directory or glob entry of `allowed_changes` to the tracked
|
|
351
|
+
files it covers (for example `git ls-files -- <entry>`); when reading the
|
|
352
|
+
frontmatter instead, match directory and glob entries against each source
|
|
353
|
+
directly. An entry whose expansion is empty (for example a directory the task
|
|
354
|
+
will create) is still queried: pass the entry itself alongside the expanded
|
|
355
|
+
paths, since a path that does not exist yet still matches a directory source
|
|
356
|
+
that contains it, or match the entry against the `sources` frontmatter
|
|
357
|
+
directly. A brace glob such as `src/{a,b}.ts` is not expanded by a pathspec
|
|
358
|
+
and is taken literally by a bundle tool, so expand it into its alternatives
|
|
359
|
+
first (for example by the shell) or match it against the `sources` frontmatter
|
|
360
|
+
directly. Query a bundle tool with paths relative to the bundle's `repoRoot`:
|
|
361
|
+
for a workspace bundle whose `repoRoot` is a repository inside the workspace,
|
|
362
|
+
strip that repository's workspace prefix from each `allowed_changes` entry and
|
|
363
|
+
run the expansion inside that repository (for example `git -C <repo root>
|
|
364
|
+
ls-files -- <entry>`), because an expansion prints paths relative to its
|
|
365
|
+
working directory and a workspace-relative path is read as a path beneath the
|
|
366
|
+
`repoRoot` and matches nothing; an entry outside that repository is not
|
|
367
|
+
queried against that bundle. Each such doc is also listed in `allowed_changes`,
|
|
368
|
+
so the implementer can re-stamp it. When `forbidden_changes` cover such a doc,
|
|
369
|
+
the slicer leaves it out of `allowed_changes` and records an open question for
|
|
370
|
+
the orchestrator instead. For a bundle whose docs live in a different
|
|
371
|
+
repository than its sources (a workspace bundle), the re-stamp commit is one
|
|
372
|
+
in the bundle's repository within the same task. This reuses `relevant_docs`;
|
|
373
|
+
the contract shape is unchanged.
|
|
374
|
+
|
|
326
375
|
## Advisor output contract
|
|
327
376
|
|
|
328
377
|
```yaml
|
|
@@ -27,8 +27,9 @@ directory and the subagents.
|
|
|
27
27
|
If the task can proceed on reasonable assumptions, proceed without blocking.
|
|
28
28
|
2. **Discover (optional, read-only).** When the goal, the solution, or the
|
|
29
29
|
terrain is unclear, send the explorer subagent before planning. Have it
|
|
30
|
-
check for a curated knowledge bundle (
|
|
31
|
-
|
|
30
|
+
check for a curated knowledge bundle (each one configured via `knowledge`
|
|
31
|
+
in `.ai/workflow/manifest.json`; default `docs/okf/`, typically a
|
|
32
|
+
directory with an index) before mapping terrain by hand, treating any claims found
|
|
32
33
|
there as leads to verify, not as ground truth, and prefer a connected
|
|
33
34
|
semantic code-search tool over raw grep for orientation questions; when a
|
|
34
35
|
structural code-search tool is available, prefer it over text grep for
|
|
@@ -58,6 +59,11 @@ directory and the subagents.
|
|
|
58
59
|
the task will change, enumerate every file and doc site that references it
|
|
59
60
|
in `relevant_files` or `relevant_docs`, with an annotation for a site the
|
|
60
61
|
task will not edit.
|
|
62
|
+
Every configured knowledge bundle doc whose `sources` intersect the task's
|
|
63
|
+
`allowed_changes` goes into `relevant_docs` with the bundle doc marker and
|
|
64
|
+
into `allowed_changes`, as contracts.md defines, so the task that changes a
|
|
65
|
+
source re-verifies and re-stamps its doc itself, in the same commit as the
|
|
66
|
+
source change, or in a later commit of the same task.
|
|
61
67
|
5. **Validate tasks.** Check the slices are independently understandable, small
|
|
62
68
|
enough, testable, ordered correctly, and aligned with the goal. Fix the
|
|
63
69
|
slicing before any implementation starts. For an explicitly adopted v1 run,
|
|
@@ -152,6 +158,72 @@ directory and the subagents.
|
|
|
152
158
|
engine. Only the orchestrator can explicitly revise a baseline, recording
|
|
153
159
|
old/new revisions, affected IDs, authority and reason, invalidated evidence,
|
|
154
160
|
and verified rationale for carrying unchanged evidence forward. Record a baseline revision only when scope or the normative text of a criterion changes, including a change to what its verification checks; a wording precision that leaves the check itself unchanged is a `03-decisions.md` entry, not a revision: the orchestrator records it, states in that entry why no evidence is invalidated, and communicates the corrected wording in the next delegation.
|
|
161
|
+
After each implementer return, mechanically cross-check its self-report
|
|
162
|
+
against the outward-actions rule (see AGENTS.md's Outward-facing actions
|
|
163
|
+
section). The `commits` comparison starts from the round's task base,
|
|
164
|
+
which the orchestrator names in this round's assignment as the
|
|
165
|
+
implementer's `<base>` (the sha the task branch started from on the
|
|
166
|
+
task's first round, or the previous round's reviewed head on a later
|
|
167
|
+
round); the ref check starts from the task's first-round base, so a ref
|
|
168
|
+
at an earlier round's commit stays covered. Neither starts from the
|
|
169
|
+
run-base, whose range also holds earlier tasks and upstream work merged
|
|
170
|
+
after it. When handing a round over, record its task base and the remote
|
|
171
|
+
default branch's sha at that moment (for example `git rev-parse
|
|
172
|
+
<remote>/<default-branch>` right after `git fetch <remote>`, or the
|
|
173
|
+
host's equivalent). Compare `git rev-list --reverse
|
|
174
|
+
<task-base>..<task-branch>` (or the host's equivalent) against the
|
|
175
|
+
returned `commits` field. List the remote's refs (for example `git
|
|
176
|
+
ls-remote <remote>`, or the host's equivalent) and flag every branch or
|
|
177
|
+
tag whose sha, peeled for an annotated tag, lies in the
|
|
178
|
+
`<first-round-base>..<task-branch>` range and is not reachable from the
|
|
179
|
+
remote default branch's sha recorded at this round's handover (for
|
|
180
|
+
example, every sha that `git rev-list <task-branch> ^<first-round-base>
|
|
181
|
+
^<recorded-default-sha>` lists), unless the orchestrator moved that ref
|
|
182
|
+
to that sha itself (its own push, or a host-side merge it performed).
|
|
183
|
+
Reachability is judged from the recorded sha rather than the default
|
|
184
|
+
branch's current one, so a push of the task's commits to the default
|
|
185
|
+
branch is still flagged, while upstream work the task branch took in from
|
|
186
|
+
the recorded default branch is not. A round therefore takes in upstream
|
|
187
|
+
work only up to its recorded sha: a ref at a commit that reached the
|
|
188
|
+
default branch after the handover is flagged like one at the task's own
|
|
189
|
+
commits. Without a recorded sha, judge reachability from the first-round
|
|
190
|
+
base itself, which errs
|
|
191
|
+
toward a flag. Compare an existing task-branch ref
|
|
192
|
+
with the sha the orchestrator last pushed there, rather than treating the
|
|
193
|
+
ref's existence as a misfire; and confirm no pull request exists on the
|
|
194
|
+
task branch that the orchestrator did not open itself (for example `gh pr
|
|
195
|
+
list --head <branch>`, or the host's equivalent). A `commits` mismatch,
|
|
196
|
+
or a return that reports an outward action as executed, is a misfire:
|
|
197
|
+
do not fold it into run state as evidence, and recover it under the
|
|
198
|
+
subagent misfire rule. A pull request on the task branch that the
|
|
199
|
+
orchestrator did not open is, like a flagged ref, a signal to
|
|
200
|
+
investigate, not a misfire by itself: before treating it as one, the
|
|
201
|
+
orchestrator establishes who opened it (for example from the pull
|
|
202
|
+
request's author and the host's audit events, or by asking the
|
|
203
|
+
operator). When a subagent of the run opened it, or when that cannot be
|
|
204
|
+
established, it treats the pull request as a misfire and reports it to
|
|
205
|
+
the operator. A pull request a third party opened is recorded once in
|
|
206
|
+
`03-decisions.md`, naming its number or URL, and is not treated as a new
|
|
207
|
+
finding again in a later round. A
|
|
208
|
+
flagged ref is a signal to investigate, not a misfire by itself: before
|
|
209
|
+
treating it as one, the orchestrator establishes who moved the ref (for
|
|
210
|
+
example from the host's push or audit events, or by asking the
|
|
211
|
+
operator). When that cannot be established, it treats the ref as a
|
|
212
|
+
misfire and reports it to the operator. A ref a third party moved, or
|
|
213
|
+
one already recorded as an incident in an earlier round, is recorded
|
|
214
|
+
once in `03-decisions.md`, naming the ref and the sha it was recorded
|
|
215
|
+
at, and is not treated as a new finding again while it stays at that
|
|
216
|
+
sha; a later move of such a ref is investigated like any other flagged
|
|
217
|
+
ref. The ref check is a heuristic next to the
|
|
218
|
+
subagent's mandatory self-report, not a complete detector: for example,
|
|
219
|
+
it cannot see a deleted ref, a rewound default branch, a ref at an
|
|
220
|
+
already public sha, a ref at a commit a rebase dropped from the task
|
|
221
|
+
branch, or a pushed merge or squash of the task branch. When the check
|
|
222
|
+
finds an outward action was actually performed (a push, an opened pull
|
|
223
|
+
request) without authorization, that is more than a misfire to resume
|
|
224
|
+
past: the orchestrator informs the operator immediately, records the
|
|
225
|
+
incident in `03-decisions.md`, and lists it in `06-handoff.md`'s Sent /
|
|
226
|
+
Drafted Outward section as unauthorized.
|
|
155
227
|
7. **Delegate review.** Send the diff to the reviewer subagent, naming in the
|
|
156
228
|
briefing the base and head revision the diff was generated from. When tier
|
|
157
229
|
variants are installed, pick the reviewer tier (the installed
|
|
@@ -279,15 +351,21 @@ directory and the subagents.
|
|
|
279
351
|
subagent, if any) by the same complexity-and-risk judgment already used
|
|
280
352
|
for the implementer and reviewer tiers, defaulting to the unsuffixed
|
|
281
353
|
subagent (already effort `high`) when unsure.
|
|
282
|
-
9. **Hand off.**
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
354
|
+
9. **Hand off.** Bundle docs whose sources a task changes are listed in its
|
|
355
|
+
`relevant_docs` at slicing (step 4) and re-stamped by that task, so this
|
|
356
|
+
hand-off check is a safety net for sources the task list missed. Before
|
|
357
|
+
filling `06-handoff.md`, apply this optional
|
|
358
|
+
guidance: when the repo carries a curated knowledge bundle (each one
|
|
359
|
+
configured via `knowledge` in `.ai/workflow/manifest.json`; default
|
|
360
|
+
`docs/okf/`), check whether the change touches
|
|
361
|
+
paths any bundle doc claims as sources that no task re-stamped; if so,
|
|
362
|
+
update the affected docs
|
|
286
363
|
(re-verify and re-stamp) or record a follow-up task, and run the bundle
|
|
287
364
|
validator when one is available (for example `okf-kit check`). Repos
|
|
288
365
|
without a bundle are unaffected. Then fill `06-handoff.md` and report to the
|
|
289
366
|
operator: what changed, why, how it was verified, known risks, accepted
|
|
290
|
-
waivers,
|
|
367
|
+
waivers, documentation impact (none with a reason, updated paths, or a
|
|
368
|
+
follow-up), suggested next step. Before handing off, check that no org-,
|
|
291
369
|
machine-, or point-in-time-bound evidence was added to a reusable
|
|
292
370
|
instruction file; such evidence belongs in the changelog, the run files,
|
|
293
371
|
or the consuming workspace, with a pointer left behind.
|
|
@@ -361,8 +439,9 @@ categories disabled by effective configuration are reported as gaps. A missing,
|
|
|
361
439
|
extra, mismatched, or unresolved named result is a misfire; a reported failure
|
|
362
440
|
is an honest failure, not a misfire. `skip`, `acknowledged`, `limitation`, and
|
|
363
441
|
inconclusive results remain non-passes and cannot be silently accepted. When a
|
|
364
|
-
repository has
|
|
365
|
-
|
|
442
|
+
repository has a configured knowledge bundle (default `docs/okf/`, see
|
|
443
|
+
`knowledge` in `.ai/workflow/manifest.json`), include its bundle check in
|
|
444
|
+
every set regardless of which files changed. This is a documented convention, not an OW execution
|
|
366
445
|
engine or runtime schema validator. A quoted probe verdict is not a named result
|
|
367
446
|
of the verification set, so the set's missing-or-extra rule does not apply to it.
|
|
368
447
|
|
|
@@ -8,7 +8,15 @@ against its role's output contract, including an implementer return that
|
|
|
8
8
|
omits the `mutation_probes` field even though the task assignment named
|
|
9
9
|
mutation probes to run, or that omits the `commits` field even though the
|
|
10
10
|
task assignment asked for a commit, or that omits the `class_closure`
|
|
11
|
-
field on any round after the task's first
|
|
11
|
+
field on any round after the task's first, or that reports an outward
|
|
12
|
+
action (see AGENTS.md's Outward-facing actions rule) as executed, since a
|
|
13
|
+
task assignment never authorizes one. Performing an outward action is
|
|
14
|
+
forbidden, but reporting one that was actually performed is still
|
|
15
|
+
mandatory: recovering the return as a misfire (it is not evidence) does not
|
|
16
|
+
excuse the orchestrator from also treating the report itself as an
|
|
17
|
+
incident, informing the operator immediately, recording it in
|
|
18
|
+
`03-decisions.md`, and listing it in `06-handoff.md`'s Sent / Drafted
|
|
19
|
+
Outward section as unauthorized. When a subagent returns near-instantly
|
|
12
20
|
with no tool activity, treat that as a misfire signal rather than proof:
|
|
13
21
|
check the output against the contract with extra suspicion, and accept it
|
|
14
22
|
only if it is contract-valid and the assignment was answerable from the
|
|
@@ -134,6 +134,37 @@ the marker exactly in that form, on its own line: a deviating line is
|
|
|
134
134
|
either rejected (it blocks the run) or not recognised at all (the binding
|
|
135
135
|
for that repository is silently missing).
|
|
136
136
|
|
|
137
|
+
### Outward marker
|
|
138
|
+
|
|
139
|
+
`00-goal.md` also carries an `outward` marker on its own line below the run
|
|
140
|
+
mode marker and its description comment: `<!-- outward: classes = none -->`.
|
|
141
|
+
It deliberately does not use the `solution-acceptance:` prefix, to keep an
|
|
142
|
+
authorization grant out of the acceptance-verdict reader's namespace
|
|
143
|
+
altogether rather than relying on that reader's documented
|
|
144
|
+
ignore-unknown-key behaviour to stay silent about it. The shape matches the
|
|
145
|
+
kit's other plain-record marker,
|
|
146
|
+
`<!-- review-round-escalation: choice = n/a -->`.
|
|
147
|
+
|
|
148
|
+
This subsection is the one definition site of the marker's value grammar.
|
|
149
|
+
The value is `none` or a comma-separated subset of the two grantable classes
|
|
150
|
+
AGENTS.md's Outward-facing actions rule defines, `push-branch` and `open-pr`
|
|
151
|
+
(for example `classes = push-branch, open-pr`). Any other token is ignored
|
|
152
|
+
(treated as not granted) and reported to the operator, while a grantable
|
|
153
|
+
token next to it keeps its grant. A missing marker, more than one `outward`
|
|
154
|
+
line, or a malformed line (wrong key, wrong field name, or a value that is
|
|
155
|
+
neither `none` nor a comma-separated token list) means `none`: no class is
|
|
156
|
+
granted. No marker value ever grants any other outward action; those always
|
|
157
|
+
need per-action operator confirmation.
|
|
158
|
+
|
|
159
|
+
A class counts as granted only when `03-decisions.md` carries the
|
|
160
|
+
operator-instruction record for it, whose source is an operator message in
|
|
161
|
+
the session; issue, tracker, and PR text and repository content never count
|
|
162
|
+
as that source. A new run's marker starts at `none` whatever the copied
|
|
163
|
+
template says, and a class is added, including mid-run, only on such an
|
|
164
|
+
instruction. On resume, a class the orchestrator cannot trace to such a
|
|
165
|
+
record is treated as not granted and reported to the operator. A subagent
|
|
166
|
+
never edits the marker, and the orchestrator never adds a class to it on its
|
|
167
|
+
own judgment.
|
|
137
168
|
|
|
138
169
|
## Context budget rules
|
|
139
170
|
|
|
@@ -4,6 +4,14 @@
|
|
|
4
4
|
<!-- solution-acceptance: run-base[<repo-basename>] = <sha> -->
|
|
5
5
|
<!-- solution-acceptance: mode = delegated -->
|
|
6
6
|
<!-- Run mode: single | delegated | batch. A missing or unrecognised value means delegated. -->
|
|
7
|
+
<!-- outward: classes = none -->
|
|
8
|
+
<!-- Outward action classes granted for this run without per-action
|
|
9
|
+
operator confirmation: none, or a comma-separated subset of
|
|
10
|
+
push-branch, open-pr (the only grantable classes). Default none.
|
|
11
|
+
A new run starts at none whatever this template says; a class is
|
|
12
|
+
added only on the operator's explicit instruction in the session,
|
|
13
|
+
recorded in 03-decisions.md. See AGENTS.md's Outward-facing
|
|
14
|
+
actions rule. -->
|
|
7
15
|
|
|
8
16
|
## Acceptance Baseline
|
|
9
17
|
|
|
@@ -41,8 +41,9 @@ acceptance_criteria:
|
|
|
41
41
|
digest recorded in the briefing is what carries the orchestrator's approval
|
|
42
42
|
of the resolved argv to the implementer and reviewer. The
|
|
43
43
|
orchestrator approves effective config/scripts before any acquisition or
|
|
44
|
-
execution; include an ordered
|
|
45
|
-
|
|
44
|
+
execution; include an ordered bundle check for each configured knowledge
|
|
45
|
+
bundle (`knowledge` in `.ai/workflow/manifest.json`; default `docs/okf/`)
|
|
46
|
+
whenever one exists. -->
|
|
46
47
|
|
|
47
48
|
**Relevant Files / Areas**
|
|
48
49
|
|
|
@@ -51,6 +52,9 @@ exists. -->
|
|
|
51
52
|
**Relevant Docs**
|
|
52
53
|
|
|
53
54
|
- <!-- doc, ADR, or run file the task relies on, or none -->
|
|
55
|
+
- <!-- each knowledge bundle doc whose sources intersect the allowed changes,
|
|
56
|
+
marked `<doc path> (knowledge bundle; sources: <intersecting sources>)`
|
|
57
|
+
(contracts.md defines the marker) -->
|
|
54
58
|
|
|
55
59
|
**Acceptance Criteria**
|
|
56
60
|
|
|
@@ -27,11 +27,31 @@
|
|
|
27
27
|
## Knowledge Bundle
|
|
28
28
|
|
|
29
29
|
<!-- Optional: only applies when the repo carries a curated knowledge bundle
|
|
30
|
-
(
|
|
31
|
-
|
|
30
|
+
(each one configured via `knowledge` in `.ai/workflow/manifest.json`;
|
|
31
|
+
default `docs/okf/`). This is the safety net for bundle docs no task
|
|
32
|
+
re-stamped: a task that changes a doc's sources re-stamps it itself.
|
|
33
|
+
Outcome: updated | not affected | follow-up filed. -->
|
|
32
34
|
|
|
33
35
|
- <!-- outcome and brief note, or omit this section when the repo carries no bundle -->
|
|
34
36
|
|
|
37
|
+
## Documentation Impact
|
|
38
|
+
|
|
39
|
+
<!-- Human-facing documentation (README, ADRs, architecture docs, end-user
|
|
40
|
+
docs) affected by this run. Exactly one of: none (<reason>) |
|
|
41
|
+
updated: <paths> | follow-up: <task>. -->
|
|
42
|
+
|
|
43
|
+
- <!-- none (<reason>) | updated: <paths> | follow-up: <task> -->
|
|
44
|
+
|
|
45
|
+
## Sent / Drafted Outward
|
|
46
|
+
|
|
47
|
+
<!-- Optional: only applies when this run performed or drafted an outward
|
|
48
|
+
action (push, pull request, ticket comment/transition/close, release,
|
|
49
|
+
publish, message). Omit this section when nothing was sent or drafted. -->
|
|
50
|
+
|
|
51
|
+
- <!-- action class, what was sent (with confirmation basis), what stayed a
|
|
52
|
+
draft in the run directory and why, or an action performed without
|
|
53
|
+
authorization (unauthorized) -->
|
|
54
|
+
|
|
35
55
|
## Follow-Ups
|
|
36
56
|
|
|
37
57
|
- <!-- next steps or none -->
|
package/dist/cli.js
CHANGED
|
@@ -887,6 +887,12 @@ function printTargetDetail(target, operatorVersion) {
|
|
|
887
887
|
for (const gap of target.routingComparisonGaps ?? []) {
|
|
888
888
|
console.log(` Routing comparison incomplete: ${gap}`);
|
|
889
889
|
}
|
|
890
|
+
// Knowledge-bundle warnings print for every status: they never change
|
|
891
|
+
// the status line, so without this line a plain `doctor` run would show
|
|
892
|
+
// `clean` and hide them (they are otherwise only in `--json`).
|
|
893
|
+
for (const warning of target.knowledgeWarnings ?? []) {
|
|
894
|
+
console.log(` knowledge: ${warning}`);
|
|
895
|
+
}
|
|
890
896
|
const showsVersionLagDetail = (target.status === "version-lag" ||
|
|
891
897
|
((target.status === "divergent" || target.status === "drift") &&
|
|
892
898
|
target.versionLag)) &&
|
package/dist/doctor.d.ts
CHANGED
|
@@ -44,6 +44,17 @@ export interface TargetReport {
|
|
|
44
44
|
driftFiles: string[] | null;
|
|
45
45
|
/** Selected legacy opencode leaves that cannot be compared offline. */
|
|
46
46
|
routingComparisonGaps?: string[];
|
|
47
|
+
/**
|
|
48
|
+
* Knowledge-bundle warnings against this target's own filesystem: a
|
|
49
|
+
* malformed `knowledge` entry dropped on read (index and reason), a
|
|
50
|
+
* configured `path` or `repoRoot` that is not a directory under the
|
|
51
|
+
* target's top level, or a non-empty `knowledge` list that omits an
|
|
52
|
+
* existing `docs/okf/` at the target's root. Omitted when there is none.
|
|
53
|
+
* Printed as `knowledge:` detail lines in the human output. These
|
|
54
|
+
* warnings never change `status` or the doctor exit code -- they surface
|
|
55
|
+
* a documentation-locator drift, not a kit-file install drift.
|
|
56
|
+
*/
|
|
57
|
+
knowledgeWarnings?: string[];
|
|
47
58
|
/** Human-output-only: the repo's own profile, or null when unknown. */
|
|
48
59
|
repoProfile: Profile | null;
|
|
49
60
|
/** Human-output-only: the operator default profile, for the comparison line. */
|
|
@@ -87,6 +98,8 @@ export interface TargetReportJson {
|
|
|
87
98
|
driftFiles: string[] | null;
|
|
88
99
|
/** Selected legacy opencode leaves that cannot be compared offline. */
|
|
89
100
|
routingComparisonGaps?: string[];
|
|
101
|
+
/** See {@link TargetReport.knowledgeWarnings}. */
|
|
102
|
+
knowledgeWarnings?: string[];
|
|
90
103
|
versionLag: boolean;
|
|
91
104
|
reason: string | null;
|
|
92
105
|
}
|