Goldfish Review Report (Stage 8, Intermediate Zoom Out)¶
Target: /Users/gabrielgellner/dev/sdmxlib/docs/design/sharded-bundle-catalog-plan.md (1-261)
Reviewer lens: egm-zoom-out (one instance), using the earlier stage reports from stages 5, 6, 7 and 9.
Verdict: The plan's phase structure does not hold up against the earlier findings. - Phases 1-3 are sound once corrected. - Phases 4-6 depend on spec points that are unsettled or contradictory. - Phases 7-9 have no goals behind them.
Counts: 3 Blocker, 6 Major, 3 Nit.
Prioritized Findings¶
Z1. Spec contradictions must be settled in a spec PR (Phase 0) - Severity: Blocker¶
- Reviewer Lens:
egm-zoom-out - Affected Scope: Plan lines 26-27, 75, 140, 211-213, 219-221, 230. Spec §7.4 (lines 419-428), §11.2 step 2 (line 530), §6.3/§6.4.
- Discrepancy Description: Five findings share one root cause, which is that the spec is wrong or silent:
- CDN rule (critic B1). §7.4 gives the CDN
immutable, no invalidation, and a long TTL under URLs that stay the same across a release. Goal 2 (one-write visibility), Goal 3 (per-dataflow invalidation) and rollback (line 140) therefore hold only at the origin. A 404 that the CDN cached for a new dataflow stays after the flip. - Interrupted release (readiness B6). §11.2 step 2 flips
currentto the staged index. The Phase 5 test (line 221) asserts thatcurrentstays on the old index. - Manifest skip (readiness B4). Skipping manifests already parsed conflicts with invariants 4 and 10, which need artefact fingerprints and partial code ids that the index does not store.
- One fingerprint (readiness M17).
IndexEntry.dataflowscarries one fingerprint. The §7.4 key needs two: structural and table. - Q7 refusal (readiness B7). The same-URN refusal blocks CUJ 6 and line 186.
- Rationale & Recommendation:
- Add a Phase 0: spec v5 docs PR that settles items 1-5, and make Phases 4-6 depend on it.
- For the CDN: put
immutableonly on content-addressed URLs. Public SDMX URLs get a short TTL with ETag revalidation (the origin answers 304 by recomputing the key). State a TTL for cached 404s. - Restate Goals 2 and 3 and the rollback line as "visible at the origin at the put, and through the CDN within T".
Z2. Phase 1 names a release that has shipped and bundles unrelated work - Severity: Blocker¶
- Reviewer Lens:
egm-zoom-out - Affected Scope: Lines 15, 99, 165-186, 190, 225.
- Discrepancy Description:
- 0.75.0 has already shipped (PR #202). Schema 2.51, GH-12 and GH-213 landed after it, so the plan's release is 0.76, and the
<0.76pins are wrong. - Phase 1 also ties the release to work it does not need:
- the GH-185 bench and cache, which no consumer needs before Phase 6 or 8;
- an unspecified
_build.py, which duplicates Phase 3'svendor_closure.
- Rationale & Recommendation:
- Make Phase 1 "sdmxlib 0.76": the current
mainplus GH-221, with GH-221's API decided in the plan (readiness B2 notes_fetch_onemay be enough). - Pin Phases 2, 3 and 6 to
>=0.76,<0.77. - Run GH-185 as its own track, gating only Phase 8's
hostPathitem. - Move
_build.pyto Future Improvements, or makevendor_closurethe single closure implementation. - Pick one rule for cutting partials.
Z3. Components the goals depend on are owned by no phase - Severity: Blocker¶
- Reviewer Lens:
egm-zoom-out - Affected Scope: Lines 25-26, 68, 138, 255.
- Discrepancy Description: Four components have no owning phase:
- the synthetic 7,000-bundle corpus and Zipf load driver;
- the pre-materialisation job, which needs sdmxlib-rest's render code;
- the ingress resolver that maps an SDMX path to
bundle_id(critic M10); - the serving list's store and
ServingEntry(readiness B5). - Rationale & Recommendation:
- Put the corpus generator at the start of Phase 4, or in a Phase 3.5 that statcatlib owns.
- Put pre-materialisation in Phase 6.
- Make the ingress resolver a Phase 8 item, and state its behaviour during a flip.
- Define the serving list in Phase 0 (spec §6.6) and build it in Phase 5.
Z4. Shorten the planning horizon - Severity: Major¶
- Reviewer Lens:
egm-zoom-out - Affected Scope: Lines 159-247.
- Discrepancy Description: Phases 7-9 are not actionable, and Phase 7 has no goal (critic M7). The shape of Phases 4-6 depends on what Phase 0 decides.
- Rationale & Recommendation:
- Specify Phases 0-3 in full.
- For Phases 4-6, keep only the contract each hands the next, plus their gating tests.
- Move Phases 7-9 to "Later phases (outline)", to be re-planned after Phase 6 measures cold start and first attach.
- State that Phase 7 can slip without blocking Phases 8-9.
Z5. Decide where the index types live before Phase 4 - Severity: Major¶
- Reviewer Lens:
egm-zoom-out - Affected Scope: Lines 105, 109, 116-120, 225.
- Discrepancy Description: Making sdmxlib-rest depend on statcatlib:
- reverses sdmxlib-rest's recorded decision not to depend on statcatlib;
- pulls lancedb into the serving image;
- chains every sdmxlib version bump through a statcatlib release.
- Rationale & Recommendation:
- Choose among a dependency-light
statcatlib[index]or separate package, a JSON Schema contract checked against a shared fixture, or the full dependency. - Record the rejected options as Alternatives.
- State the rule for propagating version pins across the three repositories.
Z6. Phase ordering and Alternative C rest on a false deadlock - Severity: Major¶
- Reviewer Lens:
egm-zoom-out - Affected Scope: Lines 26, 128-132, 221, 231.
- Discrepancy Description:
- The zero-failure flip test is already in Phase 6, so a per-repository order also works. Alternative C's rejection reason is therefore wrong.
- The goals cite milestones whose tests live in other phases.
- Rationale & Recommendation:
- Add a phase/milestone/dependency table.
- Attribute each goal to the phase that measures it.
- State Alternative C's real cost: the first end-to-end loop comes later.
Z7. Phase 2 is larger than "small" - Severity: Major¶
- Reviewer Lens:
egm-zoom-out - Affected Scope: Lines 47, 126, 188-198.
- Discrepancy Description: Phase 2 also needs:
- the
Catalogconstruction instore.py; - the
check_bundleat=API break; - removal of the data-path surface;
- a redesigned version guard;
- a token source for the search tables;
docs/upgrading.md, which is a new file.
Alternative B's reasoning depends on Phase 2 being small.
* Rationale & Recommendation:
- Split Phase 2:
- 2a: adopt 0.76, read-only open, and the check_bundle API.
- 2b: token-named search tables, which only Phase 5 needs.
- Close Q5 as decided: break cleanly.
Z8. Consolidate the storage abstractions - Severity: Major¶
- Reviewer Lens:
egm-zoom-out - Affected Scope: Lines 219, 227, 230.
- Discrepancy Description:
- The plan adds three protocols (
ObjectStore,Fetcher,ResultStore). Each has a local-directory implementation and none has a production implementation. - The spec's §11.5 has pods pull with the deployment's own tool.
- sdmxlib already has
RemoteFile,verify_remote,content_md5/content_crc32candbundle_files. - Rationale & Recommendation:
- Define one minimal blob protocol in Phase 5 and name its production backend (obstore or fsspec).
- Drop
Fetcher, or state why the plan departs from §11.5. - Test conditional put against Azurite or MinIO.
Z9. Rollback, GC and idempotency need definitions in Phase 0 - Severity: Major¶
- Reviewer Lens:
egm-zoom-out - Affected Scope: Lines 28, 29, 110, 140.
- Discrepancy Description:
- Rollback covers data only. Schema and contract changes have no rollback.
- The rollback put races a release's conditional put.
- GC conflates the retention window with the backup window, and can delete publications after a rollback.
- "Idempotent" (line 110) is false while each run mints a new token.
- Rationale & Recommendation: Settle these in Phase 0:
- rollback for each change class;
- both GC windows;
- idempotency by content fingerprint or a caller-supplied token;
- a writer lease per
bundle_id.
Z10. Detail sits at the wrong level - Severity: Nit¶
- Reviewer Lens:
egm-zoom-out - Affected Scope: Lines 169-197, 211.
- Discrepancy Description: The plan pins line anchors into sibling repositories, some already wrong (readiness M8 and M9). The contracts the next phase needs stay undefined:
ServingEntry, the record shape and the search routes. - Rationale & Recommendation: Move the anchors into the issues and put the contracts in the plan.
Z11. Spec housekeeping is in Phase 1 - Severity: Nit¶
- Reviewer Lens:
egm-zoom-out - Affected Scope: Line 178.
- Rationale & Recommendation: Fold the Status-line edit and the §4.0 renumbering into the Phase 0 spec PR.
Z12. Goal 5 measures the wrong failure - Severity: Nit¶
- Reviewer Lens:
egm-zoom-out - Affected Scope: Line 29.
- Discrepancy Description: A fleet running mixed schema versions fails with 503 responses, not 404 (critic M12).
- Rationale & Recommendation: Measure zero non-2xx responses, and state the §9.2 precondition that no old pod remains.
Proposed restructure¶
- P0: spec v5, settling the CDN rule, the staged flip in §11.2, the index's data for invariants 4 and 10, the second fingerprint, the scope of the Q7 refusal, the serving list, rollback classes and the GC windows.
- P1: sdmxlib 0.76 with GH-221 decided. GH-185 runs as a separate track.
- P2a / P2b: statcatlib adoption, then token-named search tables.
- P3: partials and structures bundles, with one closure implementation.
- P4-P6: contracts only. The corpus generator comes early in P4 and pre-materialisation in P6.
- P7-P9: outline only, re-planned after P6.