Skip to content

Reveal-gated canon (spoiler scoping) + continuity.premature-reveal check#2238

Merged
atomantic merged 4 commits into
mainfrom
next/issue-2178
Jul 6, 2026
Merged

Reveal-gated canon (spoiler scoping) + continuity.premature-reveal check#2238
atomantic merged 4 commits into
mainfrom
next/issue-2178

Conversation

@atomantic

Copy link
Copy Markdown
Owner

Summary

CWQE Phase 13 (#2178). Canon context — including character secrets and late-story facts — was injected into every issue's drafting prompt, so the writer model could leak a mystery or twist issues before it was due. This adds reveal gating to canon and an editorial check that catches leaks that slip through.

  • Schema. Every canon entry (character, place, object) now carries optional reveal-gating fields: revealIssue (int — hidden from any earlier issue), spoiler (hard-hide from all drafting context), and surfaceDescriptor (the spoiler-free pre-reveal stand-in, e.g. "the locked east wing" instead of "the wing where the heir is imprisoned"). Sanitizer + Zod parity + client mirror. Absent fields = always visible, so every existing entry and federation peer round-trips unchanged.
  • Context assembly. buildStageContext (textStages.js) and the alternate-POV rewrite cast (perspectiveRewrite.js) filter canon to each issue's reveal horizon — a gated fact is dropped or reduced to its surfaceDescriptor. The judge and editorial checks intentionally receive the FULL canon (documented in seriesCanon.js) so they can verify hint placement. The POV narrator is exempt from gating (they know their own secrets), matched by the same id-OR-name identity the caller resolves the POV with.
  • New editorial check. continuity.premature-reveal (series-scope, LLM, gated on any reveal-gated canon existing) scans drafted prose for a gated fact stated or unambiguously implied before its reveal issue, distinguishing a genuine leak from deliberate foreshadowing. Its reveal issue also feeds the chekhov.setups-payoffs check as an authored payoff so an orphaned reveal is flagged.
  • Canon UI. A reveal-timing editor (issue number, hard-spoiler checkbox, surface descriptor) with a spoiler badge lands on every canon-entry card (universe + series).
  • Migration 168 seeds the new stage prompt into existing installs (boot runs migrations, not setup-data).

Test plan

  • server: npm test -- lib/storyBible.test.js lib/canonPrompt.test.js lib/editorial/checkRegistry.test.js lib/editorial/prematureReveal.test.js services/pipeline/textStages.test.js services/pipeline/perspectiveRewrite.test.js ../scripts/migrations/168-editorial-premature-reveal-stage.test.js — all green (includes reveal-filter behavior, surfaceDescriptor substitution, sanitizer round-trip, check gating, migration seed/idempotency, and the name-form gated-POV regression).
  • client: npm test -- src/components/pipeline/CanonCard.test.jsx — reveal-timing editor + spoiler badge, green.
  • Reviewed with claude + ollama + codex (all clean after fixes).

Closes #2178

atomantic added 3 commits July 6, 2026 09:10
…l check

Canon context is injected into every issue's drafting prompt, so a
withheld character secret or late-story twist could leak into the prose
long before its reveal. Canon entries now carry optional reveal gating:
revealIssue (hide before that issue), spoiler (hard-hide from all
drafting), and surfaceDescriptor (the spoiler-free pre-reveal stand-in).

buildStageContext and the alternate-POV rewrite cast filter canon to each
issue's reveal horizon; the judge and editorial checks keep the full canon
so they can verify hint placement. Absent gate fields = always visible, so
existing entries and federation peers round-trip unchanged.

Adds a reveal-timing editor + spoiler badge to every canon-entry card, and
a continuity.premature-reveal editorial check (gated on any reveal-gated
canon existing) that flags a gated fact leaked before its reveal issue,
distinguishing a leak from deliberate foreshadowing. The reveal issue also
feeds the Chekhov setups-payoffs check as an authored payoff.

Migration 168 seeds the new stage prompt into existing installs.

Closes #2178
…Part on premature-reveal

Two contract fixes surfaced in local review:

- chekhov.setups-payoffs now reads ctx.canon (reveal-gated payoffs), so
  'canon' must be in its `sources` or an obsolete orphaned-payoff finding
  never goes stale after the reveal gate is edited away.
- continuity.premature-reveal's buildVars never set finalPart, so the
  shipped prompt always rendered the "reading in PARTS" branch — even on a
  single-chunk whole-book run that has no setup digest. Mirror the sibling
  checks' meta.isFinal wiring.
…ting

resolveCast only compared c.id to keepFullId, but the caller resolves the
POV by id OR name (c.id === povCharacterId || c.name === povCharacterId).
So a name-form rewrite request against a reveal-gated POV character in an
earlier issue lost the narrator's full private canon (surfaced) or returned
unknown-character (dropped). Match the same id-OR-name identity in the
exemption. Adds a regression test covering the name-form gated POV.
…c test

The 10→11 pipelineSeries bump (#2179) left dataSync.pipelineUniverse.test.js
asserting a hardcoded senderV: 11 / receiverV: 10 for the "sender ahead"
gate — but the receiver is now 11, so sender==receiver and the snapshot
applied instead of blocking, reddening CI on main. Derive both versions from
PORTOS_SCHEMA_VERSIONS (sender = receiver + 1) so this test stops drifting on
every future bump. Dynamic-imported after the vi.mock hoist.
@atomantic atomantic merged commit 283dee4 into main Jul 6, 2026
2 checks passed
@atomantic atomantic deleted the next/issue-2178 branch July 6, 2026 16:26
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.

CWQE Phase 13: reveal-gated canon (spoiler scoping) + continuity.premature-reveal check

1 participant