Skip to content

Show candidate body in the Atlas review artifact#137

Merged
jpr5 merged 6 commits into
mainfrom
fix/atlas-review-artifact-show-body
Jul 7, 2026
Merged

Show candidate body in the Atlas review artifact#137
jpr5 merged 6 commits into
mainfrom
fix/atlas-review-artifact-show-body

Conversation

@jpr5

@jpr5 jpr5 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

The Atlas harvest Notion review artifact rendered only each candidate's title + tags + provenance — never the distilled body (content). So a human reviewer couldn't see the text they were approving or rejecting, which defeats the purpose of a human-ratification gate. (Found while inspecting the eval artifact and asking how one is supposed to judge content for approval.)

What this does

  • Renders each candidate's distilled why/how body as a collapsible "Content (why/how)" toggle under its approval checkbox — the reviewer can now read exactly what gets incorporated.
  • Descends the sync-side exclusion re-check into the toggle (fetchChildProse), so the body is both human-visible and machine-re-checked for credentials/exclusions on approval — closing the code's own §11 contract (previously the body was never on the page, so it was never re-checked).
  • Surrogate-safe, lossless body chunking — chunks on code-point boundaries at the guaranteed-lossless floor so astral characters (emoji/CJK-ext) are never split into U+FFFD and no tail content is silently truncated.
  • Block-budget batcher now recurses over the toggle's nested paragraphs and fails loud if a single candidate exceeds Notion's per-request block cap (rather than emitting a batch Notion 400s).

Verification

  • Live-verified against real Notion: posted the artifact to a throwaway page — the to_do → toggle → paragraph nesting is accepted (200) and the toggle + body render, astral chars intact. (Unit tests check block structure; this proves Notion accepts the shape.)
  • Red-green tests: astral char on the chunk boundary stays intact; astral-heavy >200k body round-trips with nothing dropped; deepBlockCount budget over nested children; and a credential-in-body → excluded round-trip proving the descent feeds the body to the exclusion engine.
  • Full suite: 3419 passed, 1 skipped (the opt-in real-LLM eval), 0 failed.

Review

Tier-2 CR, 3 rounds — the review caught and fixed three real bugs this feature introduced or exposed: (1) surrogate-pair corruption at the chunk boundary, (2) silent tail-drop on large astral bodies, (3) the sync round-trip not descending into the toggle (body shown but not re-checked). Converged with zero new in-subject findings.

Follow-ups (non-blocking, in the CR ledger)

  • HIGH: the deterministic credential floor (exclude.ts) misses modern OpenAI keys — sk-proj-/sk-svcacct-/sk-admin- (the /\bsk-[A-Za-z0-9]{20,}\b/ pattern stops at the hyphen). Worth its own quick PR. Also lacks shapes for xox*/github_pat_/AIza/gho_/bearer.
  • Pre-existing latents: clampTitle code-unit comment, a richText param shadow, generate.ts page.id guard, buildExclusionRuleBlocks raw rt() vs richText().

jpr5 added 6 commits July 6, 2026 22:19
The approval artifact rendered each candidate as a checkbox showing only the
canonical-key marker, title, and flag badge — never c.content, the distilled
why/how prose. A reviewer could not read the text they were approving or
rejecting.

Render c.content as a collapsible toggle child (labeled "Content (why/how)")
of both the approvable to_do and the unverified note, placed before the
provenance callout and evidence bullets. The body flows through the existing
richText() helper (2000-char run split, 100-run cap, surrogate safety) and is
split across multiple paragraph children when it exceeds one paragraph's run
budget, so nothing is dropped. Guarded on non-empty trimmed content so an empty
candidate gets no dead toggle.
…dget

blockCost counted a block plus only its DIRECT children, assuming children are
one level deep. The new content toggle adds a second nesting level (to_do →
toggle → paragraphs), whose grandchildren went uncounted — a large run could
silently exceed Notion's ~1000-block-per-request cap and 400 the whole append.

Make blockCost recurse over all descendants so the batcher budgets the true
total block count at every depth.
The content-toggle chunker sliced c.content at a fixed 200000 code units,
then fed each slice to richText. Two defects for astral-heavy bodies:

- Surrogate split: a slice boundary could cut a surrogate PAIR in half;
  richText's toWellFormedUtf16 then sanitized each lone half to U+FFFD,
  corrupting the astral char across the chunk seam.
- Tail-drop: 200000 = RICH_TEXT_RUN_MAX x RICH_TEXT_MAX_RUNS assumed richText
  renders a full 200k chunk losslessly, but its per-run surrogate backoff
  shortens runs, pushing the tail past the char cap and tripping the
  truncation branch — silently dropping ~2000 chars per chunk.

Iterate c.content by code point (never splitting a pair) and cap each chunk
at the guaranteed-lossless floor (RICH_TEXT_RUN_MAX-1) x RICH_TEXT_MAX_RUNS,
which absorbs a worst-case one-unit backoff on every run. Added red-green
tests: an astral char straddling the chunk boundary stays intact (no U+FFFD),
and an astral-heavy body >1 chunk round-trips with every code point preserved.

Also restore the console.warn spy after each test in the rule-bullet
delimiter-tolerance suite (restoreMocks is not globally on, so the spy was
leaking into later suites).
Update the stale batchBlocks comment (a candidate now nests a content toggle
whose paragraph children add a second level, so a block's recursive cost is
no longer a small constant), and throw a clear error when one block's
blockCost alone exceeds NOTION_MAX_TOTAL_BLOCKS_PER_REQUEST — such a block can
never fit any batch and would 400 the append, so surface it here rather than
at the API.
…for exclusions

The S16 review artifact renders each candidate's distilled body inside a
"Content (why/how)" toggle whose paragraph children hold the prose, but the
sync-side extractor (fetchChildProse) read only the to_do's direct children.
For the toggle that captured its static label, not the body — so the on-approval
credential/exclusion re-check (§11) judged title + label, never the body a
reviewer actually sees. A clean-titled candidate whose body leaked a credential
was approved, and the constant "Content (why/how)" leaked into the payload.

fetchChildProse now descends one level into a toggle child, folding its
paragraph grandchildren (with the same canonical-key marker filter) and skipping
the toggle's own label. Non-toggle children stay depth-1 as before. Adds a
real build->fetch->reconstruct->applyExclusions round-trip test proving a
body-only ghp_ token is caught and the toggle label never enters the payload.
The test titled "budgets by TOTAL block count (top-level + nested)" summed
only self + DIRECT children (childCountOf), so it never verified grandchild
counting — the deep/toggle-paragraph budget is covered by the sibling "budgets
by DEEP block count" test. Retitle and reword to "top-level + DIRECT children"
so the title is true and points at the sibling for the deep case.
@jpr5 jpr5 marked this pull request as ready for review July 7, 2026 06:02
@jpr5 jpr5 merged commit 3043e15 into main Jul 7, 2026
6 checks passed
@jpr5 jpr5 deleted the fix/atlas-review-artifact-show-body branch July 7, 2026 06:02
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