@jimhoyd/urlcode 0.4.2 → 0.4.6
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 +57 -14
- package/.claude/skills/urlcode-operations/SKILL.md +4 -0
- package/README.md +19 -15
- package/SECURITY.md +5 -3
- package/dist/BUILD-MANIFEST.json +30 -27
- package/dist/agent-context.js +82 -0
- package/dist/agents-guide.js +42 -42
- package/dist/authoring.js +12 -2
- package/dist/body-schema.js +159 -0
- package/dist/build-cloudflare.js +2 -0
- package/dist/capabilities.js +1 -1
- package/dist/cli.js +28 -12
- package/dist/config.js +74 -6
- package/dist/context.js +4 -6
- package/dist/errors.js +3 -1
- package/dist/examples.js +1 -1
- package/dist/extensions.js +60 -2
- package/dist/http-policy.js +19 -4
- package/dist/http-response.js +2 -2
- package/dist/init-with.js +71 -9
- package/dist/mcp.js +15 -2
- package/dist/pattern-guard.js +32 -0
- package/dist/policies/security.js +0 -0
- package/dist/project-tests.js +35 -11
- package/dist/readiness.js +184 -32
- package/dist/recipes.js +1 -1
- package/dist/router.js +17 -0
- package/dist/runtime.js +26 -3
- package/dist/scaffold.js +0 -0
- package/dist/server.js +26 -3
- package/dist/site.js +0 -0
- package/dist/tooling.js +2 -1
- package/dist/types/agent-context.d.ts +44 -0
- package/dist/types/authoring.d.ts +3 -1
- package/dist/types/body-schema.d.ts +58 -0
- package/dist/types/config.d.ts +10 -2
- package/dist/types/context.d.ts +1 -1
- package/dist/types/errors.d.ts +9 -1
- package/dist/types/examples.d.ts +1 -1
- package/dist/types/extensions.d.ts +47 -2
- package/dist/types/http-policy.d.ts +3 -0
- package/dist/types/init-with.d.ts +10 -1
- package/dist/types/pattern-guard.d.ts +10 -0
- package/dist/types/project-tests.d.ts +9 -0
- package/dist/types/readiness.d.ts +68 -0
- package/dist/types/recipes.d.ts +1 -1
- package/dist/types/runtime.d.ts +4 -0
- package/dist/types/server.d.ts +9 -1
- package/dist/types/tooling.d.ts +1 -0
- package/dist/types/types.d.ts +13 -0
- package/dist/types.js +10 -2
- package/dist/typescript-authoring.js +5 -3
- package/dist/verify-deployment.js +16 -10
- package/examples/body-validation/README.md +16 -0
- package/examples/body-validation/example.yaml +17 -0
- package/examples/body-validation/tests/requests.json +15 -0
- package/examples/body-validation/urlcode.yaml +34 -0
- package/examples/coverage-waiver/README.md +8 -0
- package/examples/coverage-waiver/example.yaml +16 -0
- package/examples/coverage-waiver/functions/notes.mjs +2 -0
- package/examples/coverage-waiver/tests/requests.json +3 -0
- package/examples/coverage-waiver/urlcode.yaml +10 -0
- package/examples/data-dir/README.md +39 -0
- package/examples/data-dir/data/welcome.txt +1 -0
- package/examples/data-dir/example.yaml +22 -0
- package/examples/data-dir/functions/note.mjs +18 -0
- package/examples/data-dir/tests/requests.json +6 -0
- package/examples/data-dir/urlcode.yaml +6 -0
- package/examples/lifecycle/README.md +15 -0
- package/examples/lifecycle/example.yaml +19 -0
- package/examples/lifecycle/functions/notes.mjs +29 -0
- package/examples/lifecycle/tests/requests.json +12 -0
- package/examples/lifecycle/urlcode.yaml +29 -0
- package/examples/not-found/README.md +10 -0
- package/examples/not-found/example.yaml +17 -0
- package/examples/not-found/public/404.html +3 -0
- package/examples/not-found/public/index.html +3 -0
- package/examples/not-found/tests/requests.json +7 -0
- package/examples/not-found/urlcode.yaml +7 -0
- package/examples/shared-blocks/README.md +11 -0
- package/examples/shared-blocks/example.yaml +17 -0
- package/examples/shared-blocks/tests/requests.json +7 -0
- package/examples/shared-blocks/urlcode.yaml +37 -0
- package/llms-full.txt +364 -49
- package/llms.txt +43 -5
- package/package.json +15 -22
- package/recipes/static-page/README.md +9 -0
- package/recipes/static-page/public/index.html +11 -0
- package/recipes/static-page/recipe.yaml +21 -0
- package/recipes/static-page/tests/requests.json +22 -0
- package/recipes/static-page/urlcode.yaml +7 -0
- package/recipes/static-plus-api/README.md +6 -0
- package/recipes/static-plus-api/urlcode.yaml +4 -0
- package/recipes/store-crud/README.md +53 -0
- package/recipes/store-crud/recipe.yaml +31 -0
- package/recipes/store-crud/tests/requests.json +18 -0
- package/recipes/store-crud/urlcode.yaml +18 -0
- package/schemas/urlcode.schema.json +125 -60
- package/skills/urlcode/SKILL.md +47 -27
- package/starters/default/AGENTS.md +43 -43
- package/starters/page/README.md +14 -0
- package/starters/page/public/index.html +12 -0
- package/starters/page/tests/requests.json +17 -0
- package/starters/page/urlcode.yaml +6 -0
- package/.claude-plugin/marketplace.json +0 -18
- package/CONTRIBUTING.md +0 -148
- package/ROADMAP.md +0 -70
- package/docs/AI-AUTHORING.md +0 -339
- package/docs/ASSETS.md +0 -107
- package/docs/AUTH-BACKUP.md +0 -32
- package/docs/AWS.md +0 -86
- package/docs/BEST-PRACTICES.md +0 -276
- package/docs/BULK.md +0 -79
- package/docs/CAPABILITIES.md +0 -192
- package/docs/CAPACITY.md +0 -305
- package/docs/CI-FOLLOWUP-2026-09-19.md +0 -97
- package/docs/CI-RELEASE-AUDIT-2026-09-19.md +0 -322
- package/docs/CI.md +0 -147
- package/docs/CLOUDFLARE.md +0 -109
- package/docs/CODEBASE-AUDIT-2026-09-20.md +0 -284
- package/docs/COMPLIANCE.md +0 -239
- package/docs/COMPOSING-A-SITE.md +0 -287
- package/docs/CONDITIONS.md +0 -74
- package/docs/CONTAINER-PROMOTION.md +0 -74
- package/docs/DEPLOYMENT-CHECKS.md +0 -108
- package/docs/DEVELOPMENT-PIPELINE.md +0 -304
- package/docs/EGRESS.md +0 -125
- package/docs/EXTENSIONS.md +0 -403
- package/docs/FRAMEWORK.md +0 -217
- package/docs/FUNCTION-SECURITY.md +0 -251
- package/docs/HTTP.md +0 -129
- package/docs/INSTALL.md +0 -128
- package/docs/INTERCHANGE.md +0 -134
- package/docs/LOAD-TESTING.md +0 -91
- package/docs/LOCAL-DEVELOPMENT.md +0 -102
- package/docs/MIDDLEWARE-EXAMPLES.md +0 -75
- package/docs/MIDDLEWARE.md +0 -102
- package/docs/MONITORING.md +0 -115
- package/docs/OBSERVABILITY.md +0 -222
- package/docs/OPEN-DECISIONS.md +0 -149
- package/docs/OPERATIONAL-PROOF.md +0 -41
- package/docs/OPERATIONS.md +0 -201
- package/docs/ORGANIZATION.md +0 -135
- package/docs/PERFORMANCE.md +0 -72
- package/docs/PLUGINS.md +0 -271
- package/docs/POLICIES.md +0 -211
- package/docs/PRERENDER.md +0 -245
- package/docs/PROJECT-DIRECTION.md +0 -118
- package/docs/PROVIDER-VERIFICATION.md +0 -84
- package/docs/READINESS.md +0 -153
- package/docs/README.md +0 -93
- package/docs/RECIPES.md +0 -99
- package/docs/RELEASE-0.4.0-alpha.3.md +0 -50
- package/docs/RELEASE-0.4.1.md +0 -73
- package/docs/RELEASE-0.4.2.md +0 -30
- package/docs/RELEASE-READINESS.md +0 -146
- package/docs/RELEASE-SECURITY.md +0 -100
- package/docs/RESILIENCE.md +0 -161
- package/docs/ROUTING.md +0 -92
- package/docs/SANDBOX-REVIEW.md +0 -72
- package/docs/SCAFFOLDING.md +0 -70
- package/docs/SECURITY-AUDIT.md +0 -164
- package/docs/SITE.md +0 -150
- package/docs/SPECIFICATION.md +0 -359
- package/docs/SPIKE-AI-FRAMEWORK-BENCHMARK.md +0 -288
- package/docs/SPIKE-BUSINESS-SUITE.md +0 -1029
- package/docs/SPIKE-CORE-LAYERING.md +0 -368
- package/docs/SPIKE-DEFAULT-TRUST-MODEL.md +0 -207
- package/docs/STANDARDS.md +0 -311
- package/docs/STARTERS.md +0 -83
- package/docs/STATIC.md +0 -105
- package/docs/TOOLING.md +0 -298
- package/docs/TUNNELS.md +0 -72
- package/docs/TYPESCRIPT-AUTHORING.md +0 -87
- package/docs/TYPESCRIPT.md +0 -123
- package/docs/VERCEL.md +0 -114
- package/docs/VERSION-ALIGNMENT.md +0 -88
- package/docs/YAML-GUIDE.md +0 -57
- package/docs/YAML-REFERENCE.md +0 -449
- package/docs/archive/2026-09-19/EXTENSION-IMPLEMENTATION.md +0 -68
- package/docs/archive/2026-09-19/MANAGEMENT-SECURITY.md +0 -102
- package/docs/archive/2026-09-19/NEXT-PHASE-PLAN.md +0 -108
- package/docs/archive/2026-09-19/NEXT-STEPS.md +0 -646
- package/docs/archive/2026-09-19/OPEN-DECISIONS.md +0 -277
- package/docs/archive/2026-09-19/RELEASE-SECURITY.md +0 -186
- package/docs/archive/2026-09-19/ROADMAP.md +0 -387
- package/docs/archive/2026-09-19/SPIKE-EXTENSION-MODEL.md +0 -430
- package/docs/archive/2026-09-19/SPIKE-EXTENSIONS.md +0 -492
- package/docs/archive/2026-09-19/SPIKE-LAMBDA-COMPILE.md +0 -365
- package/docs/archive/2026-09-19/SPIKE-MONOREPO.md +0 -778
- package/docs/archive/2026-09-19/USABILITY-REVIEW.md +0 -139
- package/docs/archive/2026-09-20/OPEN-DECISIONS-COMPLETED.md +0 -116
- package/docs/archive/README.md +0 -29
- package/docs/policies/agents.md +0 -182
- package/docs/policies/cache.md +0 -152
- package/docs/policies/compression.md +0 -169
- package/docs/policies/contract.md +0 -52
- package/docs/policies/hardened.md +0 -56
- package/docs/policies/interoperability.md +0 -169
- package/docs/policies/operations.md +0 -45
- package/docs/policies/security.md +0 -161
- package/docs/policies/throttle.md +0 -103
- package/docs/yaml/assets.md +0 -36
- package/docs/yaml/conditions.md +0 -20
- package/docs/yaml/functions.md +0 -168
- package/docs/yaml/middleware.md +0 -31
- package/docs/yaml/organization.md +0 -74
- package/docs/yaml/policies.md +0 -37
- package/docs/yaml/redirects.md +0 -64
- package/docs/yaml/responses.md +0 -57
- package/docs/yaml/site.md +0 -24
- package/packaging/claude-plugin/.claude-plugin/plugin.json +0 -19
- package/packaging/claude-plugin/skills/urlcode-authoring/SKILL.md +0 -130
- package/packaging/claude-plugin/skills/urlcode-operations/SKILL.md +0 -108
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
# Historical record
|
|
2
|
-
|
|
3
|
-
Archived 2026-09-19. This records an earlier implementation or proposal, not
|
|
4
|
-
current instructions. See the [current roadmap](../../../ROADMAP.md),
|
|
5
|
-
[current contract](../../SPECIFICATION.md) and [open decisions](../../OPEN-DECISIONS.md).
|
|
6
|
-
Remaining acceptance work is not declared complete by archiving this record.
|
|
7
|
-
|
|
8
|
-
<!-- trust-model-prose: historical-file -->
|
|
9
|
-
<!-- guidance-claims: ignore-file -->
|
|
10
|
-
|
|
11
|
-
# Open decisions
|
|
12
|
-
|
|
13
|
-
Status: written 2026-09-19 from a review of the repositories as they then
|
|
14
|
-
stood (nine; eight after `urlcode-docs` was deleted — see item 2). Every item
|
|
15
|
-
here is a maintainer decision that documentation cannot make. Each states what
|
|
16
|
-
is actually true today, what the options are, what it costs to leave open, and
|
|
17
|
-
a recommendation. Nothing here is committed scope; the
|
|
18
|
-
[roadmap](../../../ROADMAP.md) owns sequence and the
|
|
19
|
-
[readiness register](../../RELEASE-READINESS.md) owns what is proven.
|
|
20
|
-
|
|
21
|
-
This page exists because several documented positions have drifted apart from
|
|
22
|
-
each other and from the source. The drift is not the decisions themselves — it
|
|
23
|
-
is that they were never recorded in one place where the next contributor, human
|
|
24
|
-
or agent, would look.
|
|
25
|
-
|
|
26
|
-
## 1. Publish `0.4.0-alpha.2` — decided
|
|
27
|
-
|
|
28
|
-
**Decided 2026-09-19: publish `alpha.2`.** The recommendation below was taken
|
|
29
|
-
rather than walking back a correct declaration. The alignment is prepared
|
|
30
|
-
across all nine repositories and the order is recorded in
|
|
31
|
-
[the version register](../../VERSION-ALIGNMENT.md); what remains is merging and tagging.
|
|
32
|
-
|
|
33
|
-
The second hazard was taken with it: `@jimhoyd/urlcode-auth` moves `latest`
|
|
34
|
-
up to `0.1.0-alpha.2` so that a plain `npm install` no longer resolves a build
|
|
35
|
-
older than the floor `@jimhoyd/urlcode-admin` declares. That is a registry
|
|
36
|
-
operation (`npm dist-tag add`), not a source change, and it is listed in the
|
|
37
|
-
release steps.
|
|
38
|
-
|
|
39
|
-
The original entry, for the record:
|
|
40
|
-
|
|
41
|
-
> **Today:** the repository source is `0.4.0-alpha.2`. The npm dist-tags are
|
|
42
|
-
> `latest = 0.3.0` and `alpha = 0.4.0-alpha.1`. `alpha.2` carries the
|
|
43
|
-
> trusted-by-default execution change ([the decision](../../SPIKE-DEFAULT-TRUST-MODEL.md)).
|
|
44
|
-
>
|
|
45
|
-
> **Why it blocks other things:** `@jimhoyd/urlcode-middleware@0.1.0-alpha.1` is
|
|
46
|
-
> published with `peerDependencies: { "@jimhoyd/urlcode": ">=0.4.0-alpha.2" }`.
|
|
47
|
-
> No published core version satisfies that range, so a registry install of that
|
|
48
|
-
> package cannot resolve its peer. The range is correct; the publication order
|
|
49
|
-
> was not.
|
|
50
|
-
>
|
|
51
|
-
> **Recommendation:** publish `alpha.2`. It is the only option that does not
|
|
52
|
-
> require walking back a correct declaration.
|
|
53
|
-
|
|
54
|
-
## 2. Consolidate the repositories, or commit to the split
|
|
55
|
-
|
|
56
|
-
**Today (revised 2026-09-19):** eight repositories — `urlcode`,
|
|
57
|
-
`urlcode-auth`, `urlcode-admin`, `urlcode-ui`, `urlcode-middleware`,
|
|
58
|
-
`urlcode-template`, `urlcode-cloud` (private) and `homebrew-urlcode`. Five are
|
|
59
|
-
in scope for consolidation. [The monorepo spike](SPIKE-MONOREPO.md) is
|
|
60
|
-
complete, its layout is marked decided (option A), Changesets is decided, its
|
|
61
|
-
migration mechanics and sequencing are written, and it has three open questions
|
|
62
|
-
for the maintainer. It has been neither accepted nor rejected.
|
|
63
|
-
|
|
64
|
-
**What changed since this item was written:**
|
|
65
|
-
|
|
66
|
-
- The count fell rather than rose. `urlcode-dynamic-link`, `urlcode-short` and
|
|
67
|
-
`urlcode-docs` were deleted; the spike's in-scope set is **five, not six**.
|
|
68
|
-
The migration is smaller today than when this item claimed it only grows.
|
|
69
|
-
- **The spike's hard precondition is currently satisfied:** zero open pull
|
|
70
|
-
requests across all five in-scope repositories, and zero open issues outside
|
|
71
|
-
core. The issue-recreation step is a no-op. This is not a stable state.
|
|
72
|
-
- **The drift argument stopped being hypothetical.** `urlcode-auth`,
|
|
73
|
-
`urlcode-admin` and `urlcode-ui` all pin core at `d5e86017` and went 21
|
|
74
|
-
commits stale within a day of that pin being corrected by hand.
|
|
75
|
-
- **A new argument exists.** `check-trust-model-prose.ts` and
|
|
76
|
-
`check-guidance-claims.ts` now fail CI on stale or schema-contradicting
|
|
77
|
-
prose, but only within this checkout. The original observed failure —
|
|
78
|
-
`urlcode-auth/SECURITY.md` describing guest code as sandboxed — remains
|
|
79
|
-
unreachable by any check while `auth` is a separate repository. See
|
|
80
|
-
"What consolidation would newly enforce" in the spike.
|
|
81
|
-
|
|
82
|
-
**Cost of leaving it open:** the coordination work the spike describes —
|
|
83
|
-
pinning reviewed peer revisions by hand, chasing prose across repositories when
|
|
84
|
-
a contract changes — is paid again on every contract change, and the four
|
|
85
|
-
downstream repositories stay outside the enforcing checks that now protect this
|
|
86
|
-
one.
|
|
87
|
-
|
|
88
|
-
**Recommendation, sharpened:** decide before the next structural change, in
|
|
89
|
-
either direction; a recorded "no, and here is what we do instead about
|
|
90
|
-
cross-repo drift" closes this as well as a yes does. If the answer is yes, note
|
|
91
|
-
that the precondition is met now and will not stay met — the survey above is
|
|
92
|
-
the cheapest it will ever be. If the answer is no, the thing that needs
|
|
93
|
-
designing is how the trust-model and guidance checks reach the four downstream
|
|
94
|
-
repositories, because the pin drift shows the manual pass does not hold for a
|
|
95
|
-
day.
|
|
96
|
-
|
|
97
|
-
## 3. One way to attach middleware, or two
|
|
98
|
-
|
|
99
|
-
**Today:** core has the native `routes.<path>.middleware[]` array.
|
|
100
|
-
`urlcode-middleware` provides the same capability through the extension seam
|
|
101
|
-
and states that core's native array "keeps working unchanged".
|
|
102
|
-
[The layering spike](../../SPIKE-CORE-LAYERING.md) proposed *extracting* middleware
|
|
103
|
-
to narrow core to YAML plus `function`; what exists is an addition alongside it.
|
|
104
|
-
|
|
105
|
-
**Why this is a principle question:** the
|
|
106
|
-
[extension model review](SPIKE-EXTENSION-MODEL.md) rejected an earlier design
|
|
107
|
-
for exactly this reason — two ways to protect a route would drift apart — and
|
|
108
|
-
resolved it by removing one. The same test applies here.
|
|
109
|
-
|
|
110
|
-
**Options:** deprecate the native array on a stated timeline and complete the
|
|
111
|
-
extraction; or keep both and document precisely when each is correct, treating
|
|
112
|
-
the extension as a bounded variant rather than a successor.
|
|
113
|
-
|
|
114
|
-
**Recommendation:** decide explicitly and write the answer into both
|
|
115
|
-
repositories. Either is defensible; leaving both undescribed is not.
|
|
116
|
-
|
|
117
|
-
## 4. Where the backlog lives
|
|
118
|
-
|
|
119
|
-
**Today:** [next steps](NEXT-STEPS.md) holds roughly thirty tracked items
|
|
120
|
-
across nine phases. The repository has one open issue (#58). `AGENTS.md`
|
|
121
|
-
instructs contributors and agents to file what they find as issues on the
|
|
122
|
-
owning repository.
|
|
123
|
-
|
|
124
|
-
**The contradiction:** the instruction points at the issue tracker; the actual
|
|
125
|
-
plan is a Markdown file that no tracker reflects. A plan document also has no
|
|
126
|
-
state, so items stay written as future work after they ship — which is how
|
|
127
|
-
route-level `auth` came to be described as an invented field in merged agent
|
|
128
|
-
guidance (see item 7).
|
|
129
|
-
|
|
130
|
-
**Options:** move the phase items into issues and keep the document as the
|
|
131
|
-
narrative that links them; or keep the document as the system of record and
|
|
132
|
-
amend `AGENTS.md` to say so.
|
|
133
|
-
|
|
134
|
-
**Recommendation:** issues for items, document for sequence. It is the only
|
|
135
|
-
arrangement where "done" is recorded automatically.
|
|
136
|
-
|
|
137
|
-
## 5. Gate the business suite on evidence
|
|
138
|
-
|
|
139
|
-
**Today:** [the business suite spike](../../SPIKE-BUSINESS-SUITE.md) proposes seven
|
|
140
|
-
applications. [Project direction](../../PROJECT-DIRECTION.md) states the evidence
|
|
141
|
-
test: the framework grows from measured repetition, not from a list of things
|
|
142
|
-
applications might need. Phase 6 of [next steps](NEXT-STEPS.md) says candidate
|
|
143
|
-
areas are built only when the repetition log shows them repeating. The
|
|
144
|
-
repetition log does not exist yet, and the Phase 0 agent benchmark has not been
|
|
145
|
-
run.
|
|
146
|
-
|
|
147
|
-
**Recommendation:** record on the spike itself that it is gated behind the
|
|
148
|
-
benchmark and the repetition log, or amend the evidence test. Holding both
|
|
149
|
-
positions unannotated makes the stated principle decorative.
|
|
150
|
-
|
|
151
|
-
## 6. Where documentation is authored — decided
|
|
152
|
-
|
|
153
|
-
**Decided 2026-09-19: documentation is authored in this repository, in
|
|
154
|
-
`docs/`.** The instruction that sent new reader-facing pages to urlcode-docs is
|
|
155
|
-
removed from `AGENTS.md`, `CONTRIBUTING.md`, `README.md` and `docs/README.md`.
|
|
156
|
-
A behaviour change and its documentation now ship in the same pull request,
|
|
157
|
-
which is the arrangement where neither can land alone.
|
|
158
|
-
|
|
159
|
-
The original entry, for the record:
|
|
160
|
-
|
|
161
|
-
> **Today:** `AGENTS.md` states that urlcode-docs is the documentation home and
|
|
162
|
-
> the only place readers are sent, that new reader-facing pages go there, and
|
|
163
|
-
> that pages still under `docs/` here are being migrated. Roughly forty
|
|
164
|
-
> reader-facing pages remain in this repository, several duplicated in
|
|
165
|
-
> urlcode-docs.
|
|
166
|
-
>
|
|
167
|
-
> **Observed consequence:** the same fact drifts between copies. The public
|
|
168
|
-
> documentation site carried the correct trusted-by-default contract while
|
|
169
|
-
> `docs/OPERATIONS.md` in this repository still described functions as
|
|
170
|
-
> untrusted and isolated by default. <!-- trust-model-prose: historical -->
|
|
171
|
-
|
|
172
|
-
**The duplication is resolved by retirement, not by merging.** `urlcode-docs`
|
|
173
|
-
was deleted on 2026-09-19, along with `urlcode-short` and
|
|
174
|
-
`urlcode-dynamic-link`; all three GitHub repositories are gone, so links to
|
|
175
|
-
them 404 with no redirect. Rather than reconcile 51 drifted page pairs, the
|
|
176
|
-
content that was genuinely ahead in `urlcode-docs` was brought across before it
|
|
177
|
-
went away:
|
|
178
|
-
|
|
179
|
-
- Trusted-by-default corrections it carried and this repository did not, in
|
|
180
|
-
`POLICIES.md`, `policies/compression.md`, `BEST-PRACTICES.md`, `ASSETS.md`
|
|
181
|
-
and `PRERENDER.md`.
|
|
182
|
-
- Two pages that existed **only** there: `MANAGEMENT-SECURITY.md`, which
|
|
183
|
-
`SECURITY-AUDIT.md` already linked to twice from this repository and which
|
|
184
|
-
was therefore a live broken link, and `EXTENSION-IMPLEMENTATION.md`.
|
|
185
|
-
|
|
186
|
-
Its other pages were either behind this repository, or copies of pages owned by
|
|
187
|
-
`urlcode-auth`, `urlcode-admin`, `urlcode-ui` and `urlcode-dynamic-link`. Some
|
|
188
|
-
were actively stale: its `PRERENDER.md` and `VERCEL.md` still described the
|
|
189
|
-
`link` handler that `0.4.0-alpha.2` removed, so taking either wholesale would
|
|
190
|
-
have reintroduced a removed feature. Every page was judged individually.
|
|
191
|
-
|
|
192
|
-
**The lesson worth keeping:** the drift reached this size because the same page
|
|
193
|
-
existed in two places with no record of which side won. `AGENTS.md` now states
|
|
194
|
-
that documentation is authored here, so the second copy cannot reappear.
|
|
195
|
-
|
|
196
|
-
## 7. A review window, and a check that does not need one
|
|
197
|
-
|
|
198
|
-
**Today:** [governance](../../../GOVERNANCE.md) records one maintainer, a required
|
|
199
|
-
approval count of zero, and that "an independent human review is not yet
|
|
200
|
-
guaranteed". Pull requests and CI are mandatory; a second pair of eyes is not.
|
|
201
|
-
|
|
202
|
-
**What that permitted, concretely:** on 2026-09-19, three coordinated pull
|
|
203
|
-
requests (urlcode#158, urlcode-template#6, and urlcode-docs#17 — the last no
|
|
204
|
-
longer resolvable, that repository having been deleted) opened and merged
|
|
205
|
-
within nine minutes. They recorded a genuine improvement — the declarative-first
|
|
206
|
-
principle, propagated to every copy in one change — and alongside it the
|
|
207
|
-
statement that agents must "never invent an `auth` field". Route-level `auth` is
|
|
208
|
-
implemented: it is defined in `schemas/urlcode.schema.json` as a short form
|
|
209
|
-
expanding to `policies.extensions.auth`, expanded in `src/config.ts`, typed in
|
|
210
|
-
`src/types.ts`, and asserted in `test/recipes.test.ts`. The guidance now
|
|
211
|
-
instructs agents away from a supported declarative short form and toward the
|
|
212
|
-
lower-level policy form — the opposite of the principle the same change
|
|
213
|
-
introduced — in the generated project guide, the bundled starter, both
|
|
214
|
-
authoring skills, the packaged plugin skill and the two generated `llms` files.
|
|
215
|
-
|
|
216
|
-
Nothing failed. Lint, typecheck, generated-resource checks, the package smoke
|
|
217
|
-
test and 501 tests all passed, because no check compares what the guidance
|
|
218
|
-
claims against what the schema implements.
|
|
219
|
-
|
|
220
|
-
**The check, now implemented.** `scripts/check-guidance-claims.ts` runs inside
|
|
221
|
-
`npm run check` and exits non-zero on a contradiction between agent-facing
|
|
222
|
-
guidance and the schema, so this class of error fails CI instead of depending on
|
|
223
|
-
a reviewer's attention:
|
|
224
|
-
|
|
225
|
-
- Inputs: the agent-facing surfaces — `src/agents-guide.ts`,
|
|
226
|
-
`starters/default/AGENTS.md`, `skills/urlcode/SKILL.md`,
|
|
227
|
-
`.claude/skills/*/SKILL.md`, `packaging/claude-plugin/skills/*/SKILL.md`,
|
|
228
|
-
`llms.txt`, `llms-full.txt`, `docs/AI-AUTHORING.md`.
|
|
229
|
-
- Assertion one: every YAML field named as valid in those files resolves in
|
|
230
|
-
`schemas/urlcode.schema.json`. A guidance file may not teach a field the
|
|
231
|
-
schema does not accept.
|
|
232
|
-
- Assertion two, the one that would have caught this: no field that the schema
|
|
233
|
-
*does* define is described as unsupported, invented or nonexistent. Match the
|
|
234
|
-
negative phrasings deliberately ("never invent", "does not exist",
|
|
235
|
-
"unsupported field") within a short window of a schema-resolvable field name.
|
|
236
|
-
- Assertion three: handlers listed as available match the capability catalog,
|
|
237
|
-
so a removed handler (`link`, extracted to `urlcode-dynamic-link` in
|
|
238
|
-
`f7dbe54`) cannot linger in generated guidance.
|
|
239
|
-
- Exits non-zero on violation, with a documented `<!-- guidance-claims: ignore -->`
|
|
240
|
-
marker for text that is deliberately about another version. Verified against
|
|
241
|
-
both regressions: reintroducing the "never invent an `auth` field" sentence
|
|
242
|
-
fails the check, and adding the removed `link` handler to the inventory line
|
|
243
|
-
fails it.
|
|
244
|
-
|
|
245
|
-
What remains a decision: whether `npm run check` membership is enough, or the
|
|
246
|
-
check should also be named in the repository's required status checks so it
|
|
247
|
-
cannot be bypassed.
|
|
248
|
-
|
|
249
|
-
**Recommendation:** the check is in; keep it required. It is the part that does
|
|
250
|
-
not depend on a person being available. Whether to
|
|
251
|
-
also raise the required approval count is a separate call, and
|
|
252
|
-
[governance](../../../GOVERNANCE.md) already states the condition — when the trusted
|
|
253
|
-
maintainer team grows.
|
|
254
|
-
|
|
255
|
-
## 8. One publishing convention
|
|
256
|
-
|
|
257
|
-
**Today:** `urlcode-dynamic-link` and `urlcode-middleware` keep
|
|
258
|
-
`"private": true` on their main branch and drop it in the release commit;
|
|
259
|
-
`urlcode-auth`, `urlcode-admin` and `urlcode-ui` do not. All are published.
|
|
260
|
-
Both practices are defensible; having both means the flag no longer indicates
|
|
261
|
-
publication state.
|
|
262
|
-
|
|
263
|
-
**Recommendation:** pick one and state it where release process is documented.
|
|
264
|
-
|
|
265
|
-
## 9. Adjudicate the vendored skill drift
|
|
266
|
-
|
|
267
|
-
**Today:** `npm run check:downstream-skills` reports that `urlcode-template`'s
|
|
268
|
-
vendored authoring and operations skills differ from core's current `main` by
|
|
269
|
-
79 and 91 lines. The report is advisory by design and never fails, because a
|
|
270
|
-
downstream repository can correctly pin an older published core version
|
|
271
|
-
([issue 155](https://github.com/jimhoyd-com/urlcode/issues/155)).
|
|
272
|
-
|
|
273
|
-
**What is missing:** the judgment the report defers. No one has read the two
|
|
274
|
-
diffs and recorded which side is right for the template's `0.4.0-alpha.1` pin.
|
|
275
|
-
|
|
276
|
-
**Recommendation:** review both diffs once, record the verdict, and re-run the
|
|
277
|
-
report when the template repins.
|
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
# Historical release process — superseded September 19, 2026
|
|
2
|
-
|
|
3
|
-
This is the prior process and incident record. Current instructions live in
|
|
4
|
-
[release security](../../RELEASE-SECURITY.md). Links below resolve to the current documentation unless otherwise noted.
|
|
5
|
-
|
|
6
|
-
# Candidate and release security process
|
|
7
|
-
|
|
8
|
-
URLCode 0.3.0 is the Apache-2.0 self-hosted baseline; licensing is defined
|
|
9
|
-
in [LICENSE](../../../LICENSE). Two workflows share one audited build path and differ
|
|
10
|
-
only in what they do with its output:
|
|
11
|
-
|
|
12
|
-
- `candidate.yml` is dispatched manually on main and retains a **signed build
|
|
13
|
-
candidate** for 30 days without publishing it. Use it to review a commit
|
|
14
|
-
before tagging it.
|
|
15
|
-
- `release.yml` runs on a `v*` tag whose commit is already on main, and publishes
|
|
16
|
-
a GitHub release. Publication to npm and GHCR is opt-in per repository variable
|
|
17
|
-
(`PUBLISH_NPM`, `PUBLISH_CONTAINER`), so a release can be artifacts-only.
|
|
18
|
-
|
|
19
|
-
Neither workflow is a statement that a release is production-ready; see
|
|
20
|
-
[release readiness](../../RELEASE-READINESS.md).
|
|
21
|
-
|
|
22
|
-
## Publishing an alpha
|
|
23
|
-
|
|
24
|
-
An alpha such as `0.4.0-alpha.1` follows the same path: tag `v0.4.0-alpha.1`
|
|
25
|
-
on a commit that is already on main. The release workflow publishes to npm
|
|
26
|
-
only when the repository variable `PUBLISH_NPM` is `true` and the npm trusted
|
|
27
|
-
publisher for this repository and `release.yml` exists; otherwise the run is
|
|
28
|
-
artifacts-only (a GitHub release with the signed tarball). Publish order is
|
|
29
|
-
core → ui → auth → admin, because the extension packages declare
|
|
30
|
-
`@jimhoyd/urlcode >=0.4.0-alpha.1 <0.5.0` and must resolve the core alpha.
|
|
31
|
-
|
|
32
|
-
1. Report vulnerabilities privately through [GitHub advisories](https://github.com/jimhoyd-com/urlcode/security/advisories/new).
|
|
33
|
-
The maintainer triages impact, confirms affected exact revisions, coordinates a
|
|
34
|
-
fix/retest privately, and publishes an advisory with upgrade guidance when safe.
|
|
35
|
-
Current reviewed main is the security support baseline; no guaranteed SLA/backports.
|
|
36
|
-
2. Change dependencies through protected PRs. Review upstream provenance/advisories,
|
|
37
|
-
lockfile integrity and tests. Direct dependencies are exact, npm installs use
|
|
38
|
-
`npm ci`, CI actions use full commit SHAs, and container bases use SHA-256 digests.
|
|
39
|
-
Dependabot proposes updates; it does not authorize merging. Never silently
|
|
40
|
-
refresh dependencies during a candidate build.
|
|
41
|
-
3. After protected main checks pass, a maintainer manually dispatches
|
|
42
|
-
`.github/workflows/candidate.yml` **on main**, or pushes a `v<version>` tag to
|
|
43
|
-
run `.github/workflows/release.yml`. The release workflow refuses a tag whose
|
|
44
|
-
commit is not an ancestor of main, refuses a tag that disagrees with
|
|
45
|
-
`package.json`, and refuses to build a private or unlicensed package. It reads and validates the digest-pinned Node image directly from Dockerfile,
|
|
46
|
-
installs without lifecycle scripts, verifies, package-tests and runs local drills.
|
|
47
|
-
It packs the runtime and creates a CycloneDX dependency SBOM plus a manifest
|
|
48
|
-
recording source commit, lockfile hash, engine versions and artifact hashes.
|
|
49
|
-
The package contains `dist/`, produced inside that build from the tagged
|
|
50
|
-
TypeScript sources by Node's type stripping (`scripts/build.ts`); `dist` is
|
|
51
|
-
never committed. The manifest records the Node version that stripped it, the
|
|
52
|
-
locked TypeScript version and a SHA-256 per emitted file
|
|
53
|
-
(`dist/BUILD-MANIFEST.json`), so a download can be verified by running
|
|
54
|
-
`npm run build` on the tagged commit with that Node version and comparing its
|
|
55
|
-
`dist/` file by file. The build strips types and rewrites specifier
|
|
56
|
-
extensions; it never bundles, minifies or transforms syntax, so every line of
|
|
57
|
-
`dist/x.js` is the corresponding line of `src/x.ts`. CI's `build-fidelity`
|
|
58
|
-
job builds twice and diffs the trees, so the transform is known to be
|
|
59
|
-
deterministic before a tag is cut.
|
|
60
|
-
4. The pinned official `actions/attest` action signs provenance for the package,
|
|
61
|
-
SBOM and manifest using short-lived GitHub OIDC/Sigstore credentials. No long-lived
|
|
62
|
-
signing key is stored. Signing permissions exist only in this manual job; build
|
|
63
|
-
commands run in a container without passing GitHub tokens. Candidate files are
|
|
64
|
-
retained as GitHub Actions artifacts for 30 days. A release additionally attaches
|
|
65
|
-
them to the GitHub release, and publishes to npm and to GHCR when those
|
|
66
|
-
repository variables are enabled.
|
|
67
|
-
|
|
68
|
-
**npm publication holds no credential.** The registry is configured with a
|
|
69
|
-
trusted publisher naming this repository and `release.yml`, so the publish
|
|
70
|
-
step exchanges the job's OIDC identity for a credential that lives for the
|
|
71
|
-
length of one publish. There is no npm token in the repository's secrets to
|
|
72
|
-
leak, revoke or rotate, and a fork or another workflow cannot publish under
|
|
73
|
-
this package's name. Provenance is generated on that same identity, so
|
|
74
|
-
`--provenance` is not passed and its absence is not a downgrade.
|
|
75
|
-
|
|
76
|
-
A bearer token would silently take precedence over this exchange, so the
|
|
77
|
-
publish step must reference none; `test/release.test.ts` fails if one
|
|
78
|
-
reappears in it, and checks the npm and Node floors below which the exchange
|
|
79
|
-
is not attempted at all.
|
|
80
|
-
5. Download the candidate for the intended commit and verify **each file**, e.g.
|
|
81
|
-
`gh attestation verify jimhoyd-urlcode-0.3.0.tgz --repo jimhoyd-com/urlcode --signer-workflow jimhoyd-com/urlcode/.github/workflows/candidate.yml --source-ref refs/heads/main --source-digest APPROVED_COMMIT_SHA`
|
|
82
|
-
(use `release.yml` as the signer workflow for a tagged release).
|
|
83
|
-
Check the verified provenance's source commit against the approved commit, and
|
|
84
|
-
compare package/SBOM hashes with the signed manifest. A signature establishes
|
|
85
|
-
provenance, not safety, reproducible bytes or production approval. See
|
|
86
|
-
[GitHub verification](https://cli.github.com/manual/gh_attestation_verify) and
|
|
87
|
-
[the official attestation action](https://github.com/actions/attest).
|
|
88
|
-
6. Before registry publication, assign patch/release ownership and retention, and
|
|
89
|
-
document version/support policy. Before claiming hostile multi-tenant or
|
|
90
|
-
deployment-specific readiness, close independent-review and deployment gates. Keep last-good verified artifacts and compatible policies;
|
|
91
|
-
rehearse rollback. Never overwrite a published artifact/version or downgrade a
|
|
92
|
-
management writer past its audit/security baseline.
|
|
93
|
-
|
|
94
|
-
The SBOM describes npm dependencies; it is not a complete OS/container SBOM. Hosted
|
|
95
|
-
runners and action runtimes remain platform-controlled. Digest pins improve supply
|
|
96
|
-
chain integrity but do not prove byte-for-byte reproducibility or engine safety.
|
|
97
|
-
Signing verification must be demonstrated on a successful main workflow run before
|
|
98
|
-
claiming a candidate has been signed. Workflow definition alone is not that evidence.
|
|
99
|
-
`release.yml` ran successfully for the first time publishing `v0.4.0-alpha.1`
|
|
100
|
-
(2026-09-18), after the fixes below; treat any repository whose workflow has not
|
|
101
|
-
had a real successful tagged run the same way this one was treated before that.
|
|
102
|
-
|
|
103
|
-
## What broke on every first release, and why
|
|
104
|
-
|
|
105
|
-
Four repositories (core, ui, auth, admin) each cut their first tagged release in
|
|
106
|
-
the same session. Every one hit a subset of the same bugs, because each
|
|
107
|
-
`release.yml` was written and reviewed but never actually run end-to-end against
|
|
108
|
-
a real tag before. None of this is repository-specific; check for all of it
|
|
109
|
-
before trusting an unexercised release workflow:
|
|
110
|
-
|
|
111
|
-
- **`npm ci` on the bare runner's root-owned npm.** A build that runs entirely
|
|
112
|
-
inside a pinned Docker image never calls `actions/setup-node`, so a later
|
|
113
|
-
`npm install --global npm@11.5.1` (needed for the trusted-publishing floor)
|
|
114
|
-
hits the runner's preinstalled, root-owned npm and fails `EACCES`. Add
|
|
115
|
-
`actions/setup-node` before any step that installs global npm packages, even
|
|
116
|
-
if the main build never touches the runner's own Node.
|
|
117
|
-
- **The floor check must run after the pin, not before.** A guard asserting
|
|
118
|
-
"npm ≥ 11.5.1" is useless directly after `setup-node` with `node-version: '22'`,
|
|
119
|
-
which bundles npm ~10.9.x — it can never pass. The floor only means something
|
|
120
|
-
once the publish step's own `npm install --global npm@11.5.1` has actually run.
|
|
121
|
-
- **`npm publish` refuses an unqualified prerelease.** `You must specify a tag
|
|
122
|
-
using --tag when publishing a prerelease version.` npm's safety default is
|
|
123
|
-
`latest`; a prerelease must derive an explicit dist-tag from its version
|
|
124
|
-
(`0.1.0-alpha.1` → `alpha`, anything without a `-` → `latest`) and pass
|
|
125
|
-
`--tag`. This path is only exercised by a package's *first* prerelease, so it
|
|
126
|
-
silently sat broken in every repository until each hit it for the first time.
|
|
127
|
-
- **`npm pack --pack-destination candidate` needs `candidate/` to exist first.**
|
|
128
|
-
npm does not create the destination directory; `mkdir -p candidate` first.
|
|
129
|
-
- **A private repository's unauthenticated `git fetch origin main` cannot work.**
|
|
130
|
-
If checkout uses `persist-credentials: false` (correct, for a step that
|
|
131
|
-
should not need write access) and the repo is private, `git fetch` fails
|
|
132
|
-
`could not read Username for 'https://github.com'` before ever reaching the
|
|
133
|
-
version check. Compare the tag against main through the GitHub API instead
|
|
134
|
-
(`gh api repos/OWNER/REPO/compare/main...SHA --jq .status`, expecting
|
|
135
|
-
`identical` or `behind`) — it needs no credentials and stays read-only. Public
|
|
136
|
-
repositories can keep the plain fetch; it works there.
|
|
137
|
-
- **`--conditions=development` in `npm run verify`'s test script resolves peers
|
|
138
|
-
to source that a real npm install never ships.** The regular CI job symlinks
|
|
139
|
-
sibling checkouts in place of `node_modules`, so `./src/*.ts` exists and the
|
|
140
|
-
flag is correct there. A release installs real published tarballs of its
|
|
141
|
-
peers, which only ever ship `dist/`, so the same flag makes every import of a
|
|
142
|
-
peer fail `ERR_MODULE_NOT_FOUND`. Drop the flag for the release-workflow test
|
|
143
|
-
invocation specifically (run `node scripts/check-sqlite.mjs` explicitly first,
|
|
144
|
-
since bypassing `npm test` skips that pretest hook), and audit any test file
|
|
145
|
-
that separately hardcodes the flag in a spawned child process — it has to be
|
|
146
|
-
fixed the same way, independently, wherever it appears.
|
|
147
|
-
- **A peer-install command with the wrong flag combination is a silent no-op.**
|
|
148
|
-
`npm install --no-save --no-package-lock --ignore-scripts --legacy-peer-deps
|
|
149
|
-
<peer>@<version>` installed *nothing*, with no error, when the target package
|
|
150
|
-
names already appear in `peerDependencies` — `npm ci` earlier reports "added N
|
|
151
|
-
packages" as if it worked. Confirm the install actually happened
|
|
152
|
-
(`ls node_modules/@scope/*/package.json` and print each version) rather than
|
|
153
|
-
trusting the exit code; `--no-save --ignore-scripts <specs>` (no
|
|
154
|
-
`--no-package-lock`, no `--legacy-peer-deps`) is the version that works, paired
|
|
155
|
-
with `git diff --exit-code -- package.json package-lock.json` to prove nothing
|
|
156
|
-
was recorded as a dependency.
|
|
157
|
-
- **A version published from an unbuilt checkout is burned forever.** npm never
|
|
158
|
-
allows a version to be replaced. `@jimhoyd/urlcode-auth@0.1.0-alpha.1` reached
|
|
159
|
-
the registry from something other than the CI workflow (a manual `npm
|
|
160
|
-
publish` run before `npm run build` had produced `dist/`), so the published
|
|
161
|
-
tarball contained only metadata files and no code. Every consumer's typecheck
|
|
162
|
-
failed with `Cannot find module '@jimhoyd/urlcode-auth'` — a real, correct
|
|
163
|
-
failure, not a bug in the consumer. The only fix is bumping to a new version
|
|
164
|
-
and publishing that instead; nothing can repair or unpublish the bad one.
|
|
165
|
-
**Never run `npm publish` by hand outside the release workflow** — the
|
|
166
|
-
workflow is the only place that reliably builds before packing.
|
|
167
|
-
- **`ENEEDAUTH` on `npm publish` under trusted publishing usually means the
|
|
168
|
-
registry-side configuration doesn't exist or doesn't permit direct publish
|
|
169
|
-
yet**, not a workflow bug. Trusted publishing needs an entry under the
|
|
170
|
-
package's npm settings ("Trusted Publisher") naming the exact GitHub
|
|
171
|
-
org/repo and workflow filename, with no environment set unless the workflow
|
|
172
|
-
declares one; recent npm UI changes default new configurations to
|
|
173
|
-
"stage publish" only; "allow npm publish" (direct publish, which is what
|
|
174
|
-
this project's workflows do) must be explicitly enabled too. A wrong
|
|
175
|
-
org/repo/workflow match tends to surface as a 404, not `ENEEDAUTH`;
|
|
176
|
-
`ENEEDAUTH` is the signature of no matching configuration existing at all.
|
|
177
|
-
- **Publish order matters and is easy to get backwards.** Extension packages
|
|
178
|
-
declare `@jimhoyd/urlcode >=X <Y` as a peer range; publish core before ui,
|
|
179
|
-
auth or admin, or their own release-workflow peer-install step has nothing
|
|
180
|
-
real to resolve against.
|
|
181
|
-
|
|
182
|
-
None of the above is exotic; all nine bugs were found by actually running each
|
|
183
|
-
workflow against a real tag, one release at a time, and reading the actual
|
|
184
|
-
failure rather than guessing from the workflow source. Treat "the workflow file
|
|
185
|
-
looks right" and "the workflow has actually published successfully once" as two
|
|
186
|
-
different, unrelated claims.
|