Skip to content

Retire the client-side changelog registry refresh - #3760

Merged
cotti merged 1 commit into
mainfrom
changelog-retire-client-registry-refresh
Aug 11, 2026
Merged

Retire the client-side changelog registry refresh#3760
cotti merged 1 commit into
mainfrom
changelog-retire-client-registry-refresh

Conversation

@cotti

@cotti cotti commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Why

Phase 3 of elastic/docs-eng-team#688, stacked on #3738. With the scrubber Lambda as the sole producer of the public bundle manifests and the shallow per-tree maps (#3738), the client-side registry refresh is the last remaining writer in the retired multi-writer model. Keeping it would let a stale private manifest linger (nothing consumes it anymore) and would keep upload logs claiming registry responsibility the CLI no longer has.

Note

Restacked 2026-08-06: this PR previously sat on #3741 (registry reconcile/verify CLI), which was closed after review — the per-product registry cutover tooling went with it. It now stacks directly on #3738, whose rework scopes group reconciliation to the bundle tree and adds the shallow folder→token maps.

What

changelog upload now writes YAML objects only: the post-upload refresh block, RegistryBuilder, and the private-manifest write path are gone. The registry materializes from the S3 events the upload already emits. The amend end-to-end test now drives RegistryReconciler (the production path) for its registry step, and the upload tests assert that no registry.json is ever PUT.

Old binaries in the wild keep writing private manifests — harmless: bundle registry-key events only schedule a group reconcile and are never copied to the public bucket.

Important

