Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
2596381
Add dedicated D1 backup control plane
cursoragent Jul 22, 2026
1133ff5
Add disaster recovery operator tooling
cursoragent Jul 22, 2026
b0f72ce
Document production disaster recovery operations
cursoragent Jul 22, 2026
d614702
Harden backup retry and crash recovery
cursoragent Jul 22, 2026
12fe077
Harden restore and readiness evidence
cursoragent Jul 22, 2026
bccde22
Make backup retries and evidence expiry recoverable
cursoragent Jul 22, 2026
0abdb4e
Fix backup permissions and streamed restore checks
cursoragent Jul 22, 2026
aa60720
Make D1 backup capture resumable and size-bounded
cursoragent Jul 22, 2026
eaf3e29
Use supported D1 restore verification and config
cursoragent Jul 22, 2026
92fecc3
Require signed disaster recovery readiness evidence
cursoragent Jul 22, 2026
fdc6278
Assert backup size failure observability
cursoragent Jul 22, 2026
915cf1e
Enforce strict backup object size limits
cursoragent Jul 22, 2026
b9b5666
Pin trusted D1 restore identities
cursoragent Jul 22, 2026
a540076
Split signed readiness validation modules
cursoragent Jul 22, 2026
198c21e
Verify resumed backup objects against signed exports
cursoragent Jul 22, 2026
7abc5fb
Bind restore evidence to isolated destination identity
cursoragent Jul 22, 2026
6155496
Cover case-insensitive restore identity isolation
cursoragent Jul 22, 2026
62d2481
Prove restore isolation across signed evidence
cursoragent Jul 22, 2026
02ef093
Reverify manifest-less objects before canonicalization
cursoragent Jul 22, 2026
ff5f4c5
Finalize verified source and manifest atomically
cursoragent Jul 22, 2026
c78ac21
Split backup control plane tests by module
cursoragent Jul 22, 2026
bf3df6a
Require canonical Cloudflare readiness account IDs
cursoragent Jul 22, 2026
d13226c
Address final AI review feedback
cursoragent Jul 23, 2026
f94187c
Normalize numeric restore isolation IDs
cursoragent Jul 23, 2026
1bb6939
Align freshness day with backup schedule
cursoragent Jul 23, 2026
058f744
Canonicalize restore trust account IDs
cursoragent Jul 23, 2026
c061980
Refresh signed export URLs during finalization
cursoragent Jul 23, 2026
cc26594
Fix CLI entrypoints and Cloudflare ID casing
cursoragent Jul 23, 2026
eb5af86
Preserve effective backup retention policies
cursoragent Jul 23, 2026
227987f
Harden backup recovery retries
cursoragent Jul 23, 2026
ef0c1c1
Document remaining DR enablement blockers
cursoragent Jul 23, 2026
4f90fca
Address final CI review findings
cursoragent Jul 23, 2026
cad6f89
Fix strict manifest test fixtures
cursoragent Jul 23, 2026
883eaea
Run freshness and catch-up independently
cursoragent Jul 23, 2026
38d861a
Harden cross-platform restore evidence tooling
cursoragent Jul 23, 2026
85c740d
Add signed backup provenance and trusted baselines
cursoragent Jul 23, 2026
60a3945
Close restore provenance TOCTOU gaps
cursoragent Jul 23, 2026
bc93678
Bind readiness baselines to source identity
cursoragent Jul 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions docs/contributing/architecture/primitives.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,20 @@ primitives:
docs:
- docs/contributing/architecture/data-storage.md

- id: backup-control-plane
group: storage
name: Production backup control plane
summary:
Dedicated scheduled D1 export, immutable R2 retention, isolated restore
drills, and cross-store recovery readiness contracts.
code:
- packages/backup-control-plane/
- tools/ci/backup-
- tools/disaster-recovery/
docs:
- docs/contributing/disaster-recovery.md
- docs/contributing/setup-manifest.md

- id: artifacts-repos
group: storage
name: Artifacts repos
Expand Down
1,209 changes: 1,209 additions & 0 deletions docs/contributing/disaster-recovery.md

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions docs/contributing/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,15 @@ Optional Worker secrets/vars (see `packages/worker/src/env-schema.ts` and
as `session_repo_namespace` so follow-up lookups resolve the correct namespace
even after env changes.

## Backup manifest signing

The separately deployed backup Worker uses non-secret
`BACKUP_MANIFEST_SIGNING_KEY_ID`, `TRUSTED_RESTORE_BASELINE_ID`, and
`TRUSTED_RESTORE_BASELINE_SHA256` vars. Its
`BACKUP_MANIFEST_SIGNING_PRIVATE_KEY_PKCS8_BASE64` value is a secret containing
only base64-encoded Ed25519 PKCS#8 private-key bytes. Configure it with Wrangler
secret storage, never in a `.env`, checked config, log, or evidence artifact.

## Why Zod?

Zod gives type inference for `Env`-driven values and a single runtime gate that
Expand Down
1 change: 1 addition & 0 deletions docs/contributing/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ style, tests, MCP kody, and runtime architecture.
[testing](./testing-principles.md)
- [Package discovery routing evaluation](./package-discovery-evaluation.md)
- [Cursor Cloud Agent notes](./cloud-agents.md)
- [Production backup and disaster recovery](./disaster-recovery.md)
- [Remix skills and page checklist](./remix.md), [frames](./frames.md)
- [Packages and manifests](./packages-and-manifests.md)
- [Community packages](./community-packages.md)
Expand Down
41 changes: 41 additions & 0 deletions docs/contributing/setup-manifest.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,47 @@ before migrations and deploy. Preview deploys do the same per preview worker via
resources from bindings alone, so the deploy workflow runs
`node tools/ci/production-resources.ts ensure` first.

### Disaster-recovery control plane

Production backups use a separate deployment and are not provisioned or deployed
by the application workflow above. The dedicated Worker and Workflow live under
`packages/backup-control-plane/` in an independently administered DR Cloudflare
account. Its `BACKUP_BUCKET` R2 binding is private and uses immutable `daily/`
and `weekly/` prefixes.
Comment on lines +81 to +85

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Document the required public-access check.

A private BACKUP_BUCKET Worker binding does not prove that the R2 bucket has no r2.dev or custom-domain exposure. The runbook explicitly says the provisioner does not manage those APIs, so add the post-provisioning verification here or link to it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/contributing/setup-manifest.md` around lines 81 - 85, Update the
production backup documentation near the BACKUP_BUCKET description to add or
link to a post-provisioning check confirming the R2 bucket has no public r2.dev
endpoint or custom-domain exposure. Keep the existing private-binding and
provisioner-scope details, and identify the verification procedure clearly for
operators.


The retention administrator uses a separate provisioner token to create the
bucket and apply 35-day daily and 400-day weekly lock/lifecycle rules:

```sh
node tools/ci/backup-resources-cli.ts plan \
--source-account-id "<PRODUCTION_ACCOUNT_ID>" \
--destination-account-id "<DR_ACCOUNT_ID>" \
--source-d1 "<PRODUCTION_D1_UUID>:kody" \
--deny-production-resource kody-email-blobs \
--deny-production-resource kody-community-assets
```
Comment on lines +90 to +97

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Finding relevant files..."
git ls-files | rg '(^docs/contributing/setup-manifest\.md$|^docs/.*/disaster-recovery\.md$|backup-resources-cli\.ts$|disaster-recovery\.md$)' || true

echo
echo "Relevant snippet in setup-manifest.md:"
sed -n '70,125p' docs/contributing/setup-manifest.md || true

echo
echo "Search for backup-resources-cli usages and docs:"
rg -n "backup-resources-cli|backup-resources|source-d1|destination-account-id|bucket-name|worker-name|provisioner|provide.*token" docs disaster-recovery setup-manifest tools packages 2>/dev/null || true

Repository: kentcdodds/kody

Length of output: 50372


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "setup-manifest relevant section:"
sed -n '1,150p' docs/contributing/setup-manifest.md | nl -ba | sed -n '70,130p'

echo
echo "Exact relevant flag usages in tracked text files (narrow):"
rg -n --glob '!*.{min.js,js.map,tsbuildinfo,min.css}' --glob '*.md' --glob '*.ts' --glob '*.tsx' \
  "backup-resources-cli|backup-resources|plan.*--bucket-name|plan.*--worker-name|supplying|provisioner|PROVISION|token" \
  docs disaster-recovery README packages tools 2>/dev/null || true

echo
echo "Locate backup-resources-cli implementation:"
fd -a 'backup-resources-cli\.ts$' . 2>/dev/null || true

Repository: kentcdodds/kody

Length of output: 226


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "setup-manifest relevant section:"
sed -n '70,130p' docs/contributing/setup-manifest.md

echo
echo "backup CLI related occurrences in repository text files:"
rg -n --glob '!*.{min.js,js.map,tsbuildinfo,min.css}' --glob '*.md' --glob '*.ts' --glob '*.tsx' \
  "backup-resources-cli|backup-resources|\\-\\-bucket-name|\\-\\-worker-name|provisioner|PROVISION|plan" \
  docs packages tools disaster-recovery 2>/dev/null || true

echo
echo "Locate backup-resources-cli implementation:"
fd -a 'backup-resources-cli\.ts$' . 2>/dev/null || find . -name 'backup-resources-cli.ts' -print

Repository: kentcdodds/kody

Length of output: 50374


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "tools/ci/backup-resources-cli.ts argument parsing:"
sed -n '1,170p' tools/ci/backup-resources-cli.ts

echo
echo "tools/ci/backup-resources.ts resource construction relevant sections:"
sed -n '1,160p' tools/ci/backup-resources.ts
sed -n '480,550p' tools/ci/backup-resources.ts

echo
echo "disaster-recovery canonical example around plan/apply:"
sed -n '240,290p' docs/contributing/disaster-recovery.md

echo
echo "backup control plane wrangler constants for bucket/worker if present:"
rg -n "DR_R2_PROVISIONER_TOKEN|BACKUP_BUCKET|backup-resources-cli|kody-production-d1-backups|bucket-name|worker-name" packages/backup-control-plane docs/contributing/disaster-recovery.md tools/ci -g '!*.{min.js,js.map,tsbuildinfo}' || true

Repository: kentcdodds/kody

Length of output: 16672


Copy the canonical backup resources example.

The setup-manifest snippet omits the provisioner token source plus the explicit --bucket-name and --worker-name used by the operator. Add the same full command shown in disaster-recovery.md or link directly to it so the plan cannot be copied as runnable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/contributing/setup-manifest.md` around lines 90 - 97, Update the
backup-resources CLI example in setup-manifest.md to match the canonical command
in disaster-recovery.md, including the provisioner token source, explicit
--bucket-name, and --worker-name options; alternatively replace the snippet with
a direct link to that canonical example.


`apply` is an explicit mutation and must be run only after reviewing the plan.
The runtime receives a source-account token with Cloudflare Account D1 Edit as
the `CLOUDFLARE_API_TOKEN` Worker secret. Cloudflare grants this permission
account-wide and it can mutate D1; the runtime's application UUID/name allowlist
reduces operator mistakes but does not technically scope the token to one
database or make it read-only. Keep this source runtime token separate from the
destination R2 provisioning/lock-administration token and drill restore
credentials. The runtime must not receive either of those credentials or R2
bucket, lock, lifecycle, or public-access administration permissions. Scheduling
remains inert until the blocking-export benchmark is approved and both enable
variables are exactly `true`. See [Disaster recovery](./disaster-recovery.md)
for deployment, readiness, drill, credential, and exclusion details.

The backup deployment also requires reviewed non-secret
`BACKUP_MANIFEST_SIGNING_KEY_ID`, `TRUSTED_RESTORE_BASELINE_ID`, and
`TRUSTED_RESTORE_BASELINE_SHA256` vars. Store the matching base64-encoded
Ed25519 PKCS#8 private key only as the
`BACKUP_MANIFEST_SIGNING_PRIVATE_KEY_PKCS8_BASE64` Worker secret. Never commit
Comment on lines +112 to +116

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the sentence grammar.

Change “requires reviewed non-secret” to “requires the following reviewed non-secret” (or “requires review of the following non-secret”).

🧰 Tools
🪛 LanguageTool

[style] ~112-~112: The double modal “requires reviewed” is nonstandard (only accepted in certain dialects). Consider “to be reviewed”.
Context: ...s. The backup deployment also requires reviewed non-secret `BACKUP_MANIFEST_SIGNING_KEY...

(NEEDS_FIXED)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/contributing/setup-manifest.md` around lines 112 - 116, Update the
backup deployment sentence in the setup manifest to replace “requires reviewed
non-secret” with “requires the following reviewed non-secret” before listing the
variables, preserving the remainder of the key and secret guidance.

Source: Linters/SAST tools

that private key. Restore trusts only the checked-in manifest public-key,
production-identity, and restore-baseline registries.

## Optional Cloudflare offerings

The default footprint stays intentionally small. If you want to add additional
Expand Down
18 changes: 18 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
"build:client:web": "esbuild packages/worker/client/entry.tsx --bundle --format=esm --target=es2022 --outdir=packages/worker/public --entry-names=client-entry --chunk-names=assets/[name] --asset-names=assets/[name] --jsx=automatic --jsx-import-source=remix/ui --minify",
"build:client": "npm run build:client:web",
"build": "nx run worker:build",
"backup:build": "wrangler deploy --dry-run --config packages/backup-control-plane/wrangler.jsonc",
"backup:readiness": "node tools/disaster-recovery/canonical-readiness-cli.ts",
"backup:resources": "node tools/ci/backup-resources-cli.ts",
"backup:restore-drill": "node tools/disaster-recovery/d1-restore-drill-cli.ts",
"lint": "oxlint .",
"lint:fix": "oxlint . --fix",
"format": "oxfmt",
Expand All @@ -44,11 +48,11 @@
"preview": "nx run worker:build-client && npm run migrate:local && node --env-file=packages/worker/.env ./wrangler-env.ts dev --local",
"preview:e2e": "node --env-file=packages/worker/.env tools/prepare-e2e-env.ts && nx run worker:build-client && npm run migrate:e2e && node --env-file=packages/worker/.env ./wrangler-env.ts dev --local --persist-to .wrangler/state/e2e",
"generate-types": "node --env-file=packages/worker/.env ./wrangler-env.ts types ./packages/worker/worker-configuration.d.ts",
"typecheck": "nx run worker:typecheck",
"typecheck": "nx run worker:typecheck && tsc --noEmit -p packages/backup-control-plane/tsconfig.json",
"test": "nx run worker:test",
"test:push": "npm run test && npm run test:e2e:run",
"inspect": "npx -y @mcpjam/inspector inspector",
"validate": "concurrently -n format,lint,typecheck,test,e2e,mcp,primitives,migrations -c green,yellow,magenta,blue,cyan,red,white,gray \"npm run format:check\" \"npm run lint\" \"npm run typecheck\" \"npm run test\" \"npm run test:e2e:run\" \"npm run test:mcp\" \"npm run primitives:check\" \"npm run migrations:check\"",
"validate": "concurrently -n format,lint,typecheck,test,e2e,mcp,backup-build,primitives,migrations -c green,yellow,magenta,blue,cyan,red,blueBright,white,gray \"npm run format:check\" \"npm run lint\" \"npm run typecheck\" \"npm run test\" \"npm run test:e2e:run\" \"npm run test:mcp\" \"npm run backup:build\" \"npm run primitives:check\" \"npm run migrations:check\"",
Comment on lines +51 to +55

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -t f 'nx.json'
fd -t f 'project.json' packages/backup-control-plane packages/worker 2>/dev/null
cat packages/backup-control-plane/package.json 2>/dev/null
cat packages/backup-control-plane/vitest.config.ts 2>/dev/null
fd -t f -e yml -e yaml . .github/workflows 2>/dev/null --exec sh -c 'echo "== {} =="; cat {}'
rg -n 'backup-control-plane|disaster-recovery|node\.test' package.json nx.json 2>/dev/null

Repository: kentcdodds/kody

Length of output: 44530


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
fd -t f 'package.json|project.json|nx.json|vitest.config.ts|vitest.config.*|tsconfig.json|tsconfig.*' \
  packages/worker packages/backup-control-plane tools/disaster-recovery 2>/dev/null || true

echo
echo "== package.json scripts =="
node - <<'JS'
const fs = require('node:fs');
const p = JSON.parse(fs.readFileSync('package.json','utf8'));
for (const [k,v] of Object.entries(p.scripts || {})) {
  if (/^(test|typecheck|backup|validate|migrations|primitives)|backup|disaster-recovery/.test(k)) {
    console.log(`${k}: ${v}`);
  }
}
JS

echo
echo "== nx/workspace refs =="
rg -n '"workspace|apps|projects|implicitDeps|targetDefaults|backup-control-plane|worker:test|backup-control-plane:test|test":' package.json nx.json packages packages/backup-control-plane/project.json packages/worker/project.json 2>/dev/null || true

echo
echo "== disaster-recovery config/package files =="
fd -t f -e ts . tools/disaster-recovery 2>/dev/null --exec sh -c 'echo "-- {} --"; wc -l "{}"; sed -n "1,220p" "{}"'

Repository: kentcdodds/kody

Length of output: 50371


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== scripts of interest =="
sed -n '1,140p' package.json

echo
echo "== project files =="
for f in nx.json packages/worker/project.json packages/backup-control-plane/project.json; do
  echo "--- $f ---"
  sed -n '1,220p' "$f"
done

echo
echo "== validate workflow direct call =="
sed -n '1,130p' .github/workflows/validate.yml

echo
echo "== exact references to backup-control-plane and worker:test =="
rg -n 'backup-control-plane|worker:test|backup-control-plane:test|validate:|concurrently|npm run validate|test":' package.json package-lock.json .github/workflows packages . -g '!node_modules' -g '!dist' -g '!build' 2>/dev/null | sed -n '1,260p'

Repository: kentcdodds/kody

Length of output: 10625


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== worker/project vitest config files =="
fd -t f 'vitest.config.*|vite.config.*|package.json|project.json' packages/worker -x sh -c 'echo "--- $1 ---"; sed -n "1,220p" "$1"' sh {}

echo
echo "== backup-control-plane project/package/vitest files =="
fd -t f 'vitest.config.*|vite.config.*|package.json|project.json' packages/backup-control-plane -x sh -c 'echo "--- $1 ---"; sed -n "1,220p" "$1"' sh {}

echo
echo "== disaster-recovery test/vitest files only =="
fd -t f -i 'vitest.config.*|*.test.ts|*.spec.ts' tools/disaster-recovery packages/backup-control-plane 2>/dev/null -x sh -c 'echo "--- $1 ---"; sed -n "1,220p" "$1"' sh {}

echo
echo "== precise validate script decomposition =="
python3 - <<'PY'
import json
with open('package.json') as f:
    p=json.load(f)
scripts=[]
names=[]
for cmd in p['scripts']['validate'].split('" "',):
    s=cmd.strip('"')
    cmd=s.split(' ')[-1].split(' ')[0]
    scripts.append(cmd)
    names.append(s.split(' ')[-1].replace('npm run ','').replace('\"',''))
print('\n'.join(f'{k}: {v}' for k,v in zip(names, scripts)))
print('validate_names_count=', len(names))
print('validate_script_count=', len(scripts))
PY

Repository: kentcdodds/kody

Length of output: 5577


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== all top-level vitest config files =="
fd -t f 'vitest.config.*' . -maxdepth 2 -x sh -c 'echo "--- $1 ---"; sed -n "1,260p" "$1"' sh {}

echo
echo "== packages containing vitest project declarations or configs =="
rg -n 'node-unit|workers-unit|mcp-e2e|defineConfig|projects:' packages -g '*vitest*' -g '*test*' -g '!node_modules' | sed -n '1,320p'

echo
echo "== disaster-recovery test files without project config text =="
fd -t f -i '.*\.node\.test\.ts|.*\.node\.spec\.ts|vitest.*config.*' tools/disaster-recovery packages/backup-control-plane 2>/dev/null -x sh -c 'echo "--- $1 ---"; wc -l "$1"; sed -n "1,160p" "$1"' sh {}

echo
echo "== exact validate invocation in CI =="
sed -n '1,130p' .github/workflows/validate.yml 2>/dev/null || true

Repository: kentcdodds/kody

Length of output: 354


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== all top-level vitest config files =="
fd 'vitest.config\.' . -maxdepth 2 -x sh -c 'echo "--- $1 ---"; sed -n "1,260p" "$1"' sh {}

echo
echo "== packages containing vitest project declarations or configs =="
rg -n 'node-unit|workers-unit|mcp-e2e|defineConfig|projects:' packages -g '*vitest*' -g '*test*' -g '!node_modules' | sed -n '1,320p'

echo
echo "== disaster-recovery test files without project config text =="
fd '.*\.node\.test\.ts|.*\.node\.spec\.ts|vitest.*config.*' tools/disaster-recovery packages/backup-control-plane 2>/dev/null -x sh -c 'echo "--- $1 ---"; wc -l "$1"; sed -n "1,160p" "$1"' sh {}

echo
echo "== exact validate invocation in CI =="
sed -n '1,130p' .github/workflows/validate.yml 2>/dev/null || true

Repository: kentcdodds/kody

Length of output: 354


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== all top-level vitest config files =="
find . -maxdepth 2 -type f -path '*vitest.config.*' -print -exec sh -c 'echo "--- $1 ---"; sed -n "1,260p" "$1"' sh {} \;

echo
echo "== packages containing vitest project declarations or configs =="
rg -n 'node-unit|workers-unit|mcp-e2e|defineConfig|projects:' packages -g '*vitest*' -g '*test*' -g '!node_modules' | sed -n '1,320p'

echo
echo "== disaster-recovery test files with simple names =="
find tools/disaster-recovery -type f \( -name '*.node.test.ts' -o -name '*.node.spec.ts' -path '*vitest*' \) -print -exec sh -c 'echo "--- $1"; wc -l "$1"; sed -n "1,160p" "$1"' sh {} \;

echo
echo "== exact validate invocation in CI =="
sed -n '1,130p' .github/workflows/validate.yml 2>/dev/null || true

Repository: kentcdodds/kody

Length of output: 25778


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== backup-control-plane test files =="
find packages/backup-control-plane -type f -name '*.node.test.ts' -print | sort

echo
echo "== worker vitest config files inside packages/worker =="
find packages/worker -type f -path '*vitest*' -print | sort -u
for f in $(find packages/worker -type f -path '*vitest*' | sort -u); do
  echo "--- $f ---"
  sed -n '1,260p' "$f"
done

echo
echo "== package.json validate decomposition =="
node - <<'JS'
const fs = require('node:fs');
const p = JSON.parse(fs.readFileSync('package.json','utf8'));
const validate = p.scripts.validate;
const commands = validate.match(/"[^"]+"/g).map(s => s.slice(1, -1).split(' ').at(-1));
const names = validate.split('" "')
  .filter(Boolean)
  .map(part => part.replace(/^"|"$/, '')
    .replace(/npm run[ ]+/, '')
    .split(' ')[0]);
console.log('commands=', commands.join(' | '));
console.log('names=', names.join(' | '));
JS

Repository: kentcdodds/kody

Length of output: 1073


Include the backup/DR test script in npm run validate.

validate runs test (nx run worker:test), but run worker:test only executes the configured Vitest projects in packages/worker. It does not reach packages/backup-control_plane/*.node.test.ts; those only run with packages/backup-control-plane:test, which is not part of validate or CI’s authoriative gate.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` around lines 51 - 55, Update the package.json validate script
to include the backup control-plane test target alongside the existing worker
test command, ensuring packages/backup-control-plane/*.node.test.ts runs as part
of the authoritative validation gate. Add the corresponding backup test command
to the concurrently-managed validation tasks and names without removing existing
checks.

Source: Coding guidelines

"validate:fix": "npm run format && npm run lint:fix",
"test:e2e:ensure": "node tools/ensure-playwright-browser.ts",
"test:e2e:run": "nx run worker:test-e2e",
Expand Down Expand Up @@ -95,6 +99,7 @@
},
"packageManager": "npm@11.11.1",
"workspaces": [
"packages/backup-control-plane",
"packages/shared",
"packages/worker",
"packages/mock-servers/*"
Expand Down
Loading