Repository navigation
PROD-2807: read entities saved earlier in the run, not the pulled target - #242
Merged
Merged
Conversation
Every mapper's getMappedEntity(…, "target") read the target from the local cache, which holds the target as pulled at the start of the run. Anything a pusher saved was stale for the rest of the run. A template that gained a zone in the template phase was missing it when the page phase translated zone names, so that zone's modules overflowed into the template's first zone. This was patched per entity before: PROD-2346 rewrote the container cache file after a save, and PROD-2542 kept a model-only registry for content validation. Templates, galleries and assets were never covered. - core/state: one run-scoped cache (recordSavedTarget, getSavedTarget, getSavedTargetBySourceReferenceName, clearSavedTargets), by kind then source ID, for the kinds whose save returns the complete entity: model, container, template, gallery, asset. Cleared at the start of each push and by resetState. - The five mappers check it before the disk cache. - The pushers record the server's response beside each addMapping. This replaces PROD-2346's container cache write and generalizes PROD-2542's registry; preflight still records planned models. - Content items and pages are left out on purpose: their pushers hold only a partial target, and the pulled copy is what conflict detection compares against. - In memory rather than on disk so it also works under --preflight and leaves pulled files untouched. Also: - GalleryMapper.getMappedEntity listed "galleries" relative to the working directory, so it never found a pulled gallery and created an empty galleries/ folder there. Drop its stray console.log. - ContainerMapper.getContainerByReferenceName dereferenced the null mapping in its no-mapping fallback. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jules-exel
approved these changes
Oct 19, 2026
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.
Problem
Every mapper's
getMappedEntity(…, "target")reads the target from the localagility-filescache, and that cache holds the target as pulled at the start of the run. Anything a pusher saves is stale for the rest of the run.The visible symptom: a page template gains a zone during the template phase. The page phase then translates zone names against the cached template, which doesn't have that zone.
translateZoneNamesfalls back to its overflow branch and appends the new zone's modules to the template's first zone. On a real sync this put a home page banner into the main content zone.This has been patched per entity type before:
Templates, galleries and assets were never covered.
Fix
core/state:recordSavedTarget,getSavedTarget,getSavedTargetBySourceReferenceNameandclearSavedTargets.resetState.addMapping.hasTargetChanged, PROD-2628) compares against. Both mappers now have a comment saying so.--preflight, which can't write files, and it leaves the pulled files exactly as pulled. The memory cost is at most one extra copy of the saved entities. On a mid-size instance, all five kinds together are about 4 MB of JSON, andGuidDataLoaderalready holds all of it in memory.Two small related fixes
GalleryMapper.getMappedEntitylisted"galleries"relative to the process working directory. It never found a pulled gallery, and it created an emptygalleries/folder wherever the CLI was run. This also removes a strayconsole.log.ContainerMapper.getContainerByReferenceNamedereferenced the nullmappingin its no-mapping fallback, so that path threw.Tests
src/tests/sync/same-run-saved-targets.test.ts: runs the real orchestrator twice throughSyncHarness. Run 2 adds a zone to a template and moves a page module into it. The page payload must put the module in the new zone. It fails without the template mapper change: the module lands inMain.src/lib/mappers/tests/saved-target.test.ts: each of the five mappers returns the entity saved this run instead of the pulled copy, falls back to disk otherwise, and never substitutes it on the source side.tscclean; full suite 2,546 of 2,546 passing; ESLint shows no new warnings.Release
Bumps the version to 1.2.1, a patch release with bug fixes only.
Jira: PROD-2807
🤖 Generated with Claude Code