Skip to content

fix(lifecycle): own enrichment provenance in code; fix(mailbox-poller): drop numeric separators - #985

Merged
blove merged 4 commits into
mainfrom
blove/threadplane-growth-arc-rescue-35214f
Sep 3, 2026
Merged

fix(lifecycle): own enrichment provenance in code; fix(mailbox-poller): drop numeric separators#985
blove merged 4 commits into
mainfrom
blove/threadplane-growth-arc-rescue-35214f

Conversation

@blove

@blove blove commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Three commits on one branch, all in service of getting production enrichment to succeed and the resulting sequence to be correct.

1. Apps Script parse fix (tools/google-mailbox-poller/Code.gs). The editor rejects numeric separators; three literals became plain numbers.

2. Code-owned enrichment provenance (apps/lifecycle/src/enrichment/anthropic.ts). Every production enrich job was terminal with enrichment_failed. The Anthropic structured-output grammar drops array-length, numeric, and enum bounds, and the model was asked to echo provenance verbatim; it returned one draft instead of three, dropped milliseconds from retrieved_at, cited score identifiers as sources, and fabricated sources in neutral mode. The wire schema now carries only what the model judges, with no grammar-unenforceable bounds, and normalizeArtifact derives sources from the bounded evidence, copies score metadata from the input, drops signals citing anything outside the evidence, nulls drafts pointing at a dropped source or unknown angle, pads or truncates drafts to three slots, and strips company claims in neutral mode.

3. Findings from vetting against live sites (fetcher, normalizer, templates, dispatcher).

  • A single oversized, missing, or slow page aborted evidence for the whole company. The fetcher now skips that page and keeps the rest; only the caller's abort and SSRF violations (CompanyFetchSecurityError) propagate.
  • A repeated angle across slots would send the same email twice; the normalizer nulls repeats and the prompt asks for distinct angles.
  • Evidence copy on step 3 now ends with the last-follow-up notice like the default copy does.

Verification

  • nx run-many -t lint,test,check -p lifecycle passes (201 tests across the four affected specs).
  • Live against the API with the spec fixtures: 5/5 succeed (0/4 before).
  • Live end to end (fetch, build input, generate, render drafts) for threadplane.ai, ionic.io, nx.dev, and a neutral personal-email case: all succeed; ionic.io yields evidence from its one page under the 250 KiB cap; nx.dev has no page under the cap and correctly falls back to default copy.

After merge the lifecycle auto-deploys; the two failed production enrich jobs then get a one-line re-queue.

🤖 Generated with Claude Code

…r can parse Code.gs

The Apps Script editor rejects numeric separator literals (8_000, 4_000,
1_000_000) with 'Unexpected token ILLEGAL' at line 321 and refuses to save.
Plain literals keep the same values.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
threadplane Ready Ready Preview Sep 3, 2026 5:15pm UTC

Request Review

@blove
blove enabled auto-merge (squash) September 3, 2026 15:44

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated approval: this PR received an intelligent (AI) code review. See the review comments on this PR.

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Claude finished @blove's task in 0s —— View job


I'll analyze this and get back to you.

…t stops failing

Every production enrich job failed. The Anthropic structured-output grammar
drops array-length, numeric, and enum bounds from the JSON schema, and the
model was asked to echo provenance verbatim. In practice it returned one
draft instead of three, dropped milliseconds from retrieved_at, cited score
identifiers as sources, and fabricated placeholder sources in neutral mode.
Each of those tripped the strict artifact parse or a verifier and the job
went terminal after two attempts.

The wire schema now carries only what the model judges: summary,
confidence, cited signals, company profile, recommended angle, and drafts,
with no grammar-unenforceable bounds. The code derives sources from the
bounded evidence for cited ids, copies score metadata from the input, drops
signals that cite anything outside the evidence, nulls drafts that point at
a dropped source or an unknown angle, pads or truncates drafts to the three
slots, and strips all company claims in neutral mode. The prompt states the
slot count, the allowed angle ids, and which ids are citable.

Verified live against the API: five of five runs succeed across company and
neutral inputs, where zero succeeded before.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@blove blove changed the title fix(mailbox-poller): drop numeric separators so the Apps Script editor can parse Code.gs fix(lifecycle): own enrichment provenance in code; fix(mailbox-poller): drop numeric separators Sep 3, 2026
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Claude finished @blove's task in 0s —— View job


I'll analyze this and get back to you.

… close evidence sequences

Three findings from vetting enrichment against live sites:

- One oversized, missing, or slow company page aborted evidence for the
  whole company, and the enrich job then failed after retries. The fetcher
  now skips such a page and keeps the rest; only the caller's abort and
  SSRF violations (now CompanyFetchSecurityError) propagate.
- Nothing stopped the model from selecting the same angle in two slots,
  which would send the same email twice. The normalizer keeps the first
  use of an angle and nulls repeats so those slots fall back to default
  copy; the prompt asks for distinct angles.
- The default day-8 copy says it is the last automated follow-up but the
  evidence variants did not. renderEvidenceCampaignTemplate takes a
  finalStep option and the dispatcher sets it for step 3.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Claude finished @blove's task in 0s —— View job


I'll analyze this and get back to you.

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Claude finished @blove's task in 0s —— View job


I'll analyze this and get back to you.

@blove
blove merged commit 8e06bc5 into main Sep 3, 2026
31 checks passed
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