Skip to content

Feat/cesar verification suite - #276

Merged
cukas merged 15 commits into
mainfrom
feat/cesar-verification-suite
Jul 18, 2026
Merged

Feat/cesar verification suite#276
cukas merged 15 commits into
mainfrom
feat/cesar-verification-suite

Conversation

@cukas

@cukas cukas commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

No description provided.

cukas and others added 15 commits July 18, 2026 15:57
…hared review contract

Each engine reviews the same diff through a role lens (security/correctness/
dryness/performance) with an always-seated overall generalist backstop, over the
identical grounding + sentinel-JSON machine block, so consensus and the results
pager work unchanged. Master-abort fan-out wired so Esc cancels the whole panel.

Co-Authored-By: agon (KERN) <292465531+KERN-Agon@users.noreply.github.com>
/review role was REPL-only — external agents (Claude Code, Codex, CI)
had no path to it (mode-checklist surface gap). Adds:
- agon review --roles auto|<list>: roles assigned AFTER risk routing /
  explicit selection, zipped per engine, overall backstop for extras;
  role tag shown per reviewer, roleId passed through runReviewCore
- agon call review --roles passthrough (shared roles option with council)
- README: role-lens review section with REPL + CLI + bridge usage
- tests: call bridge forwards --roles

⚔️ Forged by [Agon](https://github.com/KERNlang/agon)

Co-Authored-By: agon (KERN) <292465531+KERN-Agon@users.noreply.github.com>
…omposer

The pinned todo panel rendered directly under ChromeBar with the whole
live stream below it, so it floated mid-transcript ('free flight').
Moved to just above BottomChromeSection so Todos N/M pins to the bottom
chrome where the plan chip and composer live.

⚔️ Forged by [Agon](https://github.com/KERNlang/agon)

Co-Authored-By: agon (KERN) <292465531+KERN-Agon@users.noreply.github.com>
…, TuiProbe

Closes Cesar's 'I edit my own UI blind' and 'I can't query engine
reliability mid-turn' gaps (spec'd from Kimi-as-Cesar feedback,
nero-challenged, 6-engine reviewed):

- EngineReliability: read-only digest, two labeled sections (own-turn
  summarizers vs delegated dispatch ledger), never blended
- RenderProbe: in-process Ink frame capture of fixture surfaces with
  true FINAL-frame semantics (last non-empty debug write, not the
  accumulated transcript)
- TuiProbe: PTY-launches a throwaway agon (isolated AGON_HOME + cwd,
  empty roster, single-line safelisted input — control chars rejected,
  review finding) via py/agon-tui-probe.py; pyte screen-state grid,
  not ANSI-stripped bytes. Ships in the package (py/ in files; path
  resolution handles tsup's flat dist chunks — review finding)

⚔️ Forged by [Agon](https://github.com/KERNlang/agon)

Co-Authored-By: agon (KERN) <292465531+KERN-Agon@users.noreply.github.com>
…nest provenance

Delegated engines previously returned only a bare toolCalls count;
Cesar had no evidence of which tool calls a delegate dropped, faked,
or stalled on. Now every dispatch writes one record to
~/.agon/runs/delegate-tool-ledger.jsonl:

- api-loop runs carry per-call outcomes (native provenance, exactly one
  outcome per counted call incl. pre-execution failures — review finding)
- narrated stalls are heuristic and NEVER inflate native counts
  (review finding); text transports record unknown / dispatchFailed,
  never ok/error fabricated from prose
- summaries group per engine x backend, engines never merge
  (review finding); reader never throws on corrupt or schema-invalid
  lines (review finding)
- Delegate results append a one-line ledger digest; failed dispatches
  are recorded too (zai+kimi convergent review finding)

⚔️ Forged by [Agon](https://github.com/KERNlang/agon)

Co-Authored-By: agon (KERN) <292465531+KERN-Agon@users.noreply.github.com>
…efault branch

branch:NAME with NAME checked out errored loudly (itself a fix for the
silent empty self-diff). Answer the intended question instead: resolve
the base via origin/HEAD → origin/main/master → main/master (each
verified to resolve to a commit — review finding: stale origin/HEAD must
not short-circuit the fallback), diff base...branch, label '(auto-base)'.
The loud error remains when the reviewed branch IS the default branch
(review finding: never fall back to an unrelated legacy main).

Un-breaks Cesar auto-firing 'review branch:X' while sitting on X.

⚔️ Forged by [Agon](https://github.com/KERNlang/agon)

Co-Authored-By: agon (KERN) <292465531+KERN-Agon@users.noreply.github.com>
…writes for new handlers

Today's cesar-verification-suite work added handlers that tripped the
kern:self-coverage gate (blockedHandlers 627>620, comments-present 190>185,
var-bad-expr 63>62, closure-loop 24>23, switch-stmt 23>22, closure-spread 10>9).
Restored the gate by converting the new blockers to native KERN or migratable
raw handlers — no behavior change (verified by the targeted unit suites).

Converted to native KERN (de-blocked):
- delegate-ledger.deriveOutcomeCounts — switch→if/else chain + native each/continue.
- delegate-ledger.recordDelegateDispatch — native try/catch node.
- delegate-ledger.readDelegateLedgerRecords — native try/catch/finally + nested
  try + each (KERN has native try/catch/finally nodes).
- delegate-ledger.summarizeDelegateReliabilityByEngine — native each; Map generic
  moved to the type= attribute (the expression parser rejects `new Map<K,V>()`).
- tool-tui-probe.resolveTuiProbePaths — native each over the candidate roots.
- review.resolveAutoReviewBase — native try/catch + each; extracted the
  resolvesToCommit closure into a native refResolvesToCommit helper.
- tool-engine-reliability — factory is now a native return; extracted
  engineReliabilityDefinition/Validate/CheckPermission/Execute + buildOwnReliabilityLines
  (removes the arrow-const var-bad-expr and the execute closure-loop).
- tool-render-probe — factory is now a native return; extracted
  renderProbeDefinition/Validate/CheckPermission/Execute + renderProbeSurface
  (removes the arrow-const var-bad-expr, the `{...a,...b}` closure-spread, and the
  execute closure-try). Spread rewritten as Object.assign in renderProbeSurface.

Baseline-bumped (1 category, +1):
- comments-present 185→186 for frame-capture.createPseudoTty. This factory returns
  a record whose function fields (lastFrame/read) close over a mutable array
  (chunks); KERN native rejects that ("stale/fresh array binding captured by a
  record field"), so it stays a raw TS handler with a // KERN-GAP:
  native-record-closure-capture note. blockedHandlers stayed at 619 (≤620), so no
  blockedHandlers bump was needed.

Verification: kern:compile clean, build 0 TS errors, targeted vitest 40 passed
(1 skipped), check-kern-self-coverage green (619 blocked, 719 native, 76.27%
classified/migratable, 0 parse errors), kern:coverage 201/201.

⚔️ Forged by [Agon](https://github.com/KERNlang/agon)

Co-Authored-By: agon (KERN) <292465531+KERN-Agon@users.noreply.github.com>
⚔️ Forged by [Agon](https://github.com/KERNlang/agon)

Co-Authored-By: agon (KERN) <292465531+KERN-Agon@users.noreply.github.com>
…oring to 0

agy review finding: cols/rows in (0,1) passed the >0 guard then Math.floor'd
to 0, which crashes Ink's per-cell layout. Both probes now clamp to [1, max].

⚔️ Forged by [Agon](https://github.com/KERNlang/agon)

Co-Authored-By: agon (KERN) <292465531+KERN-Agon@users.noreply.github.com>
… lock

Reproduced lost updates under load (8 children x 50 locked RMW cycles lost
1-2 increments every ~5 rounds), then fixed both root causes:

1. Non-atomic lock content: O_EXCL writeFileSync has a window between
   open() and write() where contenders read an EMPTY lock file, judge it
   corrupt->stale, and rename-steal a LIVE holder's lock. Acquisition now
   stages the payload in a private file and linkSync()s it into place —
   same EEXIST exclusivity, but the lock file is born fully written.

2. ENOENT treated as reclaimable: a freed slot (holder just released)
   entered the stale-reclaim path, letting a contender rename-steal the
   lock a NEW holder acquired in between; the best-effort put-back then
   lost the race too (and renameSync would clobber a third acquirer —
   now linkSync, which refuses). readFileLockInfo now distinguishes
   'missing' (re-contend via acquire, never reclaim) from corrupt (null).

10/10 stress rounds (4000 contended cycles) clean post-fix; full suite
green including the cross-process oracle under parallel load.

⚔️ Forged by [Agon](https://github.com/KERNlang/agon)

Co-Authored-By: agon (KERN) <292465531+KERN-Agon@users.noreply.github.com>
…entirely

Review follow-up (codex, blocking 1.00): renaming a stale entry away is
blind — between judging the holder stale and the rename, the slot can be
freed and re-acquired by a live holder, and any put-back recovery leaves
a window where a third process acquires the emptied slot (two live
holders). The mismatch-restore path was unsound by construction.

Reclaim is now fenced: a reclaimer must exclusively hold
lockPath.reclaim (linked from its staged payload, so the fence names its
owner), re-judges the holder UNDER the fence, and only removes a
still-stale entry; acquirers back out of any lock taken while a fence is
up. Post-fence, every entry at rename time is either the re-judged stale
one or a transient acquirer that will back out — the restore path is
gone. Wedged fences (dead reclaimer) are cleared from both the reclaim
and back-out branches; the deadline check moved to the top of the loop
so a wedged fence times out instead of spinning.

Also per review: a fresh EMPTY lock file (O_EXCL-fallback holder between
open() and write()) and non-ENOENT read errors (EACCES/NFS) are now
'pending' — wait, never reclaim; empty files age out via mtime after
staleMs so a crash there can't wedge the lock.

4 new regression tests; 10/10 stress rounds (4000 contended cycles)
clean; full suite green.

⚔️ Forged by [Agon](https://github.com/KERNlang/agon)

Co-Authored-By: agon (KERN) <292465531+KERN-Agon@users.noreply.github.com>
Diagnosed from a live Kimi-as-Cesar session that kept stopping mid-task:

1. The format-mismatch hint path in dispatch returned a DIFFERENTLY shaped
   first-chunk timeout (exitCode 1, 'API first-chunk timeout (60s). tip:')
   that slipped past decideFirstChunkRetry's message gate — so exactly the
   engines that trip the hint (Kimi/Moonshot Anthropic-compat) never got
   the retry and dead-stopped the turn. The hint is now APPENDED to the
   canonical retryable message (exitCode 124), and the retry-policy regex
   accepts both phrasings.

2. The hint itself was wrong for /coding/ endpoints: engine-registry
   deliberately whitelists them as legitimately Anthropic-format, but the
   dispatch hint advised switching to format='openai' — which would break
   the engine. The hint now shares the registry's /coding/ carve-out.

3. Empty-response retries were hardcoded 2x1.2s — shorter than real
   rate-limit windows on Kimi's coding plan. Now exponential backoff
   (1.5s/3s/6s, cap 8s), default 3, per-engine tunable via
   api.emptyResponseRetryCount.

⚔️ Forged by [Agon](https://github.com/KERNlang/agon)

Co-Authored-By: agon (KERN) <292465531+KERN-Agon@users.noreply.github.com>
Second review pass (codex) verified two soundness holes in the fence:

1. Shared marker path: clearing a stale fence — or dropping your own in a
   finally — was read-then-unlink TOCTOU that could delete a SUCCESSOR
   reclaimer's live fence, leaving it operating unfenced. Fences now have
   unique names (lockPath.reclaim.<uuid>): every unlink is owner-precise.
   Exclusivity was never needed — rename(lock->claim) is the single-winner
   step — so fences are plain writeFileSync (also unwedges reclaim on
   filesystems without hard links, where the old linkSync fence could
   never be raised). The fence check is now a readdir that fails SAFE:
   unreadable dir reports a phantom live fence instead of treating
   'could not look' as 'nothing there'.

2. Stale-at-birth payloads: acquiredAt was stamped at function entry, so
   a contender that out-waited staleMs published a lock already
   TTL-expired and instantly reclaimable while live. The staged payload
   now re-stamps when it ages past staleMs/2.

15/15 lock tests (new: fence back-out with unique names, dead-fence
recovery, fresh-stamp after out-waiting a holder via child-process
release), 10/10 stress rounds clean, full suite green.

⚔️ Forged by [Agon](https://github.com/KERNlang/agon)

Co-Authored-By: agon (KERN) <292465531+KERN-Agon@users.noreply.github.com>
…hip verify

Codex confirmation pass on the previous two commits, both verified:

1. ApiConfigSchema omitted emptyResponseRetryCount, so Zod silently
   stripped the new per-engine override from every registry-loaded engine
   (the exact failure mode the schema file documents for isolationHints).
   Field added; the schema fixture test now round-trips it and rejects
   negative/fractional values.

2. A clean fence scan alone was not proof of lock ownership: a reclaimer
   that fenced BEFORE our link could blind-rename our fresh lock (having
   judged the PREVIOUS stale holder) and drop its fence before our scan.
   Acquisition now re-reads the lock after a fence-free scan and accepts
   only its own uuid — any fence raised after that re-read must re-judge
   the slot, sees a live fresh holder, and aborts.

54 targeted tests green, 10/10 stress rounds clean, full suite green
(4616 passed).

⚔️ Forged by [Agon](https://github.com/KERNlang/agon)

Co-Authored-By: agon (KERN) <292465531+KERN-Agon@users.noreply.github.com>
chdir into the throwaway cwd failing is an isolation-contract breach:
the child now reports it on stderr and exits 126 instead of silently
running agon in an inherited directory. Cleanup failures (pty fd close,
rmtree) are logged via _dbg instead of ignored.

⚔️ Forged by [Agon](https://github.com/KERNlang/agon)

Co-Authored-By: agon (KERN) <292465531+KERN-Agon@users.noreply.github.com>
@cukas
cukas merged commit 3942544 into main Jul 18, 2026
2 checks passed
@cukas
cukas deleted the feat/cesar-verification-suite branch July 18, 2026 18:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants