Start with the narrow test that owns your change, add integrity suites when D1 and R2 can diverge, and finish with the repository gates. If the public contract moved, also drive the affected path through the isolated local harness. This workflow applies to deployment-repository changes and owner-requested upstream patches because each test layer should prove only the behavior it can actually observe.
Develop and verify
Each layer proves a different claim
No single test environment covers Energon’s whole contract. Node unit tests are fast and isolate helpers. Worker tests exercise routing with D1 and R2 bindings. Failure injection forces rare rollback branches. Mock-free mutation suites validate real binding behavior. Page tests protect DOM contracts. The verify harness starts a real local Worker and observes it as a human or agent would. For project-specific mutation and identity terms, use the glossary.
1. Set up local state
Run local migrations before starting the development server. The checked-in example identity defaults to dev@example.com; localhost skips Cloudflare Access.
npm install
npx wrangler d1 migrations apply energon --local
cp .dev.vars.example .dev.vars
npm run devDo not attach verification to an unknown process on port 8787, delete .wrangler/state, or kill Wrangler/workerd by process-name pattern. That state and process may belong to another local session.
2. Start with the owning test
| Change | First test |
|---|---|
Pure helper under src/ | npm run test:unit -- test/unit/NAME.spec.ts |
helpBody, /llms.txt, Markdown HTML | npm run test:unit -- test/unit/golden.spec.ts |
openapi/v1.json, /v1 routes, or API error codes | npm run test:unit -- test/unit/openapi-drift.spec.ts |
| Contribution templates or PR policy | npm run test:unit -- test/unit/pr-title.spec.ts test/unit/contribution-policy.spec.ts |
| Templates, renderer, Energon skill | npm run test:unit -- test/unit/skill-render.spec.ts |
Well-known skill route and AGENT_SKILLS_DISCOVERY | npm run test:unit -- test/unit/agent-skills.spec.ts |
Upload helper templates/skill/scripts/energon_publish.py.tmpl (needs python3) | npm run test:unit -- test/unit/publish-helper.spec.ts |
| Svelte pages/components or UI rendering | npm run check:ui and npx vitest run test/pages.spec.ts |
| Upload staging | npm run test:unit -- src/ui/uploads.spec.ts |
| Agent connection requests, approvals, and delivery | npx vitest run test/connections.spec.ts |
| Router, host rules, account API | npx vitest run test/routes.spec.ts |
| Publish/read/delete/list/auth DB/gate/Markdown | npx vitest run test/api.spec.ts |
| Loose-file write, rename, or delete failures | npx vitest run test/files.spec.ts |
| Site import/copy/delete rollback | npx vitest run test/site-integrity.spec.ts |
| Expiry and write-claim races | npx vitest run test/api.purge-claim.spec.ts |
| Site deployment sessions, commit, and receipts | npx vitest run test/site-deployments.spec.ts test/site-deployment-api.spec.ts |
| Whole-site grants | npx vitest run test/deployment-grants.spec.ts |
| ZIP reader and staged preparation | npx vitest run test/site-zip-reader.spec.ts test/site-storage.spec.ts |
| Version-keyed site cache | npx vitest run test/site-cache.spec.ts test/site-routed-cache.spec.ts |
| Older-site conversion | npx vitest run test/site-version-migrate.spec.ts test/site-admin-conversion.spec.ts |
For example, a catalog cursor change begins with:
npm run test:unit -- test/unit/catalog.spec.ts
npx vitest run test/api.spec.tsDo not run the full suite after every small edit. Focused tests make the edit loop useful; the full gate still runs before handoff.
3. Prove D1/R2 integrity twice
An integrity change needs both controlled failure and real-binding convergence evidence.
Use failure-injection suites to force the precise branch:
test/files.spec.tsfor loose-file R2/D1/cache failures.test/site-integrity.spec.tsfor import, duplicate, path delete, and site version publication behavior.test/api.purge-claim.spec.tsfor claim acquisition, stale reclaim, PATCH races, and purge ordering.
Then run the relevant mock-free suite:
test/d1-r2-mutation.spec.tsfor rename/delete catalog, keys, and quota.test/d1-r2-claim-mutation.spec.tsfor claim rollback and competing replacements.test/d1-r2-site-mutation.spec.tsfor site PUT/import/delete abort recovery.test/d1-r2-scheduled-mutation.spec.tsfor sweep boundaries and stale claims.
npx vitest run test/files.spec.ts test/d1-r2-mutation.spec.ts test/d1-r2-claim-mutation.spec.tsThe injected suite proves your recovery logic is reachable. The mock-free suite proves the same invariant with actual local D1/R2 semantics. Do not treat one as a substitute for the other.
4. Change schema in all three places
Add a new numbered migration, update runtime bootstrap/legacy upgrades, and update src/schema.sql. Create indexes only after every referenced column exists.
npx wrangler d1 migrations apply energon --local
npm run test:unit -- test/unit/db.spec.ts test/unit/schema-drift.spec.ts
npx wrangler types
npm run typecheckNever rewrite old migrations. Comments in older migrations about stamping d1_migrations are historical human recovery notes for a verified deploy-first state. They do not permit agents to stamp migration history, run production d1 execute, or improvise repair SQL. For a production duplicate-column incident, stop and use the human-only upgrade and recovery procedure.
5. Keep the agent protocol coherent
When a /v1 route, field, header, error, limit, or decision rule changes, review these together:
- Canonical HTTP schema in
openapi/v1.json. - Runtime JSON in
src/auth.tshelpBody. - Runtime plain text in
src/llms.ts. - Agent workflow and reference under
templates/skill/. - Runtime golden fixtures under
test/golden/. - Rendered plugin output under
plugins/.
npm run test:unit -- test/unit/openapi-drift.spec.ts
UPDATE_GOLDENS=1 npm run test:unit -- test/unit/golden.spec.ts
npm run skill:render
npm run test:unit -- test/unit/skill-render.spec.ts
git diff -- openapi test/golden templates pluginsThe drift test compares OpenAPI operations with the /v1 route tables and help.routes, checks application error codes, and protects the unauthenticated discovery boundary. Review the remaining diff semantically: separate snapshots can all pass while two documents disagree about a method or field. For example, loose-file rename is implemented as PUT /v1/files/{id} with X-Filename; PATCH changes password, write password, TTL, or write policy and does not rename. Guest PUT is not a /v1 path. Site routes are keyed by id. If a verification recipe says otherwise, update the recipe rather than documenting stale behavior.
The renderer’s outputs can be summarized as the Energon plugin tree plus real-host marketplace catalogs and updated this Energon’s origins, policy, and SOP. Do not hand-edit plugins/{name}/, and do not install the publish skill under this repository’s .agents/skills or .claude/skills directories because those locations autoload it while you are changing the Worker. Only verify-energon, cut-release, update-from-upstream, and backup-this-energon belong there.
6. Pair page contracts with user-path proof
test/pages.spec.ts checks server-rendered navigation, copy, catalog data, safe hydration, and asset isolation. Svelte checks template bindings; legacy inline DOM checks apply only where that code remains. Neither proves pixels, responsive behavior, or whether a person can complete the flow.
For UI changes, read upstream DESIGN.md and the UI implementation guide . Shared controls live in src/ui/components/, pages in src/ui/pages/, and supplied tokens/styles/assets in src/ui/design/. Keep generated files out of hand edits.
npm run check:ui
npm run specimen:ui
python3 -m http.server 18788 --bind 127.0.0.1 --directory .context/ui-specimenThe specimen shows local component examples without application API calls. Wrangler’s custom build and both Vitest configurations run build:ui automatically. npm run typecheck includes the UI check. Browser verification still needs the real local Worker for forms, dialogs, upload staging, and persistence.
The .agents/skills/verify-energon/ harness complements it by launching an isolated Wrangler Energon with real local D1/R2, proving process and port ownership, and driving HTTP or browser behavior. Use both when a hub control or workflow moves. .agents/skills/verify-energon/ is canonical; .claude/skills/verify-energon and .cursor/skills/verify-energon are compatibility symlinks.
export ENERGON_VERIFY_RUN="contributor-check"
export ENERGON_VERIFY_PORT="18787"
.agents/skills/verify-energon/bin/up
set -a
source "/tmp/energon-verify/$ENERGON_VERIFY_RUN/state.env"
set +abin/up launches, runs Doctor, and prepares one token. Follow every Default bullet in the matching feature recipe; run Extra bullets only when the changed sub-feature requires them. Reuse that run and token. Prefer HTTP for the default paths, saving request/status/body with bin/save and a later read-only view. Browser extras also require a screenshot showing the signed-in identity and resulting state. Doctor discovers the configured token environment and prefix, and the launcher keeps localhost identity even on a deployment repository with custom routes. The harness calls the real local Worker; do not use SELF.fetch or direct binding access as user proof.
Cleanup targets only this run’s process group, port, and isolated persist directory, while preserving evidence:
.agents/skills/verify-energon/bin/cleanupIf a named route, public URL shape, header, token prefix/environment, element id, ARIA label, or proof string changes, update the feature map in the same change. A stale map is fixed to match verified runtime behavior; it is never treated as authority over the product.
7. Run the full gate
Before handoff, schema/shared-type changes always receive the full gate. It is also the safe final check for any coherent change:
npx wrangler types
npm run typecheck
npm run lint
npm test
npm run fuzz:regression
npm run skill:render -- --checkCI uses Node 22 and runs npm ci, Wrangler type generation, typecheck, lint, unit tests, ZIP fuzz regression, and Worker tests. Production deployment is a separate opt-in job after tests; contributors must not run deployment or remote database commands as part of ordinary verification.
For ZIP parser changes, fuzz:regression replays the committed corpus. A local coverage-guided campaign is npm run fuzz:zip -- -max_total_time=60; minimize a crash, add it to the committed corpus, and add a focused unit regression with the fix.
Verification failures
Do not call a change verified because one layer is green. Persistence work needs injected and mock-free suites; UI work needs page contracts and a user-path drive; /v1 work needs the OpenAPI drift test plus semantic review across runtime docs, templates, goldens, and rendered output. Never invent a token, touch production D1 state, reuse the default local database for verification, or conceal a product failure by editing the feature map.
Report or hand off
For an upstream bug, search existing issues and pull requests, then provide reproduction evidence without secrets. Focused pull requests are welcome under the upstream contribution policy; new API surfaces, migrations, and non-obvious hub flows should begin with an issue. For a vulnerability, use private reporting and include the tested revision, reproduction, and impact without tokens, credentials, passwords, customer content, or other people’s email addresses.
Use a Conventional Commit PR title such as fix(hub): validate catalog filters. Keep the template headings What, Why, Verify, How to test, Risk, and Authorship; additional sections are allowed. How to test must give numbered commands or URLs and expected results that a triage agent can follow without asking. Name the actual model in Authorship; a human-authored patch may say None.
When handing off an authorized code change, state which focused tests ran, which cross-layer invariants they cover, whether the user path was driven, and the full-gate result. Read Architecture and integrity when deciding which boundaries changed, Contribute to Energon for the repository policy, and Security model before reporting an auth or sharing defect.