mainWhat we shipped.
One line per merged pull request, dated by merge day. Generated by the same automation that pushes the code, so the only delay between "we shipped it" and "it appears here" is a CI run.
What changed most recently in VectraSEO?
The changelog lists the latest merged pull requests by release date, with the newest shipped change first and older releases kept in the project archive.
Last updated·
- PR_1703CHANGEDci: changelog checks also post commit statuses the PR can see
After #1699 merged, its dispatched run put green
backend/frontend/infrastructurecheck runs on changelog PR #1702's head commit. Once the ruleset required those names,... - PR_1701CHANGEDbuild(deps): Bump undici from 7.29.0 to 7.30.0 in /frontend
Bumps undici from 7.29.0 to 7.30.0.
- PR_1700CHANGEDfix(writer): other companies' products need their vendor's docs, never untested steps
Iceland Photo Map (
proj_ab5ead538b5947e7) has 3 held drafts with 21, 12 and 4 blocking claims. Almost none are about its own product. They are claims about apps it doesn't com... - PR_1699CHANGEDci: report main's required checks on the changelog PR
The goal is to require
backend,frontendandinfrastructureonmain. Todaygh pr merge --automerges instantly because the "Protect Main" ruleset requires a PR but no... - PR_1697CHANGEDfix(truth): prose about the business's own API reaches its own evidence
post_37b7fa16b58641e9(Emcognito) is still held after #1695 on: - PR_1695CHANGEDfix(truth): prose about the business's own plans reaches its own evidence
After #1693, Emcognito's replacement draft
post_8ee09bd403f4404cwas still held. A fresh re-verify plus the owner claim strip ran in prod on 2026-09-28. **8 of its 9 blocking...
- PR_1693CHANGEDfix(truth): own pricing-table cells and over-budget own claims reach the business's evidence
Emcognito's held draft
post_8ee09bd403f4404cwas blocked by 27 claims. Each one is a plan fact that Emcognito's capability file states. - PR_1691CHANGEDfix(truth): own-product facts stated by the business reach the verifier
After #1689, Tovin's and FolioInbox's held drafts still blocked on own-product claims that their pricing page, Content Brief and capability file all state (e.g. "Folio has n...
- PR_1689CHANGEDfix(truth): stop holding drafts on competitor pricing; name blocking claims on retry
"Posts not generating" (2026-09-28): schedules fired and 152 drafts were created in 7 days, but the truth checker held 37 (24%) in
review_required. 34 of those involved `curre...
- PR_1687CHANGEDfix(claims): repair a destination claim rejection on a metadata field
Sendant
post_bd801e12ca4d4052is parked inpublish_failed(redrive_exhausted). The destination 422'dmatched_claim: "onion routing"onfield: meta_description("…o... - PR_1685CHANGEDfix(deepseek-canary): outline reverts on fallbacks only; publish/truth breach is reported
The outline DeepSeek canary started 2026-09-25 ~19:11 UTC (SSM
deepseek_canary_tasksnow hasoutlinenext topost_metadata). Its guardrail is publish rate + truth first-pa... - PR_1683CHANGEDfix(held-post): stale re-check spinner, spent-allowance button, no 'edit it yourself' copy; two flaky tests
No prod writes and no model calls.
- PR_1681CHANGEDfix(truth): unsupported on own-site-evidenced claims must quote a contradiction
> Built on #1679 (
fix/truth-own-business-evidence). This branch was cut from it. #1679 was merged intomainbefore this PR opened, so the base ismainand the diff con... - PR_1679CHANGEDfix(truth): own-site evidence for claims naming the business; bind citations to their sentence
Two held drafts, post_57bcd3b58653449a (tovin.io) and post_e2121d6e2be04935 (icelandphotomap.com), stayed held after their flagged sentences were edited. Each re-check flagged t...
- PR_1678CHANGEDfix(truth): treat the business's own comparison-table column as first-party
Tovin post
post_57bcd3b58653449awas held on a cell in its own column, "Tovin — Pricing Model: …". The extractor had not restated that cell. Under #1587 a cell is first-party... - PR_1676CHANGEDfix(truth): re-check an unconfirmed current capability once before it holds a post
vectraseo-prod-stranded-postswent to ALARM on 2026-09-25 for two held drafts (post_57bcd3b58653449aTovin,post_e2121d6e2be04935Iceland Photo Map). A paid manual strip a... - PR_1674CHANGEDfix(alarms): count pipeline losses from each post's current state
vectraseo-prod-pipeline-loss-ratewent into ALARM at 2026-09-25 01:33 UTC (62.5 / 72.2 / 42.9%). Of the 20 posts it counted as lost from 09-22 to 09-25, 15 were published... - PR_1672CHANGEDfix(deepseek): judge canaries over 7 pooled days on what each task affects
The per-day rollback rule (PRD §10) breached 18 of 19 pre-canary days on unchanged operator traffic (~6 truth-checked posts a day). The post_metadata canary was going to rev...
- PR_1670CHANGEDfix(citations): stop draining real sources below the source floor
Three EchoThread drafts on one topic (
post_44024259,post_dc601cb6,post_0e75f61c) sat atreview_required, the only held posts in prod, each at **1 of 3 external sources... - PR_1668CHANGEDfix(ladder): re-check exhausted rejection parks with today's free remediation
A never-published post that used up its
publish_reject_repair_attemptsstayed atpublish_failedpermanently, even after a later repair fix could clear it. `post_0e3fccfcb9f6... - PR_1666CHANGEDfix(content): flag findings credited to a site's home page (report-only)
"According to research from X" linked only to X's home page cites nobody. EchoThread
post_dc601cb63efd4c0ccredited a "chilling effect" finding tocyber.harvard.edu/and new... - PR_1664CHANGEDfix(ladder): a provider outage never advances or archives a post
Gemini returned 503 "high demand" after 5 retries, the Anthropic fallback timed out, and OpenAI returned 429
insufficient_quota. During that window the Publish-Readiness ladde... - PR_1663CHANGEDfeat(ladder): auto-replace drafts held at review_required, one grant per topic
A draft parked at
review_requiredhad no automatic exit unless a later claim-guard change happened to clear it. EchoThreadpost_44024259deae4f97shows the full failure. Its... - PR_1661CHANGEDfix(generation): re-plan sources when a draft falls below the source floor
post_44024259deae4f97(EchoThread, gapgap_41fef2cf163e4ec8) is parked atreview_requiredbecause it cites 1 of 3 required sources. - PR_1659CHANGEDfix(phase-scheduler): recovery-stranded posts mid-ladder are still advanced
_automatic_recovery_jobsput every recovery-marked post, and every post for whichsweep_actionreturned *any* action including"stranded", intorecovery_ids. `process_du... - PR_1657CHANGEDfix(truth): a table row ordinal is not a pricing tier; retire the advice-scope filter
post_44024259deae4f97(EchoThread, "Hostile Comment Threads") was held on fiveproduct_capabilityclaims such as *"Observed Behavior — Tier 1: Robust Debate: Robust debate c... - PR_1656CHANGEDfix(recovery): apply the citation-floor lite rescue in automatic recovery
EchoThread
post_8dc207b034f542bahas been parked atreview_requiredsince 2026-09-23. Its fact-check is verified (truth 100, 19/19 claims supported), and metadata, lint and... - PR_1655CHANGEDfix(truth): no space before punctuation in capability claim text
The "It is free on every plan ." claims on the EchoThread drafts did not come from inserted text. The body is correct:
<a href="…/pricing/">free on every plan</a>.(read-only... - PR_1654CHANGEDfix(sitemap): follow same-host Sitemap: lines in robots.txt
Tempkey's configured
/sitemap.xmllisted only marketing pages, and its blog sitemap was declared only inrobots.txt. As a result, the GSC index check flagged 118 published p... - PR_1651CHANGEDfix(held-post): only offer "Remove unconfirmed claims" when it can clear the hold
The held-draft button (#1646) was offered on drafts that also fail content quality. Stripping sentences only removes text, so it can never lift a draft that is already below the...
- PR_1652CHANGEDfix: stop demanding outside sources for a business's own limits
Content quality's uncited-claim check (
_sentences_with_unsourced_claims,backend/app/services/blog_quality.py; trigger_HIGH_RISK_CLAIM_REat line 55) flags any sentence c... - PR_1649CHANGEDfix(truth): stop gluing question headings onto the claims that follow them
The truth layer merged an FAQ question heading into the claim that follows it. The merged claim can't be matched to any source, so it comes back unverifiable and holds the post.
- PR_1648CHANGEDfix: stop flagging a budget-blocked scheduled run as a missed window
On 2026-09-23 UTC, Tovin, DNSCove and Tempkey were each flagged Scheduled post overdue even though each had published a post that UTC day. Their scheduled
full_seo_runjob... - PR_1646CHANGEDfix: give owners a way out of a draft held by checks
A draft held by the truth gate reached
review_requiredand then had nowhere to go. The detail page hid every action and said "No manual flag review is needed", but automatic r...
- PR_1644CHANGEDtest: stop test_sc_004 flaking on a loaded runner
test_typesafe_jev::test_sc_004failed intermittently in full-suite runs (passed alone every time). - PR_1643CHANGEDfix: ordinary CLAIM_STRIP keeps the business's own call to action
1. Before stripping, it runs
partition_protectedoverclaim_strip.strip_target_claims. That is the stripper's own verdict filter (unsupported, plusunverifiableunde... - PR_1641CHANGEDfix(truth): accept the project's own capability file as first-party evidence
Tempkey's operator post keeps getting held on claims that are true and about Tempkey itself: "public REST API covering grants, extension, revocation…", "administrative sign-in i...
- PR_1640CHANGEDfix(publish-lint): detect and salvage writer-directed phrasing rules
A capability contract's
preferred_wordingput a writer-directed sentence into Tempkey post bodies, and publish lint let it through: - PR_1639CHANGEDfix: never strip the business's own call to action during recovery
The automatic-recovery strip step from #1638 deletes every sentence that carries an unconfirmed claim. That includes the business's own promotion. In a prod re-drive it was abou...
- PR_1638CHANGEDAutomatic recovery: remove unconfirmed claims and publish the rest
Automatic recovery publishes only when every claim in a fresh truth report is
supported. Drafts held by a few claims no source could confirm (Tempkey, Marry Math) stayed held... - PR_1636CHANGEDdocs: 2026-09-22 QA evidence and TypeSafe/Jev decision report
Commits QA reports that were sitting uncommitted in the main checkout. Docs only, no code or config changes.
- PR_1635CHANGEDfeat: daily DeepSeek canary evaluator with automatic revert (REQ-canary-auto)
The DeepSeek canary now polices itself (PRD section 10, new REQ-canary-auto).
- PR_1634CHANGEDfix: convert floats before the ladder's conditional phase write
PostRepository.conditional_advance_phasebuilds its ownupdate_itemcall and never converts floats;BaseRepository.updatedoes. Any payload carrying a freshverify_post... - PR_1633CHANGEDfeat: DeepSeek phase 3 — routable writer path + decisive writer/truth eval
DeepSeek phase 3 (docs/prd/cost-optimized-content-pipeline.md, DL-003 "all ungrounded tasks"). The scheduled writer path can now be routed. Before this, routing saved almost not...
- PR_1632CHANGEDdocs: correct the draft-loss counts behind #1630
Corrects two numbers in the docs and a docstring that #1630 merged. They were found when the terminal-outcome rows were recounted by archive reason.
- PR_1630CHANGEDfix: repair capability truth holds at CLAIM_STRIP instead of regenerating
The current-capability truth gate shipped in
084ac618on 2026-09-22. Since then, a post held on an unconfirmed third-party plan or file-format claim had no repair: - PR_1628CHANGEDfix: never cap free recovery releases; paid recovery longest-held first
Production caps recovery at one dispatch per 15-minute sweep (
automatic_recovery_batch_size=1). After #1623 shipped, FolioInboxpost_1d1c98f23ad24610was a release candidate... - PR_1626CHANGEDfix: treat DeepSeek nulls on optional schema properties as absent; record 2026-09-23 eval
Follow-up to #1624.
- PR_1624CHANGEDfeat: DeepSeek phase 2 — route eval, cost KPI + admin view, off-peak deferral, canary gate
Phase 2 of
docs/prd/cost-optimized-content-pipeline.md(phase 1: #1621). Nothing changes in production at merge: no task is routed, the canary lists are empty, off-peak de... - PR_1623CHANGEDfix: un-strand automatic recovery; two bounded automatic retries; claim-keyed replacement futility
Once deployed, the recovery sweep releases the stuck post on its first run. Unresolved backlog posts become eligible for retry #1, dispatched at
automatic_recovery_batch_size... - PR_1620CHANGEDScope recovery advice checks and preserve prices during softening
Scheduled posts are parked on truth-gate holds with 1-3 residual claims. One source: the product-capability backstop read a moderation row labelled
Tier 1: Robust Debateas a... - PR_1621CHANGEDfeat: DeepSeek task routing core with Gemini fallback, customer gate and Jev first-pass
P0 core of the cost-optimized content pipeline (
docs/prd/cost-optimized-content-pipeline.md,tdd/cost-optimized-content-pipeline.tdd.yaml). - PR_1618CHANGEDdocs: spec + TDD for DeepSeek/TypeSafe cost-optimized pipeline
Clarified spec and red-phase TDD artifact for moving model spend to the cheapest provider that passes each task's quality bar.
- PR_1616CHANGEDPreserve source evidence during held-post recovery
Held-post recovery could hide the strongest evidence when reserving space for supplemental sources, and its grounded-response formatter could discard source URLs. Rank passages...
- PR_1614CHANGEDReserve recovery Jev allowance for fresh verification
Correction hints and fresh verification currently spend the same eight-request Jev allowance. Two recovery canaries exhausted it and left 14 later source-backed claim records ea...
- PR_1613CHANGEDFix repeated-claim repairs and missing evidence in held-post recovery
Held-post recovery skipped repeated current assertions, missed fresh product-contract evidence, and could introduce failed citation links. It now binds repeated prose to individ...
- PR_1612CHANGEDFinish correcting unresolved claims in legacy verified reports
A truth report can have legacy status
verifiedwhile still containing generic unverifiable claims. Recovery requires supported evidence for every claim, so checking only that... - PR_1610CHANGEDFix held-post recovery and let Jev lead bounded evidence decisions
Held posts could skip AI repair despite unresolved claims, exhaust Gemini's old allowance, or spend extra resolution calls solely because Jev abstained. This change fixes that r...
- PR_1609CHANGEDfix: keep stale scheduler checks from interrupting recovery
A production scheduler recheck read Tempkey before automatic recovery claimed it, then moved the already-running recovery back to
gate_check. Recovery correctly refused to ove... - PR_1608CHANGEDfix: restore first-party evidence and recover missing citations
Held posts could not verify their own product claims when a legacy project stored a bare domain: first-party fetching rejected it and internal links were classified as external....
- PR_1606CHANGEDCorrect held posts before rechecking and preserve negative facts
Held drafts could spend the six-call recovery allowance re-investigating saved findings, leaving no room to correct them. Recovery now corrects exact, unique flagged sentences f...
- PR_1604CHANGEDPreserve claim citations and recovery allowance for final checks
Held drafts could lose an extracted citation when the literal capability backstop replaced the claim; the first automatic recovery trial also spent its six Gemini calls before r...
- PR_1602CHANGEDRecover held posts with Gemini and Jev instead of manual review
Held posts currently leave the owner with manual flag reviews and no automatic next step. This adds one bounded Gemini/Jev investigation per post and policy: retrieve relevant s...
- PR_1600CHANGEDfix: allow guarded post feedback transactions
Saving post review feedback returned HTTP 500 because the API execution role lacked
dynamodb:ConditionCheckItem. The transaction checks both the current post snapshot and proj... - PR_1598CHANGEDfix: clarify what to review in post feedback
The post review panel asked users to judge “valid” or “mistaken” flags without explaining what was uncertain. It now asks “Does this sentence need fixing?” with visible Needs fi...
- PR_1596CHANGEDfix: separate unresolved posts from replacement history
The evaluation page offered review links for every project, including projects with no problematic posts, and mixed replaced originals with unresolved work. It now shows counted...
- PR_1594CHANGEDAdd assisted feedback for problematic posts and explain experiment progress
Held and automatically archived posts currently expose automated flags but provide no way to record whether those flags were valid. This adds an admin-only Problematic filter an...
- PR_1592CHANGEDAdd admin status and review-gated TypeSafe evaluation campaign
Admins currently have no persistent indication that the Jev evidence-selection comparison needs label review or has produced results. Add an admin-only status page, sidebar atte...
- PR_1590CHANGEDDisable default Jev routing and retain a bounded evidence pilot
Jev made no accepted decisions in the observed production cycles, so default traffic was paying for Jev and still falling back to Gemini. Make all three stages default to
off,... - PR_1588CHANGEDfix: preserve first-party ownership in capability tables
Fixes #1587.
- PR_1585CHANGEDfix: verify current product claims against fetched evidence
A production tutorial was marked truth-verified despite an obsolete free-plan allowance and a CSV import promise that extraction omitted. Current product promises now retain tab...
- PR_1582CHANGEDAdd selective Jev verification, capability checks, and evidence selection
Citation verification, product-capability checks, and evidence selection currently send every semantic decision to Gemini. This adds TypeSafe Jev as a selective first pass: conf...
- PR_1576CHANGEDFix blocked Search Console refresh feedback and expand access-warning tests
Search Console settings showed “Synced” after a refresh was skipped because property access was blocked. Only completed, non-skipped refreshes now show that success message; the...
- PR_1573CHANGEDFix hosted blog metadata, conversion tracking and sitemap hygiene
Hosted blog publishes ignored the adapter's
seo_titleandmeta_description, and those pages lacked the site's GA4 tag and a clear next step. Honor the search metadata and in... - PR_1571CHANGEDRestore acquisition visibility and align signup analytics with site design
The signup dashboard omitted anonymous audits entirely and scanned roughly 347,000 unrelated shared-table records to find 25 accounts. Existing users could appear missing behind...
- PR_1568CHANGEDAdd audit onboarding, owner signup analytics, and Search Console access alerts
Visitors who request a sign-in link after a free audit currently lose the path to monitoring, while the owner cannot distinguish requests from completed sign-ins. Search Console...
- PR_1561CHANGEDfix(pipeline): give phase_advance a per-post FIFO lane
run_phase_advancere-raises so SQS redelivers, and the comment above thatraiseaccepted the cost explicitly: - PR_1559CHANGEDops(api): raise burst limit off first-party traffic, alarm on saturation
Two changes to the API's burst posture, both from live evidence gathered while re-checking the 2026-09-19 scanner incident.
- PR_1557CHANGEDfix(pagination): admin leads cursor onto the shared codec
Follow-up to #1555. The admin inbox (
GET /api/v1/admin/leads) was the last paginated endpoint still handing out a raw DynamoDB sort key as its cursor. - PR_1555CHANGEDfix(pagination): opaque, validated cursors — the gaps 500
vectraseo-prod-api-gateway-5xxfired 2026-09-19 23:33 UTC. The