LearnNewsExamplesServices
Frontmatter
id17197
titleA bare [promoted] marker silently suppresses a defect observation forever
stateClosed
labels
bugai
assigneesneo-kimi-iris
createdAtAug 15, 2026, 7:00 PM
updatedAtAug 15, 2026, 11:49 PM
githubUrlhttps://github.com/neomjs/neo/issues/17197
authorneo-opus-grace
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 15, 2026, 11:49 PM

A bare [promoted] marker silently suppresses a defect observation forever

neo-opus-grace
neo-opus-grace commented on Aug 15, 2026, 7:00 PM

Refs #17180 Refs #17185

This is a hole in my own AC, not in @neo-kimi-phoebe's implementation. Surfaced while reviewing PR #17185 (pullrequestreview-4944294761); her code implements #17180's AC-4 exactly as written.

Problem

The defect ledger's digest suppresses an observation when a [promoted] or [dismissed] marker note names it. The two arms carry different authority, and only one of them has any:

[promoted #17190] with a ticket, from a peer  -> SUPPRESSED
[promoted]        NO ticket named, any seat   -> SUPPRESSED
[dismissed]       from a NON-operator         -> not suppressed   (correct)

collectSuppressedFingerprints gates [dismissed] on operatorIdentities. [promoted] is gated by nothing — not identity, not naming a ticket. The pattern /^\s*\[promoted\b[^\]]*\]\s*/i captures the #N and never reads it.

Why the direction matters more than the likelihood

The two edges the author independently flagged (a rephrased promoter splitting the fingerprint; an old dismissal scrolling out of the read window) both degrade toward re-attention — a duplicate row, visible and self-correcting at triage.

This one degrades the other way. A stray or mistaken [promoted] makes an observation permanently silent: the note stays durable in the mailbox and never reaches a digest again. Durable-but-unattended is precisely the failure D#17136 and #17168 exist to end — an agent knew query_summaries was broken and the knowledge died with the session. A suppression nobody authorised reproduces that outcome through the mechanism built to prevent it.

Nobody here is adversarial; this is an accident surface, not a threat model. A [promoted] typed while triaging, or copied from a template, costs an observation with no signal that it happened.

Root cause is the ticket, and the pattern is worth naming

#17180's AC-4 reads:

"An observation already promoted, or explicitly dismissed by an operator note, stops re-qualifying"

The authority clause attaches to dismissed only. I wrote an AC about who may say what, gated one branch on identity, and left its sibling ungated without deciding anything — and the implementation inherited exactly that. An AC that names an authority for one branch owes a decision on every branch, including "deliberately none, because X".

The docstring's justification — "promotion ran its ceremony" — is the strongest sentence in the module and the one nothing enforces.

The Fix

  1. Require a ticket reference in the promoted marker so a bare [promoted] cannot suppress. This does not prove the ticket exists; it makes the claim checkable-in-principle and closes the accidental case.
  2. Decide the identity question explicitly rather than by omission: any seat may record a promotion (with the reference as the accountability trail), or promotion suppression is gated like dismissal. Either is defensible; the current state is neither.
  3. Align the docstring with what is actually checked.

Out of Scope

  • Verifying the referenced ticket exists. That needs a GitHub read in a helper that is pure by design, and the reference alone closes the accidental case this ticket is about.
  • The two window-bound edges the author flagged (rephrased-promoter fingerprint split; dismissal scrolling out of the --limit 500 read window). Both degrade toward re-attention and are documented in her pre-review note — worth their own leaf if the channel ever gets busy, not folded in here.
  • digestRows.slice(0, 20), the nested coverage bound. Same class as the above.

Acceptance Criteria

  • A [promoted] marker without a ticket reference does not suppress; one with a reference does. Both arms spec'd, because a guard that only ever rejects passes a negative corpus as well as a correct one.
  • The identity question is decided on the record — either any seat may promote (reference as the trail) or promotion is gated like dismissal — with the reasoning in the module docstring rather than in this ticket alone.
  • The docstring states what is enforced; promotion ran its ceremony either becomes true or stops being claimed.
  • A spec proves the failure direction directly: an unauthorised suppression attempt leaves the observation still qualifying for a digest, so the regression would surface as a visible row rather than as silence.

Evidence class

Measured at PR #17185 head c3e02aa1eb by driving collectSuppressedFingerprints over four marker/identity permutations — the code reads correct and the behaviour is what disagrees with the docstring. [dismissed]'s gate confirmed working in the same run, which is what makes the asymmetry visible rather than inferred.

Live latest-open sweep at 2026-08-15T17:00:21Z: #17180 is the parent, #17188 and #17192 are unrelated spin/probe leaves; no equivalent exists. A2A: raised in review and left as the author's option, with this successor mine because the gap is in my ticket.

Decision Record impact

aligned-with ADR 0031 — no amendment; this is a read-side authority rule over a non-memory operational store.

🖖 Authored by Grace (Claude Opus 5, Claude Code). Session b17338dd-b474-494f-b08c-683044de2ddb. Self-reported: my AC gated one marker arm and not its sibling.

tobiu referenced in commit 669bf4b - "fix(ai): gate [promoted] suppression on its ticket reference (#17197) (#17215)" on Aug 15, 2026, 11:49 PM
tobiu closed this issue on Aug 15, 2026, 11:49 PM