@jimhoyd/urlcode 0.4.0-alpha.2 → 0.4.1
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.
- package/.claude/skills/urlcode-authoring/SKILL.md +17 -19
- package/.claude/skills/urlcode-operations/SKILL.md +9 -9
- package/.claude-plugin/marketplace.json +1 -1
- package/CONTRIBUTING.md +20 -16
- package/README.md +59 -64
- package/ROADMAP.md +66 -376
- package/dist/BUILD-MANIFEST.json +26 -25
- package/dist/agents-guide.js +6 -6
- package/dist/authoring.js +15 -1
- package/dist/build-static.js +2 -0
- package/dist/capability-query.js +0 -1
- package/dist/catalog.js +0 -1
- package/dist/cli.js +25 -9
- package/dist/config.js +1 -1
- package/dist/explain-cli.js +4 -2
- package/dist/explain.js +8 -2
- package/dist/extensions.js +1 -1
- package/dist/http-response.js +1 -1
- package/dist/index.js +1 -0
- package/dist/init-with.js +36 -11
- package/dist/manifest.js +8 -2
- package/dist/mcp-authoring.js +4 -4
- package/dist/mcp.js +1 -1
- package/dist/policies/cache.js +2 -2
- package/dist/policies.js +3 -1
- package/dist/prerender.js +4 -0
- package/dist/project-dependencies.js +305 -0
- package/dist/readiness.js +3 -0
- package/dist/route-diff.js +12 -5
- package/dist/runtime.js +1 -1
- package/dist/trusted-functions.js +4 -5
- package/dist/types/authoring.d.ts +9 -1
- package/dist/types/capability-query.d.ts +0 -1
- package/dist/types/catalog.d.ts +0 -4
- package/dist/types/config.d.ts +1 -9
- package/dist/types/explain.d.ts +6 -1
- package/dist/types/extensions.d.ts +1 -1
- package/dist/types/http-response.d.ts +0 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/init-with.d.ts +7 -13
- package/dist/types/manifest.d.ts +5 -2
- package/dist/types/project-dependencies.d.ts +78 -0
- package/dist/types/readiness.d.ts +2 -0
- package/dist/types/trusted-functions.d.ts +1 -4
- package/dist/types/types.d.ts +8 -1
- package/dist/types.js +8 -1
- package/dist/typescript-authoring.js +18 -7
- package/docs/AI-AUTHORING.md +15 -7
- package/docs/ASSETS.md +2 -1
- package/docs/AUTH-BACKUP.md +32 -0
- package/docs/AWS.md +9 -0
- package/docs/BEST-PRACTICES.md +17 -9
- package/docs/CAPABILITIES.md +1 -1
- package/docs/CI-FOLLOWUP-2026-09-19.md +97 -0
- package/docs/CI-RELEASE-AUDIT-2026-09-19.md +322 -0
- package/docs/CI.md +8 -3
- package/docs/CODEBASE-AUDIT-2026-09-20.md +284 -0
- package/docs/COMPOSING-A-SITE.md +278 -0
- package/docs/DEVELOPMENT-PIPELINE.md +270 -0
- package/docs/EXTENSIONS.md +51 -11
- package/docs/FRAMEWORK.md +67 -48
- package/docs/FUNCTION-SECURITY.md +44 -0
- package/docs/INSTALL.md +13 -8
- package/docs/LOCAL-DEVELOPMENT.md +3 -0
- package/docs/MIDDLEWARE.md +10 -4
- package/docs/OPEN-DECISIONS.md +224 -212
- package/docs/OPERATIONAL-PROOF.md +3 -3
- package/docs/OPERATIONS.md +3 -3
- package/docs/POLICIES.md +13 -5
- package/docs/PRERENDER.md +23 -11
- package/docs/PROJECT-DIRECTION.md +3 -3
- package/docs/READINESS.md +10 -5
- package/docs/README.md +20 -44
- package/docs/RELEASE-0.4.0-alpha.3.md +50 -0
- package/docs/RELEASE-0.4.1.md +73 -0
- package/docs/RELEASE-READINESS.md +6 -6
- package/docs/RELEASE-SECURITY.md +96 -181
- package/docs/RESILIENCE.md +3 -3
- package/docs/ROUTING.md +3 -4
- package/docs/SECURITY-AUDIT.md +2 -2
- package/docs/SPECIFICATION.md +12 -6
- package/docs/SPIKE-AI-FRAMEWORK-BENCHMARK.md +6 -5
- package/docs/SPIKE-BUSINESS-SUITE.md +14 -6
- package/docs/SPIKE-CORE-LAYERING.md +49 -18
- package/docs/SPIKE-DEFAULT-TRUST-MODEL.md +7 -5
- package/docs/STARTERS.md +17 -5
- package/docs/STATIC.md +14 -3
- package/docs/TOOLING.md +10 -7
- package/docs/TYPESCRIPT-AUTHORING.md +6 -1
- package/docs/VERCEL.md +10 -2
- package/docs/VERSION-ALIGNMENT.md +76 -201
- package/docs/archive/2026-09-19/EXTENSION-IMPLEMENTATION.md +68 -0
- package/docs/archive/2026-09-19/MANAGEMENT-SECURITY.md +102 -0
- package/docs/{NEXT-PHASE-PLAN.md → archive/2026-09-19/NEXT-PHASE-PLAN.md} +15 -5
- package/docs/{NEXT-STEPS.md → archive/2026-09-19/NEXT-STEPS.md} +15 -3
- package/docs/archive/2026-09-19/OPEN-DECISIONS.md +277 -0
- package/docs/archive/2026-09-19/RELEASE-SECURITY.md +186 -0
- package/docs/archive/2026-09-19/ROADMAP.md +387 -0
- package/docs/{SPIKE-EXTENSION-MODEL.md → archive/2026-09-19/SPIKE-EXTENSION-MODEL.md} +11 -0
- package/docs/{SPIKE-EXTENSIONS.md → archive/2026-09-19/SPIKE-EXTENSIONS.md} +25 -14
- package/docs/archive/2026-09-19/SPIKE-LAMBDA-COMPILE.md +365 -0
- package/docs/archive/2026-09-19/SPIKE-MONOREPO.md +778 -0
- package/docs/{USABILITY-REVIEW.md → archive/2026-09-19/USABILITY-REVIEW.md} +12 -2
- package/docs/archive/README.md +28 -0
- package/docs/policies/agents.md +1 -1
- package/docs/policies/compression.md +3 -2
- package/docs/policies/security.md +3 -2
- package/docs/yaml/functions.md +10 -2
- package/docs/yaml/middleware.md +5 -3
- package/examples/assets/example.yaml +1 -1
- package/examples/cookbook/middleware/envelope.mjs +4 -2
- package/examples/cookbook/route-index.json +1 -1
- package/examples/cookbook/routes/middleware.yaml +1 -1
- package/examples/prerender/README.md +14 -6
- package/examples/prerender/functions/page.mjs +4 -2
- package/examples/prerender/middleware/template.mjs +1 -1
- package/examples/prerender/prerender.mjs +1 -1
- package/examples/prerender/urlcode.yaml +8 -4
- package/llms-full.txt +503 -88
- package/llms.txt +6 -4
- package/package.json +27 -4
- package/packaging/claude-plugin/.claude-plugin/plugin.json +2 -2
- package/packaging/claude-plugin/skills/urlcode-authoring/SKILL.md +17 -19
- package/packaging/claude-plugin/skills/urlcode-operations/SKILL.md +9 -9
- package/recipes/authenticated-json-api/README.md +4 -3
- package/recipes/authenticated-json-api/functions/profile.mjs +2 -1
- package/recipes/authenticated-json-api/recipe.yaml +1 -1
- package/recipes/contact-form/functions/contact.mjs +2 -1
- package/recipes/contact-form/recipe.yaml +2 -2
- package/recipes/cors-api/README.md +2 -2
- package/recipes/cors-api/recipe.yaml +1 -1
- package/recipes/health-page/README.md +1 -1
- package/recipes/json-api/README.md +1 -1
- package/recipes/json-api/recipe.yaml +3 -3
- package/recipes/middleware/README.md +8 -4
- package/recipes/middleware/middleware/envelope.mjs +4 -2
- package/recipes/protected-download/README.md +1 -1
- package/recipes/protected-download/recipe.yaml +1 -1
- package/recipes/static-plus-api/README.md +2 -2
- package/recipes/static-plus-api/public/index.html +1 -1
- package/recipes/static-plus-api/recipe.yaml +1 -1
- package/recipes/static-plus-api/urlcode.yaml +1 -1
- package/recipes/typescript/recipe.yaml +4 -4
- package/skills/urlcode/SKILL.md +6 -6
- package/starters/default/AGENTS.md +6 -6
- package/docs/SPIKE-LAMBDA-COMPILE.md +0 -201
- package/docs/SPIKE-MONOREPO.md +0 -322
package/docs/OPEN-DECISIONS.md
CHANGED
|
@@ -1,212 +1,224 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
##
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
##
|
|
62
|
-
|
|
63
|
-
**
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
[
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
and
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
`
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
1
|
+
# Decisions to align
|
|
2
|
+
|
|
3
|
+
Reviewed 2026-09-19 against core `db375bf` and the current public package sources.
|
|
4
|
+
This is the maintainer's decision list, not a second implementation backlog.
|
|
5
|
+
The [roadmap](../ROADMAP.md) gives sequence and the [archive](archive/README.md)
|
|
6
|
+
keeps earlier discussions. Recommendations below are not accepted decisions.
|
|
7
|
+
|
|
8
|
+
## Principles already settled, in plain language
|
|
9
|
+
|
|
10
|
+
- **Describe first, code only when needed.** Use a supported YAML feature or
|
|
11
|
+
extension before writing plumbing. Custom application code is still welcome.
|
|
12
|
+
- **Your application code runs like normal Node code.** Functions and middleware
|
|
13
|
+
are trusted by default. `sandbox: true` deliberately restricts a route's whole
|
|
14
|
+
function/middleware chain. Request data still needs validation in either mode.
|
|
15
|
+
- **A grant controls what URLCode supplies, not what trusted code can access.**
|
|
16
|
+
Trusted code can independently read the host environment, files and network.
|
|
17
|
+
Opt-in sandboxing retains its existing isolation and revision-pinned grants.
|
|
18
|
+
- **Portable does not mean every host supports every feature.** Keep infrastructure
|
|
19
|
+
out of route YAML and reject unsupported targets before activation.
|
|
20
|
+
- **Core works alone; optional packages add accounts, admin and presentation.**
|
|
21
|
+
Core never imports those implementations. Shared UI belongs in `urlcode-ui`.
|
|
22
|
+
- **Documentation stays beside the owning code.** Core guides live here;
|
|
23
|
+
extension contracts and implementation status live in their repositories.
|
|
24
|
+
`urlcode-docs` is deleted. `urlcode-short` and `urlcode-dynamic-link` are retired.
|
|
25
|
+
- **Passing tests proves the tested behavior.** It does not prove deployment,
|
|
26
|
+
accessibility, hostile tenant isolation or independent security assessment.
|
|
27
|
+
- **Keep the free runtime useful.** Apache-2.0 remains unchanged; no mandatory
|
|
28
|
+
hosted account, paid capability gate or provider lock-in belongs in core.
|
|
29
|
+
|
|
30
|
+
## Decisions still needed
|
|
31
|
+
|
|
32
|
+
| Decision | What the code says today | Recommendation and consequence |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| 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
|
+
| 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
|
+
| 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. |
|
|
37
|
+
| 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. |
|
|
38
|
+
|
|
39
|
+
The broader [AI benchmark proposal](SPIKE-AI-FRAMEWORK-BENCHMARK.md) also needs a
|
|
40
|
+
chosen application, model-run budget and execution authorization. The existing
|
|
41
|
+
small-task harness can supply evidence without committing to that larger study.
|
|
42
|
+
|
|
43
|
+
## Closed questions removed from the active list
|
|
44
|
+
|
|
45
|
+
- Publishing convention is recorded in [version alignment](VERSION-ALIGNMENT.md):
|
|
46
|
+
publishable manifests on main, releases through reviewed tags/workflows.
|
|
47
|
+
- Core `0.4.0-alpha.2` and current extension releases exist; publishing that
|
|
48
|
+
already-shipped version is not a next step.
|
|
49
|
+
- Auth/admin kit adoption and shared form helpers are implemented in their code.
|
|
50
|
+
- The UI primitive fallback is retired, which settles the question this table
|
|
51
|
+
carried. Auth and admin now render every screen through the kit and refuse
|
|
52
|
+
activation without it (`packages/auth/src/auth.ts`: "there is no
|
|
53
|
+
shared-primitive fallback"), so "keep both" no longer describes the code.
|
|
54
|
+
- The template pins `0.4.0-alpha.2`. Its skill differences were read against that
|
|
55
|
+
pin: omitted handlers and advice about the removed management API are stale,
|
|
56
|
+
not intentional older-version behavior.
|
|
57
|
+
- The guidance checks run through `npm run check` inside `verify`; a regex check
|
|
58
|
+
is not a schema validator for every example. Extending its coverage is tracked
|
|
59
|
+
separately, not a reason to weaken review or bypass required checks.
|
|
60
|
+
|
|
61
|
+
## Accepted: one Node deployment per project
|
|
62
|
+
|
|
63
|
+
**Decided 2026-09-19.** Projects that use `function` or `middleware` deploy as
|
|
64
|
+
**one trusted Node process** — a container or a VM running the project as it
|
|
65
|
+
runs locally. That is the supported execution model, and it needs no new work:
|
|
66
|
+
it is what the runtime already does.
|
|
67
|
+
|
|
68
|
+
**Per-route Lambda compilation is not pursued.** The alternative on the table
|
|
69
|
+
was a build step emitting one Lambda per `function` route
|
|
70
|
+
([the proposal](archive/2026-09-19/SPIKE-LAMBDA-COMPILE.md)). It is declined for now, on three
|
|
71
|
+
grounds the proposal itself states:
|
|
72
|
+
|
|
73
|
+
1. It would replace the sandbox guarantee rather than preserve it, and lose the
|
|
74
|
+
fresh-per-invocation state that `sandbox: true` currently guarantees.
|
|
75
|
+
2. It would make this project the author of generated IAM roles — a
|
|
76
|
+
security-critical output it has never owned.
|
|
77
|
+
3. It would trade an honest refusal for a larger claim nobody has deployed.
|
|
78
|
+
|
|
79
|
+
Against that, a single Node deployment supports every route type today with no
|
|
80
|
+
compiler, no generated infrastructure and no second isolation story to document.
|
|
81
|
+
|
|
82
|
+
**What follows from this decision:**
|
|
83
|
+
|
|
84
|
+
- AWS and Vercel continue to refuse `function` and `middleware` at activation,
|
|
85
|
+
naming the route (`src/capabilities.ts`, `activateNativeOnly` in
|
|
86
|
+
`src/adapters.ts`). That refusal is now a **deliberate position**, not a gap
|
|
87
|
+
awaiting an adapter. Documentation should say so rather than implying the
|
|
88
|
+
support is coming.
|
|
89
|
+
- Serverless targets remain first-class for the declarative route types they can
|
|
90
|
+
actually serve; nothing about static or native-only deployment changes.
|
|
91
|
+
- [SPIKE-LAMBDA-COMPILE.md](archive/2026-09-19/SPIKE-LAMBDA-COMPILE.md) is kept as the analysis
|
|
92
|
+
behind this decision, not as a plan. Reopen it only on evidence of real demand
|
|
93
|
+
for URLCode `function` routes specifically on AWS serverless — the proposal's
|
|
94
|
+
own §6 already scopes what a first attempt would be.
|
|
95
|
+
|
|
96
|
+
This decision is about the *execution model*, not about AWS. Deploying the Node
|
|
97
|
+
process to AWS (ECS, EC2, App Runner) is an operator choice this fully supports.
|
|
98
|
+
|
|
99
|
+
## Accepted: per-package release tags
|
|
100
|
+
|
|
101
|
+
**Decided 2026-09-19.** Workspace packages under `packages/` release on
|
|
102
|
+
Changesets' own `<package name>@<version>` form — for example
|
|
103
|
+
`@jimhoyd/urlcode-ui@0.1.0-alpha.6`. Core keeps bare `v*`.
|
|
104
|
+
|
|
105
|
+
**The problem.** Core and all three extensions arrived here triggering on
|
|
106
|
+
`tags: ['v*']`, and their alpha tags overlap outright: ui shipped
|
|
107
|
+
`v0.1.0-alpha.2` through `-alpha.5`, admin `v0.1.0-alpha.1` and `-alpha.3`,
|
|
108
|
+
auth `v0.1.0-alpha.1` through `-alpha.3`. Across four repositories that was
|
|
109
|
+
fine. In one repository a single bare tag push starts more than one release
|
|
110
|
+
workflow. Each one fails closed on its own tag-matches-manifest check, so
|
|
111
|
+
nothing can mis-publish — but "two workflows race and one errors on every
|
|
112
|
+
release" is not a release process, and the failure is confusing rather than
|
|
113
|
+
informative.
|
|
114
|
+
|
|
115
|
+
**Why Changesets' form rather than a prefix like `ui-v0.1.0-alpha.6`.** Both
|
|
116
|
+
work and both are valid ref names. The deciding factor is that Changesets is
|
|
117
|
+
already the chosen release flow, and `changeset tag` emits the
|
|
118
|
+
`<name>@<version>` form natively. Picking anything else means writing and
|
|
119
|
+
maintaining a translation layer between the tool that computes the version and
|
|
120
|
+
the tag that triggers the publish — new code whose only job is to disagree
|
|
121
|
+
with a default. The spike chose Changesets partly because it is "cheap and
|
|
122
|
+
low-risk for an agent or a human to generate correctly"; hand-rolling the tag
|
|
123
|
+
shape undercuts exactly that.
|
|
124
|
+
|
|
125
|
+
**Why the two schemes cannot collide.** A scoped package name begins with `@`,
|
|
126
|
+
and GitHub's `v*` filter requires a leading `v`, so no tag can match both.
|
|
127
|
+
Verified rather than assumed, including that `*` does not match `/` in a filter
|
|
128
|
+
pattern, so `@jimhoyd/urlcode-ui@*` matches the version segment only.
|
|
129
|
+
|
|
130
|
+
**Core's asymmetry is forced, not preferred.** Under layout A core is the
|
|
131
|
+
repository root rather than a workspace member, so Changesets does not manage
|
|
132
|
+
it and `changeset version` will not bump it. Core therefore keeps the tag
|
|
133
|
+
scheme and release workflow it already had.
|
|
134
|
+
|
|
135
|
+
[`scripts/check-release-tags.ts`](../scripts/check-release-tags.ts) enforces
|
|
136
|
+
this in `npm run check`: it rejects a workspace package workflow that does not
|
|
137
|
+
trigger on its own `<name>@*`, rejects any workflow other than core's claiming
|
|
138
|
+
`v*`, and independently asserts that no two filters can match the same tag. The
|
|
139
|
+
reasoning above is the kind of prose that rots as soon as `auth` and `admin`
|
|
140
|
+
arrive, which is the whole argument this repository makes for enforcing checks
|
|
141
|
+
over documented intent.
|
|
142
|
+
|
|
143
|
+
## Done: the monorepo migration is complete
|
|
144
|
+
|
|
145
|
+
**Closed 2026-09-19.** `urlcode-ui`, `urlcode-auth` and `urlcode-admin` are
|
|
146
|
+
workspace packages under `packages/`, and all three have been released from
|
|
147
|
+
this repository — `@jimhoyd/urlcode-ui@0.1.0-alpha.6`,
|
|
148
|
+
`@jimhoyd/urlcode-auth@0.1.0-alpha.6`, `@jimhoyd/urlcode-admin@0.1.0-alpha.4`,
|
|
149
|
+
each on `alpha` with `latest` deliberately held behind. Core's dist-tags are
|
|
150
|
+
unchanged. The three source repositories are gone; their history survives only
|
|
151
|
+
as verified `git bundle`s, because the repository allows squash merges only and
|
|
152
|
+
the imported commits did not survive onto `main`.
|
|
153
|
+
|
|
154
|
+
The operational runbook is [DEVELOPMENT-PIPELINE.md](DEVELOPMENT-PIPELINE.md)
|
|
155
|
+
and [RELEASE-SECURITY.md](RELEASE-SECURITY.md). The plan itself is archived at
|
|
156
|
+
[archive/2026-09-19/SPIKE-MONOREPO.md](archive/2026-09-19/SPIKE-MONOREPO.md),
|
|
157
|
+
whose closing note records what the plan got wrong — chiefly that its
|
|
158
|
+
strongest argument, the reach of the enforcing checks, only became true after
|
|
159
|
+
both checkers were changed to discover workspace packages.
|
|
160
|
+
|
|
161
|
+
The section below is kept for the middleware decision it records, which is
|
|
162
|
+
still the reason there is no `packages/middleware`.
|
|
163
|
+
|
|
164
|
+
## Accepted: monorepo first — middleware withdrawn rather than consolidated
|
|
165
|
+
|
|
166
|
+
The maintainer confirmed that monorepo work is starting now. The earlier
|
|
167
|
+
recommendation to keep repositories separate for now is superseded.
|
|
168
|
+
|
|
169
|
+
**Reversed 2026-09-19: the middleware half of this decision no longer applies.**
|
|
170
|
+
This section used to say "move middleware into the monorepo as its own package
|
|
171
|
+
first, preserving its existing API and behavior," and explicitly: "do not
|
|
172
|
+
unpublish or retire the middleware package as part of the initial move."
|
|
173
|
+
That instruction was overtaken. `@jimhoyd/urlcode-middleware` has been
|
|
174
|
+
**unpublished** from npm at `0.1.0-alpha.2` and `jimhoyd-com/urlcode-middleware`
|
|
175
|
+
**deleted** — the package was withdrawn outright instead of migrated, so there
|
|
176
|
+
is no `packages/middleware` to create and no subsequent fold-into-core step.
|
|
177
|
+
The reversal is recorded here rather than deleted because the instruction it
|
|
178
|
+
replaces was explicit, and a reader who remembers it should be able to see that
|
|
179
|
+
it was changed deliberately and not simply forgotten.
|
|
180
|
+
|
|
181
|
+
Nothing was lost in capability terms: per-route middleware is **native to
|
|
182
|
+
core** via the `middleware:` array ([MIDDLEWARE.md](MIDDLEWARE.md)), and the
|
|
183
|
+
deleted package only ever offered the same behavior through the extension
|
|
184
|
+
seam. Trust remains the default and explicit sandbox choices keep their
|
|
185
|
+
meaning. The generic extension wrapping hook (`ExtensionInstance.middleware`,
|
|
186
|
+
`RuntimeExtension.cacheSensitive`) stays in core's contract for other
|
|
187
|
+
extensions — it is no longer exercised by any shipped package, which is worth
|
|
188
|
+
knowing before it is assumed to be covered. Static targets continue rejecting
|
|
189
|
+
request-time middleware because there is no server to run it.
|
|
190
|
+
|
|
191
|
+
Migration scope is therefore **core, auth, admin and UI**. Template and the
|
|
192
|
+
distribution tap stay outside that package move. The observed stale peer pins
|
|
193
|
+
and checkout-limited guidance checks strengthen the case for shared
|
|
194
|
+
verification: carry those checks across the new package paths, since merely
|
|
195
|
+
moving files does not prove every generated skill is covered. The cleanup PRs
|
|
196
|
+
that superseded the earlier zero-open-PR survey have since merged, and a fresh
|
|
197
|
+
survey again reports zero open pull requests across all four in-scope
|
|
198
|
+
repositories — re-run it per repository immediately before that repository
|
|
199
|
+
moves rather than trusting this line.
|
|
200
|
+
|
|
201
|
+
The [archived monorepo plan](archive/2026-09-19/SPIKE-MONOREPO.md) records
|
|
202
|
+
migration context.
|
|
203
|
+
[Issue 172](https://github.com/jimhoyd-com/urlcode/issues/172), which tracked
|
|
204
|
+
"consolidate middleware into core after moving it into the monorepo," was
|
|
205
|
+
**closed on 2026-09-19** as moot — there was nothing left to consolidate.
|
|
206
|
+
Migration starting is not a claim that it has landed.
|
|
207
|
+
|
|
208
|
+
## Source review baseline
|
|
209
|
+
|
|
210
|
+
| Repository | Reviewed commit | Code checked |
|
|
211
|
+
|---|---|---|
|
|
212
|
+
| core | `db375bf` | Runtime dispatch, schema normalization, capabilities, static compiler, prerender, MCP and resource generators |
|
|
213
|
+
| auth | `71957dd` | Lifecycle hooks, UI rendering and shared helper imports |
|
|
214
|
+
| admin | `f3b4882` | UI rendering, auth-service integration and shared helper imports |
|
|
215
|
+
| UI | `0e96f7f` | Shared forms, kit/host exports and copied core contract |
|
|
216
|
+
| ~~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`** |
|
|
217
|
+
| template | `4e09e50` | Exact core pin, generated guide and both vendored skills |
|
|
218
|
+
|
|
219
|
+
The Homebrew tap (`73eaaef`) still selects stable core `0.3.0`; its old trust
|
|
220
|
+
behavior belongs to that pin and must not be rewritten as alpha.2 behavior.
|
|
221
|
+
The other organization tap and Scoop bucket contain Gitroll, not URLCode.
|
|
222
|
+
The deleted documentation repository is historical context, not a second source
|
|
223
|
+
of current contracts; its former GitHub links no longer resolve. This review is targeted source inspection, not an audit of
|
|
224
|
+
every execution path or an independent security assessment.
|
|
@@ -13,9 +13,9 @@ only (3 of the 9 combinations); the macOS/Windows legs only run once a PR
|
|
|
13
13
|
merges, per `.github/workflows/ci.yml`'s matrix.
|
|
14
14
|
|
|
15
15
|
Core has no durable store of its own, so this drill has no backup/restore or
|
|
16
|
-
disk-exhaustion exercise:
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
disk-exhaustion exercise: an extension package owning durable state is
|
|
17
|
+
responsible for its own persistence proof. No such package ships today — the
|
|
18
|
+
`urlcode-dynamic-link` package that did has been retired.
|
|
19
19
|
|
|
20
20
|
## Required proof on the intended deployment
|
|
21
21
|
|
package/docs/OPERATIONS.md
CHANGED
|
@@ -149,9 +149,9 @@ deployment controls, not portable route behavior. Horizontal replicas
|
|
|
149
149
|
must use identical application/config versions and secret bindings. In-memory
|
|
150
150
|
function state is reset after every invocation, not durable/shared application state.
|
|
151
151
|
General application storage needs a future explicit capability broker; no
|
|
152
|
-
storage/network access is exposed to the guest.
|
|
153
|
-
|
|
154
|
-
|
|
152
|
+
storage/network access is exposed to the guest. Core no longer has a native
|
|
153
|
+
link store, and the `urlcode-dynamic-link` extension package that replaced it
|
|
154
|
+
has been retired and unpublished.
|
|
155
155
|
|
|
156
156
|
The health version combines route-definition and asset-representation digests;
|
|
157
157
|
it does not identify the complete function/runtime release. Record runtime commit,
|
package/docs/POLICIES.md
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
Policies are host-enforced behavior declared in YAML around a route: a
|
|
4
4
|
per-client request budget, a User-Agent deny list, a security-header profile,
|
|
5
5
|
content-coding negotiation and an HTTP caching strategy. They run in the host
|
|
6
|
-
process, outside
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
process, outside function/middleware execution — trusted or sandboxed alike —
|
|
7
|
+
so they can see the client address, keep counters across requests and touch
|
|
8
|
+
the transport, which route middleware by design cannot
|
|
9
|
+
([middleware](MIDDLEWARE.md), [function security](FUNCTION-SECURITY.md)).
|
|
9
10
|
|
|
10
11
|
Everything here is optional and off by default. A project with no `policies`
|
|
11
12
|
key and no `profiles` key behaves exactly as before: no policy module is
|
|
@@ -20,7 +21,7 @@ compiled and the request path is unchanged. Each policy has its own page:
|
|
|
20
21
|
| `cache` | [cache](policies/cache.md) | Named strategies from RFC 9111/5861/8246/9213 plus an origin memory cache |
|
|
21
22
|
|
|
22
23
|
The design and the reasoning behind each choice are in the
|
|
23
|
-
[extensions spike](SPIKE-EXTENSIONS.md). Operators who need behavior the
|
|
24
|
+
[extensions spike](archive/2026-09-19/SPIKE-EXTENSIONS.md). Operators who need behavior the
|
|
24
25
|
declarative block cannot express pass host [plugins](PLUGINS.md) in code; plugins
|
|
25
26
|
are never named in YAML.
|
|
26
27
|
|
|
@@ -42,7 +43,14 @@ routes:
|
|
|
42
43
|
`policies` at the top level sets project defaults; `routes.<path>.policies`
|
|
43
44
|
adjusts them for one route. Two route-level short forms exist. `auth`
|
|
44
45
|
expands to `policies.extensions.auth` when the project declares an auth
|
|
45
|
-
[extension](EXTENSIONS.md)
|
|
46
|
+
[extension](EXTENSIONS.md), carrying the same keys minus `required`;
|
|
47
|
+
`required: false` documents the intent and emits no policy. It accepts
|
|
48
|
+
`required`, `role`, `permission`, `verified`, `freshWithinSeconds` and
|
|
49
|
+
`onDeny` and nothing else — `role` is singular, and there is no `roles`. Like
|
|
50
|
+
`cache` below, it is refused rather than silently ignored in three cases: when
|
|
51
|
+
the project declares no `extensions.auth`, when the route also sets
|
|
52
|
+
`policies.extensions.auth` (use one form), and when the route sets
|
|
53
|
+
`policies.extensions: false`. `cache: {strategy, maxAge, ...}` expands to
|
|
46
54
|
`policies.cache` the same way — the compiler merges it into that route's
|
|
47
55
|
`policies` before anything else reads the project, so `routes`, `audit` and
|
|
48
56
|
`explain` see only the expanded long form, and it is refused alongside a
|