@zerotal/arch 1.14.0 → 1.14.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.
package/docs/ai.md CHANGED
@@ -287,6 +287,48 @@ after a crash before another worker may take over". If the lock is ever lost the
287
287
  loop's signal aborts, because at that point somebody else may be doing the same work.
288
288
  See [Locking](/docs/lock) for the mechanism.
289
289
 
290
+ ## Prompt caching
291
+
292
+ A long, stable prefix is worth caching: a cached read costs a tenth of an ordinary input
293
+ token. A _write_ costs more than one, so caching something that changes every request is
294
+ strictly more expensive than not caching it.
295
+
296
+ **The system prompt is cached for you** when `cacheSystem` is on (the default) and it is
297
+ long enough to be worth a breakpoint.
298
+
299
+ **Anything else you mark yourself.** Put `cache: true` on the last message of the stable
300
+ prefix — a retrieved document, a fixed few-shot block — and everything up to and including
301
+ it is cached:
302
+
303
+ ```ts fragment
304
+ await Ai.generate({
305
+ messages: [
306
+ { role: "user", content: policyDocument, cache: true },
307
+ { role: "user", content: question },
308
+ ],
309
+ });
310
+ ```
311
+
312
+ The marker goes on the **last** message of the prefix, not on every message in it: a
313
+ breakpoint caches everything before it, so marking each one spends four breakpoints to
314
+ describe one boundary. Anthropic allows four per request and the framework refuses a fifth
315
+ by name rather than letting the provider return a 400 about a field you did not write.
316
+
317
+ Before 1.14.1 only the system prompt could be cached, so a long document in the message
318
+ history could not be — which is the case caching is most worth having for.
319
+
320
+ ### What it costs
321
+
322
+ `estimateCost` prices a cache read at 0.1× input and a **5-minute** write at 1.25×. A
323
+ **1-hour** write costs 2×, and the two are tracked separately in `AiUsage`
324
+ (`cacheWrite1hTokens`, counted inside `cacheWriteTokens`) because one number cannot be
325
+ priced two ways.
326
+
327
+ Zerotal never requests a 1-hour cache, so that figure is `0` unless you reach past the
328
+ driver with `providerOptions`. It used to be priced at 1.25× regardless, which
329
+ underestimated by 37.5% — in the unsafe direction for a spend ceiling, since a limit that
330
+ under-counts lets spend through rather than blocking it.
331
+
290
332
  ## Refusals
291
333
 
292
334
  A provider's safety classifiers can decline a request. That arrives as a **successful
