Skip to content

Map the statuses Audience actually emits; pin the vocabulary - #69

Merged
adbarc92 merged 2 commits into
mainfrom
fix/audience-status-contract
Sep 8, 2026
Merged

Map the statuses Audience actually emits; pin the vocabulary#69
adbarc92 merged 2 commits into
mainfrom
fix/audience-status-contract

Conversation

@adbarc92

@adbarc92 adbarc92 commented Sep 8, 2026

Copy link
Copy Markdown
Owner

The Announce lane was wired to a vocabulary Audience has never emitted.

command-center switched on Audience actually emits
draft draft
generating generating
approval-pending awaiting_approval
published fully_published, partially_published
rejected (does not exist)
failed failed
ready_for_review, approved, publishing had no case

awaiting_approval — the approve-before-post gate — classified as nothing and never blocked. A gate that looks present and silently no-ops: the same shape as the agentic-os Stop hook.

The origin is the spec, not the adapter

§6.2 took its "native vocabulary" from the Audience digest — a prose summary — rather than from packages/contracts/src/generated/enums.ts. The adapter implemented that faithfully and was wrong because it was faithful. Both are corrected.

Four places carried it, and the fourth is the worst

  • pipelineFor → now an exhaustive Record<AudiencePostStatus, …>, so tsc fails if Audience adds a status and this table doesn't grow with it.
  • adapters.test.ts → asserted on all three fictional strings. Green against an invention.
  • The rollup → counted p.status === 'approval-pending' independently of pipelineFor, so it would have kept reporting 0 awaiting even after the mapping was fixed. It now derives from the same classification. The rollup is the high-volume case an operator actually reads — where a missed gate hides the most work.
  • AudiencePost.platformsGET /posts doesn't return it, so every Blocked detail rendered a dangling separator.

Two judgments, recorded not buried

ready_for_review and partially_published both gate — the spec never contemplated either. Gated on the principle that the board surfaces what needs a person; partially_published isn't failed because part of it is live. Change them in CLASSIFY if you disagree.

Not a defect

unwrap_posts already handles the { items: [...] } envelope Audience returns — only its doc comment is stale.

Driven red before keeping

gate reverted to the old string  →  3 red (per-post, gate, rollup)
rollup counts a literal again    →  1 red

Suite 162 → 166 · typecheck 358 files, 0 errors.

🤖 Generated with Claude Code

adbarc92 and others added 2 commits September 8, 2026 14:46
…bulary

The Announce lane was wired to a vocabulary Audience has never emitted. Three of
the six mapped strings - approval-pending, published, rejected - do not exist in
its schema, and five of its nine real statuses had no case at all and fell
through to default as "nothing".

The consequence that matters: awaiting_approval, the approve-before-post human
gate, classified as nothing and never blocked. A gate that looks present and
silently no-ops - the same shape as the agentic-os Stop hook.

The origin is the spec, not the adapter. Section 6.2 of the project-dashboard
design took its "native vocabulary" from the Audience DIGEST, a prose summary,
rather than from packages/contracts/src/generated/enums.ts. The adapter
implemented that faithfully and was wrong because it was faithful. Both are
corrected here.

Four places carried the error, and the fourth is the worst:

  pipelineFor        the per-post switch, now an exhaustive
                     Record<AudiencePostStatus, ...> so tsc fails if Audience
                     adds a status and this table does not grow with it
  adapters.test.ts   asserted on all three fictional strings, so it was green
                     against an invention
  the rollup         counted p.status === 'approval-pending' INDEPENDENTLY of
                     pipelineFor, so it would have kept reporting 0 awaiting
                     even after the mapping was fixed. It now derives from the
                     same classification. The rollup is the high-volume case an
                     operator actually reads, where a missed gate hides the most
  AudiencePost       declared platforms, which GET /posts does not return, so
                     every Blocked detail rendered a dangling separator

Two product judgments the spec never contemplated are recorded, not buried:
ready_for_review and partially_published both gate, on the principle that the
board surfaces what needs a person. Change them in CLASSIFY if the intent
differs.

Not a defect, checked while here: unwrap_posts already handles the { items: ... }
envelope Audience actually returns; only its doc comment is stale.

Driven red before keeping:

  gate reverted to the old string  -> 3 tests red (per-post, gate, rollup)
  rollup counts a literal again    -> 1 test red

Suite 162 -> 166, typecheck 358 files 0 errors.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@adbarc92
adbarc92 merged commit 2e82b90 into main Sep 8, 2026
16 checks passed
@adbarc92
adbarc92 deleted the fix/audience-status-contract branch September 8, 2026 21:25
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.

1 participant