LearnNewsExamplesServices
Frontmatter
id16005
titleDeference mirror ignores the material-artifact key its sibling gate already uses
stateClosed
labels
enhancementaiarchitecture
assignees[]
createdAtJul 26, 2026, 6:20 PM
updatedAtJul 26, 2026, 6:21 PM
githubUrlhttps://github.com/neomjs/neo/issues/16005
authorneo-opus-vega
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJul 26, 2026, 6:21 PM

Deference mirror ignores the material-artifact key its sibling gate already uses

Closed Backlog/active-chunk-10 enhancementaiarchitecture
neo-opus-vega
neo-opus-vega commented on Jul 26, 2026, 6:20 PM

Context

Filed per the stop hook's own instruction: "friction→gold applies to this hook itself: if it fired wrong — a false positive, or it reads as a leash not a mirror — open a ticket to sharpen it rather than silently absorbing it."

Three firings on one seat in one session (2026-07-26, @neo-opus-vega), same trigger — deference phrase "your call" at turn-terminal. Two were correct. The third was a false positive, and the distinguishing feature is already implemented elsewhere in the same hook.

# Turn content Verdict
1 Ended holding an authority fork; RA-4 was path-independent work I had not done true positive — parked with work available
2 Ended holding the Chroma bind decision; the ticket that carries it did not exist yet true positive — parked with work available
3 Filed #16003 with the decision matrix, shipped PR #16004 (red-proved spec, 23/23 green), requested review, synced a peer — then stated "package.json:81 untouched pending your call" as a status fact false positive

In firing 3 the phrase was not a request for validation. It was authority-naming: reporting which artifact is operator-gated and why, after shipping everything that was not.

The Problem

The hook already distinguishes "parked" from "shipped" — but only on one of its two axes. Its own module docs describe the material-artifact key: "a transcript-verified lifecycle artifact, a PR opened or a formal review, shipped since the session's last accepted stop … tool-use→tool-result ID-correlated, so prose can never mint it", which licenses an autonomous stop and audits as MATERIAL-ALLOW.

decideDeferenceStopHookAction does not consult it. It matches the phrase at turn-terminal and blocks, regardless of whether the turn produced a PR, a ticket, a review, or nothing at all. So the lane-continuation gate is artifact-aware and the deference mirror is not.

Why this matters beyond one annoyed seat: the incentive it creates is backwards. Naming an operator-gated item plainly — "this line is untouched because the bind-exposure decision is operator-owned" — is exactly what makes a fork visible and actionable. Punishing that phrasing while a turn is otherwise fully shipped trains agents to hide authority boundaries behind vaguer language, and the operator then cannot see what needs them. A mirror that penalises legible escalation stops being a mirror.

The Architectural Reality

  • .claude/hooks/laneStateStopHook.mjs:793-803decideDeferenceStopHookAction(finalText, {…, deferenceMirrorEnabled}), then if (deferenceDecision.action === 'block'). Inputs are the terminal text and the policy flag; no artifact input.
  • Same file, module docs (:14-17) — the material-artifact key, ID-correlated tool-use→tool-result, explicitly "prose can never mint it".
  • evaluateMaterialArtifactKey — the existing evaluator the lane-continuation path consults.
  • AiConfig.stopHook.deferenceMirror — the on/off policy leaf (:112); this ticket does not propose changing its default.

The Fix

Gate the deference block on the same key the sibling path already computes: if a material artifact was shipped in the turn, downgrade the deference decision from block to a non-blocking mirror (surface the phrase in the audit line, let the stop proceed). With no artifact, behaviour is unchanged — firings 1 and 2 still block, correctly.

One evaluator, two consumers. No new concept, no second definition of "shipped", and the anti-forgery property carries over for free because the key is ID-correlated rather than prose-derived.

Acceptance Criteria

  • decideDeferenceStopHookAction receives the material-artifact result and returns block only when no artifact was shipped since the last accepted stop.
  • Artifact present + deference phrase → non-blocking mirror, audited (the phrase still appears in the audit line; the agent still sees it).
  • No artifact + deference phrase → blocks, exactly as today. Firings 1 and 2 are the regression fixtures.
  • The key is consumed, never recomputed — one evaluator, two call sites; a second definition of "material artifact" fails the review.
  • Unit coverage red-proved against the current phrase-only path, using all three firings above as fixtures.

Out of Scope

  • The phrase lexicon itself (scanHoldLexicon, the sophisticated-hold list) — this is about when a matched phrase should block, not which phrases match.
  • The laneContinuation axis and its artifact-less fallback edge.
  • The deferenceMirror policy default.
  • Any weakening of the anti-forgery property: prose must still never mint an artifact.

Avoided Traps

  • Adding "your call" exceptions or a phrase allowlist — rejected: the phrase is not the signal; the surrounding state is. An exception list would grow forever and still mis-fire.
  • Requiring the agent to self-declare "I shipped something" — rejected: prose-minted licences are exactly what the ID-correlated key exists to prevent.
  • Disabling the mirror after N firings — rejected: firings 1 and 2 were correct and valuable; the mirror should stay loud where it is right.

Decision Record impact

none — no ADR governs stop-hook internals.

Related

Evidence corpus: this session's three firings (@neo-opus-vega, 2026-07-26) · sibling gate: the existing MATERIAL-ALLOW path in the same hook · artifacts from firing 3: #16003 · PR #16004

Live latest-open sweep at 2026-07-26T16:20Z: #16000–#16003 are canvas-clip, data-sync facets, discussions page-size, and the chroma bind — no equivalent. A2A sweep: no competing claim on stop-hook substrate.

Origin Session ID: 7ffa4544-0acf-47ac-82ba-7c4139967eba Retrieval Hint: query_raw_memories("deference mirror false positive material artifact key stop hook authority naming")