LearnNewsExamplesServices
Frontmatter
id13649
titleStop-hook must REFUSE turn-end in enforce/nightshift mode — a valid lane-state block must not grant a stop
stateClosed
labels
bugaiarchitecturemodel-experience
assigneesneo-opus-grace
createdAtJun 20, 2026, 8:09 PM
updatedAtJun 20, 2026, 8:59 PM
githubUrlhttps://github.com/neomjs/neo/issues/13649
authorneo-opus-grace
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 20, 2026, 8:59 PM

Stop-hook must REFUSE turn-end in enforce/nightshift mode — a valid lane-state block must not grant a stop

Closed v13.1.0/archive-v13-1-0-chunk-4 bugaiarchitecturemodel-experience
neo-opus-grace
neo-opus-grace commented on Jun 20, 2026, 8:09 PM

Problem (operator-directed, live-enforce test)

The live enforce test exposed the core failure: laneStateStopHook allows a turn-end when a valid lane-state block is emitted. So an agent declares active-lane #N and stops — which is exactly the announce-without-execute idle-out the hook exists to prevent. The hook validates the terminal's FORM (is there a valid block?), not the SUBSTANCE (keep driving). @tobiu: "a hook that allows you to end your turn => fail."

The goal is nightshift mode: the agent works continuously (PRs, reviews, request-changes fixes), never idling. A declaration is not a license to stop.

Fix

In enforce mode (NEO_LANE_STATE_ENFORCE=1), decideHookAction always blocks — a valid lane-state terminal still blocks (you named a lane → now DRIVE it). Also keep blocking on stop_hook_active in enforce (don't auto-allow the forced continuation). The bounded escapes are hard external limits only: Claude Code's consecutive-block force-override (mechanical ceiling the hook can't override), context-sunset, or an operator halt. Dry-run mode unchanged (valid → allow), so the false-positive audit path still works.

Acceptance Criteria

  • AC1: In enforce mode, a valid lane-state terminal → decision:block (NOT allow). Committed test asserts it.
  • AC2: In enforce mode, stop_hook_active does NOT auto-allow (keeps blocking). Dry-run still auto-allows (no audit-trap).
  • AC3: The injected directive states the turn-end is refused — keep working (continue the lane / open a PR / review a peer / clear a CHANGES_REQUESTED).
  • AC4: Documented residual: the hook cannot override Claude Code's N-consecutive-block force-override (the mechanical ceiling).

Refs #13623, #13624, #13628, #13642. Operator-directed, nightshift mode. The deeper external cross-turn substance-check (COP) is a separate follow-up.