Skip to content

Bound and checkpoint analysis payload retention - #305

Open
abhi1693 wants to merge 11 commits into
masterfrom
fix/298-bounded-job-retention
Open

abhi1693 wants to merge 11 commits into
masterfrom
fix/298-bounded-job-retention

Conversation

@abhi1693

@abhi1693 abhi1693 commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner

What changes and why?

Retention searched old analysis history on every scheduler tick, spending about three seconds to select five payloads in issue #298.

Persist one sweep checkpoint per history. Each due page scans at most 1,000 identities and redacts at most 100 payloads, then waits 30 seconds; a completed sweep waits one hour. Ordinary ticks check only the two checkpoint rows. Redaction and progress commit together, so crashes and competing schedulers cannot lose the cursor.

Preserve the last retained successful result when newer attempts fail or remain active, alongside lease, age, provenance, review, verification and relationship protections. Lock jobs before rechecking eligibility in a fresh statement to close a verification-admission race. Partial successor indexes and explicit tuple bounds keep deep-page selection bounded. Parent locks permit ingestion foreign-key inserts.

Related issues

Closes #298.

Validation

  • Merge validation on 9698777d: 465 Python regressions, 62 security/reporting tests and 23 reader-fixture/dispatch tests passed. This includes retention concurrency and page bounds, the real PostgreSQL 17.11 benchmark smoke, migration upgrade/downgrade and invalid-index retry, metadata comparison, and CI/Sonar contracts. Full Python checks, actionlint, formatting and commit hooks passed. Master 20b8fdf9 is included; retention is now migration 0037 after 0036, preserving master’s existing 0035/0036 migrations.
  • 50 focused retention cases passed against disposable PostgreSQL 17.11 and Redis, including concurrent verification/completion, protected/locked rows, interrupted pages, backlog convergence, migration retry and final-page cursor boundaries. The retention module has 100% statement and branch coverage. A real transaction timeout rolls back payload/checkpoint changes without a success log.
  • 19 benchmark unit cases and both real smoke/version-guard pairs passed on PostgreSQL 17.11 and 18.6. Reports use fixed numeric filenames under reports/retention, with descriptor-held directories/files, link rejection and stale-report invalidation before database changes.
  • 21 combined JavaScript/security tests passed; reporter coverage is 100% for statements, branches, functions and lines. The matching CodeQL 2.27.3 security-extended scan ran 105 queries with zero findings. The workflow generates and masks a random disposable database password, publishes only to localhost and waits for TCP readiness; startup/authentication/cleanup passed a real PostgreSQL 17.11 smoke.
  • Previous native ARM64 benchmark passed on aa0c153 at 100,000 articles/344,000 jobs and 250,000 articles/854,000 jobs (about 2.7× the observed production history of 315,450 jobs). Both datasets passed bounds, convergence, sustained-writer and deep-page assertions. At 250k, idle median fell 1,330.959 → 2.265 ms (+99.83%); latest-only first/deep queries examined at most 1,000 job rows, with zero temporary blocks. The 75-second writer comparison also recorded regressions: p95 5.312 → 5.567 ms, p99 18.402 → 21.747 ms and worst transaction 83.096 → 128.465 ms. These results do not establish an ingestion-latency improvement.
  • The existing results comment is reused for the new native benchmark. It displays the current run status and keeps previous results explicitly labeled until fresh measurements arrive. Completed reports use six rendered Before / After / Improvement (+/-) tables, including regressions and workload limits. Denied PATCH requests fail without creating a duplicate.
  • All six browser variants passed on the pre-merge commit aa0c1536: reader web, built Chrome and Edge extensions, plus their partner variants. Native-touch fixtures use keyboard setup and viewport capture to avoid injected mouse input and full-page touch reapplication. Coarse-pointer, 44 px target and native-tap assertions remain; no retry or assertion suppression was added.
  • Latest full CI is rerunning on 9698777 after merging master. The preceding full CI passed on aa0c153, including CI required, all 12 ARM64 image builds, six integration shards, all six browser variants, CodeQL and Sonar. Fresh hosted checks and native volume benchmarks remain pending on the merged head.
  • Ruff, formatting, mypy (367 source files), actionlint, pre-commit and whitespace checks passed.

