Add changelog registry reconcile and verify commands - #3741
Conversation
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>
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>
dacbeae to
d5a2c93
Compare
Mpdreamz
left a comment
There was a problem hiding this comment.
Request changes: reconcile/verify against the wrong registry model
Same architectural pushback as on #3738 — please don't build CLI cutover (registry reconcile / registry verify) around per-product / per-group changelogs/<product>/registry.json.
Why
Automated release discovery always has a list of PRs first (elastic/docs-eng-team#698: prestage query, GitHub Release PR list, serverless query). From that list we probe CloudFront; 404 means no checked-in changelog, and changelog bundle inlines one into the bundle anyway.
S3 changelogs/ is a mirror of repo-checked-in entries, not a required inventory at bundle time. A product-scoped registry would only grow. Drop that contract and the reconcile/verify surface that exists to prove convergence of it.
What to keep / retarget
What we actually want on S3 is the shallow cache-opt-out maps:
changelogs/registry.jsonbundles/registry.json
{
"<folder>": "<etag>"
}ETag = last-touched file under that folder, so caches can skip per-folder work eagerly.
Please reshape (or largely remove) the reconcile/verify commands so they target that folder→etag registry if anything — not an object-level per-product manifest heal. Much of ChangelogGroupDiscovery, group listing, divergence taxonomy (Missing/Stale/Corrupt/ObjectDivergent), and the cutover heal queue flow can go with the old model.
Why
Phase 2 of elastic/docs-eng-team#688, stacked on #3738. Once the scrubber Lambda owns the public
registry.json(Phase 1), two things are still missing: a way to trigger the cutover heal (every existing public manifest is a legacy pass-through copy that needs one authoritative rebuild — and historical drift needs repairing retroactively), and a way to prove convergence before Phase 3 retires the client-side refresh.What
changelog registry reconcileplans the affected groups — a single scope, or the union of groups discovered in both buckets, so orphan public groups (including manifest-only leftovers) are covered — and sends one explicit reconcile message per group to the scrubber queue:{"kind":"reconcile","version":1,"scope":"bundle"|"changelog","group":"…","correlation_id":"…"}, strictly validated throughChangelogKeyson both ends and serialized with the same source-generated context the Lambda parses with (AOT). The CLI never mutates S3 — the Lambda stays the public bucket's single writer.--dry-runprints the plan; the non-dry-run path asks for confirmation (--yesfor non-interactive use). Each run stamps one correlation id and prints a ledger line (group, SQS message id, correlation id) for the cutover checkpoint. Attributes:[RequiresAuth],[CommandIntent(Intent.Destructive | Intent.Idempotent)],[MutationScope(MutationScope.Global)].republish). Reads the (already-provisioned)PRIVATE_BUCKET_NAMELambda env var — S3 events keep working without it since they carry their source bucket. Malformed reconcile messages are rejected to the DLQ, where the Phase 0 alarm makes the sender bug visible — redelivery can't fix a bad message.changelog registry verifyis the read-only sibling and the cutover gate: for each planned group it compares the public manifest against what a reconcile of the current public listing would write — same listing spec and entry rules by construction (RegistryReconciler.VerifyGroupAsync) — and reports divergence using Add changelog registry state discovery and reconciliation commands #3717's taxonomy:Missing/Stale/Corrupt/ObjectDivergent, withUnsupportedSchemareported distinctly. Non-zero exit on any divergence.ETagas"e_tag", while the consumer contract (ChangelogRegistryBundle) and the documented format read"etag"— every recorded ETag has been invisible to every consumer.[JsonPropertyName("etag")]aligns the writer with the documented format; old"e_tag"manifests now parse as corrupt and get rebuilt, which the cutover forces anyway via theproducermismatch.docs/cli-schema.jsonregenerated; supplemental CLI pages added underdocs/cli/changelog/registry/.Part of elastic/docs-eng-team#688 (Phase 2).
🤖 Generated with Claude Code