@r1z4x/tezgah 1.11.0 → 1.14.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 +507 -1
- package/MANIFEST +40 -0
- package/NOTICE +152 -0
- package/README.de.md +41 -20
- package/README.es.md +39 -19
- package/README.fr.md +41 -20
- package/README.md +18 -10
- package/README.tr.md +39 -21
- package/bin/codegen +9 -2
- package/bin/consult +6 -0
- package/bin/tezgah-adhd +3 -0
- package/bin/tezgah-agents +3 -0
- package/bin/tezgah-capture +3 -0
- package/bin/tezgah-design +329 -54
- package/bin/tezgah-docs +158 -42
- package/bin/tezgah-dsh +1 -1
- package/bin/tezgah-gate +7 -2
- package/bin/tezgah-import-ai-research +16 -4
- package/bin/tezgah-index +3 -0
- package/bin/tezgah-lessons +13 -4
- package/bin/tezgah-mcp +4 -0
- package/bin/tezgah-migrate +3 -0
- package/bin/tezgah-ocr-review +2 -1
- package/bin/tezgah-optimize +4 -1
- package/bin/tezgah-pony +3 -0
- package/bin/tezgah-research +51 -10
- package/bin/tezgah-rollback +3 -0
- package/bin/tezgah-route +1 -1
- package/bin/tezgah-setup +1741 -95
- package/bin/tezgah-status +11 -1
- package/bin/tezgah-task +58 -17
- package/bin/tezgah.js +10 -3
- package/commands/adhd.md +1 -1
- package/docs/README.md +19 -8
- package/docs/architecture.md +2 -2
- package/docs/citations-baseline.json +11 -17
- package/docs/clarity-baseline.json +12 -6
- package/docs/contract.md +83 -34
- package/docs/environment.md +59 -24
- package/docs/evidence.md +128 -25
- package/docs/gate.md +77 -23
- package/docs/glossary.md +1 -1
- package/docs/hosts.md +343 -48
- package/docs/layers.md +2 -2
- package/docs/models.md +6 -0
- package/docs/operations.md +83 -29
- package/docs/research.md +37 -11
- package/docs/skills.md +31 -8
- package/docs/status-line.md +39 -23
- package/docs/testing.md +50 -17
- package/docs/vision.md +6 -2
- package/hooks/hooks.json +1 -1
- package/hooks/lang/en.json +16 -2
- package/hooks/lang/tr.json +14 -2
- package/hooks/projects-posttooluse.py +11 -3
- package/hooks/projects-stop.py +3 -2
- package/hooks/tezgah_agents.py +27 -3
- package/hooks/tezgah_attest.py +79 -10
- package/hooks/tezgah_context.py +61 -31
- package/hooks/tezgah_gate.py +480 -126
- package/hooks/tezgah_integrity.py +577 -133
- package/hooks/tezgah_lessons.py +5 -2
- package/hooks/tezgah_paths.py +60 -8
- package/hooks/tezgah_policy.py +48 -18
- package/hooks/tezgah_replay.py +8 -2
- package/hooks/tezgah_research.py +167 -24
- package/hooks/tezgah_skill_pick.py +1 -1
- package/hooks/tezgah_snapshot.py +6 -3
- package/hooks/tezgah_stack.py +236 -1
- package/hooks/tezgah_stopspec.py +2 -1
- package/hooks/tezgah_task.py +2 -1
- package/hosts/amp/hook.py +217 -0
- package/hosts/amp/tezgah-plugin.ts.in +396 -0
- package/hosts/antigravity/hook.py +255 -0
- package/hosts/codex/hook.py +3 -2
- package/hosts/commandcode/hook.py +239 -0
- package/hosts/copilot/hook.py +284 -0
- package/hosts/cursor/hook.py +4 -2
- package/hosts/droid/hook.py +259 -0
- package/hosts/dsh/hooks.json +1 -1
- package/hosts/gemini/hook.py +213 -0
- package/hosts/goose/hook.py +145 -0
- package/hosts/omp/hook.py +5 -2
- package/hosts/omp/tezgah-hook.ts.in +157 -42
- package/hosts/opencode/plugins/tezgah.js +209 -63
- package/hosts/qwen/hook.py +206 -0
- package/output-styles/tezgah.md +11 -6
- package/package.json +6 -3
- package/packaging/build.sh +4 -4
- package/packaging/install.sh +11 -0
- package/packaging/upgrade.sh +3 -0
- package/skills/ai-research/LICENSE +21 -0
- package/skills/design-contract/SKILL.md +27 -6
- package/skills/design-library/LICENSE +21 -0
- package/skills/harness/SKILL.md +2 -0
- package/skills/i-have-adhd/SKILL.md +10 -1
- package/skills/plan-add/SKILL.md +5 -1
- package/skills/plan-add/render_table.py +7 -0
- package/skills/pm-frameworks/LICENSE +21 -0
- package/skills/research/SKILL.md +22 -9
- package/skills/rl-env/LICENSE +201 -0
- package/skills/tezgah-contract/SKILL.md +21 -8
- package/statusline.py +20 -9
- package/third_party/open-code-review/LICENSE +201 -0
- package/third_party/open-code-review/README.md +15 -0
- package/third_party/open-code-review/prompts/main_task_system.md +26 -0
- package/third_party/open-code-review/prompts/review_filter_task_system.md +13 -0
- package/workflows/graph-map.js +14 -5
- package/workflows/graph-review.js +14 -2
package/docs/status-line.md
CHANGED
|
@@ -15,8 +15,8 @@ host-neutrally by `health_segments()` (`hooks/tezgah_context.py::health_segments
|
|
|
15
15
|
groups (`hooks/tezgah_context.py::render_line`). The group is *data on each segment*: a renderer building its
|
|
16
16
|
own line from `--json` separates on `seg.group` and matches `render_line()`
|
|
17
17
|
without a second copy of the partition (`hooks/tezgah_context.py::health_segments`) — opencode and dsh do exactly
|
|
18
|
-
that (hosts/opencode/tui/tezgah-tui.tsx
|
|
19
|
-
hosts/dsh/statusline/lib/client.js
|
|
18
|
+
that (`TezgahBar` in `hosts/opencode/tui/tezgah-tui.tsx`,
|
|
19
|
+
`TezgahStatusLine` in `hosts/dsh/statusline/lib/client.js`).
|
|
20
20
|
|
|
21
21
|
| group | members | why together |
|
|
22
22
|
|---|---|---|
|
|
@@ -173,7 +173,12 @@ group separators stay identical for every extension. An extension never has to
|
|
|
173
173
|
know the gutter. It must name `text` and `state`. tezgah fills a missing `glyph`
|
|
174
174
|
from the state's own mark, so a chip reads like a built-in. The per-extension cap
|
|
175
175
|
(`MAX_SEGMENTS`) and the hard timeout (`timeout_ms`, default
|
|
176
|
-
`DEFAULT_TIMEOUT_MS`) bound one row.
|
|
176
|
+
`DEFAULT_TIMEOUT_MS`) bound one row. The command prints one JSON object whose
|
|
177
|
+
`segments` key holds that list. tezgah reads a bare list on stdout as malformed output:
|
|
178
|
+
|
|
179
|
+
```json
|
|
180
|
+
{"segments": [{"key": "cyber-eng", "state": "on", "text": "eng"}]}
|
|
181
|
+
```
|
|
177
182
|
|
|
178
183
|
It is a subprocess and not an import on purpose. The extension is the user's
|
|
179
184
|
repo, in whatever language, and may be slow or broken. A bounded child keeps a
|
|
@@ -229,10 +234,13 @@ python is asked (`hooks/tezgah_context.py::skill_read_kind`). A surface that can
|
|
|
229
234
|
was never opened", so it declares what it can see and those marks render `info`
|
|
230
235
|
(dim, no glyph) instead of `ready` (`observable`, `hooks/tezgah_context.py::health_segments`; the set constant
|
|
231
236
|
`TOOL_USE_MEASURES`, `hooks/tezgah_context.py::TOOL_USE_MEASURES`). The `--observable=` flag carries it on the CLI
|
|
232
|
-
(`bin/tezgah-status::main`).
|
|
233
|
-
|
|
234
|
-
`
|
|
235
|
-
|
|
237
|
+
(`bin/tezgah-status::main`). Every host whose line reads the store and cannot see
|
|
238
|
+
a skill read passes the tool-use set: the status line for Cursor, Qwen, Droid, Copilot and Antigravity
|
|
239
|
+
(`statusline.py::HOST`, `statusline.py::observable`), and Codex, Command Code
|
|
240
|
+
and Gemini, which render the line plain into `systemMessage`
|
|
241
|
+
(`hosts/codex/hook.py::main`, `hosts/commandcode/hook.py::status`,
|
|
242
|
+
`hosts/gemini/hook.py::status`); dsh passes the literal flag
|
|
243
|
+
string (`OBSERVABLE` in `hosts/dsh/statusline/lib/index.js`), which names the five marks its
|
|
236
244
|
own hook can record - `judge` included, since dsh wires the same PostToolUse hook
|
|
237
245
|
every other host does. The set is what a host can write, not what it happens to
|
|
238
246
|
have written: a mark the literal omits reads `info` there rather than a claim.
|
|
@@ -248,15 +256,15 @@ the five kinds are ever written (`hooks/tezgah_context.py::record`).
|
|
|
248
256
|
|
|
249
257
|
Writers: the shared PostToolUse hook `hooks/projects-posttooluse.py` — `graph` from
|
|
250
258
|
an MCP tool name, else the shell tokenizer's answer, which counts a tool only when
|
|
251
|
-
the command really ran it (
|
|
259
|
+
the command really ran it (`hooks/projects-posttooluse.py::used_kind`) and is the one writer that can earn `judge`
|
|
252
260
|
(a run of `bin/tezgah-triage` or `bin/tezgah-docs`, `shell_kind`, `hooks/tezgah_context.py::shell_kind`)
|
|
253
261
|
— plus `hooks/projects-auto-init.py::main`
|
|
254
262
|
(`orch` on subagent start), `hosts/codex/hook.py::main`,
|
|
255
|
-
`hosts/cursor/hook.py::dispatch`, hosts/opencode/plugins/tezgah.js
|
|
256
|
-
|
|
263
|
+
`hosts/cursor/hook.py::dispatch`, `record` in `hosts/opencode/plugins/tezgah.js`,
|
|
264
|
+
`hosts/omp/hook.py::handle`. Both Claude (hooks/hooks.json) and dsh
|
|
257
265
|
(hosts/dsh/hooks.json) wire PostToolUse to that one shared hook, which is how dsh
|
|
258
266
|
gets any used mark at all: with no local transcript, the store is the only channel
|
|
259
|
-
its line has (hooks/projects-posttooluse.py
|
|
267
|
+
its line has (`hooks/projects-posttooluse.py::used_kind`).
|
|
260
268
|
|
|
261
269
|
Claude's line never reads the store: it parses `tool_use` blocks out of
|
|
262
270
|
`payload["transcript_path"]` plus the subagent transcripts under it, which is how
|
|
@@ -269,15 +277,15 @@ Every other surface reads the store.
|
|
|
269
277
|
picks the host from `--cursor` or `TEZGAH_STATUS_HOST`, renders
|
|
270
278
|
`render_line(segs, color=color_default())`, and joins Orca's own status line to
|
|
271
279
|
the tezgah segment with ` | `; `TEZGAH_STATUS_LEGEND=1` appends the legend
|
|
272
|
-
(
|
|
280
|
+
(`statusline.py::HOST`, `statusline.py::seg`, `statusline.py::out`). ANSI is dropped under `NO_COLOR` or
|
|
273
281
|
`TEZGAH_STATUS_COLOR=0` (`color_default()`, `hooks/tezgah_context.py::color_default`).
|
|
274
282
|
- **omp** — hosts/omp/tezgah-hook.ts.in: `draw()` prefers
|
|
275
283
|
`ctx.ui.setWidget("tezgah", [line], {placement: "belowEditor"})`, which renders
|
|
276
284
|
the colored string as-is; `setStatus` is the fallback for a build without
|
|
277
|
-
`setWidget`, and it is plain because omp strips ANSI (
|
|
285
|
+
`setWidget`, and it is plain because omp strips ANSI (`draw` in `hosts/omp/tezgah-hook.ts.in`). `status_line()`
|
|
278
286
|
builds the line and carries `idx_override`, so a per-tool redraw forks no git
|
|
279
287
|
(`hosts/omp/hook.py::status_line`); it redraws on session start, session switch, turn end
|
|
280
|
-
and each watched tool result (hosts/omp/tezgah-hook.ts.in
|
|
288
|
+
and each watched tool result (`refresh` and `WATCHED` in `hosts/omp/tezgah-hook.ts.in`).
|
|
281
289
|
**Motion:** while the agent runs (`agent_start` until an `agent_end` whose
|
|
282
290
|
`isTerminal` is not `false`) the widget leads with a braille spinner, the tool
|
|
283
291
|
in flight (`tool_execution_start`/`_end`, "thinking" between tools) and the
|
|
@@ -297,20 +305,26 @@ Every other surface reads the store.
|
|
|
297
305
|
(`tui.json`'s `plugin` array, not the server plugin) registering an `app_bottom`
|
|
298
306
|
slot, shelling out to `tezgah-status <dir> --json <sessionID>`, coloring each
|
|
299
307
|
segment from the active theme and rebuilding the separator from `seg.group`
|
|
300
|
-
(
|
|
301
|
-
`--legend` (
|
|
308
|
+
(`TezgahBar` in `hosts/opencode/tui/tezgah-tui.tsx`). Its `tezgah: status legend` command opens a dialog running
|
|
309
|
+
`--legend` (`LegendDialog` in `hosts/opencode/tui/tezgah-tui.tsx`).
|
|
302
310
|
On opencode 2 the same line comes from hosts/opencode/tui/cli/tui.tsx, a
|
|
303
311
|
`Plugin.define` CLI plugin listed in `cli.json`. It reuses the v1 file's `run`.
|
|
304
312
|
- **dsh** — hosts/dsh/statusline/lib/index.js serves `GET /api/tezgah.status`
|
|
305
313
|
behind the Web UI's own authenticated fetch fence, so the browser fetches it
|
|
306
|
-
same-origin with no extra token handling (
|
|
307
|
-
`--observable=consult,research,graph,orch,judge` (
|
|
308
|
-
legend}` for `?format=json`, plain text otherwise (
|
|
314
|
+
same-origin with no extra token handling (`apply` in `hosts/dsh/statusline/lib/index.js`); it always passes
|
|
315
|
+
`--observable=consult,research,graph,orch,judge` (`OBSERVABLE` in `hosts/dsh/statusline/lib/index.js`) and returns `{segments,
|
|
316
|
+
legend}` for `?format=json`, plain text otherwise (`statusText` in `hosts/dsh/statusline/lib/index.js`). Its client half
|
|
309
317
|
(hosts/dsh/statusline/lib/client.js) renders the marks in the session header in
|
|
310
318
|
fixed light/dark colors, polls every 10 s while the tab is visible, and shows the
|
|
311
|
-
legend on hover, pins it on click (
|
|
319
|
+
legend on hover, pins it on click (`TezgahStatusLine` in `hosts/dsh/statusline/lib/client.js`).
|
|
312
320
|
- **Codex** — hosts/codex/hook.py puts the plain line in `systemMessage`
|
|
313
|
-
(
|
|
321
|
+
(`hosts/codex/hook.py::main`).
|
|
322
|
+
- **Amp** — the plugin draws the widest plain tier
|
|
323
|
+
(`hosts/amp/hook.py::status_line`) on Amp's experimental status item
|
|
324
|
+
(`createStatusItem`, TUI only, plain text). It draws only for the thread the
|
|
325
|
+
user is looking at. It redraws on `session.start`, `agent.end` and each
|
|
326
|
+
watched tool result, and shows `hook✗` while the hook fails. A build without
|
|
327
|
+
the API has no status surface (`hosts/amp/tezgah-plugin.ts.in`).
|
|
314
328
|
|
|
315
329
|
## Seeing and debugging the line
|
|
316
330
|
|
|
@@ -330,7 +344,8 @@ tezgah-status --judge # what the judge used last, and why
|
|
|
330
344
|
|
|
331
345
|
The session id is the second positional argument or `TEZGAH_SESSION`; without it
|
|
332
346
|
the used marks cannot light up (`bin/tezgah-status::main`). `--color`/`--no-color` force ANSI or plain,
|
|
333
|
-
`--observable=` narrows the measures as above, and an unknown flag exits 2
|
|
347
|
+
`--observable=` narrows the measures as above, and an unknown flag exits 2. So does
|
|
348
|
+
an `--observable=` measure outside `TOOL_USE_MEASURES` plus `pony` and `adhd` (`bin/tezgah-status::main`).
|
|
334
349
|
|
|
335
350
|
`--counters` is not the marks: it prints `tezgah_integrity.counters(session)` —
|
|
336
351
|
`steps`, `tool_error_rate`, `claims`, `false_completion`, `shape_blocked`,
|
|
@@ -407,7 +422,8 @@ could not be read - so the mark refuses to say either fresh or stale, and
|
|
|
407
422
|
`index_notice()` says on the turn that the graph's age is unknown. On a host that
|
|
408
423
|
sandboxes hook writes (dsh) the stamp is never written, and before that state
|
|
409
424
|
existed the mark read green there for good. That is why `observable` exists (`hooks/tezgah_context.py::health_segments`),
|
|
410
|
-
why the skill-read check is documented as unavailable on
|
|
425
|
+
why the skill-read check is documented as unavailable on every host that passes
|
|
426
|
+
the tool-use set or the dsh literal (see `--observable=` above)
|
|
411
427
|
(`hooks/tezgah_context.py::skill_read_kind`), why omp ignores any `idx` value that is not one of
|
|
412
428
|
its five glyphs (`hosts/omp/hook.py::status_line`) - a value outside that set re-probes
|
|
413
429
|
instead of being reused, one fork and never a wrong mark - and
|
package/docs/testing.md
CHANGED
|
@@ -47,7 +47,7 @@ baseline on the next run. Only `--clarity --update` raises it.
|
|
|
47
47
|
A pin is a claim about what ran, not a guarantee about what will. This repository
|
|
48
48
|
has two, and both are about the language rather than about dependencies: the
|
|
49
49
|
floor `py310` (`pyproject.toml:5`) and the CI matrix that proves it
|
|
50
|
-
(`.github/workflows/ci.yml
|
|
50
|
+
(the `test` job's `python-version` matrix in `.github/workflows/ci.yml`). There is no dependency lockfile to pin
|
|
51
51
|
because there is no package: tezgah is a set of scripts run in place, and no
|
|
52
52
|
`[project]` or build system is declared (`pyproject.toml:1-2`). The only
|
|
53
53
|
third-party tool the checks name is ruff, at a version in
|
|
@@ -65,8 +65,15 @@ conclude from either.
|
|
|
65
65
|
|
|
66
66
|
`.github/workflows/ci.yml` runs on a push to `main` and on a pull request, so
|
|
67
67
|
a branch commit runs once, through its pull request, not twice. A tag push does
|
|
68
|
-
not start it. `release.yml` calls it (`
|
|
69
|
-
brew publish only after CI passed on the release commit.
|
|
68
|
+
not start it. `release.yml` calls it (its `workflow_call` trigger) as its `ci` job, so npm and
|
|
69
|
+
brew publish only after CI passed on the release commit. Its first job,
|
|
70
|
+
`on-main`, fails the release when the tag's commit is not on `origin/main`.
|
|
71
|
+
Then no job builds or uploads anything. Next, `green` looks for a finished push
|
|
72
|
+
run of `ci.yml` on the same commit. It waits for a running one and counts only
|
|
73
|
+
`success`, and then `ci` does not run: a release does not run the suite twice. No
|
|
74
|
+
such run, or any other outcome, runs `ci` as before. `npm-publish` and
|
|
75
|
+
`brew-formula` need `green` and `ci`, and publish when either answered green.
|
|
76
|
+
A newer push to the
|
|
70
77
|
same ref cancels the run it replaces, except on a release (`concurrency`). Every
|
|
71
78
|
job has a `timeout-minutes`, so a hung test cannot hold a runner for six hours.
|
|
72
79
|
No matrix cancels its other legs when one fails (`fail-fast: false`).
|
|
@@ -77,33 +84,58 @@ No matrix cancels its other legs when one fails (`fail-fast: false`).
|
|
|
77
84
|
empty diff, a base it cannot read, a release or a manual run runs everything.
|
|
78
85
|
- `docs`, prose only: the citations audit, the clarity audit and
|
|
79
86
|
`tests/impacted.py --ref <base>`, which maps a docs page to the docs modules.
|
|
80
|
-
- `test`
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
87
|
+
- `test` runs on Python 3.10 and 3.14, the floor and the ceiling. Its first steps
|
|
88
|
+
are "Byte-compile every script", "Install ruff" (from `requirements-dev.txt`,
|
|
89
|
+
pip cached) and "Lint". Then come "Every docs citation lands in the symbol it
|
|
90
|
+
names" and "The docs prose audit". The last two are "The plan and decision
|
|
91
|
+
rules, in a real project" (`TEZGAH_E2E_STRICT=1 python3 tests/e2e_plan_flow.py`)
|
|
92
|
+
and "The research checks against their known-truth set" (`python3
|
|
93
|
+
bin/tezgah-research release-check`). A release passes the `release` input and
|
|
94
|
+
runs one 3.10 leg.
|
|
95
|
+
- `test-sharded` on Python 3.10 and 3.14 with node 22 (the
|
|
86
96
|
first line that loads the omp `.ts` hook without a flag). On `main` and a
|
|
87
|
-
release
|
|
88
|
-
|
|
89
|
-
|
|
97
|
+
release its step "Run the suite, sharded" runs `python3 tests/impacted.py --all`.
|
|
98
|
+
On a pull request "Run the impacted modules, sharded (pull request)" runs
|
|
99
|
+
`--ref <base>` instead. That runs the modules the change maps to, or the whole
|
|
100
|
+
suite when the map does not know a path. It replaced the serial `unittest discover` step on
|
|
90
101
|
2026-10-13: both caught the same failures, and the serial step took about 30
|
|
91
102
|
minutes.
|
|
92
|
-
- `apps-e2e`
|
|
103
|
+
- `apps-e2e` on Python 3.12 and node 20: one step, "App MCP handshake
|
|
104
|
+
(playwright + mobile-mcp)",
|
|
93
105
|
`TEZGAH_E2E_STRICT=1 python3 tests/e2e_analyze_wiring.py`. It completes the
|
|
94
106
|
app-MCP handshake only - no browser, no device - so it stays deterministic;
|
|
95
107
|
strict mode makes a server that cannot start a failure rather than a skip, so
|
|
96
108
|
a broken wire cannot hide behind a skip (`e2e_analyze_wiring.py:4-12`).
|
|
97
|
-
- `artifact-install`
|
|
109
|
+
- `artifact-install` on Python 3.10 and 3.12: builds the
|
|
98
110
|
tarball, installs from it under a temp prefix, and runs the artifact smoke on
|
|
99
111
|
the installed tree instead of the checkout.
|
|
100
|
-
- `artifact-install-windows`
|
|
112
|
+
- `artifact-install-windows` on `windows-latest`: the same
|
|
101
113
|
build, install and smoke through `packaging/install.ps1` - the twin a Windows
|
|
102
114
|
user runs - so it is the only place the Windows claim is proven. It then runs
|
|
103
115
|
the opencode plugin's path tests natively, `tezgah update --dry-run`, the
|
|
104
116
|
opencode live probe and `--uninstall` from the installed tree. Any residue
|
|
105
117
|
under the prefix fails it.
|
|
106
118
|
|
|
119
|
+
Four node harnesses run JavaScript and TypeScript the suite cannot import. Their
|
|
120
|
+
Python modules drive them, so they run wherever those modules run: in
|
|
121
|
+
`test-sharded`, which installs node 22, and locally under `tests/impacted.py`.
|
|
122
|
+
|
|
123
|
+
- `tests/_opencode_plugin_harness.mjs` loads the opencode plugin
|
|
124
|
+
(`tests/test_opencode_plugin.py`).
|
|
125
|
+
- `tests/_omp_extension_harness.mjs` loads the omp extension
|
|
126
|
+
(`tests/test_omp_extension.py`) and `tests/_amp_plugin_harness.mjs` the Amp
|
|
127
|
+
plugin (`tests/test_amp_plugin.py`). Both need a node that strips types
|
|
128
|
+
(22.18+).
|
|
129
|
+
- `tests/_workflow_harness.mjs` is a stub of the Workflow runtime. It runs
|
|
130
|
+
`workflows/graph-review.js`, `workflows/graph-impact.js` and
|
|
131
|
+
`workflows/graph-map.js` as async function
|
|
132
|
+
bodies. It answers each `agent()` from a fixture, and `null` is a failed agent.
|
|
133
|
+
`python3 -m pytest tests/test_graph_workflows.py` runs it.
|
|
134
|
+
|
|
135
|
+
Without node, or with a node too old for `.ts`, these modules skip rather than
|
|
136
|
+
fail, so a leg with no node passes them silently. `test-sharded` is the leg
|
|
137
|
+
that proves them.
|
|
138
|
+
|
|
107
139
|
`.github/workflows/neuter.yml` runs two jobs weekly, on demand, and on a push to
|
|
108
140
|
`main` that changes a guard, the matrix or a test module it runs. The matrix is
|
|
109
141
|
CI's, not the local loop's. The first job, `neuter`, asks the question the suite
|
|
@@ -125,10 +157,11 @@ row.
|
|
|
125
157
|
Each mutant first runs alone the test that killed it last time, read from
|
|
126
158
|
`tests/neuter_killers.json`. When that test passes or is gone, the mutant runs
|
|
127
159
|
every module in its own HOME and TMPDIR. The module that reads the mutated file
|
|
128
|
-
goes first.
|
|
160
|
+
goes first. With `--update-killers`, the first failing test becomes its new
|
|
161
|
+
entry. Without it, the tracked cache is left as it was. The
|
|
129
162
|
control runs every module, then every cached killer alone, so a killer that
|
|
130
163
|
fails without a mutant voids the run. A session that adds a deny rule checks its
|
|
131
|
-
one mutant with `python3 tests/neuter_matrix.py --only <name
|
|
164
|
+
one mutant with `python3 tests/neuter_matrix.py --only <name> --update-killers`.
|
|
132
165
|
|
|
133
166
|
The second, `fuzz-shell`, runs the bash-oracle fuzzer (`tests/fuzz_shell.py`)
|
|
134
167
|
under the ubuntu runner's bash 5.x. Locally, macOS ships bash 3.2. A first step
|
package/docs/vision.md
CHANGED
|
@@ -117,8 +117,12 @@ conflicting SWE-bench split, the agent cheated in 0 of 132 runs with tezgah and
|
|
|
117
117
|
no headroom. Hand labels of final messages on those impossible tasks found
|
|
118
118
|
false done claims in 3 of 30 runs with tezgah and 6 of 30 without. The CI of
|
|
119
119
|
that difference includes 0. The Stop rule's claim reader
|
|
120
|
-
flagged far more runs than that. On Turkish replies it
|
|
121
|
-
(verified) on a partial fix as a claim,
|
|
120
|
+
flagged far more runs than that. On Turkish replies it counted `doğrulandı`
|
|
121
|
+
(verified) on a partial fix as a claim, even beside a `doğrulanmadı`. Commit
|
|
122
|
+
9cb4d1d fixed that shape. Its held-out recall is 0.857, below the 0.9 bar. A
|
|
123
|
+
narrower gap remains. A Turkish partial fix with no admission word
|
|
124
|
+
(`hâlâ başarısız`, `kısmen`) still reads as done and verified. Its English twin
|
|
125
|
+
reads as verification only. The
|
|
122
126
|
numbers, the per-task counts and the instrument flaws are in
|
|
123
127
|
[the results bundle](results/paired-outcome-2026-10.md).
|
|
124
128
|
|
package/hooks/hooks.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
{ "hooks": [ { "type": "command", "command": "TEZGAH_HOST=claude \"${TEZGAH_PYTHON:-python3}\" \"${CLAUDE_PLUGIN_ROOT}/hooks/projects-auto-init.py\"", "timeout": 10 } ] }
|
|
14
14
|
],
|
|
15
15
|
"PreToolUse": [
|
|
16
|
-
{ "matcher": "Agent|agent|Task|task|Grep|grep|Bash|bash|PowerShell|pwsh|Shell|shell|subagent|Edit|Write|MultiEdit|NotebookEdit|AskUserQuestion", "hooks": [ { "type": "command", "command": "\"${TEZGAH_PYTHON:-python3}\" \"${CLAUDE_PLUGIN_ROOT}/hooks/projects-pretooluse.py\"", "timeout": 5 } ] },
|
|
16
|
+
{ "matcher": "Agent|agent|Task|task|Grep|grep|Bash|bash|PowerShell|pwsh|Shell|shell|Monitor|monitor|subagent|Edit|Write|MultiEdit|NotebookEdit|AskUserQuestion", "hooks": [ { "type": "command", "command": "\"${TEZGAH_PYTHON:-python3}\" \"${CLAUDE_PLUGIN_ROOT}/hooks/projects-pretooluse.py\"", "timeout": 5 } ] },
|
|
17
17
|
{ "matcher": "^mcp__(?:.*[^A-Za-z0-9])?(?:append|cancel|clear|click|close|comment|commit|copy|create|delete|deploy|drag|edit|email|evaluate|exec|execute|fill|insert|install|kill|launch|merge|message|mkdir|move|navigate|notify|patch|pause|post|press|print|publish|push|put|release|remove|rename|replace|reply|resume|review|run|save|send|set|share|skip|start|stop|submit|swipe|tag|tap|terminate|type|uninstall|update|upload|write)(?:[^A-Za-z0-9].*)?$", "hooks": [ { "type": "command", "command": "\"${TEZGAH_PYTHON:-python3}\" \"${CLAUDE_PLUGIN_ROOT}/hooks/projects-pretooluse.py\"", "timeout": 5 } ] }
|
|
18
18
|
],
|
|
19
19
|
"PostToolUse": [
|
package/hooks/lang/en.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "English",
|
|
3
3
|
"done": [
|
|
4
|
-
"done|complete[d]?|finished|implemented|fixed|shipped|landed|merged|wired up|wired into|all tests
|
|
4
|
+
"done|complete[d]?|finished|implemented|fixed|(?<!\\bis )(?<!\\bare )(?<!\\bget )(?<!\\bgets )(?<!\\bbe )(?<!\\bbeing )(?<!-)updated(?!-)|shipped|landed|merged|wired up|wired into|(?:all )?(?:tests?|checks?|suite|build) passed|(?:all )?(?:tests|checks) pass|(?:suite|build) passes|(?:tests?|checks?|suite) (?:is |are )?(?:green|passing)|build is green"
|
|
5
5
|
],
|
|
6
6
|
"verified": [
|
|
7
7
|
"tested|verified|i ran|ran the (?:tests?|suite|build|lint|checks?)"
|
|
8
8
|
],
|
|
9
9
|
"negated": [
|
|
10
|
-
"unverified|not verified|could ?n[o']t verify|verification (?:was )?skipped"
|
|
10
|
+
"unverified|not verified|could ?n[o']t verify|verification (?:was )?skipped|^\\s*(?:untested|not (?:yet )?(?:been )?(?:tested|checked))\\b|(?:^|[.!;]\\s+)(?:(?:this|the) (?:change|fix|patch)|it|i)\\b[^.\\n]{0,24}?(?:not|n't) (?:yet )?(?:been )?tested|not checked yet"
|
|
11
11
|
],
|
|
12
12
|
"admitted": [
|
|
13
13
|
"contradict|unsatisfiable|(?:can ?not|can't|can ?never|never) pass|impossible"
|
|
@@ -36,6 +36,9 @@
|
|
|
36
36
|
"negation_before": [
|
|
37
37
|
"\\bnot|n't|\\bnever"
|
|
38
38
|
],
|
|
39
|
+
"condition_before": [
|
|
40
|
+
"\\b(?:if|when|once|unless|until|whether)\\b"
|
|
41
|
+
],
|
|
39
42
|
"question_particle": [],
|
|
40
43
|
"question_end": [],
|
|
41
44
|
"clause_join": [
|
|
@@ -224,6 +227,9 @@
|
|
|
224
227
|
"plan_build": [
|
|
225
228
|
"\\bplans?\\b[^.?!\\n]{0,40}\\b(?:is ready|ready|written|drafted)\\b|\\b(?:wrote|opened|drafted|added|created) (?:the |a |this )?plans?\\b|\\b(?:build|implement|execute|start on|start) (?:the |this |that )?plans?\\b"
|
|
226
229
|
],
|
|
230
|
+
"owner_choice": [
|
|
231
|
+
"\\bwhich (?:variant|option|approach|design)s?\\b|\\b(?:v\\d+|option [a-h1-9]|variant [a-z0-9]+),? or (?:v\\d+|option [a-h1-9]|variant [a-z0-9]+)\\b|\\b(?:another|other|the other) session\\w*|\\bsession'?s (?:line|plan|branch)\\b|\\bclos\\w*\\b[^?\\n]{0,40}\\bline\\b|--allow-open|--limit\\b|\\.staging\\b|\\bhidden (?:dir|directory|folder)\\b|\\b(?:another|a different) (?:folder|dir|directory)\\b|\\b(?:work ?)?around\\b[^?\\n]{0,40}\\brefusal\\b"
|
|
232
|
+
],
|
|
227
233
|
"spend": [
|
|
228
234
|
"spend\\w*|\\bpaid\\b|billing|\\bcost\\w*|\\bbudget\\w*|\\busd\\b|\\$\\s?\\d"
|
|
229
235
|
],
|
|
@@ -236,6 +242,12 @@
|
|
|
236
242
|
"cheap_answer": [
|
|
237
243
|
"yes|yep|yeah|ok(?:ay)?|sure|go(?: on| ahead)?|continue|proceed|do it|carry on|keep going|approved"
|
|
238
244
|
],
|
|
245
|
+
"hand_over": [
|
|
246
|
+
"\\bplease\\s+(?:run|execute)\\b|\\byour\\s+(?:step|turn|move)\\b(?=\\s*[:.;,!]|\\s*$)|\\bover to you\\b"
|
|
247
|
+
],
|
|
248
|
+
"ran_it": [
|
|
249
|
+
"\\bi (?:ran|tested|verified|checked|executed)\\b|\\bran the (?:tests?|suite|build|lint|checks?)\\b|\\bwe ran\\b"
|
|
250
|
+
],
|
|
239
251
|
"outward": {
|
|
240
252
|
"push": "\\bpush\\w*",
|
|
241
253
|
"release": "\\brelease\\w*|\\btag(?:s|ged|ging)?\\b|version bump|bump the version",
|
|
@@ -329,6 +341,8 @@
|
|
|
329
341
|
"slice_lead": "",
|
|
330
342
|
"ready_lead": "",
|
|
331
343
|
"ask_lead": "",
|
|
344
|
+
"handed_lead": "",
|
|
345
|
+
"plan_lead": "",
|
|
332
346
|
"approval_heading": "Approval questions",
|
|
333
347
|
"recommended": "Recommended",
|
|
334
348
|
"grant_examples": "\"push without asking\", \"I approve\""
|
package/hooks/lang/tr.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "Turkish",
|
|
3
3
|
"done": [
|
|
4
|
-
"yaptım|tamamladım|tamamlandı|bitirdim|bitirildi|ekledim|eklendi|düzelttim|düzeltildi|hallettim|güncellendi|kuruldu|uygulandı|yayına girdi|kapatıldı|yüklendi|tüm testler geçti|testler geçti|testler yeşil|çalışıyor"
|
|
4
|
+
"yaptım|tamamladım|tamamlandı|bitirdim|bitirildi|ekledim|eklendi|düzelttim|düzeltildi|hallettim|güncellendi|kuruldu|uygulandı|yayına girdi|kapatıldı|yüklendi|tüm testler geçti|testler geçti|testler geçiyor|testler yeşil|çalışıyor"
|
|
5
5
|
],
|
|
6
6
|
"verified": [
|
|
7
7
|
"doğruladım|test ettim|kontrol ettim|denetledim|doğrulandı|test edildi"
|
|
@@ -89,6 +89,7 @@
|
|
|
89
89
|
"negation_before": [
|
|
90
90
|
"\\bdeğil"
|
|
91
91
|
],
|
|
92
|
+
"condition_before": [],
|
|
92
93
|
"question_particle": [
|
|
93
94
|
"m[ıiuü]|değil"
|
|
94
95
|
],
|
|
@@ -200,7 +201,7 @@
|
|
|
200
201
|
"ürün(?!\\w*_)\\w*|yol harita\\w*|kuzey yıldız\\w*|aktivasyon\\w*|dönüşüm\\w*|fiyatlandır\\w*|önceliklendir\\w*|kullanıcı araştırma\\w*|ürün keşf\\w*|müşteri geri bildirim\\w*|benimsen\\w*|konumlandır\\w*|segmentasyon\\w*|hedef kitle\\w*|(kullanıcı|müşteri) discovery|keşif (görüşme|çalışma)\\w*|fırsat\\w*|memnuniyet\\w*|anket\\w*|(kullanıcı|müşteri)[ -]?(feedback|geri bildirim)\\w*|(customer|user)[ -]?geri bildirim\\w*|şikayet\\w*|rakip\\w*|rekabet\\w*|pazar pay\\w*|terk oran\\w*|elde tutma\\w*|abonelik\\w*|gelir model\\w*|özellik\\w*|sayfa(?! numara)\\w*|ekran(?! kart)(?!a\\b[^.!?\\n]{0,40}\\b(?:yaz|bas)\\w*)\\w*|arayüz\\w*|arama kutu\\w*|filtre\\w*|tablo(?![^.!?\\n]{0,60}\\b(?:sütun|kolon|sql|index|indeks)\\w*)\\w*|adım(?! sayı)\\w*|kullanıcı liste\\w*|form(u|un|da|daki|lar|ları|unu)\\w*[^.!?\\n]{0,40}\\b(?:incele|denetle|analiz|de[ğg]erlendir|iyile[şs]tir|sadele[şs]tir|kontrol)\\w*"
|
|
201
202
|
],
|
|
202
203
|
"design": [
|
|
203
|
-
"(?:(?<![\\w'’] )|(?<=\\bbu )|(?<=\\bşu ))tasar[ıi]m\\w*|(?:dashboard|pano|g[öo]sterge panel|ekran|sayfa|aray[üu]z|landing|logo|ikon)\\w* (?:\\w+ ){0,2}(?:tasarla|tasar[ıi]m|redesign)\\w*|(?:web[ -]?)?site\\w* tasar[ıi]m\\w*|(?:mobil |web )?uygulama\\w* tasar[ıi]m\\w*|(?:web|mobil) tasar[ıi]m\\w*|tasar[ıi]m (?:sistem|token|dil|rehber)\\w*|yeniden tasarla\\w*|ba[şs]tan tasarla\\w*|design [çc]al[ıi][şs]ma\\w*|aray[üu]z\\w*|(?:ui|aray[üu]z|form|buton|d[üu][ğg]me|kart|men[üu]|sayfa|ekran|react|vue)\\w* (?:\\w+ )?bile[şs]en\\w*|bile[şs]en (?:k[üu]t[üu]phane|sistem)\\w*|tipografi\\w*|renk\\w*|tema(?:s[ıi]|y[ıi]|lar\\w*)?|kullan[ıi]labilirlik\\w*|eri[şs]ilebilirli[kğg]\\w*|g[öo]rsel (?:hiyerar[şs]i|tutarl[ıi]l[ıi]k|denetim|ele[şs]tiri)\\w*",
|
|
204
|
+
"(?:(?<![\\w'’] )|(?<=\\bbu )|(?<=\\bşu ))tasar[ıi]m\\w*|(?:dashboard|pano|g[öo]sterge panel|ekran|sayfa|aray[üu]z|landing|logo|ikon)\\w* (?:\\w+ ){0,2}(?:tasarla|tasar[ıi]m|redesign)\\w*|(?:uygulama(?:y[ıi]|s[ıi]n[ıi])?|site(?:yi|sini)?) redesign\\w*|(?:web[ -]?)?site\\w* tasar[ıi]m\\w*|(?:mobil |web )?uygulama\\w* tasar[ıi]m\\w*|(?:web|mobil) tasar[ıi]m\\w*|tasar[ıi]m (?:sistem|token|dil|rehber)\\w*|yeniden tasarla\\w*|ba[şs]tan tasarla\\w*|design [çc]al[ıi][şs]ma\\w*|aray[üu]z\\w*|(?:ui|aray[üu]z|form|buton|d[üu][ğg]me|kart|men[üu]|sayfa|ekran|react|vue)\\w* (?:\\w+ )?bile[şs]en\\w*|bile[şs]en (?:k[üu]t[üu]phane|sistem)\\w*|tipografi\\w*|renk\\w*|tema(?:s[ıi]|y[ıi]|lar\\w*)?|kullan[ıi]labilirlik\\w*|eri[şs]ilebilirli[kğg]\\w*|g[öo]rsel (?:hiyerar[şs]i|tutarl[ıi]l[ıi]k|denetim|ele[şs]tiri)\\w*",
|
|
204
205
|
{
|
|
205
206
|
"ui_ask": "iyile[şs]tir\\w*|g[üu]zelle[şs]tir\\w*|d[üu]zenle\\w*|kar[ıi][şs][ıi]k\\w*|tutars[ıi]z\\w*|da[ğg][ıi]n[ıi]k\\w*|[çc]irkin\\w*"
|
|
206
207
|
},
|
|
@@ -268,6 +269,9 @@
|
|
|
268
269
|
"plan_build": [
|
|
269
270
|
"\\bplan\\w*[^.?!\\n]{0,40}(?:hazır|yazıldı|yazdım|oluşturdum|oluşturuldu|açtım|açıldı|eklendi|uygula\\w*|başla\\w*|kur\\w*)|(?:yazdığım|açtığım|hazırladığım|oluşturduğum) plan\\w*"
|
|
270
271
|
],
|
|
272
|
+
"owner_choice": [
|
|
273
|
+
"\\b(?:v\\d+|seçenek \\w+|varyant \\w+)(?:'\\w+)? m[ıiuü]\\b,? (?:v\\d+|(?:seçenek |varyant )?\\w+)(?:'\\w+)? m[ıiuü]\\b|\\bhangi (?:varyant|seçenek|opsiyon|yaklaşım|tasarım)\\w*|\\bhangisini seç\\w*|\\b(?:başka|diğer) (?:bir )?oturum\\w*|\\bhatt[ıi]\\w* kapat\\w*|--allow-open|--limit\\b|\\.staging\\b|\\bgizli (?:dizin|klasör)\\w*|\\b(?:başka|farklı) (?:bir )?(?:klasör|dizin)\\w*|\\bred\\w* (?:aş|etrafından)\\w*|\\bengel\\w* (?:aş|etrafından)\\w*"
|
|
274
|
+
],
|
|
271
275
|
"spend": [
|
|
272
276
|
"ücret\\w*|ödeme\\w*|harca\\w*|bütçe\\w*|maliyet\\w*|\\bpara\\b|dolar\\w*|\\$\\s?\\d"
|
|
273
277
|
],
|
|
@@ -280,6 +284,12 @@
|
|
|
280
284
|
"cheap_answer": [
|
|
281
285
|
"evet|tamam|olur|devam(?: et)?|yap|başla|ilerle|okey|onay(?:lıyorum)?"
|
|
282
286
|
],
|
|
287
|
+
"hand_over": [
|
|
288
|
+
"\\b(?:sen|siz)\\b[^.!?\\n]{0,32}?\\bçalıştır(?:ın|ınız)?\\b|\\bsenin adımın\\b|\\badım(?:ı)? sende\\b|\\bsıradaki adım(?:ı)? sen\\b"
|
|
289
|
+
],
|
|
290
|
+
"ran_it": [
|
|
291
|
+
"\\b(?:test(?:ler)?i|suite'?i|komutu|kontrolü|denetimi)?\\s*(?:çalıştırdım|koştum|çalıştırdık)\\b|\\btest ettim\\b|\\bdoğruladım\\b|\\bkontrol ettim\\b|\\bdenetledim\\b"
|
|
292
|
+
],
|
|
283
293
|
"outward": {
|
|
284
294
|
"push": "\\bpush\\w*",
|
|
285
295
|
"release": "versiyon\\w*|sürüm\\w*|\\brelease\\w*|etiket\\w*",
|
|
@@ -350,6 +360,8 @@
|
|
|
350
360
|
"slice_lead": "Durmuş bir dilim var. ",
|
|
351
361
|
"ready_lead": "Hazır adımlar bekliyor. ",
|
|
352
362
|
"ask_lead": "Bu soruyu sorma: kararı ver ya da önerili onay sorusuna çevir. ",
|
|
363
|
+
"handed_lead": "Bu adımı sen çalıştır, kullanıcıya bırakma. ",
|
|
364
|
+
"plan_lead": "Plan modunda hiçbir şey koşmadı. ",
|
|
353
365
|
"approval_heading": "Onay için sorular",
|
|
354
366
|
"recommended": "Öneri",
|
|
355
367
|
"grant_examples": "\"bana sormadan pushla\", \"onay veriyorum\""
|
|
@@ -69,11 +69,19 @@ def result_size(result):
|
|
|
69
69
|
so a container is measured by its top-level length (O(1) for str, bytes,
|
|
70
70
|
list, dict, set) instead of re-serializing it: `json.dumps` on every
|
|
71
71
|
PostToolUse copied the whole tool response and broke the hook's cost bound
|
|
72
|
-
("a sha1 over a short string and a few fields; nothing else").
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
("a sha1 over a short string and a few fields; nothing else"). A shell
|
|
73
|
+
result is the exception: Claude's Bash answers `{"stdout", "stderr",
|
|
74
|
+
"interrupted", ...}`, so its field count is never 0 and a check that
|
|
75
|
+
printed nothing would read as output (`passing_check`'s silent failure,
|
|
76
|
+
B-005); its stream strings (`ran_nothing`'s keys) are measured instead.
|
|
77
|
+
ponytail: any other dict reports its field count, not its byte length."""
|
|
75
78
|
if result is None:
|
|
76
79
|
return None
|
|
80
|
+
if isinstance(result, dict):
|
|
81
|
+
streams = [result[k] for k in ("stdout", "stderr", "output")
|
|
82
|
+
if isinstance(result.get(k), str)]
|
|
83
|
+
if streams:
|
|
84
|
+
return sum(map(len, streams))
|
|
77
85
|
if isinstance(result, (str, bytes, bytearray, list, tuple, dict, set,
|
|
78
86
|
frozenset)):
|
|
79
87
|
return len(result)
|
package/hooks/projects-stop.py
CHANGED
|
@@ -48,7 +48,7 @@ def main():
|
|
|
48
48
|
if not isinstance(p, dict):
|
|
49
49
|
return
|
|
50
50
|
session_id = p.get("session_id")
|
|
51
|
-
safe(session_id, bind_session, session_id) # the switch latch
|
|
51
|
+
safe(session_id, bind_session, session_id, p.get("parent")) # the switch latch
|
|
52
52
|
cwd = p.get("cwd") or os.getcwd()
|
|
53
53
|
if p.get("hook_event_name") == "SubagentStop" and p.get("agent_id") \
|
|
54
54
|
and root_for(cwd) and not off("slices-off"):
|
|
@@ -64,7 +64,8 @@ def main():
|
|
|
64
64
|
# a core that cannot answer has refused nothing, so the turn ends: the rule
|
|
65
65
|
# never traps a session, and that holds for its own failure too
|
|
66
66
|
reason = safe(session_id, stop_reason, p.get("last_assistant_message"),
|
|
67
|
-
session_id, cwd=cwd, after_block=bool(p.get("stop_hook_active"))
|
|
67
|
+
session_id, cwd=cwd, after_block=bool(p.get("stop_hook_active")),
|
|
68
|
+
mode=p.get("permission_mode"))
|
|
68
69
|
if reason:
|
|
69
70
|
json.dump({"decision": "block", "reason": reason}, sys.stdout)
|
|
70
71
|
|
package/hooks/tezgah_agents.py
CHANGED
|
@@ -245,6 +245,15 @@ def _reviewer_body(host):
|
|
|
245
245
|
"for those files: account for every listed file as reviewed or skipped\n"
|
|
246
246
|
"with a reason, and still apply everything above - OCR output is input,\n"
|
|
247
247
|
"never a verdict.\n\n"
|
|
248
|
+
"Plan readiness. When the target is a plan file\n"
|
|
249
|
+
"(`.tezgah/plans/open/NNN-*.md`) rather than a diff, review whether it\n"
|
|
250
|
+
"can be built without a question. First restate each section's intent\n"
|
|
251
|
+
"in one sentence of your own; a section you cannot restate lacks\n"
|
|
252
|
+
"context, which is a major finding. Then check that every choice the\n"
|
|
253
|
+
"build needs is made in the plan - schema, API path, dependency,\n"
|
|
254
|
+
"edge-case handling, the files to change; a choice left to the\n"
|
|
255
|
+
"implementer is a major finding. A file the plan will create is not a\n"
|
|
256
|
+
"missing reference. Classify and report exactly as for a diff.\n\n"
|
|
248
257
|
"%s" % (_graph_howto(host), _blast_radius(host), EMPTY_IS_NOT_PROOF,
|
|
249
258
|
decision, decision, _may_use(host)))
|
|
250
259
|
|
|
@@ -265,14 +274,26 @@ def _worker_body(tier):
|
|
|
265
274
|
"report what changed and what each check printed, verbatim. Report\n"
|
|
266
275
|
"progress, but never redefine the work. Never widen or narrow the brief's\n"
|
|
267
276
|
"scope, budget or question. If the brief cannot be met as written, say\n"
|
|
268
|
-
"so and stop rather than answering a different question.\n%s\n"
|
|
277
|
+
"so and stop rather than answering a different question.\n%s\n%s"
|
|
269
278
|
"A brief that builds or changes UI: read the `design-contract` skill\n"
|
|
270
279
|
"(and `design-library` for critique) and derive/check with\n"
|
|
271
280
|
"`~/.config/tezgah/bin/tezgah-design` before editing.\n"
|
|
272
|
-
"Never spawn subagents.\n%s" % (tier, tier, scope,
|
|
281
|
+
"Never spawn subagents.\n%s" % (tier, tier, scope, OWNER_ESCALATE,
|
|
282
|
+
WORKER_OUTPUT))
|
|
273
283
|
return body
|
|
274
284
|
|
|
275
285
|
|
|
286
|
+
# A question only the owner can answer climbs past every tier to the user: a
|
|
287
|
+
# worker that settles it itself, frontier included, decided for the owner
|
|
288
|
+
# (plan 136: a line ran under a hidden dir and wrote `chosen:` with no owner
|
|
289
|
+
# choice). One text on every tier.
|
|
290
|
+
OWNER_ESCALATE = ("A question only the owner can answer - choosing a variant or option a\n"
|
|
291
|
+
"research, analysis or review recommends; a way around a tezgah\n"
|
|
292
|
+
"refusal; deciding about another session's work (its line, plan or\n"
|
|
293
|
+
"branch) - is never yours to decide, on any tier: stop and answer\n"
|
|
294
|
+
"`ESCALATE: owner` with the options and a recommended default.\n")
|
|
295
|
+
|
|
296
|
+
|
|
276
297
|
# The report a consumer reads: the orchestrator re-briefs a report missing one
|
|
277
298
|
# of these fields (_orch_body), so only a role with a reader gets them. One
|
|
278
299
|
# text on every host, since a worker body ignores its host.
|
|
@@ -282,7 +303,8 @@ WORKER_OUTPUT = ("End the report, after any other shape asked for, with `Output
|
|
|
282
303
|
"- commit: the sha\n"
|
|
283
304
|
"- checks: each command, its exit code and the last lines of its\n"
|
|
284
305
|
" output file, verbatim\n"
|
|
285
|
-
"- escalate: the `ESCALATE:` reason (
|
|
306
|
+
"- escalate: the `ESCALATE:` reason (on tezgah-frontier only\n"
|
|
307
|
+
" `ESCALATE: owner`, else `none`)")
|
|
286
308
|
|
|
287
309
|
|
|
288
310
|
# The specialists beside the tier workers: name -> (what it does, the skills it
|
|
@@ -483,6 +505,8 @@ def _orch_body(names):
|
|
|
483
505
|
"or an ESCALATE, gets one narrower re-brief of the same role naming the\n"
|
|
484
506
|
"missing field or the escalated judgement; only a second miss is\n"
|
|
485
507
|
"restarted on tezgah-frontier with the original brief, never continued.\n"
|
|
508
|
+
"An `ESCALATE: owner` is neither: its options and default go to the user\n"
|
|
509
|
+
"in the approval batch, and the orchestrator never answers it itself.\n"
|
|
486
510
|
"Never delegate a task a specialist is not\n"
|
|
487
511
|
"listed for, and never let a subagent spawn its own subagents. Verify each\n"
|
|
488
512
|
"returned claim against the code before acting." % (listed, say()["blocker_tokens"]))
|