The full-cardinality fixtures use 4 KiB inputs; the separately paced backlog uses 64 KiB input/catalog payloads and 16 KiB article step outputs. WAL includes ingestion; application CPU includes writer/observer threads, not database-server CPU. These controlled pooled-connection measurements do not establish production latency. Benchmark controls and reproduction.

Rollout notes

Stop older schedulers, apply migration 0037, then start new runtimes. The migration seeds two checkpoint rows and creates three concurrent partial indexes; it does not redact payloads. Retention caps statements at two seconds, lock waits at 100 milliseconds and PostgreSQL 17+ transactions at five seconds.

Migration retries repair invalid new indexes while preserving committed checkpoints. Rollback requires stopping new runtimes and downgrading to 0036 before starting older binaries. Pruned input/catalog/step-output bodies cannot be restored; identities, results, hashes and accounting remain.

Defaults allow at most 288,000 prunes/history/day before protected scans, cooldown and scheduler delay. Fresh production successes were 5,499 article/4,277 topic jobs over the trailing 24 hours. Monitor actual progress rather than treating the ceiling as achieved throughput.

Production has only been read for bounded sizing evidence. After deployment, compare matched workload windows for latency, ingestion freshness, WAL and interrupted-sweep recovery. Operator and rollback details.

Ready for review

  • The description explains the change and validation results, including gaps.
  • Relevant documentation and regression tests are updated.

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Backend unit coverage

PASS · minimum combined coverage 98.00%.

Tests: 10828 passed, 0 failed, 0 skipped. Source files: 367.

Workspace Lines Branches Combined
All backend code 98.67% 95.66% 98.00%
apps/admin-api 96.66% 89.65% 95.33%
apps/aggregator 97.99% 94.45% 97.18%
apps/api 99.50% 98.89% 99.39%
apps/article-enrichment-worker 80.00% 50.00% 71.43%
apps/cli 99.43% 90.76% 98.13%
apps/images-worker 80.00% 50.00% 71.43%
apps/mcp 99.86% 98.70% 99.65%
apps/notifications 100.00% 100.00% 100.00%
apps/partner-api 99.47% 95.51% 98.83%
apps/search-indexer 85.48% 85.71% 85.53%
apps/source-discovery-worker 80.00% 50.00% 71.43%
apps/user-api 99.88% 98.96% 99.72%
packages/core 99.10% 96.85% 98.54%
packages/http 99.47% 97.49% 99.03%

Unit coverage includes every backend workspace. PostgreSQL/Redis integration tests run separately.

Commit: 9698777 · HTML, JSON, XML reports and job logs · attempt 1

abhi1693 commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner Author

Analysis retention benchmark · ✅ Complete

Run and raw reports · attempt 1 · commit 9698777d90c4

Benchmark job: success.

Positive improvement = lower latency/cost; negative = regression. Native ARM64 / PostgreSQL 17. Decimal MB; benchmark observations are not production latency guarantees.

250,000 articles / 854,000 analysis jobs

Idle and protected history

Metric Before After Improvement (+/-)
Idle retention median 1246.276 ms 2.090 ms +99.83%
Idle retention p95 1312.395 ms 2.326 ms +99.82%
Latest-only due-page p95 1255.332 ms 104.361 ms +91.69%
Latest-only maximum examined job rows/query 237,499 1,000 +99.58%
Latest-only maximum shared buffers/query 954,563 4,033 +99.58%

At the 80% latest-only cursor: at most 1,000 examined job rows/query, 5,667 shared buffers/query, 0 temporary blocks.

Deployed cadence — five real 15-second scheduler ticks / 75 seconds

Metric Before After Improvement (+/-)
Ingestion p95 4.855 ms 4.902 ms -0.98%
Ingestion p99 14.644 ms 6.613 ms +54.85%
Worst ingestion transaction 53.595 ms 39.528 ms +26.25%
Application CPU 3.105 s 3.089 s +0.53%
Total WAL 202.608 MB 140.053 MB +30.87%

Ingestion transactions: 1,497 → 1,497. Payloads pruned: 1,000 → 600. Lower phase WAL includes the changed maintenance frequency; these are not equal-prune costs.

Compressed stress — 50 consecutive pages

Metric Before After Improvement (+/-)
Retention p95 112.807 ms 155.385 ms -37.74%
Ingestion p95 14.545 ms 14.714 ms -1.16%
Application CPU 1.369 s 3.379 s -146.80%
Total WAL 217.685 MB 225.306 MB -3.50%

Payloads pruned: 10,000 → 10,000. This deliberately compresses scheduler spacing; use the deployed-cadence table for the sustained writer comparison.

Fixture: 4.000 KiB full-history inputs; 64.000 KiB cadence input/catalog payloads on 1,000 subjects per history. The entire history does not use the larger payload.

100k results

100,000 articles / 344,000 analysis jobs

Idle and protected history

Metric Before After Improvement (+/-)
Idle retention median 436.847 ms 2.116 ms +99.52%
Idle retention p95 444.790 ms 2.526 ms +99.43%
Latest-only due-page p95 450.007 ms 44.048 ms +90.21%
Latest-only maximum examined job rows/query 94,999 1,000 +98.95%
Latest-only maximum shared buffers/query 381,391 4,028 +98.94%

At the 80% latest-only cursor: at most 1,000 examined job rows/query, 5,107 shared buffers/query, 0 temporary blocks.

Deployed cadence — five real 15-second scheduler ticks / 75 seconds

Metric Before After Improvement (+/-)
Ingestion p95 4.869 ms 4.991 ms -2.50%
Ingestion p99 13.208 ms 6.762 ms +48.80%
Worst ingestion transaction 43.189 ms 35.984 ms +16.68%
Application CPU 3.110 s 3.286 s -5.64%
Total WAL 187.463 MB 127.819 MB +31.82%

Ingestion transactions: 1,497 → 1,497. Payloads pruned: 1,000 → 600. Lower phase WAL includes the changed maintenance frequency; these are not equal-prune costs.

Compressed stress — 50 consecutive pages

Metric Before After Improvement (+/-)
Retention p95 105.750 ms 158.403 ms -49.79%
Ingestion p95 13.108 ms 15.607 ms -19.07%
Application CPU 1.443 s 3.535 s -144.97%
Total WAL 178.076 MB 185.402 MB -4.11%

Payloads pruned: 10,000 → 10,000. This deliberately compresses scheduler spacing; use the deployed-cadence table for the sustained writer comparison.

Fixture: 4.000 KiB full-history inputs; 64.000 KiB cadence input/catalog payloads on 1,000 subjects per history. The entire history does not use the larger payload.

CPU is Python application process time including ingestion and the wait sampler, not database-server CPU. WAL includes ingestion. Each phase starts after an explicit checkpoint; automatic checkpoints remain enabled.

@abhi1693
abhi1693 marked this pull request as ready for review October 24, 2026 11:27
@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

PR performance results

Current PR head: 9698777d90c4107667327cd17277c89953af8282

Token usage benchmark

Pending: no results have been published.

Reader API performance

Source head: 9698777d90c4107667327cd17277c89953af8282 · run 40139329865 · attempt 1

PR reader API performance

Result: INCONCLUSIVE

5 inconclusive · 3 within threshold. Zero request failures across all six runs.

Base 20b8fdf9f3b12dc368588727506d634481d4856d → PR 9698777d90c4107667327cd17277c89953af8282

Three independent GitHub-hosted ARM64 runners, each measuring base and PR sequentially with alternating order and isolated resources for every sample. 16 users, completed bootstrap and 15 seconds of warmup before each full 60-second measurement, fixed journey seed 294, 1,000 synthetic articles, cache off, five PgBouncer slots.

Latency comparison

All latency values are in milliseconds; lower is better. Values are medians of three runs, with one-millisecond histogram bins.