package/docs/changelog.md CHANGED
@@ -27,6 +27,105 @@ the section for every version you cross and apply its migration notes, not only
27
27
  majors. [Releases and versioning](/docs/support-policy#releases-and-versioning) explains
28
28
  when that carve-out ends.
29
29
 
30
+ ## 1.14.2 — 2026-09-01
31
+
32
+ **`bun run dev` was broken in every app scaffolded since 1.13.0.** Take this one.
33
+
34
+ Found by starting the adoption release the obvious way — scaffolding a fresh app and
35
+ walking the first-run path as a newcomer would, rather than reasoning about it.
36
+
37
+ ### Fixed
38
+
39
+ - **The scaffold templates shipped a retired command.** Every template's `package.json`
40
+ carried `"dev": "bun zt.ts serve --dev"`, and `serve --dev` was retired in
41
+ [1.13.0](#1130--2026-08-31) — deliberately failing loudly rather than silently starting a
42
+ plain server with no watcher. So the first command a new user runs exited 1 and told them
43
+ to use something else.
44
+
45
+ Retiring an alias meant updating the runner, the documentation and the `zt upgrade`
46
+ codemod. It did not occur to me to update the thing that _writes new apps_, which is the
47
+ one place a retired form is guaranteed to keep appearing.
48
+
49
+ A test now checks the scaffolder against the codemod's own list of retired forms, so what
50
+ generates apps cannot fall behind what migrates them. It is driven by the codemod rather
51
+ than a second list, because two lists disagree.
52
+
53
+ - **`zt upgrade` did not rewrite `zt.ts serve --dev` either.** The codemod anchored on `zt`
54
+ followed by whitespace, matching `zt serve --dev` and missing `bun zt.ts serve --dev` —
55
+ the form in every scaffolded `package.json`. So an app running `zt upgrade` to migrate off
56
+ the alias was told there was nothing to do, on the file that needed it most.
57
+
58
+ Worth naming as its own failure: the first version of the new scaffolder test passed with
59
+ the bug deliberately planted, because it was driven by that same pattern. A gate is only
60
+ worth what it catches, and the way to know is to break the thing on purpose and watch it
61
+ fail.
62
+
63
+ ## 1.14.1 — 2026-09-01
64
+
65
+ Clearing the deferred list. Three of the four are fixed; the other two were sized and moved
66
+ to 2.0 with the reasoning recorded, because deciding is also addressing.
67
+
68
+ ### Added
69
+
70
+ - **Prompt-cache breakpoints on messages.** Caching reached exactly one place — the system
71
+ prompt — so a long stable document in the message history could not be cached, which is
72
+ the case caching is most worth having for.
73
+
74
+ ```ts
75
+ await Ai.generate({
76
+ messages: [
77
+ { role: "user", content: policyDocument, cache: true },
78
+ { role: "user", content: question },
79
+ ],
80
+ });
81
+ ```
82
+
83
+ The marker goes on the **last** message of the prefix, because a breakpoint caches
84
+ everything before it — marking each message spends four breakpoints describing one
85
+ boundary. Anthropic allows four, and a fifth is refused by name rather than surfacing as
86
+ a provider 400 about a field you never wrote.
87
+
88
+ ### Fixed
89
+
90
+ - **A 1-hour cache write is priced at 2×, not 1.25×.** Every write was multiplied by the
91
+ 5-minute rate, underestimating a 1-hour write by 37.5% — in the unsafe direction for a
92
+ ceiling, since a limit that under-counts lets spend through rather than blocking it.
93
+ `AiUsage.cacheWrite1hTokens` carries the split, read from the `cache_creation` breakdown
94
+ Anthropic returns when a 1-hour cache was used. Optional on the type, because a custom
95
+ driver constructs `AiUsage` and making it required would break every one for an
96
+ accounting detail their provider probably does not report.
97
+
98
+ - **A command that declares `needsApp = false` no longer boots the application.**
99
+ `zt version`, `key:generate`, every `make:*` scaffolder and the gate commands paid for
100
+ providers, a database connection and a schedule registry they never touch — and could not
101
+ run when booting was the thing that was broken. A CLI you cannot reach when the app is
102
+ down is missing exactly when it is wanted.
103
+
104
+ Config is still bound, through the new `Application.bindConfig()`. "Does not need the
105
+ app" and "does not need config" are different claims, and only the first is true of a
106
+ scaffolder writing to a configured path.
107
+
108
+ It also makes `zt version --json` pipeable, which previously needed the `--version` form
109
+ to dodge the boot log on stdout.
110
+
111
+ ### Decided, not done
112
+
113
+ Two entries on the 2.0 ledger were filed as alias retirements and are mass renames:
114
+
115
+ - **`BaseModel` → `Model`** is **617 references across `api-surface.md` files and 354 in
116
+ non-test source.** `BaseModel` is the class's declared name, so TypeScript prints it into
117
+ every signature mentioning a model — retiring it means renaming the class and
118
+ regenerating every snapshot, which the breaking-change gate reads as hundreds of removals.
119
+ The "trivial" codemod in the ledger is the app-side rewrite, which is genuinely trivial
120
+ and already written; the framework side was never sized.
121
+ - **Prefixing the 269 `@internal` exports with `_`** is the same shape, minus the classes
122
+ that [cannot be renamed at all](#1131--2026-08-31).
123
+
124
+ Both move to 2.0 on the ledger's own rule — a break worth taking once, wanting one
125
+ migration and one `zt upgrade` run rather than hundreds of app-visible type positions
126
+ churned so there is one name instead of two. They should cross together, so an app pays for
127
+ one rename pass rather than two.
128
+
30
129
  ## 1.14.0 — 2026-09-01
31
130
 
32
131
  Rendering and the SSR endpoint become separate decisions. Small in practice — most apps
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerotal/arch",
3
- "version": "1.14.0",
3
+ "version": "1.14.2",
4
4
  "license": "MIT",
5
5
  "maturity": "stable",
6
6
  "private": false,
@@ -35,11 +35,11 @@
35
35
  "typecheck": "tsc --noEmit"
36
36
  },
37
37
  "dependencies": {
38
- "@zerotal/core": "1.14.0"
38
+ "@zerotal/core": "1.14.2"
39
39
  },
40
40
  "devDependencies": {
41
41
  "typescript": "^5.8.0",
42
- "@zerotal/orm": "1.14.0"
42
+ "@zerotal/orm": "1.14.2"
43
43
  },
44
44
  "description": "The Zerotal agent surface — an MCP server that hands coding agents the framework's machine-readable truth: exact API signatures, live routes and schema, version-matched docs, and `zt doctor`.",
45
45
  "keywords": [