Skip to content

refactor(type-catalog): extract compareBy + writeSiblingArtifact helpers#190

Merged
jakebromberg merged 1 commit into
mainfrom
worktree-refactor-type-catalog-helpers
May 30, 2026
Merged

refactor(type-catalog): extract compareBy + writeSiblingArtifact helpers#190
jakebromberg merged 1 commit into
mainfrom
worktree-refactor-type-catalog-helpers

Conversation

@jakebromberg

Copy link
Copy Markdown
Owner

Summary

  • Pulls three hand-rolled multi-key sort comparators and two parallel sibling-artifact emission blocks out of extractors/typescript/type-catalog.mjs into two small _lib helpers: compareBy(...keyFns) and writeSiblingArtifact({...}). Same byte-identical output for catalog/files/edges payloads, fewer lines, single source of truth for the sibling-wrapper shape.
  • Adds the missing extractor: {language, name, version} block to references.json's wrapper — the lone sibling artifact that wasn't carrying it. Additive change; existing consumers reading .edges keep working. Documented as such in docs/pipeline-contract.md.

Test plan

  • npm test in extractors/typescript/ — 70 tests pass (10 new across sort.test.mjs + artifacts.test.mjs, plus a references.json wrapper-shape assertion added to extract.test.mjs).
  • pipeline/queries/_tests/test_queries_integration.sh — 124 pass / 0 fail.
  • pipeline/queries/_tests/test_canonical.sh — 26 pass / 0 fail.
  • pipeline/queries/_tests/test_gojq_parity.sh — 54 pass / 0 fail.
  • End-to-end run against fixtures-files/ — catalog.json, references.json, files.json all emit with the unified {schema_version, extractor, <payloadKey>} shape.

Closes #185
Closes #186

Pulls three hand-rolled multi-key sort comparators and two parallel sibling-artifact emission blocks out of type-catalog.mjs into reusable _lib helpers. Same byte-identical output, fewer lines, single source of truth for the sibling-wrapper shape.

While consolidating the writers, references.json gains the {language, name, version} extractor block that the wrapper convention requires (catalog.json and files.json already had it; references.json was the lone holdout). Additive change — consumers reading `.edges` keep working unchanged. Documented in docs/pipeline-contract.md.

Closes #185
Closes #186
@jakebromberg
jakebromberg merged commit 05baf17 into main May 30, 2026
3 checks passed
jakebromberg added a commit that referenced this pull request May 30, 2026
Lays down the substrate that #118's cross-repo queries (#156/#157/#158) and the per-repo CI publication step (#154) consume. Four scripts plus a hermetic mock so the whole surface is exercisable without an actual R2/S3 bucket.

`pipeline/fetch-catalogs.sh` is the auditor read path — pulls `index.json`, then every ok-repo's per-catalog SHA-keyed objects, into `$AUDIT_LOCAL_CACHE`. Warm-cache via sha256 compare; supports `--repos` filtering and `file://` URLs for tests.

`pipeline/publish-catalog.sh` is the CI write path — validates each catalog against the v1.1 wrapper, uploads under `by-repo/<R>/<iso-utc>_<short-sha>/<kind>.json`, writes a `latest.json` pointer, and triggers a self-healing index rebuild.

`pipeline/refresh-index.mjs` derives `index.json` from a bucket listing. Idempotent — running it twice produces byte-identical output; running it after manual edits or partial publishes restores correctness without losing data. The "rewrite from listing, not append-on-write" pattern the brief calls out (§7.2). Per-repo `latest.catalogs[]` array reflects the multi-catalog reality (type-catalog + function-catalog + file-hashes + package-graph), not the single-catalog assumption in the original brief.

`pipeline/verify-index.sh` is the drift detector. Reports orphan bucket prefixes and dangling index references. Run by `refresh-index` callers and a nightly cron.

All four ship with a `--bucket-fs DIR` local-filesystem backend for tests and dev — same code path, no S3 SDK required. Production uses `--bucket-name`/`--bucket-endpoint` (S3-API, sigv4 via the `aws` CLI). For Cloudflare R2 the only change is the endpoint URL.

Schema reconciles the brief against current main: the catalog substrate now publishes a *directory* of catalogs per repo (the README caveat in `docs/plans/README.md` flagged this — original brief assumed one catalog file). `latest.catalogs[]` is the per-catalog manifest; per-row `extractor` provenance comes from the v1.1 wrapper that lands in PR #181/#190/#196.

Tests: 45 hermetic cases under `pipeline/_tests/test_substrate.sh`, wired into CI's `pipeline + typescript extractor` job. Covers cold/warm fetch, repo filter, malformed-index handling, sha256 mismatch + cleanup, refresh idempotence, `--known-repos` missing-repo surfacing, stale-snapshot detection, `--dry-run` no-op, drift detection on orphan and dangling cases, publish round-trip via fetch, bare-array refusal, `--skip-refresh`.

`docs/substrate.md` covers one-time R2 provisioning, IAM/token scoping with OIDC, env-var contract, local auditor workflow, recovery procedures, and the cost model (well under $1/month at 30-repo scale on R2).

Explicitly out of scope and tracked elsewhere: real R2 bucket provisioning (operational, needs the user's Cloudflare account); live integration tests against a real bucket (per brief §6.2 — follow-up); per-repo CI workflow that calls `publish-catalog.sh` on push (#154); `coverage.jq` query against the substrate's coverage block (#155); F1/F2/F3 cross-repo queries (#156/#157/#158, all blocked on this + #152).

Closes #153.
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.

Extract writeSiblingArtifact helper for type-catalog.mjs Extract compareBy(...keyFns) sort helper for type-catalog.mjs

1 participant