Route Base p95 PR p95 Change Result
All requests 100 117 +17 (+17.0%) Within threshold
Latest feed 126 144 +18 (+14.3%) Within threshold
Feed pagination 99 101 +2 (+2.0%) Inconclusive
Article detail 72 85 +13 (+18.1%) Inconclusive
Source feed 90 103 +13 (+14.4%) Inconclusive
Topic feed 107 117 +10 (+9.3%) Within threshold
Feed filters 72 98 +26 (+36.1%) Inconclusive
Sources 49 45 -4 (-8.2%) Within threshold
Topics 50 52 +2 (+4.0%) Inconclusive
Additional latency and throughput metrics

Each cell shows base → PR. Latencies are in milliseconds.

Endpoint p50 p99 Requests/s
Aggregated 34 → 36 151 → 163 28.77 → 28.63
/v1/feed [latest] 46 → 51 166 → 191 8.65 → 8.61
/v1/feed [page] 31 → 32 151 → 132 4.08 → 4.09
/v1/articles/[id] 21 → 21 128 → 127 5.83 → 5.79
/v1/feed [source] 32 → 32 135 → 115 2.02 → 2.00
/v1/feed [topic] 32 → 32 157 → 173 1.60 → 1.60
/v1/feed/options 24 → 26 107 → 133 2.20 → 2.19
/v1/sources 14 → 15 80 → 71 2.20 → 2.19
/v1/topics 16 → 18 100 → 71 2.20 → 2.19
All paired p95 samples and changes

Each pair shares a validated runner. Cells show base → PR p95 (absolute and percentage change), in milliseconds. Slower/faster counts use the same strict 20% and 20 ms thresholds against that pair's own baseline.

Route Pair 1 Pair 2 Pair 3 Slower pairs Faster pairs
All requests 108 → 120 (+12, +11.1%) 100 → 117 (+17, +17.0%) 92 → 83 (-9, -9.8%) 0 0
Latest feed 130 → 144 (+14, +10.8%) 122 → 150 (+28, +23.0%) 126 → 107 (-19, -15.1%) 1 0
Feed pagination 98 → 121 (+23, +23.5%) 115 → 101 (-14, -12.2%) 99 → 85 (-14, -14.1%) 1 0
Article detail 81 → 85 (+4, +4.9%) 66 → 108 (+42, +63.6%) 72 → 50 (-22, -30.6%) 1 1
Source feed 108 → 114 (+6, +5.6%) 90 → 103 (+13, +14.4%) 79 → 66 (-13, -16.5%) 0 0
Topic feed 107 → 137 (+30, +28.0%) 113 → 117 (+4, +3.5%) 80 → 99 (+19, +23.8%) 1 0
Feed filters 95 → 104 (+9, +9.5%) 65 → 98 (+33, +50.8%) 72 → 56 (-16, -22.2%) 1 0
Sources 49 → 45 (-4, -8.2%) 50 → 54 (+4, +8.0%) 34 → 36 (+2, +5.9%) 0 0
Topics 50 → 67 (+17, +34.0%) 59 → 52 (-7, -11.9%) 43 → 33 (-10, -23.3%) 0 0
Individual runs
Run Requests Failures Exit code
Base 1 1725 0 0
Base 2 1727 0 0
Base 3 1731 0 0
PR 1 1716 0 0
PR 2 1712 0 0
PR 3 1745 0 0
How to interpret this report

Regressed / Improved: a p95 regression needs >20% and >20 ms increase in the medians and in at least two same-runner base/PR pairs. Improvements use the inverse threshold. Within threshold means the change did not meet both thresholds.

Inconclusive: a within-revision p95 range >35% of its median and >20 ms is too noisy for a confident latency verdict. A material median change without two confirming pairs is also inconclusive; this does not prove unchanged performance.

Inconclusive latency comparisons are non-blocking: the check passes without claiming an improvement. Confirmed regressions and test/report errors fail the PR gate. Throughput is descriptive: paced users do not measure maximum capacity. This uncached public API test does not establish production health, browser performance or worker capacity. Base and PR share a runner within each pair; three pairs use independent runners. Alternating order reduces host-assignment bias but cannot eliminate changes in host load over time.

