Files
Arvin Xu 2a3f0bcff6 🗃️ chore(database): record where a distilled standard came from, and what it rests on (#19627)
* 🗃️ chore(database): record where a distilled standard came from, and what it rests on

Four columns for turning a reviewer's rejections into delivery standards. Nothing
reads them yet; the capture pipeline and the backtest are stacked on top.

**`expertise_hits.source_check_result_id`** — the reverse lookup "which rejections
taught this lesson". A hit could only reach an acceptance through `evidence_id`,
and 260 of this owner's 876 rejections circled no evidence at all, so that path
loses a third of the provenance. `on delete set null`: the link is provenance, not
ownership, so deleting an acceptance must not delete the rule it taught — pinned
by a test that deletes the check result and asserts the hit survives.

**`expertise_lessons.reason_kind`** — whether the standard rests on a mechanism or
on the owner's taste. Both are legitimate; only one can be enforced automatically,
because a taste standard has no test a delivery could be measured against. This
has to be a column rather than a note in the lesson body: the compile step reads
it to refuse compiling taste into a criterion that blocks work on its own, and the
body's wording follows the reviewer's own language, so matching on a phrase would
silently miss for anyone not writing in Chinese.

**`expertise_lessons.reason_source`** — whether the reviewer gave the reason or the
distillation supplied it. An inferred reason is worth keeping, but it must never
carry the weight of something the reviewer actually said.

Both are decided when a lesson is born. A later rejection that supplies a real
mechanism should arguably upgrade a `taste` lesson; the upgrade rule is not worked
out, so that does not happen yet.

**`expertise_lessons.backtest`** — how a standard scored against the reviewer's own
past decisions before anything compiles it. The metric is precision on the units it
fired on, deliberately not recall: every standard covers a narrow slice, so recall
is near zero for all of them and separates nothing, while firing on approved
deliveries is the failure that makes someone switch the feature off. Read against
the base rate, not 1.0 — 876 of 1,956 judged units are rejections, so random firing
already scores ~0.45. jsonb because the metric set is still moving.

**`EXPERTISE_SUBJECT_TYPES` gains `standalone`** so a practice run can mirror the
subject of the acceptance it came from (36 of 193 carry no in-product subject).
`text({ enum })` emits no constraint, so it costs no migration.

No indexes: the read paths are lesson → hits (already indexed) and the lesson row
itself, and `expertise_hits` is the one table here with real scale risk.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* 📝 docs(database): write the expertise schema comments in English

Comment-only change; the schema itself is untouched (verified by comparing the
comment-stripped AST before and after).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* 🗃️ chore(database): keep which delivery each generalized boundary rests on

A consolidation pass rewrites a standard from several rejections and may write
exemptions into its `limits`. The only thing that makes such an exemption
legitimate is a delivery the reviewer accepted while the standard's subject was
plainly in view — and the rewrite text cannot carry that: the model cites
deliveries by per-request labels ("S2") that mean nothing once the request is
gone. Without a stored link, "why is this allowed" has no answer a week later.

`expertise_lesson_revisions.evidence` (jsonb, nullable) records the rejected
deliveries the pass read, the accepted ones it was offered, and for each
boundary the accepted check result ids it was read from. null on a person's
rewrite, whose authority is `feedback`. jsonb rather than a link table: a pass
reads a handful of deliveries and is audited one revision at a time; the ids are
provenance, so a deleted check simply stops resolving.

Folded into the branch's unshipped 0165 migration by regenerating it, per the
migration guide, so the PR still carries a single migration.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 02:02:45 +08:00
..
2026-08-10 00:19:00 +08:00