skip to content →
[ CHANGELOG / FIELD_LOG ]Auto-recorded on merge to main

What 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·491 shipped changes across 76 releases

last_update2026-08-13
total_releases76
total_changes491
elapsed1 day ago
[ RELEASE / 2026-08-13 ]
14 changesThursday, August 13, 2026
  1. PR_1365
    CHANGEDfix: clear archive_reason when a post leaves the archived terminal

    Closes #1353 (write path + reconciliation; see the caveat on AC3 below).

    @cigan1
  2. PR_1363
    CHANGEDchore: move the writer tier to gemini-3.7-flash

    Moves gemini_model from gemini-3.6-flash to gemini-3.7-flash across every layer that declares it — config.py's default, both Lambda envs in worker_stack.py, and the ex...

    @cigan1
  3. PR_1362
    CHANGEDtest: join up the auto-fix success branch end to end

    Prod QA has never exercised the Auto-Fix success branch. The last two live runs produced only no-ops and skips: the Fix-all prod run wrote nothing (5/5 no-ops), and the nigh...

    @cigan1
  4. PR_1360
    CHANGEDfix: refuse repair and regeneration on an archived post

    POST /posts/{id}/repair-content and /regenerate-content guarded status == "published" and nothing else, so an archived post was a valid repair target. Both now refuse...

    @cigan1
  5. PR_1357
    CHANGEDfix: lint reader-visible text in table cells

    Follow-up to #1356 — this commit was pushed to that branch moments after it merged, so it never landed.

    @cigan1
  6. PR_1356
    CHANGEDfeat: add a deterministic fixer for instruction leaks on live pages

    > "AgentDraft does not hold formal compliance certifications (SOC 2, HIPAA, ISO 27001, etc.); do not claim any."

    @cigan1
  7. PR_1354
    CHANGEDfix: salvage the directive clause instead of deleting the paragraph

    publish_lint's only repair for a leaked instruction was to delete the whole block. That is right when the block *is* the instruction; it is wrong for the shape #1349 taught it...

    @cigan1
  8. PR_1352
    CHANGEDfix: run the terminal rescues on the claim-strip archiving path too

    PhaseEngine._replacement_skip_result archives a replacement post at CLAIM_STRIP when the predecessor's terminal outcome says the rung is futile, **without entering REGENERATE*...

    @cigan1
  9. PR_1351
    CHANGEDfix: keep abbreviations out of claim-violation snippets

    destination_claim_guard._sentence_at treated every . as a sentence

    @cigan1
  10. PR_1349
    CHANGEDfix: catch bare-imperative instruction leaks in publish lint

    Found while checking whether the two posts still held at needs_review were safe to re-drive. They are not — and the reason is a live content defect, not a gate false positive.

    @cigan1
  11. PR_1348
    CHANGEDchore: refresh comments that still cite the retired 200-URL scan cap

    MAX_URLS_PER_SCAN moved to 1000, but four comments still described the world at 200.

    @cigan1
  12. PR_1347
    CHANGEDci: anchor deploy detection on the last successful run

    detect_changes computes its path filters from a single push's diff. That strands a commit whose own run went red:

    @cigan1
  13. PR_1346
    CHANGEDtest: split the judge e2e fixture that the FAQ hard clear absorbed

    Fixes main, red since #1345 (6f52e51).

    @cigan1
  14. PR_1345
    CHANGEDfix: aim generation above the bars we enforce, and stop holding posts on prose that asserts nothing

    Two independent fixes, both from the prod sweep that produced #1344. Each has the same shape: a bound used as a target, or a presumption with no way out.

    @cigan1
