Skip to content

Commit 450db7e

Browse files
authored
fix(research): preserve source-version review checkpoints (#599)
1 parent 2d064bf commit 450db7e

4 files changed

Lines changed: 23 additions & 8 deletions

File tree

‎docs/ops/description-reviews.md‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Confirm [current model pricing](https://developers.cloudflare.com/ai/models/type
4848
The key includes the exact description, model version, rubric version, and questions.
4949
Identical descriptions reuse the same assessment. Changed descriptions require new assessments.
5050
The tool checkpoints SQL after each batch and at completion.
51+
Each checkpoint replaces the SQL file atomically. A failed write preserves the earlier complete checkpoint.
5152
Failed requests appear in `OUTPUT.sql.failures.jsonl`; the process exits with code 1.
5253
Keep these files outside the repository.
5354

@@ -59,11 +60,13 @@ Apply a completed or copied checkpoint through the existing D1 command:
5960
pnpm exec wrangler d1 execute DB --remote --config wrangler.jsonc --file OUTPUT.sql
6061
```
6162

62-
Findings live in `skill_generated`, using `description-review:<rubric-version>:<raw-sha256>` kinds.
63-
The existing JSON payload supports these fields. No schema migration is required.
63+
Findings live in `skill_generated`, using `description-review:` kinds with the rubric version and raw source hash.
64+
The existing JSON payload stores these fields.
6465
Each rubric and source version retains a separate row. Replaying SQL preserves the earlier finding.
65-
Writes require matching blob SHA, raw SHA-256, identity, and successful render status.
66-
Changed sources are skipped. Re-export them for a later run.
66+
Writes require matching identity, blob SHA, raw SHA-256, and the exact author description.
67+
Evidence can match the successful current render or a retained source snapshot in `skill_description_history`.
68+
Historical findings keep their original blob SHA. Current-source queries exclude them after a source change.
69+
Unknown source versions are skipped. Re-export changed sources to review their new descriptions.
6770

6871
The payload preserves description, source hashes, source commit, questions, probabilities, labels, model, and usage.
6972
`reviewKey` identifies the shared request for duplicate descriptions.

‎scripts/lib/description-review.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,10 @@ export function descriptionReviewStatement(source: z.infer<typeof descriptionRev
9191
answer: review,
9292
}
9393
const kind = `description-review:${DESCRIPTION_REVIEW_VERSION}:${source.rawSha256}`
94-
return `INSERT INTO skill_generated(owner,repo,name,kind,sha,payload,generated_at) SELECT owner,repo,name,${quote(kind)},current_sha,${quote(JSON.stringify(payload))},${quote(reviewedAt)} FROM skills WHERE owner=${quote(source.owner)} AND repo=${quote(source.repo)} AND name=${quote(source.name)} AND current_sha=${quote(source.sourceBlobSha)} AND rendered_raw_sha256=${quote(source.rawSha256)} AND rendered_status='ok' ON CONFLICT(owner,repo,name,kind) DO NOTHING;`
94+
const identity = `owner=${quote(source.owner)} AND repo=${quote(source.repo)} AND name=${quote(source.name)}`
95+
const current = `current_sha=${quote(source.sourceBlobSha)} AND rendered_raw_sha256=${quote(source.rawSha256)} AND rendered_status='ok' AND json_valid(rendered_frontmatter) AND json_extract(rendered_frontmatter,'$.description')=${quote(source.description)}`
96+
const historical = `EXISTS(SELECT 1 FROM skill_description_history WHERE ${identity} AND raw_sha256=${quote(source.rawSha256)} AND source_blob_sha=${quote(source.sourceBlobSha)} AND json_extract(frontmatter,'$.description')=${quote(source.description)})`
97+
return `INSERT INTO skill_generated(owner,repo,name,kind,sha,payload,generated_at) SELECT owner,repo,name,${quote(kind)},${quote(source.sourceBlobSha)},${quote(JSON.stringify(payload))},${quote(reviewedAt)} FROM skills WHERE ${identity} AND ((${current}) OR ${historical}) ON CONFLICT(owner,repo,name,kind) DO NOTHING;`
9598
}
9699
export function reviewLabel(evidence: { task: number, activation: number, scope: number, redundant: number }): 'clear' | 'needs-work' | 'uncertain' {
97100
if (evidence.task <= 0.2 || evidence.activation <= 0.2 || evidence.scope <= 0.2 || evidence.redundant >= 0.8)

‎scripts/review-skill-descriptions.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { appendFileSync, existsSync, readFileSync, writeFileSync } from 'node:fs'
1+
import { appendFileSync, existsSync, readFileSync, renameSync, writeFileSync } from 'node:fs'
22
import process from 'node:process'
33
import { setTimeout as pause } from 'node:timers/promises'
44
import { parseArgs } from 'node:util'
@@ -103,7 +103,8 @@ function writeSnapshot() {
103103
throw new Error(`Invalid review: ${key}`)
104104
return descriptionReviewStatement(row, parsed.data, record.reviewedAt)
105105
})
106-
writeFileSync(output, `${statements.join('\n')}\n`)
106+
writeFileSync(`${output}.tmp`, `${statements.join('\n')}\n`)
107+
renameSync(`${output}.tmp`, output)
107108
}
108109
const unique = [...new Set(sources.map(row => descriptionReviewKey(row.description)))].filter(key => completed.has(key)).map(key => parseDescriptionReview(completed.get(key)!.response)).filter(result => result.success)
109110
console.log(JSON.stringify({ sources: sources.length, uniqueReviews: unique.length, failed, inputTokens: unique.reduce((sum, result) => sum + result.data.usage.input_tokens, 0), inputCostUSD: unique.reduce((sum, result) => sum + result.data.usage.input_tokens * 0.042 / 1_000_000, 0), elapsedSeconds: (Date.now() - started) / 1000, sql: output }))

‎test/unit/description-review.test.ts‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ describe('description reviews', () => {
3737
if (!parsed.success)
3838
throw parsed.error
3939
try {
40-
await fixture.db.prepare(`INSERT INTO skills(owner,repo,name,display_name,slug,current_sha,rendered_raw_sha256,rendered_status) VALUES ('author','skills','review','Review','author/review',?,?,'ok')`).bind(source.sourceBlobSha, source.rawSha256).run()
40+
await fixture.db.prepare(`INSERT INTO skills(owner,repo,name,display_name,slug,current_sha,rendered_raw_sha256,rendered_status,rendered_frontmatter) VALUES ('author','skills','review','Review','author/review',?,?,'ok',?)`).bind(source.sourceBlobSha, source.rawSha256, JSON.stringify({ description: source.description })).run()
4141
const statement = descriptionReviewStatement(source, parsed.data, '2026-10-09T00:00:00Z')
4242
await fixture.db.prepare(statement).run()
4343
await fixture.db.prepare(statement).run()
@@ -46,6 +46,14 @@ describe('description reviews', () => {
4646
await fixture.db.prepare(`UPDATE skills SET rendered_raw_sha256=?`).bind('d'.repeat(64)).run()
4747
await fixture.db.prepare(descriptionReviewStatement({ ...source, rawSha256: 'd'.repeat(64) }, parsed.data, '2026-10-09T00:00:01Z')).run()
4848
expect((await fixture.db.prepare(`SELECT COUNT(*) AS count FROM skill_generated WHERE kind LIKE 'description-review:%'`).first())).toEqual({ count: 2 })
49+
await fixture.db.prepare(`DELETE FROM skill_generated WHERE json_extract(payload,'$.rawSha256')=?`).bind(source.rawSha256).run()
50+
await fixture.db.prepare(`INSERT INTO skill_description_history(owner,repo,name,raw_sha256,source_blob_sha,source_commit,frontmatter,first_observed_at,last_observed_at) VALUES ('author','skills','review',?,?,?,?,0,0)`).bind(source.rawSha256, source.sourceBlobSha, source.sourceCommit, JSON.stringify({ description: source.description })).run()
51+
await fixture.db.prepare(statement).run()
52+
expect((await fixture.db.prepare(`SELECT COUNT(*) AS count FROM skill_generated WHERE kind LIKE 'description-review:%'`).first())).toEqual({ count: 2 })
53+
await fixture.db.prepare(`DELETE FROM skill_generated`).run()
54+
await fixture.db.prepare(descriptionReviewStatement({ ...source, description: 'An altered description.' }, parsed.data, '2026-10-09T00:00:02Z')).run()
55+
await fixture.db.prepare(descriptionReviewStatement({ ...source, rawSha256: 'd'.repeat(64), description: 'An altered description.' }, parsed.data, '2026-10-09T00:00:02Z')).run()
56+
expect((await fixture.db.prepare(`SELECT COUNT(*) AS count FROM skill_generated`).first())).toEqual({ count: 0 })
4957
}
5058
finally {
5159
fixture.close()

0 commit comments

Comments
 (0)