@jimhoyd/urlcode 0.4.0-alpha.1 → 0.4.0-alpha.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 (191) hide show
  1. package/.claude/skills/urlcode-authoring/SKILL.md +24 -8
  2. package/.claude/skills/urlcode-operations/SKILL.md +10 -16
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/README.md +75 -62
  5. package/ROADMAP.md +61 -16
  6. package/SECURITY.md +23 -8
  7. package/dist/BUILD-MANIFEST.json +38 -43
  8. package/dist/agents-guide.js +18 -18
  9. package/dist/build-static.js +134 -0
  10. package/dist/capabilities.js +85 -31
  11. package/dist/capability-query.js +0 -1
  12. package/dist/cli.js +23 -31
  13. package/dist/compliance-rules/baseline.js +2 -10
  14. package/dist/compliance-rules/privacy.js +5 -16
  15. package/dist/compliance-rules/shared.js +0 -2
  16. package/dist/compliance.js +6 -8
  17. package/dist/config.js +15 -8
  18. package/dist/context.js +9 -10
  19. package/dist/examples.js +2 -2
  20. package/dist/explain-cli.js +3 -3
  21. package/dist/explain.js +5 -6
  22. package/dist/extensions.js +61 -2
  23. package/dist/function-sources.js +34 -2
  24. package/dist/function-worker.js +3 -1
  25. package/dist/functions.js +84 -13
  26. package/dist/guest-api.js +29 -3
  27. package/dist/index.js +3 -6
  28. package/dist/manifest.js +5 -7
  29. package/dist/mcp.js +1 -1
  30. package/dist/observability.js +1 -21
  31. package/dist/policies/cache.js +8 -3
  32. package/dist/policy.js +28 -9
  33. package/dist/project-tests.js +3 -3
  34. package/dist/readiness.js +32 -9
  35. package/dist/router.js +5 -7
  36. package/dist/runtime.js +77 -58
  37. package/dist/sandbox.js +48 -0
  38. package/dist/scaffold.js +0 -0
  39. package/dist/scripts/operational-drills.js +12 -54
  40. package/dist/server.js +3 -29
  41. package/dist/tooling.js +1 -1
  42. package/dist/trusted-functions.js +210 -0
  43. package/dist/types/build-static.d.ts +43 -0
  44. package/dist/types/capabilities.d.ts +14 -5
  45. package/dist/types/compliance-rules/shared.d.ts +0 -2
  46. package/dist/types/compliance.d.ts +0 -3
  47. package/dist/types/config.d.ts +2 -1
  48. package/dist/types/context.d.ts +2 -1
  49. package/dist/types/examples.d.ts +1 -1
  50. package/dist/types/extensions.d.ts +55 -0
  51. package/dist/types/function-sources.d.ts +4 -0
  52. package/dist/types/functions.d.ts +48 -5
  53. package/dist/types/guest-api.d.ts +1 -0
  54. package/dist/types/index.d.ts +3 -6
  55. package/dist/types/manifest.d.ts +1 -3
  56. package/dist/types/observability.d.ts +1 -14
  57. package/dist/types/project-tests.d.ts +1 -2
  58. package/dist/types/readiness.d.ts +10 -3
  59. package/dist/types/router.d.ts +2 -1
  60. package/dist/types/runtime.d.ts +0 -27
  61. package/dist/types/sandbox.d.ts +12 -0
  62. package/dist/types/scaffold.d.ts +0 -2
  63. package/dist/types/server.d.ts +1 -4
  64. package/dist/types/tooling.d.ts +3 -3
  65. package/dist/types/trusted-functions.d.ts +29 -0
  66. package/dist/types/types.d.ts +14 -7
  67. package/dist/types/verify-deployment.d.ts +2 -2
  68. package/dist/types.js +17 -4
  69. package/dist/typescript-authoring.js +55 -17
  70. package/dist/verify-deployment.js +3 -3
  71. package/docs/AI-AUTHORING.md +104 -9
  72. package/docs/AWS.md +4 -4
  73. package/docs/BEST-PRACTICES.md +3 -2
  74. package/docs/CAPABILITIES.md +29 -16
  75. package/docs/CAPACITY.md +128 -31
  76. package/docs/CLOUDFLARE.md +1 -2
  77. package/docs/COMPLIANCE.md +6 -9
  78. package/docs/DEPLOYMENT-CHECKS.md +1 -1
  79. package/docs/EXTENSIONS.md +183 -11
  80. package/docs/FRAMEWORK.md +35 -19
  81. package/docs/FUNCTION-SECURITY.md +129 -32
  82. package/docs/INSTALL.md +0 -5
  83. package/docs/LOAD-TESTING.md +4 -4
  84. package/docs/MIDDLEWARE.md +27 -16
  85. package/docs/MONITORING.md +2 -19
  86. package/docs/NEXT-PHASE-PLAN.md +12 -4
  87. package/docs/NEXT-STEPS.md +259 -40
  88. package/docs/OBSERVABILITY.md +7 -16
  89. package/docs/OPEN-DECISIONS.md +212 -0
  90. package/docs/OPERATIONAL-PROOF.md +26 -30
  91. package/docs/OPERATIONS.md +23 -32
  92. package/docs/POLICIES.md +15 -4
  93. package/docs/PRERENDER.md +2 -2
  94. package/docs/PROJECT-DIRECTION.md +34 -9
  95. package/docs/README.md +13 -11
  96. package/docs/RELEASE-READINESS.md +49 -29
  97. package/docs/RELEASE-SECURITY.md +89 -3
  98. package/docs/RESILIENCE.md +16 -15
  99. package/docs/ROUTING.md +8 -10
  100. package/docs/SANDBOX-REVIEW.md +19 -6
  101. package/docs/SCAFFOLDING.md +0 -2
  102. package/docs/SECURITY-AUDIT.md +40 -0
  103. package/docs/SPECIFICATION.md +60 -26
  104. package/docs/SPIKE-AI-FRAMEWORK-BENCHMARK.md +287 -0
  105. package/docs/SPIKE-BUSINESS-SUITE.md +8 -0
  106. package/docs/SPIKE-CORE-LAYERING.md +337 -0
  107. package/docs/SPIKE-DEFAULT-TRUST-MODEL.md +209 -0
  108. package/docs/SPIKE-EXTENSION-MODEL.md +2 -2
  109. package/docs/SPIKE-EXTENSIONS.md +5 -0
  110. package/docs/SPIKE-LAMBDA-COMPILE.md +4 -2
  111. package/docs/SPIKE-MONOREPO.md +322 -0
  112. package/docs/STARTERS.md +1 -1
  113. package/docs/STATIC.md +94 -0
  114. package/docs/TOOLING.md +13 -9
  115. package/docs/TUNNELS.md +0 -3
  116. package/docs/TYPESCRIPT-AUTHORING.md +27 -12
  117. package/docs/TYPESCRIPT.md +25 -4
  118. package/docs/USABILITY-REVIEW.md +7 -1
  119. package/docs/VERCEL.md +4 -5
  120. package/docs/VERSION-ALIGNMENT.md +205 -0
  121. package/docs/YAML-GUIDE.md +0 -3
  122. package/docs/YAML-REFERENCE.md +16 -6
  123. package/docs/policies/cache.md +13 -0
  124. package/examples/assets/example.yaml +1 -1
  125. package/examples/aws/example.yaml +1 -1
  126. package/examples/cloudflare/example.yaml +1 -1
  127. package/examples/conditions/example.yaml +1 -1
  128. package/examples/cookbook/example.yaml +1 -1
  129. package/examples/cookbook/middleware/bucket.mjs +12 -2
  130. package/examples/cookbook/middleware/locale.mjs +7 -3
  131. package/examples/egress/example.yaml +1 -1
  132. package/examples/extensions/example.yaml +1 -1
  133. package/examples/prerender/README.md +2 -2
  134. package/examples/prerender/example.yaml +1 -1
  135. package/examples/provider-conformance/example.yaml +1 -1
  136. package/examples/vercel/example.yaml +1 -1
  137. package/llms-full.txt +594 -219
  138. package/llms.txt +23 -12
  139. package/package.json +10 -3
  140. package/packaging/claude-plugin/.claude-plugin/plugin.json +1 -1
  141. package/packaging/claude-plugin/skills/urlcode-authoring/SKILL.md +24 -8
  142. package/packaging/claude-plugin/skills/urlcode-operations/SKILL.md +10 -16
  143. package/recipes/authenticated-json-api/recipe.yaml +1 -1
  144. package/recipes/contact-form/recipe.yaml +1 -1
  145. package/recipes/cors-api/recipe.yaml +1 -1
  146. package/recipes/health-page/recipe.yaml +1 -1
  147. package/recipes/json-api/recipe.yaml +1 -1
  148. package/recipes/middleware/middleware/bucket.mjs +12 -2
  149. package/recipes/middleware/middleware/locale.mjs +7 -3
  150. package/recipes/middleware/recipe.yaml +1 -1
  151. package/recipes/protected-download/recipe.yaml +1 -1
  152. package/recipes/redirect/recipe.yaml +1 -1
  153. package/recipes/static-plus-api/recipe.yaml +1 -1
  154. package/recipes/typescript/README.md +2 -1
  155. package/recipes/typescript/recipe.yaml +1 -1
  156. package/recipes/webhook-receiver/README.md +5 -1
  157. package/recipes/webhook-receiver/recipe.yaml +2 -1
  158. package/recipes/webhook-receiver/urlcode.yaml +7 -0
  159. package/schemas/recipe.schema.json +4 -3
  160. package/schemas/urlcode.schema.json +14 -41
  161. package/skills/urlcode/SKILL.md +29 -8
  162. package/starters/default/AGENTS.md +18 -18
  163. package/starters/default/urlcode.yaml +0 -1
  164. package/dist/link-api.js +0 -136
  165. package/dist/link-cli.js +0 -141
  166. package/dist/link-events.js +0 -76
  167. package/dist/link-records.js +0 -31
  168. package/dist/link-store-worker.js +0 -150
  169. package/dist/link-store.js +0 -250
  170. package/dist/management-policy.js +0 -40
  171. package/dist/sqlite-version.js +0 -6
  172. package/dist/types/link-api.d.ts +0 -30
  173. package/dist/types/link-cli.d.ts +0 -37
  174. package/dist/types/link-events.d.ts +0 -27
  175. package/dist/types/link-records.d.ts +0 -11
  176. package/dist/types/link-store-worker.d.ts +0 -1
  177. package/dist/types/link-store.d.ts +0 -130
  178. package/dist/types/management-policy.d.ts +0 -8
  179. package/dist/types/sqlite-version.d.ts +0 -1
  180. package/docs/DYNAMIC-LINKS.md +0 -61
  181. package/docs/MANAGEMENT-SECURITY.md +0 -82
  182. package/docs/links/cli.md +0 -110
  183. package/docs/links/limits.md +0 -175
  184. package/docs/links/management-api.md +0 -80
  185. package/docs/links/pools.md +0 -75
  186. package/docs/links/setup.md +0 -135
  187. package/docs/yaml/links.md +0 -30
  188. package/examples/live-links/README.md +0 -11
  189. package/examples/live-links/example.yaml +0 -21
  190. package/examples/live-links/tests/requests.json +0 -6
  191. package/examples/live-links/urlcode.yaml +0 -16
@@ -75,8 +75,8 @@ largest one that makes a number go green.
75
75
 
76
76
  ## What a passing run does not prove
77
77
 
78
- - **GET and HEAD only.** Function routes with request bodies, live-link writes
79
- and the management API are not exercised. `workload` states this in every report.
78
+ - **GET and HEAD only.** Function routes with request bodies are not exercised.
79
+ `workload` states this in every report.
80
80
  - **Redirects are not followed**, so a redirect's destination is never loaded.
81
81
  - **One client, one host, no slow peers.** Tail latency under adversarial
82
82
  clients, connection churn or packet loss is not measured.
@@ -87,5 +87,5 @@ largest one that makes a number go green.
87
87
  runtime and application revisions, host, and command with any figure you keep.
88
88
 
89
89
  `scripts/operational-drills.ts` covers the adjacent ground — mixed
90
- native/function/live-link load, an invalid reload, rollback and a quiesced
91
- backup/restore — as a local proof, never a statement about production.
90
+ native/function load, an invalid reload and rollback as a local proof,
91
+ never a statement about production.
@@ -2,7 +2,10 @@
2
2
 
3
3
  Middleware is reusable JavaScript around any route handler. It is optional and
4
4
  route-local; plain redirects and assets retain their native fast path when no
5
- middleware is attached. Adding middleware requires sandbox execution.
5
+ middleware is attached. Middleware runs trusted and unsandboxed by default,
6
+ in-process with full Node access, the same as a `function` route; add
7
+ `sandbox: true` on the route to run the whole chain isolated instead (see
8
+ [trust model and sandbox opt-in](FUNCTION-SECURITY.md)).
6
9
 
7
10
  ```yaml
8
11
  version: "1"
@@ -49,37 +52,45 @@ reading one consumes it for downstream code. There is no `clone()` or streaming
49
52
  API; pass parsed data through `context.state` when needed.
50
53
 
51
54
  Function responses support the existing text/JSON guest API. To transform their
52
- body, read it and return a new `Response`. Native redirect/respond/link/page/static/
55
+ body, read it and return a new `Response`. Native redirect/respond/page/static/
53
56
  download bodies are opaque and cannot be read through `text()` or `json()`.
54
57
  Returning the same native response preserves original bytes, including binary
55
58
  files, ranges and HEAD lengths. You may add headers, but cannot change its
56
59
  original status or existing native headers while preserving that body. To replace
57
60
  status, destination or content, return a new `Response` instead. Replacement
58
- responses follow the normal sandbox text/JSON and size limits. To wrap a shared
61
+ responses follow the normal response size limits, and (on a `sandbox: true`
62
+ route) the guest's text/JSON constraints. To wrap a shared
59
63
  template around file content, render it through a function at build time and
60
64
  publish the result: see [prerendering](PRERENDER.md).
61
65
 
62
66
  Route selection, enabled/expiry checks, methods and input/body validation run
63
67
  before middleware. Their errors do not pass through the chain. A missing file
64
- inside a selected static mount is a downstream 404 response. Stored-link lookup
65
- errors (missing, disabled, expired or unavailable store) precede middleware. YAML
68
+ inside a selected static mount is a downstream 404 response. YAML
66
69
  `response.headers` apply last and override matching middleware headers. Runtime
67
70
  framing and asset metadata protections still apply.
68
71
 
69
- ## Isolation and testing
72
+ ## Trust, isolation and testing
70
73
 
71
- The whole chain and handler run in one fresh QuickJS/WASM guest with one memory
72
- budget and one deadline. No Node, filesystem, shell, fetch or ambient environment
73
- is exposed. Modules can only access this route's declared dependency graphs.
74
- All middleware receive that route's approved bindings, so review the whole chain;
75
- source changes invalidate grants. See [security](FUNCTION-SECURITY.md).
74
+ The whole chain and handler run as one unit, in one execution mode, chosen by
75
+ the route's `sandbox` field not a per-middleware-entry choice. By default
76
+ (`sandbox` false/absent) that means trusted, in-process execution with full
77
+ Node access and no fixed worker-pool ceiling. With `sandbox: true` it means
78
+ one fresh QuickJS/WASM guest with one memory budget and one deadline: no
79
+ Node, filesystem, shell, fetch or ambient environment, and modules limited to
80
+ this route's declared dependency graph. Either way, all middleware on a route
81
+ receive that route's approved bindings, so review the whole chain; source
82
+ changes invalidate grants. See [trust model and sandbox opt-in](FUNCTION-SECURITY.md).
76
83
 
77
- Invalid responses and repeated `next()` calls fail with 502, exhausted capacity
78
- returns 503, and the shared deadline returns 504. Middleware cannot extend the
79
- deadline or catch the outer worker termination. Forgotten downstream work is
80
- still drained within that deadline.
84
+ Invalid responses and repeated `next()` calls fail with 502, and the deadline
85
+ returns 504 either way. A `sandbox: true` chain also sheds load with 503 when
86
+ the shared worker pool is exhausted, and cannot extend the deadline or catch
87
+ the outer worker termination; forgotten downstream work is still drained
88
+ within it. A trusted chain has no worker pool to exhaust (see
89
+ [capacity](CAPACITY.md)), but its deadline is a race against the call's own
90
+ promise rather than a forced kill — it cannot preempt code that blocks the
91
+ event loop synchronously.
81
92
 
82
93
  Include explicit request fixtures for middleware-wrapped routes: test success,
83
94
  early responses, validation failures and every configured method. Audit will
84
95
  report missing coverage instead of assuming native handler behavior. Benchmark
85
- with middleware enabled to measure its actual sandbox overhead.
96
+ with middleware enabled to measure its actual overhead, sandboxed or trusted.
@@ -19,7 +19,7 @@ analytics from these logs, and adding it would mean logging user data. See
19
19
  | Endpoint | Meaning | Alert when |
20
20
  |---|---|---|
21
21
  | `GET /_urlcode/health` | The process is alive and not shutting down. | It fails at all (`UrlcodeDown`). |
22
- | `GET /_urlcode/ready` | The active snapshot, every function worker and every configured link-store reader are available. | It fails for longer than replacement takes (`UrlcodeNotReady`). |
22
+ | `GET /_urlcode/ready` | The active snapshot and every function worker are available. | It fails for longer than replacement takes (`UrlcodeNotReady`). |
23
23
 
24
24
  Both return `{status, version, routes}`. A third endpoint,
25
25
  `GET /_urlcode/metrics`, exists only with `startServer({ metrics: true })` and
@@ -38,27 +38,10 @@ configuration digest and route count, so keep them internal.
38
38
  | `reload` | `status` (`ok`/`rejected`); `version` and `routes` on `ok` | A `rejected` reload means the last-good snapshot is still serving and a deploy did not take effect. |
39
39
  | `watch` | `status` | Development watcher failure; not used by `serve`. |
40
40
  | `function_worker` | `status` (`started`/`restarting`), `slot`; `attempt` and `delayMs` on `restarting` | Sustained `restarting` means a function is failing on real traffic. |
41
- | `link_store_worker` | `status`, `readOnly`, `attempt`, `delayMs` | The same signal for link-store connections. `status: "restarting"` reports an automatic replacement with its backoff; sustained restarts mean the underlying fault is not recoverable. |
42
- | `link_observer` | `status` (`failed`/`dropped`/`closed`); `reason` on `failed`; `dropped` on `dropped`; the delivery totals on `closed` | Only when an operator enables `linkEvents`. The link event channel below could not keep up or its collector failed. `dropped` means click records were discarded; like `logs_dropped`, anything built on that channel is incomplete while it fires. |
43
41
  | `logs_dropped` | `count` | The logger shed records because the collector fell behind. Every other signal is unreliable while this fires. |
44
42
  | `observer` | `status` (`failed`), `name` | An in-process observer threw; the request was unaffected. Written to the log only, never to observers. Sustained failures mean the observer's own sink is broken. |
45
43
  | `throttle`, `agents`, `cache` | `route`, `outcome`; `remaining` or `list` | Policy decisions; see [policies](POLICIES.md). `throttle` logs `allowed` only in report mode. |
46
44
  | `site` | `key`, `path`, `status` (`generated`/`shadowed`); or `severity` (`info`/`warning`) and `message` | Activation records for [site conventions](SITE.md). `shadowed` means a declared route took the path; an `info`/`warning` line reports an omitted `Sitemap:` line (no `--origin`), skipped list names or a far-future `security.txt` expiry. |
47
- | `management_request` | `timestamp`, `requestId`, `collection`, `action`, `authenticated`, `principal`, `status`, `outcome`, `durationMs` | Operator activity on the link-management API. `status` 0 means no response headers were sent before the peer disconnected; such a request may still have committed a mutation. |
48
-
49
- ### The link event channel
50
-
51
- `link_request` is **not** a stdout record. It is delivered to an `observe()`
52
- function the embedding operator process supplies, after the response is over, so
53
- it can never change, delay or fail a redirect. It carries `requestId`,
54
- `collection`, `route`, `method`, `status`, `outcome`
55
- (`completed`/`aborted`/`missing`/`disabled`/`expired`/`invalid_code`/`invalid_record`/`unavailable`)
56
- and `durationMs`. The short code is redacted unless `includeCode` is set, because
57
- a code identifies the link somebody followed.
58
-
59
- The queue is bounded: under overload it drops events and reports the count
60
- through `link_observer` rather than growing memory. Alert on those drops if you
61
- count clicks — a quiet channel and a dropping channel look identical downstream.
62
45
 
63
46
  Startup prints `listening` with the effective `origin`, which is what functions
64
47
  and absolute URLs see. Behind a proxy or tunnel this must be your public origin;
@@ -69,7 +52,7 @@ forwarded headers are deliberately not trusted. See [tunnels](TUNNELS.md).
69
52
  `startServer({ metrics: true })` serves `GET /_urlcode/metrics` in Prometheus
70
53
  text format: requests by status class and by configured route, in-flight
71
54
  gauges, shed 503s, reloads, worker restarts and healthy slots, policy
72
- outcomes, link outcomes, dropped logs and observer errors, all prefixed
55
+ outcomes, dropped logs and observer errors, all prefixed
73
56
  `urlcode_`. The same numbers are available in process as `app.metrics()`. The
74
57
  endpoint shares the probes' admission budget and bind host and is off by
75
58
  default; it discloses route patterns and traffic shape, so keep it internal
@@ -5,6 +5,13 @@ the capability catalog; the subsequent source work implements the bounded
5
5
  Phase B–D features below. This describes the source additions after `0.3.0` that ship in
6
6
  `0.4.0-alpha.1`, not a claim that provider deployments have been verified.
7
7
 
8
+ > **Update:** this document describes the `0.4.0-alpha.1` source work as it
9
+ > stood on 2026-09-17, when every `function`/`middleware` route was sandboxed.
10
+ > The default changed in `0.4.0-alpha.2`: those routes now run trusted and
11
+ > unsandboxed in the host process unless the route declares `sandbox: true`,
12
+ > which gives it exactly the QuickJS/WASM execution described below. See
13
+ > [SPIKE-DEFAULT-TRUST-MODEL.md](SPIKE-DEFAULT-TRUST-MODEL.md).
14
+
8
15
  ## Implementation and evidence
9
16
 
10
17
  | Phase | Implemented source | Evidence and remaining limits |
@@ -36,10 +43,11 @@ binding resolution and activation and distinguishes implementation support from
36
43
  actual deployment evidence. Unknown or unsupported targets fail closed.
37
44
 
38
45
  Project YAML describes route behavior. Provider infrastructure and outbound
39
- origin grants stay in operator configuration. Functions remain untrusted
40
- QuickJS/WASM guests with no host-code fallback. Existing explicit external
41
- bindings and new egress grants remain pinned to the exact configuration/source
42
- revision. Compilation and conversion do not resolve credentials or manufacture
46
+ origin grants stay in operator configuration. Through `0.4.0-alpha.1`,
47
+ functions remained untrusted QuickJS/WASM guests with no host-code fallback
48
+ (see the update note above). <!-- trust-model-prose: historical -->
49
+ Existing explicit external bindings and new egress grants remain pinned to the
50
+ exact configuration/source revision. Compilation and conversion do not resolve credentials or manufacture
43
51
  grants. File authors publish new projects without overwriting unrelated work.
44
52
 
45
53
  The five policy modules remain the authority for their target-sensitive
@@ -24,14 +24,41 @@ maintain?) and the evidence test (measured repetition, not a feature list).
24
24
  The order below follows from that. **Prove the thesis before building on
25
25
  it.** Phase 0 is the benchmark; if it shows a large saving, the rest is worth
26
26
  the work, and if it shows a small one, the abstraction is not doing enough yet
27
- and the next phases change. Nothing here weakens the security model: guest
28
- code stays untrusted, grants stay operator-owned, agents cannot self-authorize,
29
- unsupported behavior fails with the route named, and inspection tooling never
30
- becomes a privilege escalation path.
27
+ and the next phases change. Nothing here weakens the security model: a
28
+ `sandbox: true` route's isolation stays exactly as strict, grants stay
29
+ operator-owned regardless of a route's trust setting, agents cannot
30
+ self-authorize, unsupported behavior fails with the route named, and
31
+ inspection tooling never becomes a privilege escalation path.
32
+
33
+ **Status 2026-09-19 (sequence).** Most of Phases 1, 3 and 4 landed before the
34
+ Phase 0 benchmark produced a single model-backed run. The instrument is built
35
+ and tested (`benchmarks/agent/harness.ts`, `benchmarks/agent/count-lines.ts`,
36
+ `benchmarks/agent/adapters/anthropic.ts`), but `benchmarks/agent/runs/` holds
37
+ only `baseline.json`, a stub record, so the application-specific code ratio is
38
+ still unmeasured and the re-prioritization 0.1 describes has never been
39
+ exercised. This is an observation about the order the work happened in, not a
40
+ change of priorities: Phase 0 still owns the evidence, and Phase 5 is still how
41
+ each shipped phase gets measured. Items below are marked from the source at this
42
+ revision.
31
43
 
32
44
  ## Phase 0: prove the thesis (M, core `benchmarks/agent/`, before anything else)
33
45
 
34
- ### 0.1 The agent benchmark
46
+ ### 0.1 The agent benchmark — partly done
47
+
48
+ Done 2026-09-19, the instrument only: the runner, the counting rule, the tasks
49
+ and the storage format exist and are tested — `benchmarks/agent/harness.ts`
50
+ (`runArm`, `summarize`, `securityChecklist`, `writeRun`),
51
+ `benchmarks/agent/count-lines.ts` (`classify`, `codeRatio`),
52
+ `benchmarks/agent/adapters.ts` (`selectAdapter`, `stubAdapter`) with
53
+ `benchmarks/agent/adapters/anthropic.ts`, ten task directories under
54
+ `benchmarks/agent/tasks/`, both arm preambles under `benchmarks/agent/prompts/`,
55
+ `npm run benchmark:agent`, and `test/agent-benchmark.test.ts` ("the counting
56
+ rule: functions and declared modules are the idea, everything else is
57
+ plumbing"). The measurement is not done: `benchmarks/agent/runs/` holds only
58
+ `baseline.json`, whose `model` is `stub`, and `benchmarks/agent/README.md`
59
+ states that no number there is evidence until a stored run with a real model
60
+ adapter backs it. Running the tasks in both arms against a real model, storing
61
+ the runs and publishing only what they support remains the work below.
35
62
 
36
63
  Fixes: there is no evidence that URLCode saves agent effort, and the whole
37
64
  plan depends on it.
@@ -61,7 +88,16 @@ plan depends on it.
61
88
  too small or too hard to discover, and Phases 1, 3 and 4 are re-prioritized
62
89
  from what the runs show the agent still had to write.
63
90
 
64
- ### 0.2 Authoring regression evals (S, once 0.1 exists)
91
+ ### 0.2 Authoring regression evals (S, once 0.1 exists) — done
92
+
93
+ Done 2026-09-19: the five prompts are `benchmarks/agent/evals/*.yaml`
94
+ (`add-redirect`, `add-authenticated-endpoint`, `serve-directory`,
95
+ `add-middleware`, `create-webhook-endpoint`), scored against the eight criteria
96
+ by `scoreEval` and `summarizeEvals` in `benchmarks/agent/harness.ts`, gated
97
+ against `benchmarks/agent/runs/baseline.json` by `benchmarks/agent/gate.ts`, and
98
+ run weekly by `.github/workflows/evals.yml`. Caveat: the committed baseline is a
99
+ stub record and the scheduled job skips cleanly when no model key is configured,
100
+ so the recorded pass rate proves the pipeline, not a model's behavior.
65
101
 
66
102
  Prompts for common requests ("add a redirect", "add an authenticated
67
103
  endpoint", "serve this directory", "add middleware", "create a webhook
@@ -80,7 +116,17 @@ read-side tools (`inspectProject`, `validateProject`, `explainRoute`,
80
116
  Keep all of it. The gap is that an agent still has to read documents to find
81
117
  facts the runtime already knows.
82
118
 
83
- ### 1.1 Application-level `AGENTS.md` from `urlcode init` (S, core)
119
+ ### 1.1 Application-level `AGENTS.md` from `urlcode init` (S, core) — done
120
+
121
+ Done 2026-09-19: `renderAgentsGuide` in `src/agents-guide.ts` generates the file
122
+ from the installed capability catalog, `initProject` in `src/authoring.ts`
123
+ writes it, and `initProjectWith` in `src/init-with.ts` calls `initProject`, so
124
+ `init --with` writes it into the project directory too; `renderMcpConfig` writes
125
+ `.mcp.json` beside it. `test/cli.test.ts` asserts the commands, the packaged
126
+ skill path and the MCP tool names the file lists, its length bound, and that the
127
+ committed `starters/default/AGENTS.md` equals what `init` generates from this
128
+ runtime. Caveat: the public `urlcode-template` copy is outside this repository
129
+ and is not checked here; `npm run check:downstream-skills` stays advisory.
84
130
 
85
131
  Fixes: a project made with URLCode is not self-describing to Claude Code,
86
132
  Codex or any repository-aware agent. Today's `AGENTS.md` explains how to work
@@ -97,14 +143,22 @@ on the runtime, not on an application.
97
143
  - Proof: starter test asserts the file exists and lists the commands; the
98
144
  public `urlcode-template` gets the same file.
99
145
 
100
- ### 1.2 `llms-full.txt` and clean Markdown for the docs site (S, core; S, urlcode-docs)
146
+ ### 1.2 `llms-full.txt` and clean Markdown for the docs site (S, core; S, urlcode-docs) — partly done
147
+
148
+ Done 2026-09-19, the core side: `scripts/build-llms-full.ts` generates
149
+ `llms-full.txt` from 15 authoring documents in reading order with a table of
150
+ contents and a token estimate in the file header, `npm run check` runs it with
151
+ `--check`, and `test/llms-full.test.ts` covers determinism, rejection of a stale
152
+ copy and the conservative link rewriting. The docs-site half is not done here:
153
+ serving `/docs/<page>.md` beside `/docs/<page>` belongs to `urlcode-docs` and is
154
+ not verifiable from this repository.
101
155
 
102
156
  Fixes: `llms.txt` must stay a compact index, but an agent that wants complete
103
157
  context has to fetch forty files.
104
158
 
105
159
  - Work: `scripts/build-llms-full.ts` concatenates the authoring documents
106
160
  (framework, AI authoring, YAML guide, field reference, specification,
107
- routing, HTTP, middleware, assets, dynamic links, policies, extensions) in
161
+ routing, HTTP, middleware, assets, policies, extensions) in
108
162
  reading order with a table of contents; checked in `npm run check` for
109
163
  staleness like the field reference. The docs site serves `/docs/<page>.md`
110
164
  beside `/docs/<page>` so agents never parse HTML. Do not adopt `agents.txt`
@@ -112,7 +166,16 @@ context has to fetch forty files.
112
166
  - Proof: `npm run check` fails on a stale `llms-full.txt`; token estimate
113
167
  recorded in the file header.
114
168
 
115
- ### 1.3 `urlcode context` with a token budget (M, core)
169
+ ### 1.3 `urlcode context` with a token budget (M, core) — done
170
+
171
+ Done 2026-09-19: `urlcode context [--project] [--budget] [--json] [--stats]` in
172
+ `src/cli.ts` over `buildContext`, `renderContext`, `estimateTokens` and
173
+ `documentationTokens` in `src/context.ts`, derived from the compiled project and
174
+ the capability catalog; `--stats` writes the estimate to stderr so stdout stays
175
+ parseable. `test/context.test.ts` covers the cookbook and starter summaries,
176
+ byte-identical output across runs, the fixed budget drop order with the estimate
177
+ never exceeded, the CLI's YAML and JSON forms, and MCP `get_context`
178
+ (`src/mcp.ts`) returning the same data read-only.
116
179
 
117
180
  Fixes: the central gap. An agent needs a handful of facts about this project
118
181
  and this runtime and spends tens of thousands of tokens reading documentation
@@ -136,7 +199,17 @@ to get them.
136
199
  same project yields byte-identical output twice; budget test that output
137
200
  never exceeds the estimate; MCP tool `get_context` returns the same data.
138
201
 
139
- ### 1.4 Capability and schema fragment queries (M, core)
202
+ ### 1.4 Capability and schema fragment queries (M, core) — done
203
+
204
+ Done 2026-09-19: `urlcode capabilities <name>` and `urlcode schema <path>` in
205
+ `src/cli.ts` over `getCapability` in `src/capability-query.ts` and
206
+ `getSchemaFragment`/`schemaPathNames` in `src/schema-query.ts`, both re-exported
207
+ from `src/tooling.ts` and served as MCP `get_capability` and `get_schema`
208
+ (`src/mcp.ts`). `test/capability-query.test.ts` asserts that every catalog name
209
+ resolves with a valid, size-bounded fragment, that every schema path yields a
210
+ valid inline fragment and an unknown path lists the valid names, that entries
211
+ report bundled usage, grants and refusals from existing data, and that the CLI
212
+ fails closed on unknown names.
140
213
 
141
214
  Fixes: `urlcode capabilities` reports target support per handler; an agent
142
215
  cannot ask "what does `throttle` accept, where does it run, which recipe
@@ -152,7 +225,15 @@ shows it" or "give me only the schema for `redirect`".
152
225
  - Proof: a test that every capability name resolves and every fragment is
153
226
  valid JSON Schema; a size test that no fragment exceeds a fixed byte cap.
154
227
 
155
- ### 1.5 The URLCode agent skill (S, core `skills/urlcode/`)
228
+ ### 1.5 The URLCode agent skill (S, core `skills/urlcode/`) — done
229
+
230
+ Done 2026-09-19: `skills/urlcode/SKILL.md` is 104 lines, ships in the package,
231
+ and is named by the generated `AGENTS.md` through `skillPath` in
232
+ `src/agents-guide.ts`; `test/cli.test.ts` asserts the reference and
233
+ `test/release.test.ts` asserts the packaged starter copy. Caveat: the
234
+ with-and-without comparison in the proof line waits on 0.1 — the URLCode arm
235
+ preamble (`benchmarks/agent/prompts/urlcode.md`) assumes the skill, and no model
236
+ run has been stored to compare against.
156
237
 
157
238
  Fixes: agents that support skills have no packaged instruction for URLCode.
158
239
 
@@ -170,7 +251,7 @@ Fixes: agents that support skills have no packaged instruction for URLCode.
170
251
  ### 2.1 Publish the three extension packages (decision, S) — done
171
252
 
172
253
  Done 2026-09-18: `@jimhoyd/urlcode-ui`, `-auth` and `-admin` are on npm as
173
- `0.1.0-alpha.1` against core `0.4.0-alpha.1`. The alpha caveat stays: source
254
+ `0.1.0-alpha.x` against core `0.4.0-alpha.1`. The alpha caveat stays: source
174
255
  complete, independent review, deployment evidence and accessibility
175
256
  assessment pending ([issue 58](https://github.com/jimhoyd-com/urlcode/issues/58)).
176
257
 
@@ -198,9 +279,22 @@ Fixes: three disagreeing lists of verified peer commits (the CI workflows,
198
279
  - Work: `peers.json` in auth and admin; the workflows read it; the pack
199
280
  script defaults from it; `ACCEPTANCE.md` links to it. 2.1 has shipped, so
200
281
  the published versions (`@jimhoyd/urlcode@0.4.0-alpha.1`,
201
- `@jimhoyd/urlcode-ui@0.1.0-alpha.1`) replace the SHAs and the file can go.
202
-
203
- ### 2.3 `urlcode init --with auth,admin,ui` (M, core plus each extension)
282
+ `@jimhoyd/urlcode-ui@0.1.0-alpha.4`) replace the SHAs and the file can go.
283
+
284
+ ### 2.3 `urlcode init --with auth,admin,ui` (M, core plus each extension) — done
285
+
286
+ Done 2026-09-19: `--with` is parsed in `src/cli.ts` and implemented by
287
+ `parseWithNames`, `loadScaffold` and `initProjectWith` in `src/init-with.ts`,
288
+ which resolves `@jimhoyd/urlcode-<name>` from the invoking directory, refuses a
289
+ missing package or one without a `scaffold` export before writing anything,
290
+ merges the fragments into the starter through a last include, and writes one
291
+ `host.mjs` (`renderHost`), one `README.md` (`renderReadme`), `.mcp.json` and the
292
+ `AGENTS.md` from 1.1, printing the `inspectExtensionRevision` digest for
293
+ pinning. `test/init-with.test.ts` uses a fake `@jimhoyd/urlcode-<name>` package
294
+ in a temporary `node_modules` and, when companion checkouts are present,
295
+ composes the real auth and admin scaffolds. Caveat: each extension's own
296
+ `scaffold` export and admin's clean-project acceptance live in those
297
+ repositories and are not verified here.
204
298
 
205
299
  Fixes: three initializers with three directory conventions; no single command
206
300
  produces the layered project the framework page describes.
@@ -217,7 +311,20 @@ produces the layered project the framework page describes.
217
311
  `node_modules`; each extension tests that its `scaffold` output validates
218
312
  with core; admin's clean-project acceptance uses the new command.
219
313
 
220
- ### 2.4 Print extension schemas: `urlcode extensions` (M, core)
314
+ ### 2.4 Print extension schemas: `urlcode extensions` (M, core) — partly done
315
+
316
+ Done 2026-09-19, the command and the MCP tool: `urlcode extensions
317
+ [--host-file] [--json]` in `src/cli.ts` over `describeExtensions` in
318
+ `src/tooling.ts` prints each registration's name, version, targets,
319
+ configuration schema, policy schema, mounts, policy routes and revision-pin
320
+ verdict, and without a host file names the declared extensions and says schemas
321
+ need one. The same function is exported from `src/index.ts` and served as MCP
322
+ `get_extensions`, offered only when the operator started the server with a host
323
+ file, which `test/extensions.test.ts` asserts against the
324
+ `examples/extensions` registry. Not done: the fold-in. `urlcode context
325
+ --host-file` reports host extension names and a plugin count rather than their
326
+ schemas (`buildContext` in `src/context.ts`), and `urlcode capabilities auth`
327
+ takes no host file, so registered contracts are not part of either view.
221
328
 
222
329
  Fixes: an agent cannot discover what `extensions.auth.config` accepts without
223
330
  reading auth's source; `urlcode mcp` cannot serve it.
@@ -231,7 +338,21 @@ reading auth's source; `urlcode mcp` cannot serve it.
231
338
 
232
339
  ## Phase 3: retrieval instead of reading (M each, core)
233
340
 
234
- ### 3.1 Recipes as the vocabulary of common behavior
341
+ ### 3.1 Recipes as the vocabulary of common behavior — done
342
+
343
+ Done 2026-09-19: every bundled recipe carries `recipe.yaml`, and the catalog is
344
+ now ten — `authenticated-json-api`, `contact-form`, `cors-api`, `health-page`,
345
+ `json-api`, `middleware`, `protected-download`, `static-plus-api`, `typescript`
346
+ and `webhook-receiver` — which covers the seven this item names.
347
+ `urlcode recipes search|show|add` runs through `src/ecosystem-cli.ts` over
348
+ `searchRecipes` and `showRecipe` in `src/recipes.ts`, matching id, description,
349
+ tags and capabilities locally with no service, and MCP gained `search_recipes`.
350
+ `npm run check` validates the metadata and requires its derived fields to equal
351
+ the capability preflight (`checkCatalog` and `derivedDifferences` in
352
+ `scripts/check.ts`), and `test/recipes.test.ts` asserts a search hit per recipe
353
+ and that every recipe validates, passes its fixtures and audits with its
354
+ declared route count. Growing the catalog from the Phase 6 repetition log has
355
+ not started; the current ten are the seed list above.
235
356
 
236
357
  Fixes: four bundled recipes with a README each and no metadata; an agent
237
358
  cannot search them, and nothing tells it to look before generating.
@@ -248,14 +369,33 @@ cannot search them, and nothing tells it to look before generating.
248
369
  - Proof: schema for `recipe.yaml` checked in `npm run check`; a search test
249
370
  per recipe; every recipe still validates, tests and audits.
250
371
 
251
- ### 3.2 Examples become searchable the same way
372
+ ### 3.2 Examples become searchable the same way — done
373
+
374
+ Done 2026-09-19: each example carries `example.yaml` in the recipe metadata
375
+ shape, `urlcode examples search <text>` runs through `src/ecosystem-cli.ts` over
376
+ `searchExamples` in `src/examples.ts` and names the smallest runnable match with
377
+ its route, and the cookbook's per-route tags are generated into
378
+ `examples/cookbook/route-index.json` by `scripts/build-cookbook-index.ts`,
379
+ checked by `npm run check`. `scripts/check.ts` holds example metadata to the
380
+ same preflight as recipes, and `test/recipes.test.ts` ("examples carry the same
381
+ metadata shape and search returns the smallest runnable match with its route")
382
+ is the search test.
252
383
 
253
384
  - Work: `examples/*/example.yaml` with the same metadata shape; `urlcode
254
385
  examples search <text>` returns the smallest matching runnable example and
255
386
  its route. The cookbook's forty routes get per-route tags in one index file.
256
387
  - Proof: search test; count audit unchanged.
257
388
 
258
- ### 3.3 `urlcode explain` from compiled semantics
389
+ ### 3.3 `urlcode explain` from compiled semantics — done
390
+
391
+ Done 2026-09-19: `urlcode explain [/route] [--json]` in `src/cli.ts` over
392
+ `runExplainCommand` in `src/explain-cli.ts` and `explainRoute`/`explainProject`
393
+ in `src/explain.ts`, derived from the compiled IR, including extension policy
394
+ requirements when a host file is supplied. `test/explain.test.ts` covers the
395
+ project table and route detail through the CLI, the sandbox boolean, the
396
+ extension-protected route with a host registry, the nearest-route miss that
397
+ never carries binding values, and that explain agrees with the runtime on
398
+ methods and policies for every route.
259
399
 
260
400
  Fixes: `explainRoute` exists in the SDK and MCP; there is no CLI, and the
261
401
  output repeats matching rather than effective behavior.
@@ -268,7 +408,15 @@ output repeats matching rather than effective behavior.
268
408
  - Proof: snapshot tests on the cookbook; a test that `explain` and the
269
409
  runtime agree on methods and policies for every route.
270
410
 
271
- ### 3.4 A generated semantic manifest
411
+ ### 3.4 A generated semantic manifest — done
412
+
413
+ Done 2026-09-19: `urlcode manifest [--json]` shares the `src/explain-cli.ts`
414
+ entry and runs `buildManifest` in `src/manifest.ts`; `build` writes
415
+ `manifest.json` beside the artifact and MCP offers `get_manifest`.
416
+ `test/manifest.test.ts` asserts determinism, that the revision equals the
417
+ extension revision digest, that external requirements and recipe provenance are
418
+ listed by name and never by value, and that the CLI prints the bytes the build
419
+ writes.
272
420
 
273
421
  - Work: `urlcode manifest [--json]` (also written by `build` and offered by
274
422
  MCP as `get_manifest`) emits routes, capabilities, recipe provenance,
@@ -278,7 +426,17 @@ output repeats matching rather than effective behavior.
278
426
  - Proof: manifest equals `inspectProject` output for the same project;
279
427
  digest equals `inspectExtensionRevision`.
280
428
 
281
- ### 3.5 MCP authoring layer, separately authorized (M, core)
429
+ ### 3.5 MCP authoring layer, separately authorized (M, core) — done
430
+
431
+ Done 2026-09-19: `src/mcp-authoring.ts` adds `create_route`, `add_recipe` and
432
+ `scaffold_feature` plus the `run_validate`, `run_test` and `run_audit` runners,
433
+ enabled only by `--allow-authoring` on the operator's command line, which
434
+ `src/cli.ts` refuses for any other command and which no tool argument or
435
+ environment variable can set (`src/mcp.ts`). Every write is validated before it
436
+ lands and returns the verdict. `test/mcp-authoring.test.ts` asserts the tools
437
+ are absent without the flag, that absolute, parent, symlinked, dotenv, git and
438
+ operator paths are refused, and that a create is followed by validation in one
439
+ call.
282
440
 
283
441
  Fixes: MCP is read-only by design; an agent that wants to add a recipe or a
284
442
  route still has to write files by hand.
@@ -297,7 +455,20 @@ route still has to write files by hand.
297
455
 
298
456
  ## Phase 4: fewer lines for the common case (schema additions, `version: "1"` stays valid)
299
457
 
300
- ### 4.1 Short form for function routes (M, core)
458
+ ### 4.1 Short form for function routes (M, core) — done
459
+
460
+ Done 2026-09-19: `normalizeRoute` in `src/config.ts` expands
461
+ `function: functions/x.mjs` into `{source, args}` with an argument per `{param}`
462
+ and a required bounded path parameter for any the route does not declare itself
463
+ (`SHORT_FORM_PATH_SCHEMA`), and a string `middleware` entry into `{source}`; the
464
+ long form stays the IR. Both shapes are in
465
+ `schemas/urlcode.schema.json` (`$defs.route.properties.function` and
466
+ `.middleware`) and the generated field reference lists them as options.
467
+ `test/config.test.ts` ("function and middleware short forms normalize to the
468
+ long form the long form compiles to") asserts identical output, that a declared
469
+ parameter keeps its schema, and that a bad short-form string is refused with the
470
+ route named; the cookbook uses the short form in
471
+ `examples/cookbook/routes/middleware.yaml`.
301
472
 
302
473
  Fixes: the smallest function route is ten lines.
303
474
 
@@ -308,7 +479,21 @@ Fixes: the smallest function route is ten lines.
308
479
  - Proof: generated reference updated; cookbook gains a short-form route with
309
480
  fixtures; a test that short and long forms compile to identical IR.
310
481
 
311
- ### 4.2 Route-level `auth` as the semantic form (M, core plus auth)
482
+ ### 4.2 Route-level `auth` as the semantic form (M, core plus auth) — done
483
+
484
+ Done 2026-09-19: the route-level `auth` key is in the schema
485
+ (`$defs.route.properties.auth` over `$defs.routeAuth` in
486
+ `schemas/urlcode.schema.json`) and expanded by `normalizeRouteAuth` in
487
+ `src/config.ts`, which refuses a route that declares `auth` without an
488
+ `extensions.auth` declaration, alongside `policies.extensions.auth`, or with
489
+ `policies.extensions: false`; `required: false` documents intent and emits
490
+ nothing. The type is documented in `src/types.ts`, and `test/recipes.test.ts`
491
+ ("the authenticated recipes use the auth short form and never let credentials
492
+ reach the guest") covers both `auth: true` and a role requirement. The `cache`
493
+ short form this item defers to later shipped with it:
494
+ `$defs.route.properties.cache` and the cache branch of `normalizeRoute`, refused
495
+ alongside `policies.cache`. Caveat: the auth repository's HTTP tests are outside
496
+ this repository and were not run here.
312
497
 
313
498
  Fixes: protecting a route today is `policies: { extensions: { auth: {} } }`,
314
499
  which is the mechanism, not the intent. The form an agent should write is
@@ -365,7 +550,15 @@ whether links become a collection. Decide after review; build nothing first.
365
550
  `hiddenField`, `postForm`, `withDeadline` in the ui main entry; auth and
366
551
  admin drop their copies (`admin-markup.ts`, `admin-deadline.ts`).
367
552
 
368
- ### 7.2 Auth and admin render through the kit (L)
553
+ ### 7.2 Auth and admin render through the kit (L) — partly done
554
+
555
+ Done 2026-09-19, the core prerequisite only: the immutable-cache exception for
556
+ hashed extension assets shipped. `ExtensionImmutableAssets` and
557
+ `validateAssetPrefix` in `src/extensions.ts` bound a declared prefix to literal
558
+ segments under the extension's mounts, and `immutableAssetResponse` is what
559
+ lets such a response carry an asset cache-control instead of `no-store`. The
560
+ rendering work itself is in the auth, admin and ui repositories and is not
561
+ verified from here.
369
562
 
370
563
  Auth exports its catalogue and templates with view models, takes an optional
371
564
  `ui` from the host, and renders with `ui.kit.page` when present; admin the
@@ -388,28 +581,54 @@ walkthrough. Retire the `presentation` option one minor version later.
388
581
  ## Phase 9: hardening left from the audit (core, S each)
389
582
 
390
583
  - Direct tests for the sandbox pool, worker crash recovery and timeout kill
391
- path (`src/functions.ts`, `src/function-worker.ts`, `src/guest-api.ts`).
392
- - Tests for `src/link-store-worker.ts` behind the WAL gate.
393
- - Re-verify the remaining line-number rows in `STANDARDS.md`; cite symbols.
394
- - Split the three longest reference documents (YAML guide, policies, dynamic
395
- links) into task pages under 200 lines, so retrieval returns one page.
584
+ path (`src/functions.ts`, `src/function-worker.ts`, `src/guest-api.ts`)
585
+ done 2026-09-19: `test/sandbox-pool.test.ts` covers load shedding with slot
586
+ reuse, parallel workers with per-slot heaps, the 250 ms-to-30 s respawn
587
+ backoff, the deadline kill with slot replacement, an abrupt worker exit
588
+ failing the in-flight invocation, startup failure and close, and the guest
589
+ `Request`/`Response`/context surface.
590
+ - Re-verify the remaining line-number rows in `STANDARDS.md`; cite symbols —
591
+ done 2026-09-19: `docs/STANDARDS.md` records that every row was re-verified
592
+ at `8d7dd01` and now cites the implementing function or constant rather than
593
+ a line number, names the test that proves it, and says "unverified at
594
+ 8d7dd01" where a row could not be re-checked; no line-number citation
595
+ remains in the file.
596
+ - Split the longest reference documents (YAML guide, policies) into task pages
597
+ under 200 lines, so retrieval returns one page — done 2026-09-19:
598
+ `docs/yaml/` holds nine pages (largest `functions.md`, 160 lines) and
599
+ `docs/policies/` nine (largest `agents.md`, 182 lines), with
600
+ `docs/YAML-GUIDE.md` down to 57 lines. Caveat: `docs/POLICIES.md` is still
601
+ 203 lines as the index page.
396
602
  - A pre-test check in the extension repos that fails fast with the SQLite
397
- requirement named.
603
+ requirement named. Not verifiable from this repository.
398
604
 
399
605
  ## Sequence at a glance
400
606
 
607
+ What remains, as of 2026-09-19:
608
+
401
609
  ```
