Skip to content

fix(docs): repair the docs search sync pipeline - #1507

Merged
schickling merged 1 commit into
mainfrom
schickling-assistant/2026-07-27-docs-search-repair
Jul 27, 2026
Merged

fix(docs): repair the docs search sync pipeline#1507
schickling merged 1 commit into
mainfrom
schickling-assistant/2026-07-27-docs-search-repair

Conversation

@schickling-assistant

Copy link
Copy Markdown
Collaborator

Docs search has been broken in production for roughly three months. This repairs the pipeline; the design rationale and the IaC that declares it live in #1330.

What was wrong

Two faults, stacked so the second hid the first.

The dev/prod split was stillborn. It was added 2026-04-30 referencing MXBAI_VECTOR_STORE_ID_DEV and MXBAI_VECTOR_STORE_ID_PRODsecrets that had never been created. So target=prod hard-failed on its :? guard, and target=dev silently fell back to the legacy bare store id.

Then sync-docs.yml stopped running at all. It was the repo's only hand-written workflow, and pinned pnpm 11.3.0 via pnpm/action-setup while packageManager moved to 11.8.0. pnpm/action-setup hard-errors on that disagreement, so every push run died at Setup pnpm before reaching the sync — masking the stillborn split underneath.

Net effect: one vector store existed, named livestore-docs-dev, and both docs surfaces read it. Production search served stale, development-named content.

What this changes

  • sync-docs.yml now generates from sync-docs.yml.genie.ts and uses livestoreSetupSteps (devenv/nix) like every other workflow. It was the last hand-written one, which is why it drifted — nothing kept its pnpm pin in step.
  • Calls the docs:search:sync:* devenv tasks instead of invoking pnpm dlx @mixedbread/cli inline, so there's one way to run a sync.
  • Adds docs:search:sync:dev; both tasks are generated from one helper so they can't drift apart, and each requires its own store id — a missing secret now fails loudly instead of silently retargeting another store.
  • Target selection is two gated jobs rather than a shell branch on an env var. A push to main only ever refreshes dev; prod is dispatch-only.
  • deploy-prod.yml and release.yml now pass MXBAI_VECTOR_STORE_ID_PROD rather than the bare alias.

Already applied outside this PR

The missing MXBAI_VECTOR_STORE_ID_DEV / _PROD secrets have been created, a livestore-docs-prod store now exists (populated from v0.4.0), the dev store was refreshed from main, and each Netlify site points at its own store. docs.livestore.dev/api/search returns results from the production store.

This PR closes a live gap: production is correct now, but main still passes the bare store id to the prod sync, so the next stable release would sync the wrong store and leave production search stale against that release.

Not addressed

