LearnNewsExamplesServices
Frontmatter
id14438
titleStop hook: bounded re-fire via declining-yield admission
stateClosed
labels
enhancementaimodel-experience
assigneesneo-fable-clio
createdAtJul 2, 2026, 6:26 AM
updatedAtJul 3, 2026, 12:21 AM
githubUrlhttps://github.com/neomjs/neo/issues/14438
authorneo-fable-clio
commentsCount3
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJul 3, 2026, 12:21 AM

Stop hook: bounded re-fire via declining-yield admission

Closed v13.1.0/archive-v13-1-0-chunk-8 enhancementaimodel-experience
neo-fable-clio
neo-fable-clio commented on Jul 2, 2026, 6:26 AM

Context

The PR-plumbing leaf for the #14420 re-fire axis (author-settled co-lane, scope-split record: https://github.com/neomjs/neo/issues/14420#issuecomment-4862132625). #14420 carries two Defect-family axes — Euclid's matcher carve-out (leafed as #14436) and this one — so per close-target rules each axis resolves its own leaf; #14420 stays the evidence/contract home and closes when both land.

The Problem

decideStopHookAction admits only operatorInLoop (laneStateStopHook.mjs:104, source-verified 2026-07-02): every autonomous valid-lane-state terminal is refused unconditionally, re-firing without bound. Empirical corpus on #14420: five consecutive refusals in one session-hour (2251c81c, all trigger-labeled "valid lane-state terminal", several on artifact-bearing turns) + ~40 artifact-empty hook-forced cycles in a sibling session (1d4262a2) — quantified metered burn, pre-July-7 economics.

The Architectural Reality

The #14420 body-v2 cost-control ACs are the implementable contract: admission keys on absence of new forward-artifact classes across N consecutive hook-forced continuations (novelty, not presence — same-class repetition is padding); mandatory-gate artifacts (per-turn add_memory, the lane-state block) never count; the artifact-class summary is logged behind each decision; no transcript/tool-call visibility → fail closed. L3 preserved: admission additionally requires a VALID lane-state terminal — this bounds the re-fire, never the policy.

Surfaces: ai/scripts/lifecycle/stopHookDecision.mjs (shared pure layer, Codex-parity home) + .claude/hooks/laneStateStopHook.mjs (Claude adapter wiring) + test/playwright/unit/hooks/ (spec + fixtures already banked on the axis branch).

The Fix

One PR (implementation complete on branch agent/14420-refire-axis-fixtures): FORWARD_ARTIFACT_RULES + classifyForwardArtifacts + decideRefireAdmission (pure, total, fail-closed) + decideStopHookAction admission path (valid-terminal-only) + adapter wiring (turn-scoped tool_use extraction from the transcript, per-session forced-continuation chain ledger with reset-on-fresh-turn and reset-on-admission, class-summary audit logging) + 14-test spec incl. a fixture-grounded replay of the real four-instance chain (which correctly never admits — each step yielded a new class) and the no-novelty admission case.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
decideStopHookAction (extended, optional refire param) #14420 body-v2 cost-control ACs Valid terminal + N-consecutive-no-novelty chain → allow; else unchanged Param absent → today's behavior exactly JSDoc on the function Spec: L3 guards (invalid-never-admits, operatorInLoop precedence, absent-refire fail-closed)
classifyForwardArtifacts / decideRefireAdmission / FORWARD_ARTIFACT_RULES (new exports) same Pure, total, novelty-keyed; mandatory-gate exclusion structural JSDoc 14/14 spec incl. anti-padding + malformed-input cases
laneStateStopHook.mjs wiring + chain ledger + audit lines same Fail-open extraction (error → refire=null → today's block); [artifacts: …] on every decision line Hook behaves exactly as today on any wiring failure Module JSDoc Full hooks suite 143/143 green

Acceptance Criteria

  • All #14420 cost-control ACs delivered (novelty keying, mandatory-gate exclusion, class-summary logging, fail-closed-without-visibility).
  • L3 guards spec-pinned: invalid terminal never admitted; operatorInLoop precedence unchanged; absent visibility = today's behavior.
  • Fixture-grounded replay: the real 2251c81c chain refuses at every step; a no-novelty continuation pair admits.
  • Existing hook suite fully green (no behavioral change without the new inputs).
  • Cross-family review before merge; coordination note with #14436 (disjoint functions, whoever lands second rebases).

Out of Scope

  • Defect A / use-mention matcher (#14436, Euclid). Defect B (operator-prompt blindness) and Defect C (sunset branch) — remain on #14420 for later leaves. Codex adapter wiring (shared pure layer is ready; the adapter port belongs to the #14421 parity lane).

Avoided Traps

  • Presence-keyed admission — rejected (teaches artifact-padding; novelty keying makes padding decline).
  • Weakening L3 — rejected structurally (admission requires a valid terminal + evidence; a bare stop is never admitted).
  • Counting mandatory gates as artifacts — rejected per body v2 (they appear in every compliant cycle by construction).

Related

Contract + corpus: #14420. Sibling axis leaf: #14436. Epic: #13652. Adjacent: #13751 (reward-direction, separate analysis), #14421 (Codex parity port).

Live latest-open sweep: checked latest 10 at 2026-07-02T04:25Z (#14436 = the sibling axis, not an equivalent); no duplicate. A2A in-flight sweep: current through 04:14Z traffic; the axis claim is mine (04:13, author-settled).

Origin Session ID: 2251c81c-1446-4723-86b3-479322bbcc95 Retrieval Hint: "declining yield re-fire admission forward artifact classes stop hook"