@jimhoyd/urlcode 0.4.0-alpha.3 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/.claude/skills/urlcode-authoring/SKILL.md +10 -0
  2. package/.claude-plugin/marketplace.json +1 -1
  3. package/CONTRIBUTING.md +36 -0
  4. package/README.md +20 -15
  5. package/ROADMAP.md +25 -16
  6. package/dist/BUILD-MANIFEST.json +20 -19
  7. package/dist/authoring.js +15 -1
  8. package/dist/capability-query.js +0 -1
  9. package/dist/catalog.js +0 -1
  10. package/dist/cli.js +24 -7
  11. package/dist/config.js +1 -1
  12. package/dist/explain.js +1 -1
  13. package/dist/extensions.js +78 -1
  14. package/dist/http-response.js +1 -1
  15. package/dist/index.js +1 -0
  16. package/dist/init-with.js +36 -11
  17. package/dist/manifest.js +1 -1
  18. package/dist/mcp-authoring.js +2 -2
  19. package/dist/mcp.js +1 -1
  20. package/dist/policies/cache.js +2 -2
  21. package/dist/policy.js +16 -0
  22. package/dist/project-dependencies.js +305 -0
  23. package/dist/readiness.js +5 -1
  24. package/dist/runtime.js +1 -1
  25. package/dist/tooling.js +2 -1
  26. package/dist/trusted-functions.js +4 -5
  27. package/dist/types/authoring.d.ts +9 -1
  28. package/dist/types/capability-query.d.ts +0 -1
  29. package/dist/types/catalog.d.ts +0 -4
  30. package/dist/types/config.d.ts +1 -9
  31. package/dist/types/explain.d.ts +0 -1
  32. package/dist/types/extensions.d.ts +58 -0
  33. package/dist/types/http-response.d.ts +0 -1
  34. package/dist/types/index.d.ts +1 -0
  35. package/dist/types/init-with.d.ts +7 -13
  36. package/dist/types/manifest.d.ts +0 -1
  37. package/dist/types/project-dependencies.d.ts +78 -0
  38. package/dist/types/readiness.d.ts +3 -0
  39. package/dist/types/tooling.d.ts +1 -0
  40. package/dist/types/trusted-functions.d.ts +1 -4
  41. package/docs/AI-AUTHORING.md +10 -5
  42. package/docs/AWS.md +9 -0
  43. package/docs/CI-FOLLOWUP-2026-09-19.md +1 -1
  44. package/docs/CODEBASE-AUDIT-2026-09-20.md +6 -0
  45. package/docs/COMPOSING-A-SITE.md +287 -0
  46. package/docs/CONTAINER-PROMOTION.md +74 -0
  47. package/docs/DEVELOPMENT-PIPELINE.md +242 -119
  48. package/docs/EXTENSIONS.md +88 -93
  49. package/docs/FRAMEWORK.md +45 -30
  50. package/docs/FUNCTION-SECURITY.md +5 -8
  51. package/docs/INSTALL.md +13 -8
  52. package/docs/MIDDLEWARE.md +10 -4
  53. package/docs/OPEN-DECISIONS.md +64 -99
  54. package/docs/READINESS.md +8 -4
  55. package/docs/README.md +18 -13
  56. package/docs/RELEASE-0.4.1.md +73 -0
  57. package/docs/RELEASE-0.4.2.md +30 -0
  58. package/docs/RELEASE-READINESS.md +40 -11
  59. package/docs/RELEASE-SECURITY.md +33 -14
  60. package/docs/SPECIFICATION.md +5 -1
  61. package/docs/SPIKE-CORE-LAYERING.md +1 -1
  62. package/docs/SPIKE-DEFAULT-TRUST-MODEL.md +9 -13
  63. package/docs/STARTERS.md +17 -5
  64. package/docs/TOOLING.md +7 -5
  65. package/docs/VERCEL.md +10 -2
  66. package/docs/VERSION-ALIGNMENT.md +50 -8
  67. package/docs/archive/2026-09-19/ROADMAP.md +1 -0
  68. package/docs/archive/2026-09-19/SPIKE-EXTENSION-MODEL.md +1 -0
  69. package/docs/{SPIKE-LAMBDA-COMPILE.md → archive/2026-09-19/SPIKE-LAMBDA-COMPILE.md} +168 -12
  70. package/docs/archive/2026-09-19/SPIKE-MONOREPO.md +2 -0
  71. package/docs/archive/2026-09-20/OPEN-DECISIONS-COMPLETED.md +116 -0
  72. package/docs/archive/README.md +2 -0
  73. package/docs/yaml/functions.md +10 -2
  74. package/docs/yaml/middleware.md +5 -3
  75. package/examples/cookbook/middleware/envelope.mjs +4 -2
  76. package/llms-full.txt +458 -143
  77. package/llms.txt +2 -1
  78. package/package.json +8 -5
  79. package/packaging/claude-plugin/.claude-plugin/plugin.json +1 -1
  80. package/packaging/claude-plugin/skills/urlcode-authoring/SKILL.md +10 -0
  81. package/recipes/middleware/middleware/envelope.mjs +4 -2
  82. package/skills/urlcode/SKILL.md +8 -1
@@ -1,6 +1,7 @@
1
1
  # Decisions to align
2
2
 