The deeper defect is that three months of red runs surfaced to nobody. Detection belongs with the disabled notify-alignment job (#1183) rather than a competing mechanism invented here.

🤖 Generated with Claude Code

Posted on behalf of @schickling
field value
agent_name cl1-bolt
agent_session_id 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent_tool Claude Code
agent_tool_version 2.1.220
agent_runtime Claude Code 2.1.220
agent_model claude-opus-5
runtime_profile /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
skills_manifest /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
worktree ls-vrs/docs-search-repair
machine dev3
tooling_profile dotfiles@b785b9f

sync-docs.yml was the repo's last hand-written workflow, and drifted for that
reason: it pinned pnpm 11.3.0 via pnpm/action-setup while packageManager moved
to 11.8.0, so every push run died at environment setup. The docs search index
went unrefreshed for roughly three months without surfacing anywhere.

It now generates from sync-docs.yml.genie.ts on the shared devenv/nix setup
like every other workflow, and calls the docs:search:sync:* devenv tasks
instead of invoking the Mixedbread CLI inline.

Target selection becomes two gated jobs rather than a shell branch: the old
single-step form fell back to a legacy store id whenever its target's secret
was unset, which is how the prod path ended up writing the dev store. Each
task now requires its own store id, so a missing secret fails loudly instead
of silently retargeting.

The MXBAI_VECTOR_STORE_ID_DEV and _PROD secrets the workflow had always
referenced did not exist until now; both surfaces read one store as a result.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f
@schickling-assistant schickling-assistant added ci:deploy-docs Trigger docs deployment for fork PRs · Set: manual area:ci CI workflows, runners, and pipeline configuration · Set: manual type:bug Something broken or a regression · Set: manual labels Jul 27, 2026
schickling-assistant added a commit that referenced this pull request Jul 27, 2026
The workflow fix ships as #1507 so a three-month
production defect is not gated on review of the state-backend design. Records
that main still passes the legacy store id to the production sync until that
merges.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f
@schickling
schickling marked this pull request as ready for review July 27, 2026 11:49
@schickling
schickling self-requested a review as a code owner July 27, 2026 11:49
@schickling
schickling enabled auto-merge (squash) July 27, 2026 11:49
@schickling
schickling merged commit ea71443 into main Jul 27, 2026
33 checks passed
@schickling
schickling deleted the schickling-assistant/2026-07-27-docs-search-repair branch July 27, 2026 11:49
schickling-assistant added a commit that referenced this pull request Jul 27, 2026
The workflow fix ships as #1507 so a three-month
production defect is not gated on review of the state-backend design. Records
that main still passes the legacy store id to the production sync until that
merges.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1a84b5e847

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +4 to +6
* Each docs surface owns its own Mixedbread vector store (LS.DOCS.SEARCH-R03),
* so a reader only ever gets hits for pages the surface they are on actually
* serves: `dev` tracks `main`, `prod` tracks the published stable release.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Define R03 in the owning intent node

This establishes a new two-store contract and cites LS.DOCS.SEARCH-R03, but the reviewed tree's context/04-docs/02-search/requirements.md ends at R02 and its spec does not define the per-surface invariant. Add R03 and update the owning search spec in this change so the intent layer remains the source of truth rather than leaving an unresolved requirement reference in executable configuration.

AGENTS.md reference: AGENTS.md:L9-L12

Useful? React with 👍 / 👎.

Comment on lines 283 to 286
"docs:search:sync:prod" = {
description = "Sync prod Mixedbread vector store from docs Markdown sources";
exec = ''
set -euo pipefail
: "''${MXBAI_API_KEY:?Missing MXBAI_API_KEY secret}"
: "''${MXBAI_VECTOR_STORE_ID:?Missing MXBAI_VECTOR_STORE_ID secret}"
timeout --signal=TERM --kill-after=1m 10m \
pnpm --dir docs exec mxbai store sync "$MXBAI_VECTOR_STORE_ID" \
"./src/content/**/*.mdx" \
"./src/content/**/*.md" \
--yes --strategy fast
'';
exec = docsSearchSync "MXBAI_VECTOR_STORE_ID_PROD";
after = [ "pnpm:install" ];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Retarget the existing production sync script

When a maintainer runs the existing pnpm --dir docs prod:docs:sync, docs/package.json:16 and its generator still pass the literal livestore-docs, bypassing the new _PROD store ID used here. The local mxbai store sync --help describes this argument as name-or-id, so this exposed command can update the legacy/different store while leaving the production index stale; remove it or route it through docs:search:sync:prod.

Useful? React with 👍 / 👎.

* so a reader only ever gets hits for pages the surface they are on actually
* serves: `dev` tracks `main`, `prod` tracks the published stable release.
*
* This workflow was the repo's last hand-written one, and drifted for exactly

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Update the workflow editing instructions

After converting this workflow to generated YAML, .github/workflows/README.md:3-5 still explicitly says that sync-docs.yml is handwritten. A contributor following that repository documentation will edit the generated YAML directly and have the change overwritten by Genie; update the README to identify sync-docs.yml.genie.ts as the source.

Useful? React with 👍 / 👎.

@github-actions

Copy link
Copy Markdown
Contributor

PR preview

Subject Status Report Details Updated
LiveStore docs preview success Docs preview deployed (livestore-docs-dev) PR aliases: pr-1507-55585b9, pr-1507 2026-07-27 11:57 UTC
web-linearlite success web-linearlite deployed (preview) Worker: example-web-linearlite-preview.livestore.workers.dev 2026-07-27 11:46 UTC
web-todomvc success web-todomvc deployed (preview) Worker: example-web-todomvc-preview.livestore.workers.dev 2026-07-27 11:46 UTC
web-todomvc-script success web-todomvc-script deployed (preview) Worker: example-web-todomvc-script-preview.livestore.workers.dev 2026-07-27 11:46 UTC
web-todomvc-sync-cf success web-todomvc-sync-cf deployed (preview) Worker: example-web-todomvc-sync-cf-preview.livestore.workers.dev 2026-07-27 11:46 UTC
Report history

PR 1507 · 2026-07-27 12:03 UTC

Subject Status Report Details Updated
LiveStore docs preview success Docs preview deployed (livestore-docs-dev) PR aliases: pr-1507-55585b9, pr-1507 2026-07-27 11:57 UTC
web-linearlite success web-linearlite deployed (preview) Worker: example-web-linearlite-preview.livestore.workers.dev 2026-07-27 11:46 UTC
web-todomvc success web-todomvc deployed (preview) Worker: example-web-todomvc-preview.livestore.workers.dev 2026-07-27 11:46 UTC
web-todomvc-script success web-todomvc-script deployed (preview) Worker: example-web-todomvc-script-preview.livestore.workers.dev 2026-07-27 11:46 UTC
web-todomvc-sync-cf success web-todomvc-sync-cf deployed (preview) Worker: example-web-todomvc-sync-cf-preview.livestore.workers.dev 2026-07-27 11:46 UTC

schickling-assistant added a commit that referenced this pull request Jul 27, 2026
The workflow fix ships as #1507 so a three-month
production defect is not gated on review of the state-backend design. Records
that main still passes the legacy store id to the production sync until that
merges.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f
schickling-assistant added a commit that referenced this pull request Jul 27, 2026
main #1507 gave each docs surface its own search index, so the prod docs sync
takes MXBAI_VECTOR_STORE_ID_PROD rather than MXBAI_VECTOR_STORE_ID. Updating the
one declaration moves both the release step's env block and the health probe,
which is the point of declaring surfaces once.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
schickling pushed a commit that referenced this pull request Jul 28, 2026
#1244) (#1330)

* feat(infra): own livestore-docs Netlify runtime env via OpenTofu (seeds #1244)

Re-home the livestore-docs Netlify env-var IaC into this repo under
`.infra/iac/netlify/` with OpenTofu, adopting the two already-live env vars
(`MXBAI_API_KEY`, `MXBAI_VECTOR_STORE_ID`) via `tofu import` so the config owns
them with zero recreation. `tofu plan` reports `No changes`.

Scope is env vars only: the site is referenced by literal `site_id`/`team_id`
(no `netlify_site` resource / data source), so OpenTofu can never mutate the
site, build settings, or deploys.

State backend: this repo is public and state holds the API key value, so state
is committed only as ciphertext via OpenTofu native state encryption
(PBKDF2/AES-GCM, `enforced = true`; passphrase in 1Password, injected at
runtime). The intended Cloudflare R2 `backend "s3"` is blocked — R2 is not
enabled on the LiveStore CF account (API code 10042, dashboard-only) — so native
encryption is the sanctioned fallback; `versions.tf` documents the R2 migration.

`MXBAI_API_KEY` declares `lifecycle { ignore_changes = [secret_values] }`
because the Netlify API treats secret values as write-only (never returned on
read/import), which would otherwise force a perpetual cosmetic diff.

Adds `dt infra:netlify:plan` / `dt infra:netlify:apply` tasks that inject
secrets via op-proxy/1Password (or env in CI) and run OpenTofu.

Seeds #1244 (LiveStore public domains -> Cloudflare-managed IaC single desired
state) by establishing the OpenTofu state + encryption + provider conventions.
Refs #1329.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
agent-session-id: c5481079-88d4-4406-b2bf-d31ff5588e67
agent-tool: Claude Code
agent-tool-version: 2.1.165
agent-model: claude-opus-4-8
agent-runtime-profile: /nix/store/ffppqrb9xkq0jamayzc05dwlm86yi5yk-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/f4bp1wnsfzypdxckkp0vyqcgw5xq4yp1-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b39be89

* Give infrastructure a VRS home and record the Netlify IaC tradeoffs

Adds context/03-delivery/04-infrastructure (LS.DEL.INFRA-*): declared
infrastructure, no recoverable secrets in-repo, 1Password as the single
credential source, adoption over recreation, org-owned accounts.

The requirements state the target, so this PR's own compromises are tracked
as deltas rather than written down to what the code happens to do:
DELTA-001 (state committed as ciphertext to a public repo, blocked on R2)
and DELTA-002 (hosting, DNS, CI runners and examples are undeclared).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f

* Correct the write-only claim in the Netlify IaC decision record

Observed 2026-07-27: a secret Netlify env var returns its `dev` context in
plaintext while other contexts are masked. Masking-on-read is what makes the
value non-round-trippable, not a write-only guarantee.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f

* Record the adoption-safety precondition in DELTA-001

Import writes non-secret values into state verbatim, so a credential a
provider holds as ordinary configuration must be moved to that provider's
secret mechanism before adoption, not after. Also drops an over-specific
observation from the decision record; the consequence is what matters.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f

* Record that docs search is stale and the two surfaces are crossed

Observed 2026-07-27: one vector store exists, named for development, last
updated 2026-04-27 with 31 content files changed since. Both docs surfaces
read it, sync-docs.yml has failed at Setup pnpm on every push for ~3 months,
and MXBAI_VECTOR_STORE_ID_PROD names no existing store.

The dev/prod search split exists only in the write path: no surface reads a
store its own sync path writes. Adopting this into declared state before
repairing it would freeze the crossed wiring.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f

* Replace the state-secrecy delta with the verified rule and its trigger

Decrypting the committed state on 2026-07-27 showed both imported resources
carry no secret material; the only value present is the non-secret vector
store id, already a literal in variables.tf. LS.DEL.INFRA-R02 is satisfied, so
DELTA-001 recorded a divergence that does not exist and is removed.

What replaces it is the rule it was groping at: state carries no secret, and
remote state is required *before* the first secret-bearing resource is
declared, not after — afterwards the commit is already permanent. R2's
account-level enablement constraint moves to .reference/ so #1244 inherits it,
including the ordering hazard that its own Cloudflare work would both trip the
trigger and provide the bucket.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f

* Require the provider secret mechanism, and one index per surface

LS.DEL.INFRA-R06: a credential in a provider surface uses that provider's
secret facility, never ordinary configuration — plain config leaks into build
logs and read APIs, and is unsafe to adopt into declared state.

LS.DOCS.SEARCH-R03: a docs surface serves the index its own sync path writes.
Measured 2026-07-27: 24 of 101 content files differ between v0.4.0 and main,
so a shared index leaves one surface wrong about a quarter of the docs
whichever way it syncs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f

* Point the Netlify IaC at the production store and correct its docs

The production surface now has its own vector store, so the declared value
moves to it and the config states that the dev surface is deliberately not
managed here.

Corrects two claims the evidence contradicts. State does not hold the API key:
the resource is adopt-only, and decrypting the committed state shows the only
value present is the non-secret store id. And rotation does not run through
OpenTofu — applying one would write the key into permanently public history;
1Password is canonical.

R2 is reframed from a blocker to a trigger: state must leave the repo before
the first secret-bearing resource is declared, not on a schedule.

tofu plan reports No changes against the corrected wiring.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f

* Record Netlify env-var behaviour and the applied search remediation

Netlify returns a secret variable's dev-context value in plaintext while
masking the others, reproduced on both docs sites — so the dev context is not
a safe place for a credential, and masking only guarantees a value cannot be
round-tripped. Non-secret values are returned verbatim, which is the concrete
reason behind LS.DEL.INFRA-R06.

Also corrects the search delta: its staleness claim rested on the store's
updated_at, which tracks metadata rather than file operations. The failing
sync runs are the real evidence.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f

* Attribute the sync-docs repair to its own PR

The workflow fix ships as #1507 so a three-month
production defect is not gated on review of the state-backend design. Records
that main still passes the legacy store id to the production sync until that
merges.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f

* Narrow the search delta to what is still unproven

Both surfaces now return results from their own store. What remains is that
the production sync path has never run successfully — the production store was
populated by hand — and that a failing sync still surfaces nowhere, which is
why the original bug survived three months.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f

* Restore the string terminator lost in the merge resolution

Resolving the mono-wrappers.nix conflict by stripping markers dropped the
closing '' of docsSearchSync, so the IaC preamble's opening '' terminated it
instead and the shell body parsed as Nix. Caught by check:quick.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f

* Govern both docs surfaces and check drift automatically

Extends the declaration from one site to both, keyed by surface, so the dev
site's env vars stop being undeclared. Adopting it is only safe now because its
API key was moved from plain configuration to Netlify's secret mechanism first
(LS.DEL.INFRA-R06) — importing it beforehand would have written a live
credential into state.

Adds infra:netlify:drift-check and a scheduled workflow that runs it. A
declaration nobody checks is documentation, not a control: nothing in the repo
ran plan, so drift was undetectable by design.

Proven end to end against the live account: import, plan reported real drift
(the dev store-id variable carried an undeclared post-processing scope), apply
converged it, and plan is clean. State still contains no secret after that
apply.

Also widens the ignore rules — `tofu state mv` writes
`terraform.tfstate.<ts>.backup`, which `*.tfstate.backup` did not match, so
those files sat untracked and one commit away from being added.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f

* Adopt livestore.dev DNS records and docs domain settings

Extends the declaration from environment variables to the rest of what this
Netlify account actually governs: the eleven hand-authored records in the
livestore.dev zone, plus the custom domains of the two docs surfaces. Seventeen
resources, all adopted by import, plan reports No changes.

Scope is deliberately the hand-authored records only. The zone also holds
NETLIFY-type records that Netlify creates and owns from each site's domain
settings; the provider cannot express that type at all, so they are governed
through netlify_site_domain_settings rather than declared directly. There is no
netlify_dns_zone resource either — the zone is referenced by literal id so
OpenTofu can never create, replace, or delete it.

Most of these records serve a live Clerk instance with no consumer anywhere in
this repository. They are declared because they are load-bearing, not because
their purpose is understood.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f

* Adopt the orphaned example domain claims

The web-todomvc-custom-elements example was removed from the repository, but
its two Netlify sites kept their livestore.dev domain claims, and a claim is
what makes Netlify publish the matching zone record. Adopted at current values
so the adoption changes nothing; releasing them is a separate diff.

This config owns the livestore.dev namespace, so a hostname under it is in
scope wherever it is driven from. An unowned claim is how the namespace
drifted in the first place.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f

* Release the orphaned livestore.dev hostnames

Both custom-elements domain claims are released and Netlify withdrew the
records it had published for them; the record that had outlived its site claim
is deleted. Zero orphaned hostnames remain in the zone.

The release could not be expressed in the config. The provider cannot say "no
custom domain" — null is silently omitted and an empty string is rejected with
`Name is blank` — so it went through the Netlify API, and the config now
asserts the absence by declaring the resources without a domain. That keeps the
absence checked rather than merely achieved.

Chasing this surfaced two provider gaps worth recording rather than
rediscovering: a desired state the provider cannot reach would leave the
scheduled drift check permanently red, and NETLIFY-type records cannot be
declared at all, so a record orphaned from its claim is invisible to drift
detection.

Records LS.DEL.INFRA-DQ2: ten of the eleven hand-authored records serve a live
Clerk instance with no consumer anywhere in this repository.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f

* Register the LS.DEL.INFRA namespace in the intent-layer ID table

The intent-layer test requires every ID namespace defined under context/ to
appear in the spec.md table that maps namespaces to owning directories. Adding
the infrastructure node introduced nine LS.DEL.INFRA-* ids without registering
the namespace, so test-unit failed with nine violations.

Worth noting for next time: check:quick does not run tests — its description
ends "without tests" — so this class of failure is invisible locally unless
test:unit or check:all is run.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f

* Address review: reconcile scope docs, and see through the ignored attribute

Two review findings, both correct.

The canonical documents still described an env-vars-only blast radius after DNS
records and site domain settings were added, so an operator reading them would
have underestimated what infra:netlify:apply can modify. The decision record,
env.tf, README, and DELTA-002 now describe the real scope. The prod-safety
claim is restated as what it actually is: resources are declared, containers
are not — no site resource, no zone resource, no data sources — so destroying a
container is not expressible.

`ignore_changes = [secret_values]` suppresses the entire attribute, not only
the write-only values, so the context entries stopped being compared too.
Verified by deleting a live context: `tofu plan` reported `No changes`, while
docs search would have broken on the next build. The drift task now asserts the
ignored shape against the provider API after planning — still a secret, with
the expected scopes and contexts, on both surfaces. Confirmed it fails on that
injected drift and passes once restored. Only the values remain unverifiable,
which is inherent to write-only.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
agent-session-id: 05bdf052-d9c2-4930-bfef-1fd90b43680b
agent-tool: Claude Code
agent-tool-version: 2.1.220
agent-model: claude-opus-5
agent-runtime-profile: /nix/store/57hz15fbcg9c3hasm0ny3axd5pg33rh3-coding-agent-runtime-profile/share/coding-agents/profile.json
agent-skills-manifest: /nix/store/d9hvhhg1k9n3j20dgcch7sz3sg98l377-agent-skills-corpus/share/agent-skills/manifest.json
tooling-profile: dotfiles@b785b9f

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:ci CI workflows, runners, and pipeline configuration · Set: manual ci:deploy-docs Trigger docs deployment for fork PRs · Set: manual type:bug Something broken or a regression · Set: manual

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants