Skip to content

PROD-2807: read entities saved earlier in the run, not the pulled target - #242

Merged
5PK merged 2 commits into
mainfrom
feature/PROD-2807-same-run-saved-targets
Oct 19, 2026
Merged

5PK merged 2 commits into
mainfrom
feature/PROD-2807-same-run-saved-targets

Conversation

@5PK

@5PK 5PK commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

Every mapper's getMappedEntity(…, "target") reads the target from the local agility-files cache, 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. translateZoneNames falls 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:

  • PROD-2346 rewrote the container cache file after a save.
  • PROD-2542 added a model-only in-memory list for content validation.

Templates, galleries and assets were never covered.

Fix

  • One cache for the run in core/state: recordSavedTarget, getSavedTarget, getSavedTargetBySourceReferenceName and clearSavedTargets.
    • Keyed by entity kind, then source ID.
    • Covers 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 the cache before the disk copy.
  • The pushers record the server's response next to each addMapping.
    • This replaces PROD-2346's container disk write and generalizes PROD-2542's model list.
    • Preflight still records planned models, so PROD-2542's preflight behavior is unchanged.
  • Content items and pages are left out on purpose. Their pushers only hold a partial target, and the pulled copy is what conflict detection (hasTargetChanged, PROD-2628) compares against. Both mappers now have a comment saying so.
  • Why in memory rather than on disk: it also works under --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, and GuidDataLoader already holds all of it in memory.

Two small related fixes

  • GalleryMapper.getMappedEntity listed "galleries" relative to the process working directory. It never found a pulled gallery, and it created an empty galleries/ folder wherever the CLI was run. This also removes a stray console.log.
  • ContainerMapper.getContainerByReferenceName dereferenced the null mapping in its no-mapping fallback, so that path threw.

Tests

  • src/tests/sync/same-run-saved-targets.test.ts: runs the real orchestrator twice through SyncHarness. 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 in Main.
  • 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.
  • Small-fix regressions: tests for the gallery folder path and the container lookup without a mapping. Each fails without its fix.
  • Existing tests:
    • The PROD-2346 container tests now check what the mapper returns instead of the file on disk.
    • The PROD-2542 tests are ported to the new API with the same assertions.
  • Results: tsc clean; 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

5PK and others added 2 commits October 19, 2026 08:34
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>
@5PK
5PK merged commit c2bd974 into main Oct 19, 2026
3 checks passed
@5PK
5PK deleted the feature/PROD-2807-same-run-saved-targets branch October 19, 2026 15:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants