Repository navigation
fix(core-ts): scope asset_refs by site and skip rebuilds on unchanged imports (#196) - #200
Merged
Merged
Conversation
… imports (#196) RFC-0045 rollout step 0 (§2.5), independent of the RFC's new field types. - refsRebuild joins nodes so only same-site assets get rows, chunks its INSERT below 90 KB per statement (SQL plus parameters), drops OR IGNORE (rows are deduplicated in JS), and is emitted by the import batch only when that batch writes the node set. An unchanged import can no longer replace a concurrent edit's fresh row with plan-time rows (#196). - deleteAsset's guard and listAssets' unused filter read asset_refs by site_id, so legacy rows a foreign archive left in another site neither block the delete nor hide the asset. - The purge planner's asset rule moves to cache-purge-assets.ts and also reads typed field assets (fieldAssetRefs, the target snapshot's site definitions). planCachePurge shrinks 233 -> 207 lines (baseline tightened); assets.ts adds no net lines. - Tests: new shared suite testing-asset-refs.ts (#196 race, foreign archive, 5,000-row rebuild under the size limit); a field-image purge case; the two "import rebuilds refs" cases now edit after the export so the import writes the node set. Closes #196 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Madraka <8898640+Madraka@users.noreply.github.com>
review) PR #200 review: the purge planner's asset rule read field values only by their definition key, so mid-rename (phase A's marker written, phase B stopped on its budget) entries still holding the old key were missed, and an asset change left their cached pages pointing at the old URL. - migratedFieldValues (media/field-refs.ts) reads a defined key the entry does not hold yet from migration.fromKey, as resolveFields' read() does. - The purge asset rule (cache-purge-assets.ts) uses it. - refsRebuild uses it too: otherwise an archive exported mid-rename would drop those entries' asset_refs rows, and an asset they still show could be deleted (RFC-0045 §2.5 point 4 asks the same of entryRefsRebuild). The writer path and fieldAssetIssues are unchanged. - Tests: a cache-purge case with a budget-stopped rename_field and three entries showing the asset; a shared-suite rebuild case with a marker. Both fail without the fallback. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Madraka <8898640+Madraka@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
RFC-0045 rollout step 0 (§2.5, "A prerequisite, decided, not optional"). It does not touch the RFC's new field types.
Closes #196
What changed
refsRebuild(packages/core-ts/src/media/refs-rebuild.ts)INSERT … SELECTjoinsnodes(a.site_id = ? AND a.kind = 'asset'), so only references to assets of the same site get rows.REFS_STATEMENT_BYTES= 90,000.INSERTnow, withoutOR IGNORE. Rows are deduplicated in JS by (asset, node, field).sync-plan.tsnodeBatch): the rebuild is emitted only inside!changes.unchanged && !changes.conflict, after the nodeINSERTs. The join needs those rows, and the chunks count against the existing 1,000-statement cap. An unchanged push, pull or import no longer replaces a concurrent edit's fresh row with plan-time rows (Sync: an 'unchanged' import rebuilds asset_refs from plan-time rows and can drop a concurrent edit's row #196).deleteAssetguard (assets.ts):NOT EXISTS (SELECT 1 FROM asset_refs WHERE site_id = ? AND asset_id = ?).unusedfilter (assets.ts): it usesUNUSED_ASSET_SQL, which matchesr.site_id = nodes.site_id. It lives inrefs-rebuild.tsso thatassets.tsadds no net lines (4+/4−).planCachePurgeinto the newcache-purge-assets.ts(planAssetPurge).fieldAssetRefs, using the target snapshot's site definitions. A changed asset shown only through animageorrichTextfield now purges that entry's node tag.planCachePurgewent from 233 to 207 lines, and the baseline is tightened.store.tsis untouched. Changeset:@cloudhal/core-tspatch.Tests
src/testing-asset-refs.ts, registered indescribeSiteGraphStore, so it runs on sqlite, D1 and DO SQLite:unchanged, then an asset-adding edit, then the planned batch. The edit's row survives, the asset is not listed as unused, and its delete is refused within_use. With the old unconditional rebuild restored, this case fails.test/cache-purge.test.ts: a changed asset purges the entry that shows it through a typedimagefield. It fails without the fix.testing-assets.ts) and "an import rebuilds the field references with the rest" (testing-fields.ts). Both used an unchanged import to repair a hand-deleted index. They now edit after the export, so the import writes the node set.Run locally
The full D1 and DO runs are left to CI because of the machine constraint.
pnpm exec vitest run test/store.test.ts -t "better-sqlite3"→ 160 passedpnpm exec vitest run test/cache-purge.test.ts→ 11 passedpnpm exec vitest run test/sync.test.ts test/sync-plan.test.ts test/media.test.ts test/multi-site.test.ts→ 61 passedpnpm --filter @cloudhal/core-ts typecheck→ cleanpnpm size:check→ ok (baseline tightened)biome checkon the touched files → clean (the complexity warnings were there before)Review notes (RFC watch list)
OR IGNOREon the rebuild. The rebuild never runs beside an unchanged node set. Every new probe carriessite_id.AssetEngine.rebuildRefsStatements(repair, no callers) still returns a standalone rebuild. Anyone who calls it later must put it beside a node-set write.🤖 Generated with Claude Code