402
- Phase 0 agent benchmark + code-ratio metric (decides everything after it)
403
- Phase 1 AGENTS.md from init → llms-full urlcode context capability/schema queries skill
404
- Phase 2 publish alphas → peers.json init --with extensions --schema
405
- Phase 3 recipe metadata + search → examples search → explain → manifest → MCP authoring
406
- Phase 4 short-form function route route-level auth
407
- Phase 5 re-run the benchmark after each phase
408
- Phase 6 repetition log collections spike, then decide
409
- Phase 7 shared helpers kit adoption
610
+ Phase 0 instrument built and tested; no model-backed run stored, so the
611
+ code-ratio evidence is still missing. Evals (0.2) run weekly.
612
+ Phase 1 done: AGENTS.md from init, llms-full, urlcode context,
613
+ capability/schema queries, the skill
614
+ left: the docs site's /docs/<page>.md (urlcode-docs)
615
+ Phase 2 done: published alphas, init --with, urlcode extensions + get_extensions
616
+ left: peers.json (auth, admin); extension schemas folded into
617
+ urlcode context and capabilities <name>
618
+ Phase 3 done: recipe metadata + search, examples search, explain, manifest,
619
+ MCP authoring behind --allow-authoring
620
+ Phase 4 done: short-form function and middleware routes, route-level auth,
621
+ the cache short form; 4.3 stays a standing rule for new fields
622
+ Phase 5 waits on a Phase 0 run with a real model
623
+ Phase 6 not started: no docs/REPETITION-LOG.md, no docs/SPIKE-COLLECTIONS.md
624
+ Phase 7 extension repos; the core immutable-asset exception 7.2 needs is done
410
625
  Phase 8 proof gaps, in parallel, as people and environments allow
411
- Phase 9 hardening, in any gap
626
+ Phase 9 done: sandbox pool tests, STANDARDS symbol citations, split reference
627
+ pages; left: the extension repos' SQLite pre-test check
412
628
  ```
413
629
 
414
630
  Phase 0 decides whether the rest is worth doing and in what order. Phases 1
415
631
  and 3 are what an agent meets first; the rest makes that cheaper or proves it.
632
+ Because Phases 1, 3 and 4 landed ahead of the first model-backed run, that run
633
+ now measures what shipped rather than choosing it; Phase 5's re-runs are where
634
+ the choosing role returns.