pgroast 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +173 -2
- package/bin/pgroast.mjs +19 -0
- package/data/precedents.sql.gz +0 -0
- package/docs/corpus.md +352 -0
- package/docs/design.md +540 -0
- package/docs/eval.md +245 -0
- package/docs/haas-paranoia-notes.md +223 -0
- package/invariants/README.md +15 -0
- package/invariants/nbtree.md +14 -0
- package/package.json +51 -4
- package/prompts/brief.md +32 -0
- package/prompts/committer-paranoia.md +149 -0
- package/prompts/critic.md +56 -0
- package/prompts/enrich.md +35 -0
- package/prompts/pushback-map.md +58 -0
- package/prompts/pushback-reduce.md +72 -0
- package/prompts/reflect.md +20 -0
- package/prompts/relevance.md +20 -0
- package/prompts/roaster-already-exists.md +23 -0
- package/prompts/roaster-common.md +88 -0
- package/prompts/roaster-demand.md +28 -0
- package/prompts/roaster-maintenance-fit.md +22 -0
- package/prompts/roaster-prior-attempts.md +29 -0
- package/prompts/roaster-replication-ondisk.md +24 -0
- package/prompts/roaster-security.md +21 -0
- package/prompts/roaster-standards-compat.md +21 -0
- package/prompts/supervisor.md +31 -0
- package/prompts/synth-self.md +19 -0
- package/prompts/synth.md +140 -0
- package/prompts/tone.md +21 -0
- package/prompts/writing.md +98 -0
- package/sql/schema.sql +45 -0
- package/src/cli.ts +391 -0
- package/src/corpus/cf.ts +220 -0
- package/src/corpus/cli.ts +189 -0
- package/src/corpus/db.ts +119 -0
- package/src/corpus/fetch.ts +104 -0
- package/src/corpus/reverts.ts +133 -0
- package/src/corpus/search.ts +201 -0
- package/src/corpus/util.ts +133 -0
- package/src/corpus/wiki.ts +80 -0
- package/src/eval/cases.ts +118 -0
- package/src/eval/cli.ts +105 -0
- package/src/eval/judge.ts +136 -0
- package/src/eval/report.ts +268 -0
- package/src/eval/run.ts +153 -0
- package/src/eval/score.ts +275 -0
- package/src/roast/doctor.ts +109 -0
- package/src/roast/enrich.ts +335 -0
- package/src/roast/invariants.ts +65 -0
- package/src/roast/llm.ts +601 -0
- package/src/roast/material.ts +133 -0
- package/src/roast/page.ts +266 -0
- package/src/roast/pipeline.ts +981 -0
- package/src/roast/precedents.ts +308 -0
- package/src/roast/pushback.ts +664 -0
- package/src/roast/render.ts +386 -0
- package/src/roast/sanitize.ts +140 -0
- package/src/roast/schema.ts +714 -0
- package/src/roast/tone.ts +216 -0
- package/src/thread/fetch.ts +172 -0
- package/src/thread/load.ts +227 -0
- package/src/thread/local.ts +73 -0
- package/src/thread/parse.ts +243 -0
- package/src/thread/patchprose.ts +143 -0
- package/src/thread/types.ts +120 -0
package/docs/corpus.md
ADDED
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
# Precedent corpus (milestone 1)
|
|
2
|
+
|
|
3
|
+
The precedent corpus is a Postgres-backed index of proposals that did not
|
|
4
|
+
land, or that landed and were then reverted. The PG Roast roaster searches it
|
|
5
|
+
to find earlier attempts at an idea. Every row comes from a fetched public
|
|
6
|
+
page or from `git` output. The builder never makes up a link (see
|
|
7
|
+
[Provenance](#provenance-no-fabricated-links)).
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
bun run src/corpus/cli.ts build [--source cf|reverts|wiki|all] [--limit N] [--offline]
|
|
11
|
+
bun run src/corpus/cli.ts search "<query>" [--before YYYY-MM-DD] [--kind cf,revert,do_not_want] [-n 10] [--json] [--include-undated]
|
|
12
|
+
bun run src/corpus/cli.ts stats
|
|
13
|
+
bun run src/corpus/cli.ts selftest
|
|
14
|
+
bun test # parser unit tests (fixtures in test/fixtures/)
|
|
15
|
+
bunx tsc --noEmit # typecheck (strict)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The same commands are available as package scripts: `bun run corpus:build`,
|
|
19
|
+
`corpus:search`, `corpus:selftest` and `corpus:stats`.
|
|
20
|
+
|
|
21
|
+
## Layout
|
|
22
|
+
|
|
23
|
+
| path | what |
|
|
24
|
+
|---|---|
|
|
25
|
+
| `src/corpus/fetch.ts` | polite cached HTTP client |
|
|
26
|
+
| `src/corpus/cf.ts` | CommitFest archive, list and patch page parsers, crawl |
|
|
27
|
+
| `src/corpus/reverts.ts` | git revert extractor (reads `$PGROAST_PG_REPO`, default `../postgres` next to this repo) |
|
|
28
|
+
| `src/corpus/wiki.ts` | wiki `Not_Worth_Doing` parser |
|
|
29
|
+
| `src/corpus/util.ts` | HTML text, message-id canonicalisation, touch-point rules, record type |
|
|
30
|
+
| `src/corpus/db.ts` | DSN parsing, schema apply, idempotent upsert |
|
|
31
|
+
| `src/corpus/search.ts` | `searchPrecedents()` and the `Precedent` type (imported by the roaster) |
|
|
32
|
+
| `src/corpus/cli.ts` | CLI and selftest |
|
|
33
|
+
| `sql/schema.sql` | DDL, applied by `build` |
|
|
34
|
+
| `data/cache/<host>/…html` | raw fetched pages (git-ignored) |
|
|
35
|
+
|
|
36
|
+
Runtime: Bun 1.3.5 built-ins only (`Bun.sql`, global `fetch`, `Bun.spawn`).
|
|
37
|
+
The only packages are dev dependencies used for the typecheck
|
|
38
|
+
(`typescript`, `@types/bun`). The builder never calls an LLM.
|
|
39
|
+
|
|
40
|
+
## Database
|
|
41
|
+
|
|
42
|
+
- Postgres database `pgroast`. The connection comes from `PGROAST_DSN`;
|
|
43
|
+
default `dbname=pgroast host=/tmp`.
|
|
44
|
+
- Both libpq keyword strings and URLs are accepted, for example
|
|
45
|
+
`postgres://localhost/pgroast?host=/tmp`.
|
|
46
|
+
- Bun 1.3.5 forwards an unknown URL parameter such as `?host=` to the server
|
|
47
|
+
as a startup GUC, and the connection fails. For this reason `db.ts` parses
|
|
48
|
+
the DSN itself and turns a socket directory into Bun's `path` option
|
|
49
|
+
(`/tmp/.s.PGSQL.5432`). A non-`/` host uses TCP.
|
|
50
|
+
- `build` creates the schema if it is missing, then upserts on
|
|
51
|
+
`(kind, raw_ref)`, so rebuilds are idempotent. A full (non-`--limit`) build
|
|
52
|
+
of a source also deletes rows of that kind that the source no longer
|
|
53
|
+
produces.
|
|
54
|
+
- `pg_trgm`: `build` runs `create extension if not exists pg_trgm` and, if
|
|
55
|
+
that works, creates a trigram GIN index on `title`. If the extension cannot
|
|
56
|
+
be created, search runs without the similarity signal. On this host
|
|
57
|
+
(2026-11-11) it cannot be created: the running server binary is 18.3, but
|
|
58
|
+
Homebrew already installed 18.6 contrib libraries, and loading fails with
|
|
59
|
+
`Symbol not found: _palloc0_mul`. A server restart onto 18.6 fixes this.
|
|
60
|
+
After that, re-run `build` (or create the extension) to enable it.
|
|
61
|
+
|
|
62
|
+
Export and ship the corpus as one file (committed as `data/precedents.sql.gz`, about 0.5 MiB):
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
pg_dump -h /tmp -d pgroast --no-owner --no-privileges -t precedent -t build_log | gzip -9 > data/precedents.sql.gz
|
|
66
|
+
createdb pgroast && gunzip -c data/precedents.sql.gz | psql -d pgroast
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
This is a plain SQL dump, not the custom format, so no role name is
|
|
70
|
+
recorded. The generated columns `tsv` and `tsv_kw` are recomputed on
|
|
71
|
+
restore. After restoring, run `build` once (with or without `--offline`) to
|
|
72
|
+
create pg_trgm if it is available. Only `precedent` and `build_log` are
|
|
73
|
+
dumped. Other tables in the `pgroast` database belong to other components
|
|
74
|
+
(for example `precedent_enrichment`), and `build` never drops or changes
|
|
75
|
+
them.
|
|
76
|
+
|
|
77
|
+
## Sources
|
|
78
|
+
|
|
79
|
+
### 1. CommitFest: `kind = 'cf'`
|
|
80
|
+
|
|
81
|
+
- `https://commitfest.postgresql.org/archive/` lists every CommitFest. On
|
|
82
|
+
2026-11-11 the IDs were 3..63 (61 CFs, 2014-12 to PG20-4). IDs 1 and 2 do
|
|
83
|
+
not exist.
|
|
84
|
+
- For each CF, the builder fetches `/<cf>/?status=6` (Rejected), `?status=7`
|
|
85
|
+
(Returned with feedback) and `?status=8` (Withdrawn). That is 183 list
|
|
86
|
+
pages, crawled in this order: Rejected for all CFs, then RwF, then
|
|
87
|
+
Withdrawn. Rows whose badge does not match the requested status are
|
|
88
|
+
dropped (none did).
|
|
89
|
+
- List pages have the title, ID, tags, authors, reviewers and latest-mail
|
|
90
|
+
time. They have no thread links, no thread start and no close date. That
|
|
91
|
+
is not enough, so every patch page `/patch/<id>/` is fetched once (deduped
|
|
92
|
+
by patch ID). From the patch page:
|
|
93
|
+
- **Final status**: the per-CF status lines are listed newest first; the
|
|
94
|
+
final one is the line with the highest CF ID. A patch whose final status
|
|
95
|
+
is not Rejected, RwF or Withdrawn (later Committed, or still open) is
|
|
96
|
+
dropped and counted in the coverage report.
|
|
97
|
+
- `Emails` gives each thread's `https://www.postgresql.org/message-id/flat/<msgid>`
|
|
98
|
+
(copied from the page), its subject, and "First at <ts> by".
|
|
99
|
+
- `History` gives `date`: the newest line
|
|
100
|
+
"Closed in commitfest X with status: <final>".
|
|
101
|
+
- It also gives authors, reviewers, committer, target version, tags, and
|
|
102
|
+
`Links` (stored in `other_links`).
|
|
103
|
+
- `first_date` = the earliest "First at" across threads. If no thread is
|
|
104
|
+
attached, it is the record's `Created` time.
|
|
105
|
+
- `summary` = title + tags + thread subjects. `objection` and `objectors`
|
|
106
|
+
stay empty at this milestone.
|
|
107
|
+
- If a patch page cannot be fetched, the row is stored from the list page
|
|
108
|
+
only (no threads, no dates; `provenance.source` says so).
|
|
109
|
+
|
|
110
|
+
### 2. Reverts: `kind = 'revert'`
|
|
111
|
+
|
|
112
|
+
- `git -C $PGROAST_PG_REPO log --grep='^Revert' -i` gives 586 commits on the
|
|
113
|
+
local master. The repo is read only.
|
|
114
|
+
- If the subject starts with "Revert", `status = 'Reverted'` (508 rows).
|
|
115
|
+
- Otherwise the commit is kept only if a commit hash within 120 characters
|
|
116
|
+
after a "revert" word resolves in the repo: `status = 'Partially reverted'`
|
|
117
|
+
(39 rows). The other 39 matches are skipped. In those, "revert…" only
|
|
118
|
+
starts a line in passing.
|
|
119
|
+
- Reverted commits:
|
|
120
|
+
- any 7..40-hex token that `git rev-parse --verify <x>^{commit}` resolves
|
|
121
|
+
(for partial reverts, only tokens near "revert");
|
|
122
|
+
- otherwise, for `Revert "<subject>"`, the latest earlier commit on
|
|
123
|
+
master with exactly that subject.
|
|
124
|
+
|
|
125
|
+
`provenance.reverted_commit_match` says which rule matched. 381 of 547 rows
|
|
126
|
+
resolved a target.
|
|
127
|
+
- `title` = the subject. Many CVS-era commits put the whole message on the
|
|
128
|
+
subject line; when the subject is over 160 characters, `title` is its
|
|
129
|
+
first sentence, and the full subject is still in `summary`.
|
|
130
|
+
- `url` = `https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=<sha>`.
|
|
131
|
+
`other_links` holds the same link for each reverted commit.
|
|
132
|
+
- `thread_urls`: all `postgr.es/m/<id>` and `postgresql.org/message-id/<id>`
|
|
133
|
+
links in the revert message and in the reverted commits' messages,
|
|
134
|
+
converted to `/message-id/flat/<id>`.
|
|
135
|
+
- `objection` = the revert message, word for word, minus the subject and the
|
|
136
|
+
trailers (Discussion:, Backpatch-through:, Reported-by: and so on).
|
|
137
|
+
- `date` = the revert commit date (UTC). `first_date` = the earliest
|
|
138
|
+
reverted commit's date, or the revert date if no target resolved.
|
|
139
|
+
- `authors` = the git authors of the reverted commits. The person who
|
|
140
|
+
reverted is `provenance.reverted_by`. `objectors` stays empty, because the
|
|
141
|
+
person who reverts is often not the person who objected.
|
|
142
|
+
|
|
143
|
+
### 3. Wiki: `kind = 'do_not_want'`
|
|
144
|
+
|
|
145
|
+
- "Features We Do Not Want" is not on `wiki/Todo`. The Todo page says
|
|
146
|
+
retired items move to `https://wiki.postgresql.org/wiki/Not_Worth_Doing`,
|
|
147
|
+
and the section is `<h2 id="Features_We_Do_Not_Want">` there.
|
|
148
|
+
- One row per item (`<dl><dt>title</dt><dd>text</dd></dl>`):
|
|
149
|
+
- the 6 items under that heading get `status = 'Not wanted'`;
|
|
150
|
+
- the other 65 retired items on the page get `status = 'Not worth doing'`.
|
|
151
|
+
- `url` = `Not_Worth_Doing#<section anchor>`. Headings that contain "/"
|
|
152
|
+
use the URL-safe legacy anchor, for example `Optimizer_.2F_Executor`.
|
|
153
|
+
- `objection` = the item's description. Message-id links go to
|
|
154
|
+
`thread_urls`. Old `archives.postgresql.org/...msgNNNNN.php` links and wiki
|
|
155
|
+
links go to `other_links`.
|
|
156
|
+
- No dates (see `--before`).
|
|
157
|
+
|
|
158
|
+
## Schema (`sql/schema.sql`)
|
|
159
|
+
|
|
160
|
+
| column | type | meaning |
|
|
161
|
+
|---|---|---|
|
|
162
|
+
| `id` | text PK | `cf:<patch id>`, `revert:<sha>`, `wiki:<anchor>:<n>` |
|
|
163
|
+
| `kind` | text | `cf`, `revert`, `do_not_want` |
|
|
164
|
+
| `raw_ref` | text | stable source key: `patch/<id>`, `<sha>`, `Not_Worth_Doing#<anchor>:<n>`; `unique (kind, raw_ref)` |
|
|
165
|
+
| `title`, `status` | text | status ∈ Rejected, Returned with feedback, Withdrawn, Reverted, Partially reverted, Not wanted, Not worth doing |
|
|
166
|
+
| `date` | date | decision: CF close (history line), revert commit (UTC) |
|
|
167
|
+
| `first_date` | date | thread start (CF), earliest reverted commit (revert) |
|
|
168
|
+
| `url` | text | CF patch page, gitweb commit, wiki anchor |
|
|
169
|
+
| `thread_urls` | text[] | `https://www.postgresql.org/message-id/flat/<msgid>` |
|
|
170
|
+
| `authors`, `reviewers`, `objectors` | text[] | `objectors` empty at this milestone |
|
|
171
|
+
| `tags` | text | CF tags; wiki section |
|
|
172
|
+
| `summary`, `objection` | text | see the sources above |
|
|
173
|
+
| `touch_points` | text[] | keyword rules (below) |
|
|
174
|
+
| `other_links` | text[] | other real URLs found in the source |
|
|
175
|
+
| `provenance` | jsonb | source, cache URL, exact timestamps (`decided_at`, `first_at`), CF history, reverted commits |
|
|
176
|
+
| `tsv` | tsvector, stored generated | `title` weight A, `summary \|\| tags` weight B, `objection` weight C (`english`); GIN index |
|
|
177
|
+
| `tsv_kw` | tsvector, stored generated | `title` in the `simple` config (keeps SQL keywords that `english` drops); GIN index |
|
|
178
|
+
|
|
179
|
+
`build_log(kind, built_at, coverage jsonb)` stores the coverage report of
|
|
180
|
+
the last build of each source.
|
|
181
|
+
|
|
182
|
+
**Touch points** come from fixed regexes over the title, tags and subjects
|
|
183
|
+
(plus the commit body for reverts and the description for wiki rows). The
|
|
184
|
+
buckets are pg_dump/restore, psql, GUC, WAL/replication, planner,
|
|
185
|
+
protocol/libpq, catalog, on-disk/pg_upgrade, security, SQL syntax,
|
|
186
|
+
ABI/extension, and hot-path performance. They are rough hints: for example,
|
|
187
|
+
"plan" and "join" trigger planner, and "slot" triggers replication.
|
|
188
|
+
|
|
189
|
+
## Search
|
|
190
|
+
|
|
191
|
+
`searchPrecedents({query, before?, kinds?, limit?, includeUndated?})` in
|
|
192
|
+
`src/corpus/search.ts` returns `Precedent[]` (snake_case fields; dates as
|
|
193
|
+
`YYYY-MM-DD`; `match` ∈ `and | or | trgm`).
|
|
194
|
+
|
|
195
|
+
1. **AND path**: `websearch_to_tsquery('english', q)`, ranked by
|
|
196
|
+
`ts_rank_cd(tsv, q, 1)`. All terms must match.
|
|
197
|
+
2. **OR fallback**, if the AND path returns fewer than `limit` rows: an
|
|
198
|
+
IDF-weighted term-coverage score. The terms are:
|
|
199
|
+
- each `english` lexeme of the query, prefix-matched and expanded with a
|
|
200
|
+
small curated synonym map (`SYNONYMS`: planner↔optim(izer);
|
|
201
|
+
pooler/pool↔pgbouncer, pgpool; posit(ion)↔order, reorder, attnum;
|
|
202
|
+
timestamp→time, date). Weak words are dropped: add, support, allow, new,
|
|
203
|
+
option, use, make, patch, feature, and `pg` (from `pg_dump`, `pg_ctl`…);
|
|
204
|
+
- SQL keywords that `english` drops as stop words (where, having, between,
|
|
205
|
+
into, only, any, all, off, over), matched against `tsv_kw`, the title in
|
|
206
|
+
the `simple` config. Without this, "pg_dump WHERE" could never find
|
|
207
|
+
"pg_dump --where option";
|
|
208
|
+
- underscore identifiers in the query (`pg_dump`, `shared_buffers`), as a
|
|
209
|
+
phrase on `tsv_kw` (`'pg' <-> 'dump'`).
|
|
210
|
+
|
|
211
|
+
Score = Σ over terms of `ln((N+1)/(df+1))` × (matches anywhere + matches
|
|
212
|
+
in the title), plus `ts_rank_cd`. Rare terms such as "pooler" count more
|
|
213
|
+
than common ones such as "table". Terms are built only from lexemes,
|
|
214
|
+
keywords and identifiers matching `[a-z0-9]+`, so user text never reaches
|
|
215
|
+
tsquery syntax.
|
|
216
|
+
|
|
217
|
+
OR rows come after all AND rows. Their scores are on a different scale
|
|
218
|
+
from AND scores; only the order matters.
|
|
219
|
+
3. **pg_trgm** (when installed): `0.5 * similarity(title, q)` is added to
|
|
220
|
+
the score. Titles with similarity > 0.3 fill any remaining slots.
|
|
221
|
+
|
|
222
|
+
The user query is always a bind parameter. Results are stored rows only, so
|
|
223
|
+
every URL printed was read from a source. If nothing matches, the CLI prints
|
|
224
|
+
"no precedent found".
|
|
225
|
+
|
|
226
|
+
### The `--before` rule (leak-free evaluation)
|
|
227
|
+
|
|
228
|
+
With `--before D`, a row is kept only if **every date it has is strictly
|
|
229
|
+
before D**:
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
coalesce(first_date, date) < D and coalesce(date, first_date) < D
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
- A CF entry whose thread started before D but was closed on or after D is
|
|
236
|
+
excluded, because the rejection had not happened yet.
|
|
237
|
+
- A commit made before D but reverted on or after D is excluded.
|
|
238
|
+
- The proposal under evaluation is itself excluded, because its first date
|
|
239
|
+
is not before its own cutoff.
|
|
240
|
+
- Rows with **no date** (all wiki rows, and any CF row built from the list
|
|
241
|
+
page only) are excluded unless `--include-undated` / `includeUndated: true`
|
|
242
|
+
is given. The wiki does not say when an item was added.
|
|
243
|
+
- Dates are calendar dates. CF times are as shown on the site, which is
|
|
244
|
+
probably UTC. Git times are converted to UTC. The exact timestamps are in
|
|
245
|
+
`provenance.decided_at` / `first_at`.
|
|
246
|
+
|
|
247
|
+
## Provenance: no fabricated links
|
|
248
|
+
|
|
249
|
+
Links are only ever built from an identifier read from a source:
|
|
250
|
+
|
|
251
|
+
- CF `url` = fixed prefix + a patch ID from an `href="/patch/<id>/"` on a
|
|
252
|
+
fetched list page;
|
|
253
|
+
- revert `url` = fixed prefix + a SHA printed by `git log`;
|
|
254
|
+
- wiki `url` = page URL + an `id="..."` anchor from the fetched HTML;
|
|
255
|
+
- `thread_urls` = `…/message-id/flat/` + a message-id copied from a link on
|
|
256
|
+
the fetched page or in the commit message. It is normalised by
|
|
257
|
+
percent-decoding and then re-quoting with one fixed safe set.
|
|
258
|
+
|
|
259
|
+
`selftest` checks the following:
|
|
260
|
+
|
|
261
|
+
1. The DB is reachable. The schema is present: table, stored generated
|
|
262
|
+
`tsv`, GIN index, `unique (kind, raw_ref)`. There are rows of all three
|
|
263
|
+
kinds and no empty tsvectors.
|
|
264
|
+
2. Search returns rows for "optimizer hints". A hostile query does not raise
|
|
265
|
+
an error. `--before 2010-01-01` returns only rows dated before the cutoff
|
|
266
|
+
and no undated rows.
|
|
267
|
+
3. In SQL, `url` matches the per-kind regex and is consistent with
|
|
268
|
+
`raw_ref`. Every thread URL matches
|
|
269
|
+
`^https://www.postgresql.org/message-id/flat/<x>@<y>$`. Every
|
|
270
|
+
`other_links` value is an http(s) URL.
|
|
271
|
+
4. Provenance, per row:
|
|
272
|
+
- CF: the patch ID appears in the cached page, and each thread
|
|
273
|
+
message-id appears as a `message-id/flat/` link on the cached patch
|
|
274
|
+
page;
|
|
275
|
+
- revert: `git show` of the commit and its reverted commits succeeds, and
|
|
276
|
+
each message-id appears in those messages;
|
|
277
|
+
- wiki: the anchor exists on the cached page, and each message-id appears
|
|
278
|
+
on it.
|
|
279
|
+
|
|
280
|
+
Negative test: on a scratch copy of the DB, a made-up thread URL, a wrong CF
|
|
281
|
+
patch URL and a non-wiki URL were injected. `selftest` reported all of them
|
|
282
|
+
and exited with status 1.
|
|
283
|
+
|
|
284
|
+
## Crawl etiquette
|
|
285
|
+
|
|
286
|
+
- User-Agent `pgroast-research/0.1`, GET only, no sign-in, no cookies.
|
|
287
|
+
- At least 1.05 s between requests to the same host.
|
|
288
|
+
- Every 200 response is cached under `data/cache/<host>/` and is never
|
|
289
|
+
fetched again. A 404 leaves a `.404` marker.
|
|
290
|
+
- On 429 or 5xx: honour `Retry-After`, otherwise exponential back-off from
|
|
291
|
+
5 s to 300 s, at most 6 tries.
|
|
292
|
+
- `--offline` builds from the cache only.
|
|
293
|
+
- The cache file names are the same as the earlier Python prototype's, so
|
|
294
|
+
pages it crawled were reused, not fetched again. The full crawl
|
|
295
|
+
(2026-11-11) made 2,118 requests in about 95 minutes, with no 429 or 5xx
|
|
296
|
+
responses and no failures.
|
|
297
|
+
|
|
298
|
+
## Known gaps
|
|
299
|
+
|
|
300
|
+
- **No pgsql-hackers crawl yet.** Only threads linked from CF entries,
|
|
301
|
+
commits and the wiki are indexed, and thread text is not fetched.
|
|
302
|
+
`objection` and `objectors` are empty for CF rows.
|
|
303
|
+
- **CF coverage starts at 2014-12** (CF ID 3). Older ideas appear only
|
|
304
|
+
through reverts or the wiki.
|
|
305
|
+
- **Final-status filter:** a patch that was returned with feedback and later
|
|
306
|
+
committed or reopened is dropped, so the earlier feedback is lost.
|
|
307
|
+
- **Stale cache for open CFs:** list pages for open or in-progress CFs (60,
|
|
308
|
+
62, 63) were cached on 2026-11-11. Delete those cache files to pick up later
|
|
309
|
+
closes.
|
|
310
|
+
- **Sparse CF tags:** old patches have none, because the CF app replaced
|
|
311
|
+
"Topic" with tags. `summary` is mostly the title + thread subjects.
|
|
312
|
+
- **Unresolved reverts:** 166 revert rows name no resolvable reverted
|
|
313
|
+
commit, mostly from before about 2014. One example is "This reverts commits
|
|
314
|
+
24c35ec and 57169ad", where neither hash is on master. These rows keep
|
|
315
|
+
only the revert's own message and links.
|
|
316
|
+
- **Wiki rows are undated**, so `--before` hides them unless
|
|
317
|
+
`--include-undated` is given.
|
|
318
|
+
- **Touch points** are keyword hints. They both over-match and
|
|
319
|
+
under-match.
|
|
320
|
+
- **pg_trgm is unavailable on this host** until the server is restarted
|
|
321
|
+
(see [Database](#database)).
|
|
322
|
+
- **Lexical search only**, with no synonyms. "connection pooler" does not
|
|
323
|
+
find "pgbouncer" unless that word is in the text.
|
|
324
|
+
|
|
325
|
+
## Build results (2026-11-11)
|
|
326
|
+
|
|
327
|
+
| kind | status | rows | with thread URL | first_date range | date range |
|
|
328
|
+
|---|---|---:|---:|---|---|
|
|
329
|
+
| cf | Rejected | 251 | 234 | 2011-10-07..2026-09-29 | 2015-01-12..2026-10-20 |
|
|
330
|
+
| cf | Returned with feedback | 1116 | 1002 | 2008-05-31..2026-08-05 | 2015-04-30..2026-11-09 |
|
|
331
|
+
| cf | Withdrawn | 562 | 538 | 2016-05-06..2026-11-08 | 2019-01-04..2026-11-10 |
|
|
332
|
+
| revert | Reverted | 508 | 255 | 1999-02-08..2026-08-25 | 1999-02-08..2026-08-25 |
|
|
333
|
+
| revert | Partially reverted | 39 | 28 | 1999-03-14..2026-03-30 | 2011-11-22..2026-05-15 |
|
|
334
|
+
| do_not_want | Not wanted | 6 | 2 | – | – |
|
|
335
|
+
| do_not_want | Not worth doing | 65 | 11 | – | – |
|
|
336
|
+
| **total** | | **2547** | **2070** | | |
|
|
337
|
+
|
|
338
|
+
CommitFest coverage:
|
|
339
|
+
|
|
340
|
+
- 61 CFs (IDs 3..63);
|
|
341
|
+
- 183 of 183 list pages;
|
|
342
|
+
- 1,933 unique patches;
|
|
343
|
+
- 1,933 of 1,933 patch pages fetched (0 failed, 0 unparsed).
|
|
344
|
+
|
|
345
|
+
1,929 patches are stored. The other 4 have a final status of "Moved to
|
|
346
|
+
different CF" in their highest CF and are dropped.
|
|
347
|
+
|
|
348
|
+
Every CF row has `date` and `first_date`. 573 of the CF rows have at least
|
|
349
|
+
one touch point.
|
|
350
|
+
|
|
351
|
+
`selftest`: 2,547 rows; 0 URL violations; 2,464 thread links checked
|
|
352
|
+
against their source.
|