Full HTML/CSV reports and logs · attempt 1

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Lighthouse · ⚠️ Targets exceeded

⚠️ 10 target warnings · Bold values need attention.

Page FCP LCP CLS TBT JS Total
Latest (/latest) 1.21 s 3.25 s 0.001 108 ms 361 KiB 663 KiB
Article preview (/articles/…) 1.37 s 4.10 s 0.005 273 ms 364 KiB 685 KiB
Topics (/topics) 1.21 s 2.96 s 0.000 102 ms 319 KiB 471 KiB
Sources (/sources) 1.22 s 3.04 s 0.000 282 ms 332 KiB 488 KiB
Public profile (/users/…) 1.22 s 2.83 s 0.009 89 ms 280 KiB 428 KiB
Leaderboard (/leaderboard) 1.07 s 1.99 s 0.000 74 ms 276 KiB 383 KiB

Mobile reader · Three cold loads per page · Median timings · Largest transfer size.

Needs attention

Page Finding Measured Target / limit
Latest (/latest) ⚠️ Target · JS transfer 361 KiB 330 KiB
Latest (/latest) ⚠️ Target · LCP 3.25 s 2.50 s
Article preview (/articles/…) ⚠️ Target · JS transfer 364 KiB 330 KiB
Article preview (/articles/…) ⚠️ Target · LCP 4.10 s 2.50 s
Article preview (/articles/…) ⚠️ Target · TBT 273 ms 200 ms
Topics (/topics) ⚠️ Target · LCP 2.96 s 2.50 s
Sources (/sources) ⚠️ Target · JS transfer 332 KiB 330 KiB
Sources (/sources) ⚠️ Target · LCP 3.04 s 2.50 s
Sources (/sources) ⚠️ Target · TBT 282 ms 200 ms
Public profile (/users/…) ⚠️ Target · LCP 2.83 s 2.50 s

Full reports and logs · 9698777 · Attempt 1

Comment thread scripts/ci/job-retention-report.mjs Fixed
Comment thread .github/workflows/job-retention-performance.yml Fixed
Comment thread scripts/ci/job-retention-report.mjs Fixed
Comment thread scripts/ci/job-retention-report.mjs Fixed
Comment thread scripts/ci/job-retention-report.mjs Fixed
Comment thread scripts/job_retention_benchmark.py Fixed
Comment thread scripts/job_retention_benchmark.py Fixed
Comment thread scripts/job_retention_benchmark.py Fixed
Comment thread scripts/job_retention_benchmark.py Fixed
Comment thread scripts/job_retention_benchmark.py Fixed
Confine generated reports to fixed paths held through validated file descriptors, generate disposable database credentials at runtime, and use reproducible SHAKE fixtures. Guard empty history pages explicitly and cover cursor, output isolation, and report freshness boundaries.
Set reader preferences through keyboard input and capture the emulated viewport. This avoids injecting mouse input or triggering Playwright full-page touch reapplication while retaining coarse-pointer, target-size, and native-tap assertions.
@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

Feed-options scale comparison

COMPLETE · measurement job: success.

Baseline: 20b8fdf9f3b1 · Candidate: 9698777d90c4

Full SQL plans, timing samples and job logs · attempt 1

Feed options benchmark: COMPLETE

50/50 scenarios returned identical public JSON; 250 timed before/after pairs.
Native architecture: aarch64; PostgreSQL 17.11 (Debian 17.11-1.pgdg13+2). Before 20b8fdf9 → after 9698777d.

Improvement = (before − after) / before × 100. + means less time/work; − means more.

Default English: full options call

Workload Before After Improvement
2,000 / English, idle 30.16 ms 29.90 ms +0.9%
100,000 / English, idle 32.67 ms 33.10 ms -1.3%
1,000,000 / English, idle 56.24 ms 55.58 ms +1.2%
1,000,000 / English, ingestion 55.78 ms 55.70 ms +0.2%

Source work at 1,000,000 articles, default English