Do not merge until the Phase 2 cutover checkpoint passes (scrubber Lambda deployed with #3738, queue drained, DLQ empty, and a spot-check that public bundle/{product}/registry.json manifests carry the reconciler's producer field — see elastic/docs-eng-team#688). Releasing this before the Lambda owns the public registry would leave registries permanently stale.

After this releases, the now-dead private registry.json objects can be deleted (operational step, no code): their ObjectRemoved events only schedule redundant reconciles.

Part of elastic/docs-eng-team#688 (Phase 3).

@cotti
cotti requested a review from a team as a code owner August 4, 2026 01:32
@cotti
cotti requested a review from reakaleek August 4, 2026 01:32
@cotti
cotti requested a review from a team as a code owner August 4, 2026 01:50
@cotti
cotti force-pushed the changelog-retire-client-registry-refresh branch from 4cefbe5 to cc65ecf Compare August 4, 2026 01:50
@cotti
cotti force-pushed the changelog-retire-client-registry-refresh branch from cc65ecf to 95b64ed Compare August 6, 2026 15:30
@cotti
cotti changed the base branch from changelog-registry-reconcile-cli to changelog-registry-scrubber-ownership August 6, 2026 15:34
cotti added a commit that referenced this pull request Aug 6, 2026
Restacked on the scrubber-ownership chain: the scrubber Lambda owns the
public bundle/{product}/registry.json manifests and the shallow per-tree
maps (#3738), and the client-side refresh machinery is retired (#3760).
The migration command now writes YAML bundle objects only; the S3 events
those creates emit trigger the reconciliation that materializes the
manifests. Tests assert no registry.json is ever PUT.
@cotti

cotti commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Restacked: #3741 was closed with the per-product cutover tooling, so this now sits directly on #3738 (rebased onto its reworked branch — shallow per-tree maps, group reconcile scoped to the bundle tree). Same single commit, no content changes beyond the rebase; 849/849 tests green on the new chain. Now part of stack #3800 (#3738 ← this ← #3794).

@cotti
cotti force-pushed the changelog-retire-client-registry-refresh branch from 95b64ed to 5695678 Compare August 10, 2026 16:21
cotti added a commit that referenced this pull request Aug 10, 2026
Restacked on the scrubber-ownership chain: the scrubber Lambda owns the
public bundle/{product}/registry.json manifests and the shallow per-tree
maps (#3738), and the client-side refresh machinery is retired (#3760).
The migration command now writes YAML bundle objects only; the S3 events
those creates emit trigger the reconciliation that materializes the
manifests. Tests assert no registry.json is ever PUT.
@cotti
cotti force-pushed the changelog-retire-client-registry-refresh branch from 5695678 to ba57fc6 Compare August 10, 2026 19:01
cotti added a commit that referenced this pull request Aug 10, 2026
Restacked on the scrubber-ownership chain: the scrubber Lambda owns the
public bundle/{product}/registry.json manifests and the shallow per-tree
maps (#3738), and the client-side refresh machinery is retired (#3760).
The migration command now writes YAML bundle objects only; the S3 events
those creates emit trigger the reconciliation that materializes the
manifests. Tests assert no registry.json is ever PUT.
Base automatically changed from changelog-registry-scrubber-ownership to main August 11, 2026 12:54
The scrubber Lambda is the sole producer of the public registry.json,
reconciled from public bucket state on the S3 events every upload already
emits (elastic/docs-eng-team#688 Phase 3). Uploads now write YAML objects
only; RegistryBuilder and the private-manifest write path are removed, and
the amend end-to-end test exercises RegistryReconciler instead.
cotti added a commit that referenced this pull request Aug 11, 2026
Restacked on the scrubber-ownership chain: the scrubber Lambda owns the
public bundle/{product}/registry.json manifests and the shallow per-tree
maps (#3738), and the client-side refresh machinery is retired (#3760).
The migration command now writes YAML bundle objects only; the S3 events
those creates emit trigger the reconciliation that materializes the
manifests. Tests assert no registry.json is ever PUT.
@cotti
cotti force-pushed the changelog-retire-client-registry-refresh branch from ba57fc6 to 31d19e6 Compare August 11, 2026 12:54
@cotti
cotti merged commit a5df34e into main Aug 11, 2026
25 checks passed
@cotti
cotti deleted the changelog-retire-client-registry-refresh branch August 11, 2026 14:39
cotti added a commit that referenced this pull request Aug 11, 2026
Restacked on the scrubber-ownership chain: the scrubber Lambda owns the
public bundle/{product}/registry.json manifests and the shallow per-tree
maps (#3738), and the client-side refresh machinery is retired (#3760).
The migration command now writes YAML bundle objects only; the S3 events
those creates emit trigger the reconciliation that materializes the
manifests. Tests assert no registry.json is ever PUT.
cotti added a commit that referenced this pull request Aug 13, 2026
Restacked on the scrubber-ownership chain: the scrubber Lambda owns the
public bundle/{product}/registry.json manifests and the shallow per-tree
maps (#3738), and the client-side refresh machinery is retired (#3760).
The migration command now writes YAML bundle objects only; the S3 events
those creates emit trigger the reconciliation that materializes the
manifests. Tests assert no registry.json is ever PUT.
cotti added a commit that referenced this pull request Aug 13, 2026
Restacked on the scrubber-ownership chain: the scrubber Lambda owns the
public bundle/{product}/registry.json manifests and the shallow per-tree
maps (#3738), and the client-side refresh machinery is retired (#3760).
The migration command now writes YAML bundle objects only; the S3 events
those creates emit trigger the reconciliation that materializes the
manifests. Tests assert no registry.json is ever PUT.
cotti added a commit that referenced this pull request Aug 13, 2026
* Changelog: add temporary migrate-from-web command

* Changelog: test and document migrate-from-web

* Changelog: migrate-from-web writes bundles only (no registry refresh)

Restacked on the scrubber-ownership chain: the scrubber Lambda owns the
public bundle/{product}/registry.json manifests and the shallow per-tree
maps (#3738), and the client-side refresh machinery is retired (#3760).
The migration command now writes YAML bundle objects only; the S3 events
those creates emit trigger the reconciliation that materializes the
manifests. Tests assert no registry.json is ever PUT.

* Changelog: migrate-from-web covers the scope table, --products narrows

Review feedback (#3794): drop the standing config surface. The former
config/migrate-from-web.yml becomes a checked-in table in the command
itself (MigrateFromWebScope.All) — temporary tooling state, added per
rollout wave and deleted with the command. A run covers every product
in the table by default; --products x,y,z narrows it for tests and
pilots. The page→product mapping stays explicit because bundle product
ids appear in no published metadata: page frontmatter carries the site
taxonomy, not bundle ids.

One product's failure no longer aborts the run: each product migrates
independently and the run fails at the end if any of them did.

* FileSystemFactory: extend the mock-temp scope workaround to Windows

MockFileSystem hardcodes its temp path on every OS (C:\temp on Windows,
unix-ified /temp elsewhere) instead of calling Path.GetTempPath(), while
AllowedSpecialFolder.Temp resolves the real temp. The existing workaround
only covered non-Windows, assuming the two coincide there — they don't:
GitHub runners' real temp is under the user profile, so the first test to
write through mockFs.Path.GetTempPath() on Windows (migrate-from-web's
bundle staging) failed scope validation. Add the inner mock's temp as an
explicit root unconditionally; drop once TestableIO#1454 ships.
cotti added a commit that referenced this pull request Aug 13, 2026
Everything outside docs/ resolves to main (the stacked code merged via #3738/#3760); docs/cli-schema.json resolves to main (the registry commands were dropped with #3741).
cotti added a commit that referenced this pull request Aug 13, 2026
The draft predated the #3738 review rework: RegistryReconciler is now BundleRegistryReconciler and reconciles the bundle/{product}/ tree only, the changelog/ pool manifests remain legacy client-authored pass-through (changelog bundle still enumerates pools through them, RFC #698 replaces that), the registry reconcile/verify operator CLI was dropped with #3741, and the scrubber now also maintains the shallow per-tree folder-to-token maps (consumer side: #3801). Infra bullets match the applied docs-infra#360 IAM (no registry-operator grant, no private ListBucket) and observability as it exists (metric stream to docs-o11y; alerts and runbook tracked in docs-eng-team#692).
cotti added a commit that referenced this pull request Aug 13, 2026
* Scrubber Lambda owns the public changelog registry via state reconcile

Phase 1 of elastic/docs-eng-team#688. The public registry.json was a log of
upload operations (client-written, pass-through copied); every known
consistency gap followed from that. The scrubber Lambda now derives it from
the public bucket's actual state: registry = f(state), never f(event).

- Extract the Lambda's top-level handler logic into testable classes in
  Elastic.Changelog: ScrubberProcessor (batch coalescing by key and group,
  object-level reconcile with post-write source validation) and
  RegistryReconciler (delimited/paginated group listing, ETag reuse with
  amends always recomputed, semantic idempotence, conditional PUT/DELETE
  with bounded jittered retries on 412/409, newer-schema refusal).
  Program.cs is now a thin adapter.
- Retire the registry pass-through in the same deploy: registry-key events
  only schedule a group reconcile, so client-authored JSON no longer
  reaches the public bucket uninspected.
- Add a producer (algorithm version) field to the manifest; a mismatch —
  including legacy pass-through manifests — forces a full metadata
  recompute and a write even when entries are identical.
- Emit per-invocation reconcile metrics as CloudWatch EMF (the Phase 0
  observability item that could only land with the reconciler).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Add changelog registry reconcile and verify commands

Phase 2 of elastic/docs-eng-team#688. The cutover/heal tooling for the
Lambda-owned public registry:

- `changelog registry reconcile` plans groups (one scope, or the union of
  both buckets so orphan public groups are covered) and sends one versioned,
  discriminated reconcile message per group to the scrubber queue —
  {kind, version, scope, group, correlation_id}, validated through
  ChangelogKeys on both ends. The CLI never mutates S3; the Lambda stays the
  public bucket's single writer. --dry-run prints the plan; the non-dry-run
  path asks for confirmation (--yes for CI). Each run stamps one correlation
  id and prints a ledger line per group.
- On a reconcile message the Lambda performs a full group heal:
  object-level reconcile over the union of both buckets' listings (copy
  what's live, delete what isn't), then the group reconcile — recovering
  lost/DLQ-expired scrub events. Requires the new optional
  PRIVATE_BUCKET_NAME Lambda env var; malformed messages are rejected to
  the DLQ where the Phase 0 alarm surfaces them.
- `changelog registry verify` is the read-only sibling and cutover gate:
  compares each public manifest against what a reconcile would write (same
  listing spec and entry rules by construction) and reports divergence as
  missing/stale/corrupt/object-divergent, with unsupported schemas reported
  distinctly.
- Fix the manifest ETag wire format: the snake_case policy serialized the
  producer-side field as "e_tag" while consumers and the documented format
  read "etag" — recorded ETags were invisible to every consumer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Suppress CA1001 on ChangelogRegistryServiceTests

Same suppression RegistryBuilderTests carries: xUnit owns the test class
lifetime and TestDiagnosticsCollector needs no disposal in these tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Retire the client-side registry refresh from changelog upload

The scrubber Lambda is the sole producer of the public registry.json,
reconciled from public bucket state on the S3 events every upload already
emits (elastic/docs-eng-team#688 Phase 3). Uploads now write YAML objects
only; RegistryBuilder and the private-manifest write path are removed, and
the amend end-to-end test exercises RegistryReconciler instead.

* Rewrite changelog registry docs for scrubber Lambda ownership

The registry docs still described the retired model: client-side refresh,
registry pass-through, pre-scrub ETags, a 1 h CloudFront TTL (caching is
disabled), and a refresh "skipped for --artifact-type changelog". Documents
the reconciler as sole producer, the public-object ETag, convergence
semantics, absent-vs-empty manifests, the reconcile message contract, and
the registry reconcile/verify operator commands (docs-eng-team#688 Phase 4).

* Align registry docs with the merged #3738 rework and #3760

The draft predated the #3738 review rework: RegistryReconciler is now BundleRegistryReconciler and reconciles the bundle/{product}/ tree only, the changelog/ pool manifests remain legacy client-authored pass-through (changelog bundle still enumerates pools through them, RFC #698 replaces that), the registry reconcile/verify operator CLI was dropped with #3741, and the scrubber now also maintains the shallow per-tree folder-to-token maps (consumer side: #3801). Infra bullets match the applied docs-infra#360 IAM (no registry-operator grant, no private ListBucket) and observability as it exists (metric stream to docs-o11y; alerts and runbook tracked in docs-eng-team#692).

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants