Skip to content
This repository was archived by the owner on Jun 23, 2026. It is now read-only.

v1.7.0 — Reliable async jobs · token-lean result handoff · deterministic stack detection

Latest

Choose a tag to compare

@VKirill VKirill released this 25 May 23:35

Languages: 🇬🇧 English · 🇷🇺 Русский

🇬🇧 English

Reliability + token-efficiency release. Async agy jobs no longer report false deaths, the worker result handoff is fully structured (no transcript mining), and the planner now plans on the project's real stack instead of guessing. Verified end-to-end with 3 coders running in parallel — 0 false-deaths, 0 retries, 192/192 tests green.

🚀 Highlights

Area Before After
Async job death detection Jobs that succeeded were reported failed → wasted retries Grace window + sidecar authority → recovered as success
Result handoff Mined from the raw transcript (regex, brittle, token-heavy) Strict result.yaml sidecar + YAML.parse validation
Polling cost async_status + sleep poll loop re-billed the whole conversation Blocking async_wait + slim _status (Layer 0/1)
Planner stack Guessed .js / node:test on a TS/bun project (2 of 3 runs) Orchestrator injects a stack_profile → correct .ts / bun test, first try

🐛 Reliability — the agy false-death arc (fixed)

Root cause (confirmed via docs/plans/agy-process-lifecycle/SPEC.md): agy --print spawns an internal engine grandchild that inherits the stdout pipe and outlives the tmux pane. The session vanishes (tmux has-session → false) while the grandchild is still flushing its output and its result.yaml a few seconds later — so declaring death the instant the session disappeared reported a succeeded job as failed, and sometimes triggered a wasteful retry.