Metric Before After Improvement
Source SQL replay 30.20 ms 31.61 ms -4.7%
Origin lookups 500 500 +0.0%
Article lookups 661 661 +0.0%
Buffer hits 9,162 9,162 +0.0%
Temporary blocks written 0 0 0.0%
Request CPU 22.76 ms 22.79 ms -0.1%

Concurrent ingestion at 1,000,000 articles: 20,460 additional articles committed; 0 errors.

All 50 route scenarios: before, after and signed improvement
Workload Before After Improvement
2,000 / English, idle 30.16 ms 29.90 ms +0.9%
2,000 / All languages, idle 29.11 ms 29.81 ms -2.4%
2,000 / Rare language, idle 14.24 ms 14.16 ms +0.6%
2,000 / Absent language, idle 13.11 ms 13.78 ms -5.1%
2,000 / Minority content type, idle 17.31 ms 18.30 ms -5.7%
2,000 / Topic + tag, idle 4.79 ms 4.66 ms +2.6%
2,000 / Search, idle 4.13 ms 4.07 ms +1.4%
2,000 / English, ingestion 28.47 ms 28.60 ms -0.5%
2,000 / All languages, ingestion 29.60 ms 31.19 ms -5.4%
2,000 / Rare language, ingestion 15.20 ms 15.33 ms -0.9%
2,000 / Absent language, ingestion 14.71 ms 14.83 ms -0.8%
2,000 / Minority content type, ingestion 20.33 ms 17.56 ms +13.6%
2,000 / Topic + tag, ingestion 6.32 ms 6.26 ms +1.0%
2,000 / Search, ingestion 5.06 ms 5.54 ms -9.5%
100,000 / English, idle 32.67 ms 33.10 ms -1.3%
100,000 / All languages, idle 31.50 ms 32.04 ms -1.7%
100,000 / Rare language, idle 232.65 ms 234.76 ms -0.9%
100,000 / Absent language, idle 400.83 ms 401.13 ms -0.1%
100,000 / Minority content type, idle 46.89 ms 46.83 ms +0.1%
100,000 / Topic + tag, idle 66.04 ms 65.29 ms +1.1%
100,000 / Search, idle 19.87 ms 19.85 ms +0.1%
100,000 / English, generic plan, idle 35.30 ms 35.01 ms +0.8%
100,000 / Rare language, generic plan, idle 234.01 ms 239.67 ms -2.4%
100,000 / English, ingestion 32.17 ms 32.85 ms -2.1%
100,000 / All languages, ingestion 31.78 ms 32.74 ms -3.0%
100,000 / Rare language, ingestion 236.26 ms 235.19 ms +0.5%
100,000 / Absent language, ingestion 379.50 ms 395.96 ms -4.3%
100,000 / Minority content type, ingestion 65.97 ms 64.43 ms +2.3%
100,000 / Topic + tag, ingestion 126.27 ms 40.81 ms +67.7%
100,000 / Search, ingestion 20.20 ms 20.36 ms -0.8%
100,000 / English, generic plan, ingestion 37.23 ms 35.02 ms +5.9%
100,000 / Rare language, generic plan, ingestion 245.15 ms 261.01 ms -6.5%
1,000,000 / English, idle 56.24 ms 55.58 ms +1.2%
1,000,000 / All languages, idle 54.69 ms 54.94 ms -0.5%
1,000,000 / Rare language, idle 355.00 ms 361.68 ms -1.9%
1,000,000 / Absent language, idle 5,875.68 ms 5,982.77 ms -1.8%
1,000,000 / Minority content type, idle 158.94 ms 159.21 ms -0.2%
1,000,000 / Topic + tag, idle 855.20 ms 864.65 ms -1.1%
1,000,000 / Search, idle 74.24 ms 75.74 ms -2.0%
1,000,000 / English, generic plan, idle 156.18 ms 155.91 ms +0.2%
1,000,000 / Rare language, generic plan, idle 474.35 ms 475.05 ms -0.1%
1,000,000 / English, ingestion 55.78 ms 55.70 ms +0.2%
1,000,000 / All languages, ingestion 56.40 ms 56.64 ms -0.4%
1,000,000 / Rare language, ingestion 398.19 ms 378.73 ms +4.9%
1,000,000 / Absent language, ingestion 6,123.26 ms 6,219.63 ms -1.6%
1,000,000 / Minority content type, ingestion 160.57 ms 159.52 ms +0.7%
1,000,000 / Topic + tag, ingestion 527.25 ms 516.67 ms +2.0%
1,000,000 / Search, ingestion 78.64 ms 78.62 ms +0.0%
1,000,000 / English, generic plan, ingestion 165.72 ms 165.87 ms -0.1%
1,000,000 / Rare language, generic plan, ingestion 489.86 ms 491.65 ms -0.4%