3
- Reviewed 2026-09-19 against core `db375bf` and the current public package sources.
3
+ Last reconciled 2026-09-20 against open and closed issues (#242); the source
4
+ review it began from is dated 2026-09-19 (core `db375bf`, now archived).
4
5
  This is the maintainer's decision list, not a second implementation backlog.
5
6
  The [roadmap](../ROADMAP.md) gives sequence and the [archive](archive/README.md)
6
7
  keeps earlier discussions. Recommendations below are not accepted decisions.
@@ -33,27 +34,51 @@ keeps earlier discussions. Recommendations below are not accepted decisions.
33
34
  |---|---|---|
34
35
  | Where does work status live? | Several old plans repeated issues and continued calling delivered work unfinished. | Issues for actionable status, this short roadmap for sequence, archive for completed proposals. Preserve evidence gaps when archiving. |
35
36
  | Expand into business applications now? | No collection handler or proposed business suite is implemented; the model-backed benchmark evidence is missing. | Measure existing tasks and record repeated application plumbing before selecting a collection/CMS/forms project. Retired short-link products stay retired. [Proposal](SPIKE-BUSINESS-SUITE.md). |
36
- | Which provider execution model next? | AWS/Vercel still reject function/middleware despite the trusted default. | Decide demand first, then compare one Node deployment per project against one Lambda per route. Do not promise either today. [Proposal](SPIKE-LAMBDA-COMPILE.md). |
37
- | Fold extension schemas into retrieved context? | `urlcode extensions` and the MCP `get_extensions` query return the registered configuration and policy schemas, but `src/context.ts:113` reports `extensions` as names only, so an author writing `extensions.<name>.config` or `policies.extensions.<name>` must run the separate operator-authorized query first. | Decide from retrieval and task evidence, not preference: the existing small-task harness can measure whether folding schemas into bounded context improves authoring. Keep the token budget bounded and never auto-load a project-selected host file. This is a discovery improvement, not a defect in the existing query. |
38
- | Retire the UI primitive fallback? | Auth and admin use the kit when supplied, and retain tested primitive rendering without it. | Keep both until an explicit compatibility/deprecation decision; adoption is already implemented. |
37
+ | Fold extension schemas into retrieved context? ([#174](https://github.com/jimhoyd-com/urlcode/issues/174), open) | `urlcode extensions` and the MCP `get_extensions` query return the registered configuration and policy schemas, but `src/context.ts:113` reports `extensions` as names only, so an author writing `extensions.<name>.config` or `policies.extensions.<name>` must run the separate operator-authorized query first. | Decide from retrieval and task evidence, not preference: the existing small-task harness can measure whether folding schemas into bounded context improves authoring. Keep the token budget bounded and never auto-load a project-selected host file. This is a discovery improvement, not a defect in the existing query. |
38
+ | Build the tested-image promotion path? ([#233](https://github.com/jimhoyd-com/urlcode/issues/233), open) | [Design and an inert invariant helper](CONTAINER-PROMOTION.md) are merged. `release.yml` still rebuilds from source when `PUBLISH_CONTAINER` is true, and a retry accepts an existing `:VERSION` on its `revision` label alone. Live GHCR state and whether GHCR preserves an OCI digest through `skopeo`/`crane` are unverified. | The reason is integrity (tested bytes are the shipped bytes), not speed: CI's image build took about 12 seconds, so a cross-run build cache is not justified and should not be added. Recommendation: do not implement while publication is off and GHCR is uninspected. First grant `read:packages` and inspect historical labels and digests; then land a candidate-side image build behind an operator input, inspect one real candidate, and only then change the publisher. Not changed here. |
39
+ | Keep the POST-plus-`request.body` sandbox advisory? | `src/readiness.ts` nudges any code-running route that accepts POST with a declared `request.body` and declares neither `sandbox: true` nor `sandboxReason`. It is advisory only: never fails `audit`, never changes `ready`. | The nudge keys on request *shape* while [AI authoring](AI-AUTHORING.md) tells authors to decide on *code* trust, so it can read as "untrusted input implies sandbox" -- the reasoning that guidance explicitly rejects. It still has value as a prompt to record a decision. Recommendation: keep the trigger, restate the message as a request to record the trust decision (`sandbox: true` or `sandboxReason`) rather than as a suggestion that this route may need isolation. Not changed here; #196 was a docs/tooling alignment pass. |
39
40
 
40
41
  The broader [AI benchmark proposal](SPIKE-AI-FRAMEWORK-BENCHMARK.md) also needs a
41
42
  chosen application, model-run budget and execution authorization. The existing
42
43
  small-task harness can supply evidence without committing to that larger study.
43
44
 
44
- ## Closed questions removed from the active list
45
+ ## Accepted: one Node deployment per project
45
46
 
46
- - Publishing convention is recorded in [version alignment](VERSION-ALIGNMENT.md):
47
- publishable manifests on main, releases through reviewed tags/workflows.
48
- - Core `0.4.0-alpha.2` and current extension releases exist; publishing that
49
- already-shipped version is not a next step.
50
- - Auth/admin kit adoption and shared form helpers are implemented in their code.
51
- - The template pins `0.4.0-alpha.2`. Its skill differences were read against that
52
- pin: omitted handlers and advice about the removed management API are stale,
53
- not intentional older-version behavior.
54
- - The guidance checks run through `npm run check` inside `verify`; a regex check
55
- is not a schema validator for every example. Extending its coverage is tracked
56
- separately, not a reason to weaken review or bypass required checks.
47
+ **Decided 2026-09-19.** Projects that use `function` or `middleware` deploy as
48
+ **one trusted Node process** — a container or a VM running the project as it
49
+ runs locally. That is the supported execution model, and it needs no new work:
50
+ it is what the runtime already does.
51
+
52
+ **Per-route Lambda compilation is not pursued.** The alternative on the table
53
+ was a build step emitting one Lambda per `function` route
54
+ ([the proposal](archive/2026-09-19/SPIKE-LAMBDA-COMPILE.md)). It is declined for now, on three
55
+ grounds the proposal itself states:
56
+
57
+ 1. It would replace the sandbox guarantee rather than preserve it, and lose the
58
+ fresh-per-invocation state that `sandbox: true` currently guarantees.
59
+ 2. It would make this project the author of generated IAM roles — a
60
+ security-critical output it has never owned.
61
+ 3. It would trade an honest refusal for a larger claim nobody has deployed.
62
+
63
+ Against that, a single Node deployment supports every route type today with no
64
+ compiler, no generated infrastructure and no second isolation story to document.
65
+
66
+ **What follows from this decision:**
67
+
68
+ - AWS and Vercel continue to refuse `function` and `middleware` at activation,
69
+ naming the route (`src/capabilities.ts`, `activateNativeOnly` in
70
+ `src/adapters.ts`). That refusal is now a **deliberate position**, not a gap
71
+ awaiting an adapter. Documentation should say so rather than implying the
72
+ support is coming.
73
+ - Serverless targets remain first-class for the declarative route types they can
74
+ actually serve; nothing about static or native-only deployment changes.
75
+ - [SPIKE-LAMBDA-COMPILE.md](archive/2026-09-19/SPIKE-LAMBDA-COMPILE.md) is kept as the analysis
76
+ behind this decision, not as a plan. Reopen it only on evidence of real demand
77
+ for URLCode `function` routes specifically on AWS serverless — the proposal's
78
+ own §6 already scopes what a first attempt would be.
79
+
80
+ This decision is about the *execution model*, not about AWS. Deploying the Node
81
+ process to AWS (ECS, EC2, App Runner) is an operator choice this fully supports.
57
82
 
58
83
  ## Accepted: per-package release tags
59
84
 
@@ -99,86 +124,26 @@ reasoning above is the kind of prose that rots as soon as `auth` and `admin`
99
124
  arrive, which is the whole argument this repository makes for enforcing checks
100
125
  over documented intent.
101
126
 
102
- ## Done: the monorepo migration is complete
103
-
104
- **Closed 2026-09-19.** `urlcode-ui`, `urlcode-auth` and `urlcode-admin` are
105
- workspace packages under `packages/`, and all three have been released from
106
- this repository — `@jimhoyd/urlcode-ui@0.1.0-alpha.6`,
107
- `@jimhoyd/urlcode-auth@0.1.0-alpha.6`, `@jimhoyd/urlcode-admin@0.1.0-alpha.4`,
108
- each on `alpha` with `latest` deliberately held behind. Core's dist-tags are
109
- unchanged. The three source repositories are gone; their history survives only
110
- as verified `git bundle`s, because the repository allows squash merges only and
111
- the imported commits did not survive onto `main`.
112
-
113
- The operational runbook is [DEVELOPMENT-PIPELINE.md](DEVELOPMENT-PIPELINE.md)
114
- and [RELEASE-SECURITY.md](RELEASE-SECURITY.md). The plan itself is archived at
115
- [archive/2026-09-19/SPIKE-MONOREPO.md](archive/2026-09-19/SPIKE-MONOREPO.md),
116
- whose closing note records what the plan got wrong — chiefly that its
117
- strongest argument, the reach of the enforcing checks, only became true after
118
- both checkers were changed to discover workspace packages.
119
-
120
- The section below is kept for the middleware decision it records, which is
121
- still the reason there is no `packages/middleware`.
122
-
123
- ## Accepted: monorepo first — middleware withdrawn rather than consolidated
124
-
125
- The maintainer confirmed that monorepo work is starting now. The earlier
126
- recommendation to keep repositories separate for now is superseded.
127
-
128
- **Reversed 2026-09-19: the middleware half of this decision no longer applies.**
129
- This section used to say "move middleware into the monorepo as its own package
130
- first, preserving its existing API and behavior," and explicitly: "do not
131
- unpublish or retire the middleware package as part of the initial move."
132
- That instruction was overtaken. `@jimhoyd/urlcode-middleware` has been
133
- **unpublished** from npm at `0.1.0-alpha.2` and `jimhoyd-com/urlcode-middleware`
134
- **deleted** — the package was withdrawn outright instead of migrated, so there
135
- is no `packages/middleware` to create and no subsequent fold-into-core step.
136
- The reversal is recorded here rather than deleted because the instruction it
137
- replaces was explicit, and a reader who remembers it should be able to see that
138
- it was changed deliberately and not simply forgotten.
139
-
140
- Nothing was lost in capability terms: per-route middleware is **native to
141
- core** via the `middleware:` array ([MIDDLEWARE.md](MIDDLEWARE.md)), and the
142
- deleted package only ever offered the same behavior through the extension
143
- seam. Trust remains the default and explicit sandbox choices keep their
144
- meaning. The generic extension wrapping hook (`ExtensionInstance.middleware`,
145
- `RuntimeExtension.cacheSensitive`) stays in core's contract for other
146
- extensions — it is no longer exercised by any shipped package, which is worth
147
- knowing before it is assumed to be covered. Static targets continue rejecting
148
- request-time middleware because there is no server to run it.
149
-
150
- Migration scope is therefore **core, auth, admin and UI**. Template and the
151
- distribution tap stay outside that package move. The observed stale peer pins
152
- and checkout-limited guidance checks strengthen the case for shared
153
- verification: carry those checks across the new package paths, since merely
154
- moving files does not prove every generated skill is covered. The cleanup PRs
155
- that superseded the earlier zero-open-PR survey have since merged, and a fresh
156
- survey again reports zero open pull requests across all four in-scope
157
- repositories — re-run it per repository immediately before that repository
158
- moves rather than trusting this line.
159
-
160
- The [archived monorepo plan](archive/2026-09-19/SPIKE-MONOREPO.md) records
161
- migration context.
162
- [Issue 172](https://github.com/jimhoyd-com/urlcode/issues/172), which tracked
163
- "consolidate middleware into core after moving it into the monorepo," is
164
- **moot and still open** — there is nothing left to consolidate. It should be
165
- closed with a pointer to this section. Migration starting is not a claim that
166
- it has landed.
167
-
168
- ## Source review baseline
169
-
170
- | Repository | Reviewed commit | Code checked |
171
- |---|---|---|
172
- | core | `db375bf` | Runtime dispatch, schema normalization, capabilities, static compiler, prerender, MCP and resource generators |
173
- | auth | `71957dd` | Lifecycle hooks, UI rendering and shared helper imports |
174
- | admin | `f3b4882` | UI rendering, auth-service integration and shared helper imports |
175
- | UI | `0e96f7f` | Shared forms, kit/host exports and copied core contract |
176
- | ~~middleware~~ | `f201f4b` | Extension wrapping, per-entry sandbox dispatch and scaffolding — **repository deleted 2026-09-19; this baseline is unreachable except through the local `urlcode-middleware.bundle`** |
177
- | template | `4e09e50` | Exact core pin, generated guide and both vendored skills |
178
-
179
- The Homebrew tap (`73eaaef`) still selects stable core `0.3.0`; its old trust
180
- behavior belongs to that pin and must not be rewritten as alpha.2 behavior.
181
- The other organization tap and Scoop bucket contain Gitroll, not URLCode.
182
- The deleted documentation repository is historical context, not a second source
183
- of current contracts; its former GitHub links no longer resolve. This review is targeted source inspection, not an audit of
184
- every execution path or an independent security assessment.
127
+ ## Completed work (archived)
128
+
129
+ Closed questions, the completed monorepo migration (ui, auth and admin are
130
+ workspace packages; released from this repository) and the 2026-09-19 source
131
+ review baseline live in
132
+ [archive/2026-09-20/OPEN-DECISIONS-COMPLETED.md](archive/2026-09-20/OPEN-DECISIONS-COMPLETED.md).
133
+ The migration plan is [archived](archive/2026-09-19/SPIKE-MONOREPO.md). Versions
134
+ and channels are in [version alignment](VERSION-ALIGNMENT.md) and
135
+ `npm run release:status`, not here.
136
+
137
+ ## Accepted: middleware withdrawn rather than consolidated
138
+
139
+ **Decided 2026-09-19.** `@jimhoyd/urlcode-middleware` was unpublished and its
140
+ repository deleted; there is no `packages/middleware` and nothing to fold into
141
+ core afterward (#172, closed as moot). Per-route middleware is native to core
142
+ via the `middleware:` array ([MIDDLEWARE.md](MIDDLEWARE.md)). The generic
143
+ extension wrapping hook (`ExtensionInstance.middleware`,
144
+ `RuntimeExtension.cacheSensitive`) stays in core's contract for other extensions
145
+ but is no longer exercised by any shipped package, so do not assume it is
146
+ covered. Static targets keep rejecting request-time middleware. The earlier
147
+ instruction to move middleware into the monorepo first was overtaken; its full
148
+ text is retained in the archived record.
149
+
package/docs/READINESS.md CHANGED
@@ -10,9 +10,10 @@ urlcode audit --project ../my-links --expect-routes 2
10
10
  urlcode benchmark --project ../my-links --requests 1000 --concurrency 2 --max-p95-ms 50
11
11
  ```
12
12
 
13
- All three activate/validate the project with the same isolated runtime and use
14
- local environment loading like `test`. Pass an external `--policy` for explicitly
15
- authorized bindings. No destination redirects are followed, credentials are not
13
+ All three activate/validate the project with the same runtime that serves it --
14
+ each route in its own declared trust mode, trusted in-process unless it declares
15
+ `sandbox: true` -- and use local environment loading like `test`. Pass an
16
+ external `--policy` for explicitly authorized bindings. No destination redirects are followed, credentials are not
16
17
  printed, and no remote load-test target is accepted.
17
18
 
18
19
  ## Inventory and count reconciliation
@@ -81,7 +82,10 @@ parameter patterns still need explicit negative fixtures to exercise them.
81
82
 
82
83
  `ready: true` requires a nonempty active project, matching expected count (when
83
84
  supplied), zero failed checks and no uncovered active route/method combinations.
84
- It means this local gate passed, not that all branches, parameter values or assets
85
+ When `ready` is false, `notReadyReasons` lists each failed condition:
86
+ `no-active-routes`, `route-count-mismatch`, `failed-checks` and
87
+ `uncovered-route-methods` (see `uncovered` for the pairs). `unassertedCases` never
88
+ affects `ready`. It means this local gate passed, not that all branches, parameter values or assets
85
89
  have independent business assertions. Function routes intentionally serving only
86
90
  errors cannot satisfy normal-response coverage in this release. Time-dependent
87
91
  expiry is evaluated at audit start; avoid running a gate exactly at expiry.
package/docs/README.md CHANGED
@@ -1,10 +1,20 @@
1
1
  # URLCode documentation
2
2
 
3
- Start with [the framework](FRAMEWORK.md): the four packages, the ladder from
4
- redirects to a full application, the composition contract and the rules an AI
5
- agent must follow. [Project direction](PROJECT-DIRECTION.md) states the
6
- boundary and the license. Use documentation pinned to your runtime revision;
7
- `version: "1"` is the stable project-format contract for this release line.
3
+ Choose a starting point, then use the topic directory below when you need detail.
4
+ Use documentation from the same pinned revision as your runtime.
5
+
6
+ | I want to… | Start here |
7
+ |---|---|
8
+ | Understand what URLCode does | [Framework](FRAMEWORK.md) |
9
+ | Build my first project | [Installation](INSTALL.md), then [YAML guide](YAML-GUIDE.md) |
10
+ | Build a site with UI, accounts and admin | [Composing a site](COMPOSING-A-SITE.md) |
11
+ | Have an AI author a project | [AI authoring](AI-AUTHORING.md), [agent index](../llms.txt) |
12
+ | Deploy and operate a project | [Operations](OPERATIONS.md) |
13
+ | Contribute to URLCode | [Contributing](../CONTRIBUTING.md), [local development](LOCAL-DEVELOPMENT.md) |
14
+
15
+ The [specification](SPECIFICATION.md) owns implemented semantics; the
16
+ [generated field reference](YAML-REFERENCE.md) lists accepted fields.
17
+ [Project direction](PROJECT-DIRECTION.md) explains the product boundary.
8
18
 
9
19
  ## Author a project
10
20
 
@@ -13,11 +23,9 @@ boundary and the license. Use documentation pinned to your runtime revision;
13
23
  | Install the CLI | [Installation](INSTALL.md) |
14
24
  | Write YAML with examples | [YAML guide and recipes](YAML-GUIDE.md) |
15
25
  | Look up every accepted field | [Generated field reference](YAML-REFERENCE.md), [JSON Schema](../schemas/urlcode.schema.json) |
16
- | Let an AI build routes | [AI authoring guide](AI-AUTHORING.md), [llms.txt](../llms.txt) |
17
26
  | Load authoring/operations rules into an agent | [Authoring skill](../.claude/skills/urlcode-authoring/SKILL.md), [operations skill](../.claude/skills/urlcode-operations/SKILL.md), [how they are distributed](AI-AUTHORING.md#agent-skills) |
18
- | Run examples | [25-route cookbook](../examples/cookbook/README.md), [prerender recipe](../examples/prerender/README.md), [small starter](STARTERS.md) |
19
27
  | Understand exact behavior | [Specification](SPECIFICATION.md), [routing](ROUTING.md), [HTTP](HTTP.md) |
20
- | Run examples | [40-route cookbook](../examples/cookbook/README.md), [prerender recipe](../examples/prerender/README.md), [small starter](STARTERS.md) |
28
+ | Run examples | [Executable cookbook](../examples/cookbook/README.md), [prerender recipe](../examples/prerender/README.md), [small starter](STARTERS.md) |
21
29
  | Let an AI build routes | [The framework](FRAMEWORK.md), [AI authoring guide](AI-AUTHORING.md), [llms.txt](../llms.txt), [SDK and read-only MCP](TOOLING.md) |
22
30
  | Reuse code around routes | [Middleware](MIDDLEWARE.md), [middleware examples](MIDDLEWARE-EXAMPLES.md) |
23
31
  | Handle secrets and decide what to sandbox | [Function security](FUNCTION-SECURITY.md) |
@@ -39,11 +47,10 @@ boundary and the license. Use documentation pinned to your runtime revision;
39
47
 
40
48
  | Goal | Start here |
41
49
  |---|---|
42
- | Add accounts, sign-in and protected routes | [urlcode-auth](https://github.com/jimhoyd-com/urlcode-auth#readme) |
43
- | Manage users, sessions, roles and audit | [urlcode-admin](https://github.com/jimhoyd-com/urlcode-admin#readme) |
50
+ | Add accounts, sign-in and protected routes | [urlcode-auth](../packages/auth#readme), [auth security](../packages/auth/SECURITY.md) |
51
+ | Manage users, sessions, roles and audit | [urlcode-admin](../packages/admin#readme) |
44
52
  | Restyle every extension page and translate copy | [urlcode-ui](../packages/ui#readme), [ui contract](../packages/ui/CONTRACT.md) |
45
53
  | Write or install a versioned extension | [Extensions](EXTENSIONS.md), [example fixture](../examples/extensions/README.md) |
46
- | Follow implementation of the auth, admin and UI extensions | [Extension implementation sequence](archive/2026-09-19/EXTENSION-IMPLEMENTATION.md) |
47
54
  | Know which core version an extension package supports, and how it says so | [Core version alignment](VERSION-ALIGNMENT.md) |
48
55
  | Add host behavior in operator code | [Plugins](PLUGINS.md) |
49
56
  | Use the API from TypeScript | [TypeScript: shipped declarations, exports, build and fidelity](TYPESCRIPT.md) |
@@ -59,7 +66,6 @@ boundary and the license. Use documentation pinned to your runtime revision;
59
66
  | Review security findings and gaps | [Internal security audit](SECURITY-AUDIT.md) |
60
67
  | Assess release readiness | [Evidence and open gates](RELEASE-READINESS.md) |
61
68
  | See unfinished work | [Roadmap](../ROADMAP.md) |
62
- | Read the design for compiling function routes into per-route Lambdas | [Lambda compile spike](SPIKE-LAMBDA-COMPILE.md) |
63
69
  | Verify a running deployment matches the project | [Deployment checks](DEPLOYMENT-CHECKS.md) |
64
70
  | Inspect target support | [Capabilities and normalized representation](CAPABILITIES.md) |
65
71
  | Deploy to Vercel, AWS Lambda or Cloudflare Workers | [Vercel](VERCEL.md), [AWS](AWS.md), [Cloudflare](CLOUDFLARE.md), [provider verification evidence](PROVIDER-VERIFICATION.md) |
@@ -79,7 +85,6 @@ in the guides above and the [specification](SPECIFICATION.md).
79
85
  - [Version alignment](VERSION-ALIGNMENT.md) and [release security](RELEASE-SECURITY.md)
80
86
  describe peer compatibility and publication.
81
87
  - Open proposals: [middleware layering](SPIKE-CORE-LAYERING.md),
82
- [Lambda compilation](SPIKE-LAMBDA-COMPILE.md),
83
88
  [agent benchmark](SPIKE-AI-FRAMEWORK-BENCHMARK.md), and
84
89
  [business suite](SPIKE-BUSINESS-SUITE.md). None is an implementation promise.
85
90
  - [Historical plans and reviews](archive/README.md) are archived separately.
@@ -0,0 +1,73 @@
1
+ # URLCode 0.4.1
2
+
3
+ Core, UI, auth and admin share this explicitly selected stable version. This does not enable permanent fixed versioning. Internal peer minimums advance to this version; install the coordinated set together.
4
+
5
+ ```sh
6
+ npm install --save-exact @jimhoyd/urlcode@0.4.1 @jimhoyd/urlcode-ui@0.4.1 @jimhoyd/urlcode-auth@0.4.1 @jimhoyd/urlcode-admin@0.4.1
7
+ ```
8
+
9
+ This coordinated release moves core, UI, auth and admin from `0.4.0-alpha.3` to stable `0.4.1`. It makes the reviewed monorepo release line available through npm `latest` and keeps the four packages' peer minimums aligned.
10
+
11
+ The runtime retains its existing trust model: project functions and middleware run trusted in Node by default; routes declaring `sandbox: true` retain QuickJS/WASM isolation. The stable label is a distribution decision, not an independent security assessment or hostile multi-tenant readiness claim.
12
+
13
+ Release preparation now supports an explicit exit from alpha. Publication promotes the exact signed candidate archives, pins their manifest digest in immutable tags, checks actual npm installability, and updates the standalone starter to the published core version. Historical alpha versions and tags remain unchanged.
14
+
15
+ ### admin-kit-only-console.md
16
+
17
+ **Breaking:** the console renders only through the urlcode-ui kit. `ui` is now a
18
+ required option of `adminExtension` and of `createAdministrationRuntime`'s
19
+ `admin` block, which is itself no longer optional.
20
+
21
+ `@jimhoyd/urlcode-ui` was already a required peer dependency, so nothing new has
22
+ to be installed. What changed is that the `ui` *extension* must now be supplied
23
+ and active: the primitive render path — the same `admin/*` templates rendered
24
+ through the shared primitives inside a console shell admin built itself — is
25
+ gone, along with the `RenderPath` seam, the `activeKit()` helper, the
26
+ `ScreenOptions.shell.sidebar` markup and `src/admin-presentation.ts`. The kit
27
+ builds the sidebar, page header and skip target from the `nav` items and account
28
+ `menu` admin supplies, so the console shell has one representation instead of
29
+ two. `ScreenOptions.preferences` is gone too: the kit layout now renders through
30
+ the same resolved presentation as the body, so the document's `lang` matches the
31
+ copy on the page.
32
+
33
+ Activation refuses up front, rather than failing per request in production, when
34
+
35
+ - `ui` is missing,
36
+ - `ui` is supplied but not active yet — declare `ui` before `admin` under
37
+ `extensions` in `urlcode.yaml`, since the runtime activates in declaration
38
+ order, and mount its assets route, or
39
+ - the kit was built without `adminUiTemplates`.
40
+
41
+ To migrate, build the extension with admin's templates and pass it:
42
+
43
+ ```js
44
+ const ui = createUiExtension({projectSha256, projectRoot, sources: [authCatalogue], extensions: [authUiTemplates, adminUiTemplates]});
45
+ adminExtension({service, csrfKey, projectSha256, ui});
46
+ ```
47
+
48
+ Scaffolding emits that wiring for you: `scaffold()`, `initAdministration` and
49
+ `urlcode init --with ui,auth,admin` compose the kit and register the admin
50
+ templates with it. `ui` is now required, and must come before `admin`; the
51
+ scaffold refuses otherwise before writing anything.
52
+
53
+ ### auth-kit-only-render.md
54
+
55
+ Breaking: the `ui` extension is now required. Every account screen renders through the `urlcode-ui` kit; the shared-primitive fallback is gone. `authExtension({ui, ...})` refuses activation when `ui` is absent or when the runtime has not activated it, naming the missing piece instead of failing per request. Declare `ui` before `auth` in `urlcode.yaml` (with its asset route) and list `ui.registration` before `authExtension` in the host: the runtime activates extensions in the order `urlcode.yaml` declares them. `@jimhoyd/urlcode-ui` was already a required peer dependency, so nothing new needs installing; what changes is that the extension must be supplied and active. `ScreenOptions.ui` is no longer optional and `screenObserver` no longer reports a render path.
56
+
57
+ Scaffolding composes the kit for you: `urlcode init --with ui,auth` and the standalone `initAuthentication` now write a project whose `urlcode.yaml` declares `ui` first and whose host passes it to `authExtension`. The scaffold refuses when `ui` is missing, or ordered after `auth`, before anything is written.
58
+
59
+ ### auth-store-startup-diagnostics.md
60
+
61
+ Report which startup phase an auth store worker reached when its 15-second bound elapses, and reject at once when the worker fails or exits before reporting readiness instead of waiting the bound out. The status and code are unchanged; the detail is attached as the error's cause for operator logs and never reaches a response.
62
+
63
+ ### pin-generated-site-dependencies.md
64
+
65
+ `urlcode-auth init` now writes a `package.json` that pins this package and each declared peer at the exact version installed beside it, instead of a manifest with no dependencies at all; `initAuthentication` returns those pins and names any peer it could not resolve. Nothing is installed: running `npm install` in the generated directory to produce a lockfile stays the operator's explicit step, and no upgrade command exists.
66
+
67
+ ### ui-scaffold-peer-registration.md
68
+
69
+ The scaffold wires kit-rendering peers into the host it generates. `scaffold()` reads the composed `names` and emits `createUiExtension({..., sources: [authCatalogue], extensions: [authUiTemplates, adminUiTemplates]})`, importing each peer it needs, so `urlcode init --with ui,auth,admin` produces a project that activates. Previously it always wrote `sources: []` and no `extensions`, which left auth and admin without their copy and templates. `ui` alone still registers nothing and imports no peer.
70
+
71
+ Name `ui` first: the runtime activates extensions in the order `urlcode.yaml` declares them, core writes that file in `--with` order, and auth and admin both refuse to activate before the kit is active.
72
+
73
+ Publish to the npm `latest` channel in core → UI → auth → admin order after exact-commit CI and candidate verification. Existing tags and the `alpha` channel stay unchanged; this stable release advances `latest`. Changesets prerelease mode is exited. Update the standalone starter's exact core pin after registry installability is verified. This preparation is not evidence of publication or an independent security assessment.
@@ -0,0 +1,30 @@
1
+ # URLCode 0.4.2
2
+
3
+ Core, UI, auth and admin share this explicitly selected stable version. Independent package versioning remains enabled.
4
+
5
+ ```sh
6
+ npm install --save-exact @jimhoyd/urlcode@0.4.2 @jimhoyd/urlcode-ui@0.4.2 @jimhoyd/urlcode-auth@0.4.2 @jimhoyd/urlcode-admin@0.4.2
7
+ ```
8
+
9
+ ### admin-copy-project-override.md
10
+
11
+ Project translations of `adminUi.*` ids in `ui/copy/<locale>.json` now reach the admin console.
12
+
13
+ In a composed site the console copy source is built with `createAdminPresentation({ base: kit.presentation })`, and the admin ids were resolved only from the bundled English, so a project's `adminUi.*` entries were silently ignored. When a base presentation is given, an admin id the base resolves for the request's locale now wins; otherwise the bundled admin English still answers. Hosts that pass no `base` and hosts that supply their own presentation are unchanged.
14
+
15
+ ### ui-styles-once-per-verify.md
16
+
17
+ Compile Tailwind once per `npm run verify`.
18
+
19
+ No API change and no change to the generated stylesheet. `verify` used to run
20
+ `typecheck` then `build`, and each of those runs `styles`, so
21
+ `scripts/build-styles.mjs` compiled the same minified CSS twice per
22
+ verification. `verify` now runs `styles` once and then the compiler-only
23
+ `typecheck:tsc` and `build:tsc` scripts. `typecheck` and `build` are unchanged
24
+ from a caller's point of view: each still runs `styles` first, so either one
25
+ works on its own from a fresh checkout.
26
+
27
+ Nothing is cached and nothing is skipped because an output already exists; the
28
+ single run is unconditional, so a source change is still picked up.
29
+
30
+ Publish to the npm `latest` channel only after exact-commit CI and candidate verification. Existing tags and the `alpha` channel stay unchanged. Update the standalone starter after core registry installability is verified. This preparation is not evidence of publication or an independent security assessment.
@@ -1,13 +1,14 @@
1
1
  # Release readiness
2
2
 
3
- Status: `0.4.0-alpha.2` (`package.json`) alpha of the extension contract and
4
- agent tooling on top of the `0.3.0` self-hosted release; `0.4.0-alpha.1` is the
5
- most recent alpha actually published; the npm dist-tags for `@jimhoyd/urlcode`
6
- were `latest` = `0.3.0` and `alpha` = `0.4.0-alpha.1` when checked against the
7
- registry on 2026-09-19, so the repository's `0.4.0-alpha.2` is unpublished (see
8
- "Packaging" below). Production approval remains specific to
9
- the workload and deployment environment.
10
- This register describes the current public runtime, not future promises.
3
+ Status: this register records evidence and open gates for the public runtime.
4
+ It deliberately carries no current version table: the manifests are the version
5
+ authority, [VERSION-ALIGNMENT.md](VERSION-ALIGNMENT.md) explains channels and
6
+ ownership, and `npm run release:status` reads live registry and tag state. A
7
+ stable release is a packaging fact. It is not production approval and does not
8
+ perform any gate under "Gates before production approval" below; neither does a
9
+ passing CI run. Production approval remains specific to the workload and
10
+ deployment environment. Registry channels and deployments were not re-checked
11
+ when this register was reconciled on 2026-09-20 (#242).
11
12
  Use the contract and docs from the same pinned commit as your installed runtime.
12
13
 
13
14
  ## What is aligned
@@ -41,7 +42,34 @@ deferred to the post-merge run.
41
42
  | Worker replacement | Repeated guest deadlines shed load and the pool returns to service after backoff, rather than latching off for the life of the process | Bounded by the configured worker count; no cross-process load balancing |
42
43
  | Shutdown | New work rejects; repeated close shares completion | Existing deadlines can still fail during shutdown |
43
44
  | Activation/recovery | Invalid reload retains last-good snapshot; corrupt revision metadata rejects activation | No deployment orchestration |
44
- | Packaging | Packed installation and starter examples tested; sensitive files excluded | `0.3.0` and `0.4.0-alpha.1` are published to npm as `@jimhoyd/urlcode` (`latest` and `alpha` dist-tags respectively; dist-tags verified against the npm registry on 2026-09-19, when the repository stood at the unpublished `0.4.0-alpha.2`). Published extension packages on the same date: `@jimhoyd/urlcode-auth@0.1.0-alpha.2`, `@jimhoyd/urlcode-admin@0.1.0-alpha.2`, `@jimhoyd/urlcode-ui@0.1.0-alpha.4`. (`@jimhoyd/urlcode-short@0.1.0-alpha.1`, `@jimhoyd/urlcode-dynamic-link@0.1.0-alpha.1` and `@jimhoyd/urlcode-middleware@0.1.0-alpha.2` were also published on that date, then retired and unpublished later the same day; all three repositories were deleted. Middleware's withdrawal removed no capability — per-route middleware is native to core.) Observed in passing on that date: auth's dist-tags were split — `alpha` at `0.1.0-alpha.2` while `latest` lagged at `0.1.0-alpha.1`, so a plain `npm install @jimhoyd/urlcode-auth` resolved a build below admin's declared floor. That is resolved: auth and admin both read `latest` = `alpha` = `0.1.0-alpha.3`. `@jimhoyd/urlcode-ui` now carries a split of its own — `alpha` = `0.1.0-alpha.6`, `latest` = `0.1.0-alpha.5` — which is deliberate rather than drift, and safe only because admin's ui floor is exactly `>=0.1.0-alpha.5`. See [VERSION-ALIGNMENT.md](VERSION-ALIGNMENT.md). GitHub Releases attach a Homebrew formula (`urlcode.rb`) for manual copy into a tap, not an automated Homebrew Core/tap publish. No provider adapter guarantee. |
45
+ | Packaging | Packed installation and starter examples tested; sensitive files excluded | Published versions and channels: see VERSION-ALIGNMENT.md and `release:status`; this row asserts none. Dated registry observations are kept under "Dated packaging observations" below. GitHub Releases attach a Homebrew formula (`urlcode.rb`) for manual copy into a tap, not an automated Homebrew Core/tap publish. No provider adapter guarantee. |
46
+
47
+ ## Dated packaging observations
48
+
49
+ Kept as observed; each is true only of its date and none is current status.
50
+ Use `npm run release:status` for the present.
51
+
52
+ - **2026-09-19, registry check.** `@jimhoyd/urlcode` had `latest` = `0.3.0` and
53
+ `alpha` = `0.4.0-alpha.1`; the repository then stood at `0.4.0-alpha.2`, which
54
+ was unpublished. Published extension packages that day:
55
+ `@jimhoyd/urlcode-auth@0.1.0-alpha.2`, `@jimhoyd/urlcode-admin@0.1.0-alpha.2`,
56
+ `@jimhoyd/urlcode-ui@0.1.0-alpha.4`.
57
+ - **2026-09-19, retired packages.** `@jimhoyd/urlcode-short@0.1.0-alpha.1`,
58
+ `@jimhoyd/urlcode-dynamic-link@0.1.0-alpha.1` and
59
+ `@jimhoyd/urlcode-middleware@0.1.0-alpha.2` were published that day, then
60
+ retired and unpublished later the same day; all three repositories were
61
+ deleted. Middleware's withdrawal removed no capability: per-route middleware
62
+ is native to core.
63
+ - **2026-09-19, observed in passing.** auth's dist-tags were split (`alpha` at
64
+ `0.1.0-alpha.2`, `latest` at `0.1.0-alpha.1`), so a plain install resolved a
65
+ build below admin's declared floor.
66
+ - **Later 2026-09-19 or after (the source did not date these; treat as
67
+ superseded).** auth and admin both read `latest` = `alpha` =
68
+ `0.1.0-alpha.3`, resolving the split above; `@jimhoyd/urlcode-ui` carried a
69
+ deliberate `alpha` = `0.1.0-alpha.6` / `latest` = `0.1.0-alpha.5` split, safe
70
+ only because admin's ui floor was exactly `>=0.1.0-alpha.5`. The stable
71
+ `0.4.1` alignment described in [VERSION-ALIGNMENT.md](VERSION-ALIGNMENT.md)
72
+ postdates these.
45
73
 
46
74
  `npm run check:downstream-skills` is a manual, advisory report worth running
47
75
  before a release: it diffs core's `.claude/skills/` copies against copies
@@ -80,7 +108,8 @@ benchmark into a universal throughput claim.
80
108
  extension needs its own backup/restore drill; core has no durable store.
81
109
  4. Alerting and ownership for sustained errors, latency, readiness, dropped logs,
82
110
  disk space, restarts and backups. Pick service objectives for the actual app.
83
- 5. Stable-release support commitments before packaging/public reuse claims.
111
+ 5. Stable-release support commitments before packaging/public reuse claims;
112
+ a stable release exists, but that does not by itself record such commitments.
84
113
  Private security reporting and the current support baseline are documented in
85
114
  SECURITY.md.
86
115
 
@@ -88,7 +117,7 @@ License selection is resolved: URLCode is released under the Apache License 2.0,
88
117
  `package.json` declares it, and the repository carries the full license text.
89
118
  The remaining gates above are engineering and operational, not legal.
90
119
 
91
- The unreleased next-phase source now includes strict bulk/provider interchange,
120
+ The next-phase source (shipped in the alpha releases; see the archived plan) includes strict bulk/provider interchange,
92
121
  local recipes, TypeScript authoring, bounded self-hosted proxy/signals and read-only
93
122
  MCP. Local AWS/Vercel/Cloudflare adapter tests and deployment probe tooling exist,
94
123
  but actual provider deployments remain unverified. Node process/container hosting
@@ -18,16 +18,18 @@ means a successful nightly or manual `ci.yml` run across every supported OS/Node
18
18
  combination; the compact push/PR matrix alone does not authorize publication. Package manifests,
19
19
  lockfile versions and tag names must agree. Published peer floors must exist and
20
20
  extension tests must resolve the published packages, not workspace source.
21
- The manual core candidate and tagged core release use the same preparation
22
- script with the digest-pinned Node image from Dockerfile. Locked dependencies,
21
+ The candidate builds all package archives once using the digest-pinned Node
22
+ image from Dockerfile; publishers promote those exact signed bytes. The builder
23
+ installs Git from Debian for repository-fixture tests; Git is a test dependency,
24
+ not an addition to the runtime image or npm package. Locked dependencies,
23
25
  verification, runtime audit, package installation tests and local drills precede
24
26
  packing. Build commands in that container receive no GitHub token.
25
27
 
26
28
  The candidate workflow stores artifacts without publishing. A tagged release
27
29
  publishes npm only when `PUBLISH_NPM=true` and core images only when
28
- `PUBLISH_CONTAINER=true`. Preparation retains original artifacts for 90 days
29
- before publication so reruns of the same run reuse them. Manual candidates retain
30
- their existing 30-day retention. Keep independent last-good artifacts and
30
+ `PUBLISH_CONTAINER=true`. Candidate and release artifacts are retained for 90 days, and each package
31
+ GitHub release stores the complete signed candidate bundle. Retries verify and
32
+ reuse original retained or durable bytes; missing originals fail closed. Keep independent last-good artifacts and
31
33
  rehearse deployment rollback; Actions retention is not an archival guarantee.
32
34
 
33
35
  ## Identity and provenance
@@ -39,9 +41,12 @@ requires a reviewed registry trust migration. Successful preparation does not
39
41
  prove the registry-side identity permits direct publication.
40
42
 
41
43
  `actions/attest` signs the candidate files with GitHub OIDC/Sigstore provenance.
42
- Core includes its package archive, dependency SBOM, build manifest, checksums,
43
- and, for a release, Homebrew formula. Extensions include their archive and
44
- checksums. The core manifest records source SHA, lockfile hash, Node and
44
+ The candidate bundle includes all four archives, dependency SBOM, build manifest,
45
+ train metadata, checksums and Homebrew formula. Each publisher retains that
46
+ bundle and publishes only its selected npm archive. New annotated version tags
47
+ pin the candidate run ID and signed-manifest SHA256. The run ID is also bound
48
+ into the manifest; the digest prevents another attempt of that run from
49
+ substituting different artifacts. The core manifest records source SHA, lockfile hash, Node and
45
50
  TypeScript versions and emitted-file hashes. `dist/` is built, never committed.
46
51
 
47
52
  Verify an artifact with `gh attestation verify <tarball> --repo
@@ -59,18 +64,26 @@ identical SHA-512 integrity. GitHub assets are compared and missing assets added
59
64
  existing unequal assets are never clobbered. Transient registry errors fail
60
65
  closed rather than count as an unpublished version.
61
66
 
62
- Alpha versions use npm/GHCR `alpha` and GitHub prerelease classification. New
63
- GitHub releases are not automatically promoted to GitHub `latest`. Mutable npm
67
+ Alpha versions use npm/GHCR `alpha` and GitHub prerelease classification.
68
+ Explicit stable versions use npm `latest` and normal GitHub releases. Only the
69
+ stable core release advances GitHub `latest`, so the core installer cannot pick
70
+ an extension release. Stable preparation removes Changesets prerelease mode;
71
+ existing alpha artifacts, tags and channel pointers remain unchanged. Mutable npm
64
72
  and container channels cannot regress to an older version. Existing core image
65
73
  versions are reused only with matching source labels; unlabeled historical
66
74
  images require a reviewed migration rather than an inferred identity.
67
75
 
68
- The coordinator creates one package tag at a time and waits for success before
69
- releasing dependents. Shared publication concurrency avoids cross-version races.
76
+ The coordinator verifies candidate availability and provenance before creating
77
+ any version tag, then creates one at a time and waits for successful publication
78
+ and consumer-facing registry installability before releasing dependents. Shared publication concurrency avoids cross-version races.
70
79
  The active immutable-tag rule blocks release tag updates/deletions with no
71
80
  bypass actors; its configuration is in `.github/rulesets/release-tags.json`. No automation needs permission to bypass main checks or approve
72
- its own PR. A repository-scoped GitHub App is the preferred eventual automation
73
- identity; a narrowly scoped fine-grained PAT can support a maintainer script.
81
+ its own PR. Manual package/all release workflows share the coordinator and need
82
+ `RELEASE_AUTOMATION_TOKEN` because events created by the ordinary `GITHUB_TOKEN`
83
+ do not trigger tag publishers. A repository-scoped GitHub App is preferred. A
84
+ fine-grained PAT may select only `urlcode` and `urlcode-template`, with Contents,
85
+ Pull requests and Actions read/write plus Checks read. Neither identity needs
86
+ ruleset bypass, administration, npm secrets or review approval.
74
87
 
75
88
  ## Remaining validation
76
89
 
@@ -79,3 +92,9 @@ publish path, OIDC trust for every package, tag protection, GHCR behavior and
79
92
  partial-failure recovery must be verified on an authorized release; local tests
80
93
  and workflow inspection cannot prove them. The release helpers do not alter
81
94
  historical npm channels, GitHub flags, tags or registry artifacts.
95
+
96
+ The coordinated `.3` release proved the existing OIDC identities, but exposed
97
+ missing-artifact retry behavior tracked in #223. New workflows fail closed or
98
+ recover verified durable bytes; old immutable tags retain their original
99
+ workflow code. The new promotion path still needs a future explicitly authorized
100
+ release rehearsal; implementing it does not publish a new version.
@@ -202,7 +202,11 @@ entry may likewise be a string, normalized to `{source: <string>}`. Only the
202
202
  long form exists after loading, so `routes`, `audit`, `explain`, revision hashes
203
203
  and the field reference describe the expansion.
204
204
 
205
- ES modules only (`.mjs` or `.js`, independent of Node package settings).
205
+ ES modules only. `.mjs` is loaded as ESM in both modes. A `sandbox: true` route
206
+ also reads `.js` as ESM independently of Node package settings, but a trusted
207
+ route imports `.js` through Node's own loader, so an ESM `.js` module needs the
208
+ nearest `package.json` to declare `"type": "module"`; under `"type": "commonjs"`
209
+ it fails activation. Prefer `.mjs` for modules that must work in either mode.
206
210
  [Build-time TypeScript authoring](TYPESCRIPT-AUTHORING.md) can produce these
207
211
  JavaScript modules in a separate output project; serving does not transpile them.
208
212
  The build never imports application code into Node, uses fixed compiler settings,
@@ -35,7 +35,7 @@ either is blocked on the other.
35
35
  Core's job is to stay the smallest thing that is still a complete product on
36
36
  its own: YAML routing (`redirect`/`respond`/`page`/`static`/`download`) plus
37
37
  `function`, the one primitive with an actual serverless story
38
- ([`SPIKE-LAMBDA-COMPILE.md`](SPIKE-LAMBDA-COMPILE.md) — compile each `function`
38
+ ([`SPIKE-LAMBDA-COMPILE.md`](archive/2026-09-19/SPIKE-LAMBDA-COMPILE.md) — compile each `function`
39
39
  route to its own Lambda, the pattern `src/build-cloudflare.ts` already uses).
40
40
  That base alone serves static and dynamic content and deploys anywhere
41
41
  (`docs/FRAMEWORK.md` layer 1–3). Everything past that — accounts, admin,