Three layered fixes:

  1. Run agy directly in the pane — removed the setsid -w wrapper that detached agy into its own session (it survived the pane's SIGHUP and ran orphaned, widening the false-death window). 45572c4
  2. Grace window — on “session gone + no exit code + no sidecar yet” the job stays running (deathSuspectedAt stamped) for AGY_DEATH_GRACE_MS (default 30 s, ~2× the observed ~14 s flush gap), then the sidecar fallback marks it success once result.yaml lands. Bounded by the wall-clock AGY_TIMEOUT_MS. f53fa2b
  3. Late sidecar recovery — a job already marked failed only via the premature-death path is re-checked against result.yaml and upgraded to success if the envelope parses (strictly scoped — never a real non-zero exit, parse error, or crash-monitor 137). 45572c4
Before:  session gone @50s ──▶ FAILED ──▶ retry (work was already done)
After:   session gone @50s ──▶ running (grace) ──▶ result.yaml @64s ──▶ SUCCESS

⚡ Token efficiency — structured result handoff

  • Layer 0 — envelope only. async_result returns just the worker's result: envelope, never the raw transcript. c7676c5
  • Layer 1 — blocking wait + slim status. New async_wait blocks server-side until the batch settles; async_status slimmed. Kills the status-poll-sleep loop. 179fcaf · f33dd6e
  • result.yaml sidecar. The worker writes its envelope to a file as its last action; the server reads that file instead of scraping stdout. d8e230a
  • Strict validation. Server-side YAML.parse (top-level result: mapping required). 54571b7

📉 A monitored run went from ~158 antigravity calls + 10 sleeps to 6 calls, 0 sleeps.

🎯 Planner — deterministic stack detection

The planner runs on graph-only tools (gitnexus / serena), and package.json scripts.test is not in the code graph — so it couldn't see bun test vs node --test and fell back to a wrong guess. Fix (2b9564e):

  • Orchestrator injects a stack_profile — before dispatch it Reads package.json + ls-es the target dir and passes authoritative facts (language, file_ext, test_command, test_file) into the contract.
  • Planner reads the manifest first — stack detection is now Step 1; the NOT raw grep rule was narrowed to repo-wide grep only (targeted single-file reads allowed any time).

✅ Verified live: planner produced src/utils/*.ts + bun test + dependencies: [] on the first try, no correction round.

🧰 Other improvements

  • Skills catalog auto-generated from the runtime skill dir, 12 categories, + sync test. a3430e3 · a3c181d · 5733777
  • MCP config isolation into the per-session agy worker home. ab80f2b
  • Usage metric — average successful-job duration. d87eca2
  • async_wait added to the dev-orchestrator-agy tools allowlist + made the universal await. f33dd6e
  • 📚 Docs — comprehensive bilingual README (architecture, async engine, worker roster, full tool & env reference). 9c7c4c3

✅ Verification

  • bun run build — clean · bun test192 pass / 0 fail (24 files).
  • End-to-end parallel run (takeWhile / dropWhile / partition): 3 coders dispatched concurrently, planner emitted correct .ts / bun test with no correction round, 2 of 3 coders hit the grandchild detach and were recovered as success0 false-deaths, 0 retries, clean fast-forward push.

🇷🇺 Русский

Релиз про надёжность и экономию токенов. Async-джобы agy больше не отчитываются ложной смертью, передача результата воркера полностью структурирована (без выскребания транскрипта), а планировщик теперь планирует на реальном стеке проекта, а не угадывает. Проверено сквозным прогоном с 3 кодерами параллельно — 0 ложных смертей, 0 ретраев, 192/192 теста зелёные.

🚀 Главное

Область Было Стало
Детект смерти async-джобы Успешные джобы отчитывались как failed → лишние ретраи Grace-окно + авторитет сайдкара → восстановление в success
Передача результата Выскребалась из сырого транскрипта (регексп, хрупко, дорого по токенам) Строгий сайдкар result.yaml + валидация YAML.parse
Стоимость поллинга Петля async_status + sleep перебиливала весь диалог Блокирующий async_wait + слим _status (Layer 0/1)
Стек планировщика Угадывал .js / node:test на TS/bun-проекте (2 из 3 прогонов) Оркестратор инжектит stack_profile → корректные .ts / bun test с первого раза

🐛 Надёжность — арк ложной смерти agy (исправлено)

Корень (подтверждён через docs/plans/agy-process-lifecycle/SPEC.md): agy --print порождает внутренний engine-внук, который наследует stdout-pipe и переживает tmux-pane. Сессия исчезает (tmux has-session → false), пока внук ещё дописывает вывод и result.yaml через несколько секунд — поэтому объявление смерти в момент исчезновения сессии отчитывало успешную джобу как failed и иногда запускало лишний ретрай.

Три слоя фикса:

  1. Запуск agy прямо в pane — убран обёртка setsid -w, отвязывавшая agy в свою сессию (он переживал SIGHUP pane и работал «сиротой», расширяя окно ложной смерти). 45572c4
  2. Grace-окно — при «сессия исчезла + нет exit-кода + нет сайдкара» джоба остаётся running (deathSuspectedAt) на AGY_DEATH_GRACE_MS (по умолчанию 30 с, ~2× от наблюдаемых ~14 с задержки записи), затем сайдкар-фолбэк помечает её success, как только result.yaml прилетит. Ограничено wall-clock AGY_TIMEOUT_MS. f53fa2b
  3. Позднее восстановление по сайдкару — джоба, помеченная failed только через путь преждевременной смерти, перепроверяется против result.yaml и апгрейдится до success, если конверт парсится (строго — никогда для реального ненулевого кода, parse-error или kill-137 краш-монитора). 45572c4
Было:  сессия исчезла @50с ──▶ FAILED ──▶ ретрай (работа уже сделана)
Стало: сессия исчезла @50с ──▶ running (grace) ──▶ result.yaml @64с ──▶ SUCCESS

⚡ Экономия токенов — структурированная передача результата

  • Layer 0 — только конверт. async_result возвращает только конверт result: воркера, никогда сырой транскрипт. c7676c5
  • Layer 1 — блокирующее ожидание + слим-статус. Новый async_wait блокирует на сервере до завершения батча; async_status ужат. Убивает петлю status-sleep. 179fcaf · f33dd6e
  • Сайдкар result.yaml. Воркер пишет конверт в файл последним действием; сервер читает файл, а не выскребает stdout. d8e230a
  • Строгая валидация. Серверный YAML.parse (нужен top-level result:). 54571b7

📉 Один прогон ушёл со ~158 вызовов antigravity + 10 sleep до 6 вызовов, 0 sleep.

🎯 Планировщик — детерминированный детект стека

Планировщик работает на только графовых инструментах (gitnexus / serena), а scripts.test из package.json нет в графе кода — поэтому он не видел bun test против node --test и скатывался к неверной догадке. Фикс (2b9564e):

  • Оркестратор инжектит stack_profile — перед раздачей он Read-ит package.json + ls-ит целевую папку и передаёт авторитетные факты (language, file_ext, test_command, test_file) в контракт.
  • Планировщик читает манифест первым — детект стека теперь Шаг 1; правило NOT raw grep сужено до repo-wide grep (точечное чтение одного файла разрешено в любой момент).

✅ Проверено в живую: планировщик выдал src/utils/*.ts + bun test + dependencies: [] с первого раза, без круга коррекции.

🧰 Прочие улучшения

  • Авто-генерация каталога скиллов из рантайм-папки, 12 категорий, + sync-тест. a3430e3 · a3c181d · 5733777
  • Изоляция MCP-конфига в per-session домашку воркера agy. ab80f2b
  • Метрика usage — средняя длительность успешной джобы. d87eca2
  • async_wait добавлен в allowlist инструментов dev-orchestrator-agy + сделан универсальным ожиданием. f33dd6e
  • 📚 Документация — подробный двуязычный README (архитектура, async-движок, реестр воркеров, полная справка по инструментам и env). 9c7c4c3

✅ Проверка

  • bun run build — чисто · bun test192 pass / 0 fail (24 файла).
  • Сквозной параллельный прогон (takeWhile / dropWhile / partition): 3 кодера раздались одновременно, планировщик выдал корректные .ts / bun test без круга коррекции, 2 из 3 кодеров словили детач внука и были восстановлены в success0 ложных смертей, 0 ретраев, чистый fast-forward push.

📦 Full commit log (v1.6.1...v1.7.0)
2b9564e fix(planner): deterministic stack detection — orchestrator injects stack_profile + planner reads manifest first
f53fa2b fix(jobs): grace window for agy grandchild — stop false-death before sidecar flush
45572c4 fix(jobs): eliminate false-death of agy jobs — run agy in pane, recover via sidecar
0f58594 fix(jobs): stop intermittent "tmux died before echo" false-crashes + planner stack detection
f33dd6e fix(orchestrator-agy): add async_wait to the agent tools allowlist + make it the universal await
54571b7 feat(result): strict server-side YAML.parse validation of result envelopes
d8e230a feat(result): result.yaml sidecar — strict, file-based result handoff (no transcript mining)
179fcaf perf(polling): Layer 1 — blocking batch wait + slim _status (cut polling token burn)
c7676c5 feat(result): Layer 0 — return only the result envelope, never the raw transcript
a3430e3 feat(skills): generate catalog from the runtime skill dir, grouped by category
a3c181d refactor(skills): drop the per-role DEFAULT table from the catalog
5733777 feat(skills): described auto-generated catalog + de-dup defaults + sync test
ab80f2b fix(isolation): propagate MCP config to agy worker home (gitnexus/serena/postgres/perplexity)
d87eca2 feat(usage): add average successful job duration metric
3c5a9ec test(usage): cover average successful job duration metric
ad25053 chore: remove test-run artifacts (validate, debounce, zod dep)
9c7c4c3 docs: comprehensive bilingual README (GitNexus-grade)

Test fixtures (small sample utilities added while validating the orchestrator end-to-end, each with unit tests + public export): chunk, clamp, uniqueBy, flatten, takeWhile, dropWhile, partition.

Compare: v1.6.1...v1.7.0


🤖 Generated with Claude Code