Warmed query medians include SQL, ORM hydration, validation and JSON serialization. Each pair shares a read-only snapshot; order alternates. Source SQL metrics come from later EXPLAIN replay with supplied binds, separately from route timings and the exact prepared plans. This is synthetic evidence, not production HTTP p95.

Unchanged content-type probes can still dominate absent-language requests; no speedup is claimed for every filter. Historical fixture loading bypasses USER triggers with FKs/indexes retained; measured ingestion runs migrated triggers. Shared ingestion measures contention, not before/after write amplification or capacity.

@github-actions

Copy link
Copy Markdown

Scheduler recheck scale results

PASS · native ARM64 · PostgreSQL 17.11 · 5 × 50 rechecks + 50 concurrent ingests per dataset.

Improvement: positive = less work or time; negative = regression. Before and after use identical historical populations.

100,000 articles

Valid controlled comparison: native ARM64, PostgreSQL 17, matched dataset and workload.

Metric Before After Delta Improvement (+/-)
Workload runtime (s) 17.765 15.157 -2.608 +14.7%
Application CPU (s) 15.128 13.294 -1.834 +12.1%
Clock-only events 0 0 0 0.0%
Cohort card hydrations 0 0 0 0.0%
SQL calls 5,635 5,636 +1 -0.0%
Shared blocks hit 483,466 491,172 +7,706 -1.6%
Shared blocks read 3,731 625 -3,106 +83.2%
Temporary blocks written 0 0 0 0.0%
WAL records 8,406 8,424 +18 -0.2%
WAL full-page images 895 880 -15 +1.7%
WAL bytes 6,813,951 6,739,690 -74,261 +1.1%

Positive improvement means reduced cost; negative means increased cost. Delta = after - before.

Base 20b8fdf9f3b12dc368588727506d634481d4856d → candidate 9698777d90c4107667327cd17277c89953af8282.
Workflow run.

150,000 articles

Valid controlled comparison: native ARM64, PostgreSQL 17, matched dataset and workload.

Metric Before After Delta Improvement (+/-)
Workload runtime (s) 20.803 19.287 -1.517 +7.3%
Application CPU (s) 18.904 17.348 -1.556 +8.2%
Clock-only events 0 0 0 0.0%
Cohort card hydrations 0 0 0 0.0%
SQL calls 5,636 5,634 -2 +0.0%
Shared blocks hit 689,670 692,291 +2,621 -0.4%
Shared blocks read 6,714 18,136 +11,422 -170.1%
Temporary blocks written 0 0 0 0.0%
WAL records 8,380 8,420 +40 -0.5%
WAL full-page images 852 853 +1 -0.1%
WAL bytes 6,410,236 6,548,929 +138,693 -2.2%

Positive improvement means reduced cost; negative means increased cost. Delta = after - before.

Base 20b8fdf9f3b12dc368588727506d634481d4856d → candidate 9698777d90c4107667327cd17277c89953af8282.
Workflow run.

Head: 9698777 · base: 20b8fdf

Measurements, query plans and job logs · attempt 1

Synthetic warmed scheduler/publisher workload; not production p95. Production reference: 92,581 articles on 2026-10-24. No deployment is performed.

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.

Bound analysis-job retention work and avoid costly maintenance on every scheduler tick

2 participants