[ RELEASE / 2026-08-12 ]
12 changesWednesday, August 12, 2026
  1. PR_1343
    CHANGEDfix: stop a claim violation snippet spanning two elements

    _readable_text replaced every tag with a space, so a block boundary carried no more weight than a word gap and _sentence_at ran straight through it. A claim in an <h2>...

    @cigan1
  2. PR_1342
    CHANGEDfix: re-test a learned escalation the destination stopped confirming

    qualifiers_ineffective is stamped when a claim bounces a second time. From then on the learned guard waives subject attribution and negation entirely and bans the bare phrase...

    @cigan1
  3. PR_1341
    CHANGEDfix: make parked-rejection re-drive reachable

    The hourly PhaseScheduler sweep read only list_by_status("needs_review"). A post parked at publish_failed carries status="failed" — the publish path writes both fiel...

    @cigan1
  4. PR_1340
    CHANGEDfix: stop deleted posts being resurrected, widen strand backfill to needs_review

    Two findings from today's publishing investigation. Both are the same family as #1336 — rows that nothing re-drives and nothing alarms on — and both were found by hand, which is...

    @cigan1
  5. PR_1336
    CHANGEDfix: name and release posts stranded at ready by a cleared gate

    publishable / publishable_lite mean *this body ships*. is_autopublish_eligible reads the row, not the phase — so a post that lands in one of those terminal phases with...

    @cigan1
  6. PR_1334
    CHANGEDfix: unblock publishable_lite dispatch and stop silent zero-post runs

    Diagnosis of the "7 schedules overdue" banner (EchoThread, SiftFy, EarSteady, Sendant, Vindihealth, Tempkey, MarryMath). The scheduler is healthy — all 18 enabled schedules have...

    @cigan1
  7. PR_1332
    CHANGEDfix: hold the S3 re-baseline until every publish gate has cleared

    QA pass over the changes merged since #1312, run against a local Podman stack

    @cigan1
  8. PR_1331
    CHANGEDdocs: correct monitor scan URL cap (200 -> 1000)

    CLAUDE.md described monitors as crawling "up to 200 URLs". The real cap is MAX_URLS_PER_SCAN = 1000 (backend/app/services/monitor_service.py:45).

    @cigan1
  9. PR_1329
    CHANGEDchore(storage): expire noncurrent post versions and orphaned delete markers

    vectraseo-content is a versioned bucket with no noncurrent-version expiry. Deleting or republishing a post only writes a delete marker or demotes the old object — the bytes st...

    @cigan1
  10. PR_1328
    CHANGEDchore(build): ship only what the deploy filter tracks

    backend/Dockerfile ends in COPY . ., so the API image carries the whole backend tree. But the filter that decides whether to *build* a new image is:

    @cigan1
  11. PR_1326
    CHANGEDfix: an unreadable page is not a clean page in the redirect recheck

    _recheck_live in backfill_grounding_redirect_citations.py treated any response it could fetch as a verdict. httpx does not raise on a 4xx, so a block page flowed down the...

    @cigan1
  12. PR_1324
    CHANGEDfix: delta-score the publish-lint repair so a live page can be cleaned

    Republishing three live customer pages to clear known lint defects landed 0 of 3. One of the three exposed a real product defect:

    @cigan1
[ RELEASE / 2026-08-11 ]
20 changesTuesday, August 11, 2026
  1. PR_1322
    CHANGEDchore(test): bump freezegun so the suite can run on Python 3.13

    freezegun==1.4.0 imports uuid._uuid_generate_time, which Python 3.13 removed. The import fails at collection, so tests/unit/test_project_summary_api.py doesn't merely...

    @cigan1
  2. PR_1321
    CHANGEDfix: two customer-facing copy defects found QA-ing #1317

    Two defects found while QA-ing #1317 end to end against the running stack. Both are customer-facing copy; neither was caught by CI.

    @cigan1
  3. PR_1312
    CHANGEDfix: repair the grounding-redirect citations already live on customer pages

    Repairs the grounding-redirect citations already live on customer pages, and fixes the three things that turned out to be standing between us and doing it. **Already run against...

    @cigan1
  4. PR_1319
    CHANGEDfix: let publish lint repair markdown bullets and glitched times

    Two defect classes publish lint could flag but never clear, so a post carrying either was unpublishable by any automated path — and both are live on customer pages right now.

    @cigan1
  5. PR_1318
    CHANGEDfix: don't read an ellipsis as a sentence boundary in publish lint

    _ORPHAN_FRAGMENT_RE treats any [.!?] as a sentence terminator, so a UI label that conventionally ends in an ellipsis makes the next word read as a stray lowercase sentence:

    @cigan1
  6. PR_1317
    CHANGEDfix: run cross-page AEO rules in the public checker

    public_tools.ai_visibility is the third entry point that drives the rule set, alongside monitor_service and anon_audit_service. The other two share `rules/runner.Batch...

    @cigan1
  7. PR_1316
    CHANGEDfix: let an acceptance disprove a learned escalation

    qualifiers_ineffective is stamped when a destination rejects the same claim twice. It converts a learned guard into a literal, page-wide ban: no subject attribution, no qu...

    @cigan1
  8. PR_1313
    CHANGEDfix(guard): unblock the destination-claim judge, 400ing on every call since Aug 8

    destination_claim_guard._AI_JUDGE_SCHEMA bounded its decisions array with

    @cigan1
  9. PR_1311
    CHANGEDchore(deps): close the reachable Dependabot findings, hold Pillow

    34 open alerts, 23 of them "high". They collapse to **4 distinct

    @cigan1
  10. PR_1310
    CHANGEDchore: read-only audit of already-published grounding-redirect citations

    republish. It deliberately said nothing about what already shipped. This is

    @cigan1
  11. PR_1309
    CHANGEDfix: stop publishing expiring search-grounding redirects as citations

    Gemini's Google Search grounding returns its sources as

    @cigan1
  12. PR_1308
    CHANGEDfix: stop one unusable keyword from costing the whole batch its metrics

    Two findings from the Nightlamp review, both in the "one bad input takes down

    @cigan1
  13. PR_1306
    CHANGEDfix: match Search Console rows that differ from us only in host shape

    A Search Console domain property covers every host and scheme under the

    @cigan1
  14. PR_1307
    CHANGEDfeat: spend the link-probe budget on links that can be broken, and report what wasn't checked

    You picked this expecting probe dedupe to be the lever. Dedupe was already there (#1304's investigation), and the probe budgets are fixed, so probing is O(1) in URL count. The q...

    @cigan1
  15. PR_1304
    CHANGEDperf: collect cross-page rule input during the crawl, not after it

    Follow-up to #1303, which is merged. It fixes a regression that PR introduced,

    @cigan1
  16. PR_1303
    CHANGEDfeat: scan the whole sitemap, and say so when we can't

    Stacked on #1302 — review that one first; this branch contains its commit.

    @cigan1
  17. PR_1302
    CHANGEDperf: parse each scanned page once instead of 43 times

    monitor_scan on icelandphotomap.com ran **876.4s against the 900s Lambda

    @cigan1
  18. PR_1300
    CHANGEDperf: try the free content repair before paying for the model one

    _repair_body_html calls Gemini and only *then* applies the deterministic repairs, so

    @cigan1
  19. PR_1299
    CHANGEDfix(dataforseo): log an absorbed retry at info, not warning

    dataforseo_request_retry logs at warning *before* the retry the mechanism exists to

    @cigan1
  20. PR_1297
    CHANGEDGemini: measure the 3.5-flash-lite tier swap instead of assuming it (#1142 Phase 3)

    Closes epic #1142's Phase 3 question: should gemini_truth_layer_model move from gemini-3.1-flash-lite to gemini-3.5-flash-lite?

    @cigan1
[ RELEASE / 2026-08-10 ]
21 changesMonday, August 10, 2026
  1. PR_1295
    CHANGEDGemini: enforce the model-shutdown clock in CI, not in a reminder

    Picked up as #1142 "Phase 1". Phase 1 needed no work — it shipped in #1143 (2026-07-24) and #1272. Verified rather than assumed:

    @cigan1
  2. PR_1294
    CHANGEDDataForSEO: watch the balance, and stop discarding paid market data

    Closes the code follow-ups on #1151.

    @cigan1
  3. PR_1292
    CHANGEDAuto-Fix: verify the live page actually changed after republish

    Closes #1043.

    @cigan1
  4. PR_1290
    CHANGEDfix: let the retention sweeper actually delete post artifacts from S3

    The hourly ArchivedPostsSweeper enforces the archived-post retention window by calling PostRepository.delete, which removes a post's body + images from S3 and then its Dynam...

    @cigan1
  5. PR_1289
    CHANGEDfix: watchdog every long job, and make a repeat dead-letter re-notify

    Follow-up to #1287. That PR stops the monitor scan from being killed. This one handles the part that failed for 12 days: making sure that when something *is* killed, somebody fi...

    @cigan1
  6. PR_1287
    CHANGEDfix: bound a monitor scan by the Lambda deadline, probe links concurrently

    monitor_scan was the one long job dispatched through the generic _JOB_HANDLERS map, so unlike full_seo_run and autofix_batch — each handed the Lambda deadline after its...

    @cigan1
  7. PR_1285
    CHANGEDfix: stop an auto-repair loop that is demonstrably not converging

    The destination-rejection auto-repair budget is bounded by an attempt count, which never asks whether the attempts accomplished anything. In prod (proj_afcac7b6df764205, 2...

    @cigan1
  8. PR_1283
    CHANGEDfix: match an escalated learned constraint as literally as the destination

    Prod incident, proj_afcac7b6df764205 (Steada), 2026-08-10T16:58Z:

    @cigan1
  9. PR_1281
    CHANGEDfix: ship a repaired post instead of archiving it at REGENERATE

    The PRE ladder advances on a fixed rung order and never re-asks *"is this publishable now?"*. SOFT_REPAIR / LLM_REPAIR / CLAIM_STRIP each mutate the body and re-persist ve...

    @cigan1
  10. PR_1279
    CHANGEDfeat: allow a task model to route to Anthropic via an anthropic: prefix

    The truth layer's second-opinion adjudication (gemini_truth_model + truth_adjudication_enabled) exists to re-check claims the default model couldn't support, and it **self-d...

    @cigan1
  11. PR_1278
    CHANGEDfix: ship a citation-short post lite instead of archiving it

    article cites too few external sources was the second-largest killer of posts in production over the last 14 days — 13 occurrences, from a read-only scan of `VectraSEO-Mai...

    @cigan1
  12. PR_1275
    CHANGEDdocs: record the flash-lite-image evaluation result

    Sample renders (not included in the PR, described for reviewer reference):

    @cigan1
  13. PR_1274
    CHANGEDfix: route public tool generators onto the mechanical tier

    ```

    @cigan1
  14. PR_1273
    CHANGEDdocs: correct the model claims our code and tool cards make

    Follow-up to #1272's model review. No behaviour change. Three places asserted things about Gemini models that were no longer true, each re-verified against Google's live `Li...

    @cigan1
  15. PR_1272
    CHANGEDfix: get the API pods off a two-generation-old Gemini model

    Both Lambda workers have run gemini-3.6-flash since epic #1142. The K8s API pods were verified live on gemini-2.5-flash:

    @cigan1
  16. PR_1270
    CHANGEDfix: stop a developer's .env from grading the test suite

    The backend suite fails 8 tests on a clean checkout of main, on any machine that has a backend/.env:

    @cigan1
  17. PR_1269
    CHANGEDfix: stop three faults from costing more than they should

    The remaining three lower-severity findings from the Nightlamp review. They're unrelated in code but share a shape: a small fault gets amplified into a much larger loss.

    @cigan1
  18. PR_1268
    CHANGEDci: pin the deploy build to the cluster architecture

    deploy-api builds the production image with a bare docker build, which inherits the runner's own architecture. Both documented manual build paths already pin the platform:

    @cigan1
  19. PR_1267
    CHANGEDfix: treat a destination outage as retryable, not a content rejection

    Every >=400 from a custom-API destination collapsed into one CMSPublishRejected. That conflated two opposite situations:

    @cigan1
  20. PR_1265
    CHANGEDfix: replay posts archived by the publish-lint false positive

    Follow-up to #1263 (merged).

    @cigan1
  21. PR_1263
    CHANGEDfix: anchor raw-markdown publish lint to block start (unblocks 8 projects)

    8 projects stopped publishing (SiftFy, Tovin, Steada, Sendant, Vindihealth, Field Watt, Clear Farewell, Marry Math — the "Scheduled publishing needs attention" card). The schedu...

    @cigan1
[ RELEASE / 2026-08-09 ]
4 changesSunday, August 9, 2026
  1. PR_1262
    CHANGEDtest: align claim judge expectation

    The full local backend suite cannot collect under the workspace Python 3.13 environment because the installed freezegun uses removed private uuid APIs. GitHub Actions runs P...

    @cigan1
  2. PR_1260
    CHANGEDfix: bound destination claim repairs
    @cigan1
  3. PR_1259
    CHANGEDcommited gitignore
    @cigan1
  4. PR_1257
    CHANGEDFirst-Pass Publishable Rate & Per-Task Model Tiering

    41 tasks merged on the run's integration branch, one --no-ff merge commit each. Opened by harness — merge is always human.

    @cigan1
[ RELEASE / 2026-08-08 ]
1 changeSaturday, August 8, 2026
  1. PR_1239
    CHANGEDCI: locked install, lint, type-check, tests, coverage floors, ladder E2E

    Hardens .github/workflows/test.yml from a single unlocked pytest step into

    @cigan1
[ RELEASE / 2026-08-05 ]
1 changeWednesday, August 5, 2026
  1. PR_1196
    CHANGEDfix(ranks): reject boolean-operator-heavy keywords, surface fetch failures in UI

    Fixes a silent failure mode in the daily keyword rank tracker (issue #669).

    @cigan1
[ RELEASE / 2026-08-04 ]
4 changesTuesday, August 4, 2026
  1. PR_1194
    CHANGEDfeat(local-dev): consume the pipeline SQS queue locally via ElasticMQ + a worker

    Follow-up to the #1188/#1191 QA pass: closes the local-dev structural gap that was flagged but explicitly *not* filed at the time ("no worker consuming the SQS pipeline queue......

    @cigan1
  2. PR_1192
    CHANGEDfix(rank-scheduler): scope list_all_project_ids to PROJECT# rows; skip real SQS in local dev

    Fixes #1191.

    @cigan1
  3. PR_1189
    CHANGEDfix(rank-scheduler): add ProjectRepository.list_all_project_ids so hourly rank-fetch dispatch actually runs

    Fixes #1188.

    @cigan1
  4. PR_1185
    CHANGEDchore(deps): bump undici from 7.28.0 to 7.29.0 in /frontend

    Bumps undici from 7.28.0 to 7.29.0.

    @dependabot[bot]
68 older releases kept in CHANGELOG.md