@fleetless/contracts 1.0.2 → 1.0.4

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/dist/config.js CHANGED
@@ -48,22 +48,20 @@ import { alertSeverity } from './alerts.js';
48
48
  * index. Splitting them would put one rule here and its three siblings there
49
49
  * — the shape this file has twice had to undo.
50
50
  *
51
- * **Every refusal that answers one of the spec's codes carries
51
+ * **Every refusal that answers one of the format's validation codes carries
52
52
  * `params: { code }`** with that code, which zod passes through `safeParse`
53
53
  * untouched. The cloud maps an issue to a code and its repair by reading that
54
54
  * field, never by matching the message prose — a join nobody notices
55
55
  * breaking.
56
56
  *
57
- * Read the sentence narrowly, because a wider reading is false and was
58
- * written here once. Plenty of refusals in this file carry no `params.code`,
59
- * and correctly: the section caps (`parameterMap`'s fifty, `messageMap`'s two
60
- * hundred), the camera device-path rules, and every refusal zod raises on its
61
- * own — `unrecognized_keys` behind `unknown_key`, `too_big` behind
62
- * `invalid_rate`. Those are not spec codes wearing a different hat; the cloud
63
- * reaches them through zod's own issue codes. The one *spec* code with no
64
- * `params` is a reversed pair of bounds — `min_value`/`max_value` on a
65
- * parameter, `y_min`/`y_max` on a chart: `invalid_range` was deleted with
66
- * `expected_range`, and no code replaced it.
57
+ * Read that sentence narrowly. Plenty of refusals in this file carry no
58
+ * `params.code`, and correctly: the section caps (`parameterMap`'s fifty,
59
+ * `messageMap`'s two hundred), the camera device-path rules, and every refusal
60
+ * zod raises on its own — `unrecognized_keys` behind `unknown_key`, `too_big`
61
+ * behind `invalid_rate`. Those are not validation codes wearing a different
62
+ * hat; a consumer reaches them through zod's own issue codes. The one named
63
+ * code with no `params` is a reversed pair of bounds — `min_value`/`max_value`
64
+ * on a parameter, `y_min`/`y_max` on a chart — for which no code exists.
67
65
  *
68
66
  * `robotConfigDoc` carries all six sections — messages, datapoints, actions,
69
67
  * services, publishers and cameras — plus the alerts, the chart bounds and the
@@ -91,16 +89,12 @@ import { alertSeverity } from './alerts.js';
91
89
  * which is a published artifact other tools validate against and which a person
92
90
  * reads. One constant with two readers, never two strings that happen to agree
93
91
  * — `config-zod-messages.test.ts` asserts the two readings are the same string
94
- * at all 24 pattern positions the document has, because under D3 nothing
95
- * consumes `patternErrorMessage` at runtime and an unwatched second spelling of
96
- * a live rule drifts word for word, forever and invisibly.
92
+ * at every pattern position the document has. An unwatched second spelling of a
93
+ * live rule drifts word for word, forever and invisibly.
97
94
  *
98
- * In the console `patternErrorMessage` is also the live pattern diagnostic
99
- * **until wave 3 lands**: `useMonacoYaml.ts` still passes `validate: true`, so
100
- * between task 7's artifacts and D3 these sentences are what monaco-yaml shows.
101
- * D3 then turns that validation off, and from there the message a developer
102
- * sees comes from this schema's own parser and from the cloud — the same
103
- * sentence, which is the point of there being one.
95
+ * An editor that validates against the published JSON Schema shows
96
+ * `patternErrorMessage`; one that does not shows whatever the server's parser
97
+ * says. They are the same sentence, which is the point of there being one.
104
98
  *
105
99
  * The tense matters because the two states look identical from inside this
106
100
  * file. Whoever reads it after wave 3 should find a claim that was true when
@@ -136,11 +130,10 @@ const mapKey = slug.meta({ patternErrorMessage: SLUG_RULE });
136
130
  /**
137
131
  * One field, carrying the sentence it says when it is absent.
138
132
  *
139
- * **Three shapes of "this key is not here", and the first version of this
140
- * helper caught one of them.** A walk over every required key of a fully
141
- * populated document — `config-zod-messages.test.ts`, which is the guard that
142
- * found it — says the format has 52 required-key positions and that 14 were
143
- * still answering in zod's words:
133
+ * **Three shapes of "this key is not here", and a helper has to cover all
134
+ * three.** A walk over every required key of a fully populated document —
135
+ * `config-zod-messages.test.ts` — enumerates every required-key position in the
136
+ * format and asserts none of them still answers in zod's words:
144
137
  *
145
138
  * - `invalid_type`, the ordinary case: a string, a number, an object.
146
139
  * - `invalid_value` from a `z.literal` or a `z.enum`. A missing `fleetless:`
@@ -160,10 +153,10 @@ const mapKey = slug.meta({ patternErrorMessage: SLUG_RULE });
160
153
  * **`z.unknown()` needs a wrapper before it can be given a sentence at all.**
161
154
  * It accepts `undefined`, so zod marks the key required and raises its own
162
155
  * `expected nonoptional, received undefined` — an issue it attributes to
163
- * neither the field nor the object, so no error map of ours is consulted
164
- * (measured). `z.nonoptional` puts a schema there that can carry one. The JSON
165
- * Schema and the inferred type are byte-identical either way (measured, zod
166
- * 4.4.3), and a field that is genuinely optional is `.optional()` and is
156
+ * neither the field nor the object, so no error map of ours is consulted.
157
+ * `z.nonoptional` puts a schema there that can carry one. The JSON Schema and
158
+ * the inferred type are identical either way, and a field that is genuinely
159
+ * optional is `.optional()` and is
167
160
  * skipped here — but it is **not** behaviourally free, and that is the one
168
161
  * place this task changed what the format accepts: a required key *present*
169
162
  * holding `undefined` is now refused where zod's internal check accepted it.
@@ -179,11 +172,11 @@ const mapKey = slug.meta({ patternErrorMessage: SLUG_RULE });
179
172
  *
180
173
  * `clone` is the only way to add an `error` to a schema that is already built,
181
174
  * and **it drops the schema's registry entry** — its `description`, its
182
- * `examples`, every annotation this wave added, all of which live in
175
+ * `examples` and every other annotation, all of which live in
183
176
  * `z.globalRegistry` keyed by the schema instance rather than in its
184
- * definition. So the entry is read back and put on the clone. Measured on zod
185
- * 4.4.3: `z.globalRegistry.get` resolves the whole `.meta()` parent chain into
186
- * one object, so what is copied is what the export would have produced, and a
177
+ * definition. So the entry is read back and put on the clone.
178
+ * `z.globalRegistry.get` resolves the whole `.meta()` parent chain into one
179
+ * object, so what is copied is what the export would have produced, and a
187
180
  * later `.meta()` on the result merges with it as it did before. A wrapper that
188
181
  * silently emptied every hover in the format would be the worst available way
189
182
  * to improve one message.
@@ -234,8 +227,8 @@ const saysItIsMissing = (field) => {
234
227
  * The second arm is the discriminated union: zod hands its error map the whole
235
228
  * object and points the path at the discriminator, so `input` is not
236
229
  * `undefined` and the first arm cannot see it. `Object.hasOwn` rather than
237
- * `in`, on this project's own rule — a document's keys are chosen by a
238
- * developer, and `constructor` satisfies the slug grammar.
230
+ * `in`, because a document's keys are chosen by a developer and `constructor`
231
+ * satisfies the slug grammar.
239
232
  */
240
233
  const absent = (issue, key) => issue.input === undefined
241
234
  || (issue.code === 'invalid_union'
@@ -327,8 +320,8 @@ const describeValues = (values, table) => values.map((value) => table[value]);
327
320
  *
328
321
  * The two syntaxes collide. `defaultSnippets` bodies are inserted as LSP
329
322
  * snippets, where `${1:front}` is a tab stop and `${speed}` is a *variable* —
330
- * and an unknown variable is not left alone. Measured against
331
- * monaco-editor 0.52.2's own `SnippetParser`, which is what the console runs:
323
+ * and an unknown variable is not left alone. Against monaco-editor's own
324
+ * `SnippetParser`:
332
325
  *
333
326
  * | body holds | the editor inserts |
334
327
  * |---|---|
@@ -351,17 +344,16 @@ const param = (name) => `\\\${${name}}`;
351
344
  * `{ battery: … }`, and `battery: ▮` offers the `…`. Both positions are real
352
345
  * and both were silent, but they are **one skeleton**, so each is authored once
353
346
  * as a `Snippet` constant and wrapped here for the section — never copied.
354
- * Two copies of one skeleton is the drift this wave caught three times in three
355
- * reviews: a body inventing a value its sibling had already answered, under a
356
- * label that still agreed. `config-snippets.test.ts` deep-compares the two
357
- * positions rather than trusting this.
347
+ * Two copies of one skeleton drift: a body invents a value its sibling had
348
+ * already answered, under a label that still agrees.
349
+ * `config-snippets.test.ts` deep-compares the two positions rather than
350
+ * trusting this.
358
351
  *
359
352
  * **The slug key belongs to the wrapper, not to the skeleton**, because it
360
353
  * differs per snippet — `battery_voltage` for a plain datapoint, `battery` for
361
354
  * the numeric one. It therefore takes tab stop `${1}`, and an entry body's own
362
355
  * stops are numbered from `${2}` throughout. At the entry position that leaves
363
- * no `${1}` at all, which costs nothing — measured against
364
- * monaco-editor 0.52.2's own `SnippetParser`, the version the console runs: it
356
+ * no `${1}` at all, which costs nothing: monaco-editor's `SnippetParser`
365
357
  * sorts placeholders by index and requires neither that they start at 1 nor
366
358
  * that they be contiguous, so a body of `a: ${2:x}` visits `2` first, and one
367
359
  * of `a: ${2:x}` / `b: ${5:y}` visits `2` then `5`.
@@ -588,9 +580,9 @@ export const parameterSpec = strictObject({
588
580
  * A default must satisfy the same constraints a caller's value must.
589
581
  *
590
582
  * Without this, a default is the one way past bounds that are otherwise
591
- * the enforcement point — the spec calls `min_value`/`max_value` "the
592
- * speed limit that actually holds", enforced in the cloud before anything
593
- * reaches the robot. But a caller who simply omits the parameter gets the
583
+ * the enforcement point. `min_value`/`max_value` are the speed limit that
584
+ * actually holds, enforced in the cloud before anything reaches the robot.
585
+ * But a caller who simply omits the parameter gets the
594
586
  * default, and the bridge fills it at the template walk without
595
587
  * re-checking bounds, deliberately: a second enforcement point there
596
588
  * would be the weaker of two policies. So `{min_value: -1, max_value: 1,
@@ -787,10 +779,9 @@ export const datapointAlert = strictObject({
787
779
  * `getInsertTextForProperty` (`yaml.worker.js:8520`) takes
788
780
  * `defaultSnippets[0].body` only when a node carries **exactly one**
789
781
  * snippet, so accepting `condition` from the key list writes the bare key
790
- * here where every other node this wave touched writes its whole block.
791
- * The two stay anyway: the value position — a developer who has written
792
- * `condition:` and pressed ⏎ — is where the question "what goes here?" is
793
- * actually asked, and that is the position this wave exists to answer.
782
+ * here where every other node writes its whole block. The two stay anyway:
783
+ * the value position — a developer who has written `condition:` and pressed
784
+ * ⏎ — is where the question "what goes here?" is actually asked.
794
785
  * Merging them into one would buy back the key completion by deleting the
795
786
  * choice the schema deliberately does not name, which is the worse trade;
796
787
  * anyone tempted to make it should change the key-completion behaviour
@@ -962,9 +953,9 @@ const NUMERIC_DATAPOINT_SNIPPET = {
962
953
  /**
963
954
  * The quotes inside `unit` are part of the inserted text and are not
964
955
  * decoration. A body string is written into the document verbatim, and `%`
965
- * is a YAML directive indicator: measured with `yaml` 2.9.0, `unit: %` is a
966
- * **syntax error** ("Plain value cannot start with directive indicator
967
- * character %") while `unit: "%"` parses to `%`. Nothing between here and
956
+ * is a YAML directive indicator: `unit: %` is a **syntax error** ("Plain
957
+ * value cannot start with directive indicator character %") while
958
+ * `unit: "%"` parses to `%`. Nothing between here and
968
959
  * the buffer quotes a scalar for us.
969
960
  */
970
961
  numeric: { scale: 100, unit: '"%"', decimals: 1 },
@@ -1144,10 +1135,9 @@ export const datapointConfig = strictObject({
1144
1135
  * `z.unknown()`, because a template can be any shape a ROS message can — so
1145
1136
  * nothing below the top of it is checked by the type at all.
1146
1137
  *
1147
- * That gap was measured and missed once already: a top-level `message: null`
1148
- * was refused while `message: { linear: { x: null } }` parsed clean, and a
1149
- * check written to catch exactly this was deleted on the strength of six test
1150
- * cases, none of which reached inside a body.
1138
+ * The gap is easy to miss: a top-level `message: null` is refused while
1139
+ * `message: { linear: { x: null } }` parses clean, and a test suite that never
1140
+ * reaches inside a body cannot tell the two apart.
1151
1141
  *
1152
1142
  * Walked with an explicit stack and a seen-set, not recursion: a YAML anchor
1153
1143
  * can make a template both very deep and genuinely cyclic, and a developer can
@@ -1231,10 +1221,9 @@ export const messageBody = messageTemplate;
1231
1221
  * contract.** This runs inside `publisherConfig`'s failsafe refinement, so a
1232
1222
  * `RangeError: Maximum call stack size exceeded` did not stay here: it
1233
1223
  * propagated out of `safeParse`, which is specified to return a result and
1234
- * not to throw. Measured on the recursive version — fine at 8 000 levels of
1235
- * nesting, throwing at 20 000 — and a flow-style YAML one-liner reaches that
1236
- * in about 120 KB of input. A draft PUT would have answered 500 where it
1237
- * meant 400.
1224
+ * not to throw. A recursive walk survives a few thousand levels of nesting and
1225
+ * throws somewhere above that, which a flow-style YAML one-liner reaches in
1226
+ * about 120 KB of input — so a draft PUT would answer 500 where it meant 400.
1238
1227
  *
1239
1228
  * `seen` is not an optimisation. YAML anchors can express a cycle
1240
1229
  * (`&a { b: *a }`), and the parser resolves an alias to the same object, so
@@ -1302,14 +1291,13 @@ const SHARED_MESSAGE_SNIPPET = {
1302
1291
  * that paragraph would be a second thing to keep true.
1303
1292
  *
1304
1293
  * **How the description gets here is zod behaviour, not something written
1305
- * below.** Measured against zod 4.4.3: `.meta()` on an already-registered
1306
- * schema merges rather than replaces, and the clone resolves the parent's entry
1294
+ * below.** `.meta()` on an already-registered schema merges rather than
1295
+ * replaces, and the clone resolves the parent's entry
1307
1296
  * *lazily* — a clone taken before the parent was registered at all still sees
1308
1297
  * the parent's description afterwards. So no spread is needed and there is no
1309
- * evaluation-order hazard. This was first written as
1310
- * `.meta({ ...messageTemplate.meta(), … })`; dropping the spread was measured
1311
- * to change nothing in the export, and two mechanisms for one description is
1312
- * the shape this file removes rather than adds.
1298
+ * evaluation-order hazard. A defensive `.meta({ ...messageTemplate.meta(), … })`
1299
+ * spread changes nothing in the export and is a second mechanism for one
1300
+ * description, so it is deliberately absent.
1313
1301
  *
1314
1302
  * It is undocumented behaviour all the same, so `config-snippets.test.ts`
1315
1303
  * asserts this node still carries a description and that it is the same string
@@ -1598,8 +1586,8 @@ export const cameraCredentials = strictObject({
1598
1586
  * therefore no validation rule to forget.
1599
1587
  *
1600
1588
  * **Each branch carries its own `defaultSnippets`, rather than one list on the
1601
- * union.** Both placements were measured and both work; this one keeps a
1602
- * label beside the branch it names, so the two cannot drift, and it makes a
1589
+ * union.** Both placements work; this one keeps a label beside the branch it
1590
+ * names, so the two cannot drift, and it makes a
1603
1591
  * fifth source impossible to add without one — `config-snippets.test.ts`
1604
1592
  * walks the exported branches and fails on any that carries none.
1605
1593
  */
@@ -1637,15 +1625,14 @@ export const cameraSource = z.discriminatedUnion('kind', [
1637
1625
  * `rosTypeName` accepts either, publish accepts either, no diagnostic
1638
1626
  * fires anywhere, and the bridge then subscribes with the wrong type and
1639
1627
  * delivers no frames. A snippet supplying a wrong answer where it could
1640
- * have supplied a question is this project's *check that cannot fire*,
1641
- * arriving through a hint the developer trusts.
1628
+ * have supplied a question is a defect arriving through a hint the
1629
+ * developer trusts.
1642
1630
  *
1643
1631
  * `kind: 'ros'` stays a literal, because the branch really does fix it.
1644
1632
  *
1645
- * Measured through the actual pipeline rather than assumed, because
1646
- * choice syntax is the one construct here that three layers must each
1633
+ * Choice syntax is the one construct here that three layers must each
1647
1634
  * pass through unharmed: yaml-language-server's `stringifyObject` emits
1648
- * the body verbatim, and monaco-editor 0.52.2's `SnippetParser` parses
1635
+ * the body verbatim, and monaco-editor's `SnippetParser` parses
1649
1636
  * `${2|a,b|}` into a placeholder carrying both options whose
1650
1637
  * `toString()` — the text on the buffer before anyone chooses — is the
1651
1638
  * first one. So a developer who tabs past this gets a document
@@ -1795,9 +1782,9 @@ export const cameraSource = z.discriminatedUnion('kind', [
1795
1782
  *
1796
1783
  * The bound lives here once, and `rest.ts`'s `cameraDescriptor` reuses it —
1797
1784
  * the same treatment `rateThrottleHz` got, and for the same reason: the
1798
- * descriptor used to say `snapshot_interval_ms` while the document said
1799
- * seconds, so the cloud converted on one descriptor and not its sibling, with
1800
- * nothing in either file saying so.
1785
+ * two spellings of one interval — milliseconds in a descriptor, seconds in the
1786
+ * document — mean a server converting on one and not the other, with nothing in
1787
+ * either file saying so.
1801
1788
  */
1802
1789
  export const snapshotIntervalSeconds = z.number().int().min(1).max(3600);
1803
1790
  /**
package/dist/errors.js CHANGED
@@ -112,14 +112,11 @@ export const ERROR_CODES = [
112
112
  'email_taken',
113
113
  'identifier_taken',
114
114
  'weak_password',
115
- /* `not_a_member` was removed on 2026-08-29. It had no producer anywhere in
116
- * this repository or in the cloud (`grep` found exactly two hits: its own
117
- * entry here and a test asserting the entry existed), and its vocabulary was
118
- * the deleted model's — "member" of an app's pool, in a platform whose
119
- * membership is now a group and whose access is an assignment. A code that
120
- * nothing emits and whose noun no longer exists is the third failure mode in
121
- * this project's list: a guard written against a state no producer reports.
122
- * The refusals that do the work are `forbidden` (silent about existence) and
115
+ /* `not_a_member` is gone. It had no producer anywhere, and its vocabulary was
116
+ * a deleted model's — "member" of an app's pool, in a platform whose access is
117
+ * an assignment. A code that nothing emits, whose noun no longer exists, is a
118
+ * refusal a consumer must still branch on and can never receive. The refusals
119
+ * that do the work are `forbidden` (silent about existence) and
123
120
  * `tier_required` (about the caller's own tier). */
124
121
  /**
125
122
  * The account itself is blocked — distinct from `forbidden` on purpose: it
@@ -397,7 +394,7 @@ export const ERROR_CODES = [
397
394
  // `WWW-Authenticate` **header**, which is correct and present, not the body.
398
395
  //
399
396
  // So the rule is about the JSON-RPC layer, and the transport layer below it
400
- // is ordinary Fastify. Stating it as "never `apiError` anywhere" was the
397
+ // is ordinary HTTP. Stating it as "never `apiError` anywhere" was the
401
398
  // kind of tidy sentence that is easier to remember than the truth — and
402
399
  // this file has now produced two of those about itself.
403
400
  //
@@ -416,8 +413,8 @@ export const ERROR_CODES = [
416
413
  * flag; the central-MCP cut deleted the per-app `/mcp/<identifier>` endpoint
417
414
  * that flag gated, and 2026-08-29 removed the field itself from `app`, so
418
415
  * the code stood for a year with nothing able to produce it. The
419
- * app-user-auth design brings the per-app endpoint back (D7) with the switch
420
- * on `appAuthConfig` rather than on `app`, and this is its refusal again.
416
+ * per-app endpoint is back, with the switch on `appAuthConfig` rather than on
417
+ * `app`, and this is its refusal again.
421
418
  *
422
419
  * The lesson that survives is about the year in between: an enum member with
423
420
  * no producer is not harmless, because a reader arriving at it takes it for
@@ -465,7 +462,7 @@ export const ERROR_CODES = [
465
462
  * would make a client branch on which route it called.
466
463
  */
467
464
  'capability_required',
468
- // 2026-08-29 — org-central identity (D1/D2).
465
+ // Org-central identity.
469
466
  /**
470
467
  * **An org must keep at least one Owner**, so the last one is neither
471
468
  * deletable nor demotable. 409, on both `DELETE /api/org/users/:id` and
@@ -481,7 +478,7 @@ export const ERROR_CODES = [
481
478
  * caller could infer from a silence about existence.
482
479
  */
483
480
  'last_owner',
484
- // 2026-08-29 — oidc-federation (D3/D4).
481
+ // OIDC federation.
485
482
  /**
486
483
  * **The target is in a state that refuses the operation** — not the caller's
487
484
  * rights, not the target's existence, but *what the target currently is*.
@@ -545,7 +542,7 @@ export const ERROR_CODES = [
545
542
  * `409` from the configuration routes: the draft parses as YAML but its root
546
543
  * is not a mapping — a list, a scalar, or an empty document. Distinct from
547
544
  * `validation_error`, which is about a field inside a document that *is* one.
548
- * Produced by `cloud/src/routes/config.ts`.
545
+ * Produced by the configuration draft route.
549
546
  */
550
547
  'draft_not_a_document',
551
548
  /**
@@ -553,23 +550,22 @@ export const ERROR_CODES = [
553
550
  * it has no mapping for, and the code the realtime socket sends for the same
554
551
  * state. It says nothing about the request, deliberately: a caller cannot act
555
552
  * on it beyond retrying, and the detail belongs in the server's log rather
556
- * than in a body a stranger receives. Produced by `cloud/src/server.ts`'s
557
- * error handler and `cloud/src/ws/realtime.ts`.
553
+ * than in a body a stranger receives. Produced by the server's own error
554
+ * handler and by the realtime socket.
558
555
  */
559
556
  'internal_error',
560
557
  /**
561
558
  * `422` from `POST /api/robots/:id/jobs/:slug/cancel`: the job exists and the
562
559
  * caller may address it, but it is in a state that has nothing left to
563
560
  * cancel — already settled, or of a kind that does not support cancellation.
564
- * Produced by `cloud/src/commands.ts` and mapped in
565
- * `cloud/src/routes/commands.ts`.
561
+ * Produced by the command layer and mapped onto the job routes.
566
562
  */
567
563
  'not_cancellable',
568
564
  /**
569
565
  * `415`. The request carried a body in a media type the route does not read.
570
566
  * It is the cloud-wide answer from the content-type parser, not one route's:
571
567
  * a caller reaching it never got as far as validation, which is why this is
572
- * not a `validation_error`. Produced by `cloud/src/server.ts`.
568
+ * not a `validation_error`. Produced by the server itself.
573
569
  */
574
570
  'unsupported_media_type',
575
571
  /**
@@ -579,16 +575,14 @@ export const ERROR_CODES = [
579
575
  * hash recorded on the interaction row.
580
576
  *
581
577
  * **The impersonation interstitial it also named is deleted** with the rest
582
- * of the app OAuth flow (2026-09-05, D1/D2). That page is where this defence
583
- * was found missing on a GET rather than a POST — three times over, on three
584
- * different screens — which is the reason worth carrying forward: the check
585
- * belongs on every verb that *renders* the step, not only on the one that
578
+ * of the app OAuth flow. The rule that outlives it: this defence goes on
579
+ * every verb that *renders* the step, not only on the one that
586
580
  * completes it.
587
581
  *
588
582
  * Deliberately not `invalid_token` or `unauthorized`: nothing about the
589
583
  * caller's credential is being refused, and the remedy is specific and
590
- * actionable — start the flow again in this browser. Produced by
591
- * `cloud/src/routes/console-oauth.ts` and `cloud/src/routes/mcp-oauth.ts`.
584
+ * actionable — start the flow again in this browser. Produced by both
585
+ * hosted authorization flows.
592
586
  */
593
587
  'wrong_browser',
594
588
  /**
@@ -602,9 +596,8 @@ export const ERROR_CODES = [
602
596
  * why nothing noticed. The envelope validates; only the *code* was absent
603
597
  * from the one list a client can match against, so a caller branching on
604
598
  * `ERROR_CODES` fell through to its unknown-error arm for the single most
605
- * common refusal the editor produces. That is this file's own "documented
606
- * absence" failure, on the codes list itself. Produced by
607
- * `cloud/src/routes/config.ts`.
599
+ * common refusal an editor produces — a documented absence on the codes list
600
+ * itself. Produced by the configuration draft route.
608
601
  */
609
602
  'invalid_yaml',
610
603
  /**
@@ -614,7 +607,7 @@ export const ERROR_CODES = [
614
607
  *
615
608
  * Two codes rather than one, because the two say different things to whoever
616
609
  * typed the text: the first means "this is not YAML", the second means "this
617
- * is YAML I cannot keep". Produced by `cloud/src/routes/config.ts`.
610
+ * is YAML I cannot keep". Produced by the configuration draft route.
618
611
  */
619
612
  'unstorable_yaml',
620
613
  // 2026-09-05 — app-user auth (two identity spaces, the JSON client API).
@@ -2,7 +2,7 @@
2
2
  import { z } from 'zod';
3
3
  /**
4
4
  * **Fleetless users: the org's team, and the only people who reach the
5
- * console** (spec `2026-09-05-app-user-auth`, D1).
5
+ * console.**
6
6
  *
7
7
  * There are two identity spaces now and **nothing joins them**:
8
8
  *
@@ -17,7 +17,7 @@ import { z } from 'zod';
17
17
  * A Fleetless user who wants to use an app registers or is invited like
18
18
  * anybody else; there is no path from one space to the other.
19
19
  *
20
- * **What that deleted, with no successor** (D1): groups and the Org Admins
20
+ * **What that deleted, with no successor**: groups and the Org Admins
21
21
  * group, app assignments, impersonation, the per-user MCP override and the
22
22
  * org-level federation policy. The 2026-08-29 model had put developers and end
23
23
  * users into one pool per org and connected them with all of the above; in use
@@ -49,7 +49,7 @@ export declare const password: z.ZodString;
49
49
  /** The bound on a Fleetless user's display name; `APP_USER_DISPLAY_NAME_MAX` matches it, so a rename cannot be legal in one space and refused in the other. */
50
50
  export declare const USER_DISPLAY_NAME_MAX = 120;
51
51
  /**
52
- * **The two tiers a Fleetless user can hold** (D1). Owner-exclusive: delete
52
+ * **The two tiers a Fleetless user can hold**. Owner-exclusive: delete
53
53
  * the org, edit org settings, promote to owner, and later billing. Everything
54
54
  * else a Fleetless user may do, a `developer` may do.
55
55
  *
@@ -97,7 +97,7 @@ export type PatchOrgResponse = z.infer<typeof patchOrgResponse>;
97
97
  * central endpoint), and `has_password`. The last is the interesting one — it
98
98
  * existed because a pool user might have been provisioned by an identity
99
99
  * provider and hold no Fleetless credential. A Fleetless user always holds
100
- * one: the console is password-only by design (D1), which removes the
100
+ * one: the console is password-only by design, which removes the
101
101
  * IdP-lockout class entirely, so a field reporting whether the credential
102
102
  * exists would have exactly one value forever.
103
103
  */
@@ -205,7 +205,7 @@ export declare const waitlistRequest: z.ZodObject<{
205
205
  export type WaitlistRequest = z.infer<typeof waitlistRequest>;
206
206
  /**
207
207
  * Console login. Fleetless users only, always the Fleetless password — the
208
- * console has no federated door at all (D1), which removes the IdP-lockout
208
+ * console has no federated door at all, which removes the IdP-lockout
209
209
  * class entirely.
210
210
  *
211
211
  * This resolves a person by address alone, and a Fleetless user's email is
@@ -495,7 +495,7 @@ export type IdpIssuer = z.infer<typeof idpIssuer>;
495
495
  * here.** `oidcCallbackErrorCode` and `oidcCallbackError` described the page
496
496
  * `GET /mcp/oauth/idp-callback` rendered when a group's identity provider sent
497
497
  * a browser back — `jit_disabled` and `email_collision` name provisioning steps
498
- * only a group provider had. D1 makes Fleetless users password-only and deletes
498
+ * only a group provider had. Fleetless users are password-only now, which deletes
499
499
  * group providers, so the flow that produced these codes cannot start; the
500
500
  * route is gone from this manifest and from the cloud.
501
501
  *
package/dist/identity.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { z } from 'zod';
3
3
  /**
4
4
  * **Fleetless users: the org's team, and the only people who reach the
5
- * console** (spec `2026-09-05-app-user-auth`, D1).
5
+ * console.**
6
6
  *
7
7
  * There are two identity spaces now and **nothing joins them**:
8
8
  *
@@ -17,7 +17,7 @@ import { z } from 'zod';
17
17
  * A Fleetless user who wants to use an app registers or is invited like
18
18
  * anybody else; there is no path from one space to the other.
19
19
  *
20
- * **What that deleted, with no successor** (D1): groups and the Org Admins
20
+ * **What that deleted, with no successor**: groups and the Org Admins
21
21
  * group, app assignments, impersonation, the per-user MCP override and the
22
22
  * org-level federation policy. The 2026-08-29 model had put developers and end
23
23
  * users into one pool per org and connected them with all of the above; in use
@@ -49,7 +49,7 @@ export const password = z.string().min(12).max(256);
49
49
  /** The bound on a Fleetless user's display name; `APP_USER_DISPLAY_NAME_MAX` matches it, so a rename cannot be legal in one space and refused in the other. */
50
50
  export const USER_DISPLAY_NAME_MAX = 120;
51
51
  /**
52
- * **The two tiers a Fleetless user can hold** (D1). Owner-exclusive: delete
52
+ * **The two tiers a Fleetless user can hold**. Owner-exclusive: delete
53
53
  * the org, edit org settings, promote to owner, and later billing. Everything
54
54
  * else a Fleetless user may do, a `developer` may do.
55
55
  *
@@ -95,7 +95,7 @@ export const patchOrgResponse = z.object({
95
95
  * central endpoint), and `has_password`. The last is the interesting one — it
96
96
  * existed because a pool user might have been provisioned by an identity
97
97
  * provider and hold no Fleetless credential. A Fleetless user always holds
98
- * one: the console is password-only by design (D1), which removes the
98
+ * one: the console is password-only by design, which removes the
99
99
  * IdP-lockout class entirely, so a field reporting whether the credential
100
100
  * exists would have exactly one value forever.
101
101
  */
@@ -181,7 +181,7 @@ export const signUpResponse = z.object({
181
181
  export const waitlistRequest = z.object({ email: z.email().max(254) });
182
182
  /**
183
183
  * Console login. Fleetless users only, always the Fleetless password — the
184
- * console has no federated door at all (D1), which removes the IdP-lockout
184
+ * console has no federated door at all, which removes the IdP-lockout
185
185
  * class entirely.
186
186
  *
187
187
  * This resolves a person by address alone, and a Fleetless user's email is
@@ -472,7 +472,7 @@ export const idpIssuer = z
472
472
  * here.** `oidcCallbackErrorCode` and `oidcCallbackError` described the page
473
473
  * `GET /mcp/oauth/idp-callback` rendered when a group's identity provider sent
474
474
  * a browser back — `jit_disabled` and `email_collision` name provisioning steps
475
- * only a group provider had. D1 makes Fleetless users password-only and deletes
475
+ * only a group provider had. Fleetless users are password-only now, which deletes
476
476
  * group providers, so the flow that produced these codes cannot start; the
477
477
  * route is gone from this manifest and from the cloud.
478
478
  *
package/dist/index.js CHANGED
@@ -32,7 +32,7 @@ export { clientAuth, authOk, authError, clientInvoke, clientCancel, clientPublis
32
32
  export { password, org, patchOrgResponse, sessionTokens, refreshRequest, signUpRequest, signUpResponse,
33
33
  // 2026-09-04 — the public site (closed beta).
34
34
  waitlistRequest, developerLoginRequest,
35
- // 2026-09-05 — the two identity spaces (app-user-auth, D1).
35
+ // The two identity spaces.
36
36
  USER_DISPLAY_NAME_MAX, orgAdminTier, fleetlessUser, fleetlessUserListResponse, createTeamInviteRequest, teamInvite, pendingTeamInvite, pendingTeamInviteListResponse, acceptTeamInviteRequest, patchFleetlessUserRequest, tierChangeRequest,
37
37
  // Identity.
38
38
  mailStatus, tierRequiredDetails, passwordChangeRequest, passwordResetRequest, passwordResetConfirm, idpIssuer,
@@ -40,7 +40,7 @@ mailStatus, tierRequiredDetails, passwordChangeRequest, passwordResetRequest, pa
40
40
  authMeResponse, patchOrgRequest, patchAuthMeRequest, } from './identity.js';
41
41
  export { appIdentifier, app, appListResponse, createAppRequest, updateAppRequest, serverKeyToken, serverKey, serverKeyListResponse, createServerKeyResponse, role, roleListResponse, rolePermissions, } from './apps.js';
42
42
  export { clientLoginRequest, clientRefreshRequest, clientLogoutRequest, clientRegisterRequest, clientVerifyEmailRequest, clientResendVerificationRequest, clientPasswordResetRequest, clientPasswordResetConfirmRequest, clientAcceptInvitationRequest, CLIENT_OIDC_CALLBACK_PATH, clientProviderListQuery, clientProviderListResponse, clientOidcStartQuery, clientOidcCallbackQuery, clientOidcExchangeRequest, clientOidcErrorCode, clientMcpInteraction, clientMcpInteractionDecisionResponse, mcpConsentGrant, mcpConsentGrantListResponse, clientIdentity, } from './client-auth.js';
43
- // 2026-09-05 — the per-app identity space (app-user-auth, D1/D3/D4/D5).
43
+ // The per-app identity space.
44
44
  export { APP_USER_DISPLAY_NAME_MAX, APP_URL_PLACEHOLDERS, MAIL_TEMPLATE_VARIABLES, DEFAULT_MAIL_TEMPLATES, providerSlug, appUserStatus, appUser, appUserListResponse, createAppUserRequest, patchAppUserRequest, createAppInvitationRequest, appInvitation, pendingAppInvitation, appInvitationListResponse, appOidcProvider, appOidcProviderListResponse, createAppOidcProviderRequest, patchAppOidcProviderRequest, appUrlTemplate, allowedOrigin, emailDomain, appAuthConfig, putAppAuthConfigRequest, mailTemplateKind, appMailTemplate, appMailTemplateListResponse, putAppMailTemplateRequest, mailTemplatePreviewRequest, mailTemplatePreviewResponse, mailTemplateProblemDetails, mailOutcome, } from './app-users.js';
45
45
  export { assetKind, URDF_ASSET_NAME, asset, urdfCompleteness, assetListResponse, missingAssetQuery, assetSyncRequest, assetSyncResponse, assetSyncState, assetSyncStatus, assetFailure, assetFailureKind, assetTooLargeDetails, assetSyncBusyDetails, ASSET_UPLOAD_MAX_BYTES, } from './assets.js';
46
46
  export { auditActor, auditEvent, auditQuery, auditListResponse, AUDIT_CSV_COLUMNS, AUDIT_RETENTION_DAYS } from './audit.js';
package/dist/jobs.d.ts CHANGED
@@ -163,7 +163,7 @@ export declare const JOB_RUN_RETENTION_DAYS = 90;
163
163
  * invites every reader to handle it.
164
164
  *
165
165
  * **`app_user` is what a client-app caller writes now, and `end_user` stays**
166
- * (app-user auth, D1). The seam this comment used to describe — two names for
166
+ * identity spaces. The seam this comment used to describe — two names for
167
167
  * two ways into one merged pool — is settled: the two identity spaces are
168
168
  * separate tables again, and `app_user` is a row in `app_users`, belonging to
169
169
  * exactly one app. `end_user` is kept for the same reason `auditActor.kind`
@@ -188,10 +188,10 @@ export declare const jobRunKind: z.ZodEnum<{
188
188
  }>;
189
189
  export type JobRunKind = z.infer<typeof jobRunKind>;
190
190
  /**
191
- * One durable record of one invocation (spec `2026-08-20-timeseries-and-run-history`,
192
- * D2). One row per run, never one per event: the per-event timeline's write rate
191
+ * One durable record of one invocation. One row per run, never one per event:
192
+ * the per-event timeline's write rate
193
193
  * is set by the bridge, and a throttled log that cannot say it was throttled is
194
- * the instrument this codebase refuses everywhere else. The live timeline is
194
+ * an instrument that cannot say what it does not know. The live timeline is
195
195
  * delivered in full by realtime, for as long as somebody is watching.
196
196
  */
197
197
  export declare const jobRun: z.ZodObject<{
package/dist/jobs.js CHANGED
@@ -166,7 +166,7 @@ export const JOB_RUN_RETENTION_DAYS = 90;
166
166
  * invites every reader to handle it.
167
167
  *
168
168
  * **`app_user` is what a client-app caller writes now, and `end_user` stays**
169
- * (app-user auth, D1). The seam this comment used to describe — two names for
169
+ * identity spaces. The seam this comment used to describe — two names for
170
170
  * two ways into one merged pool — is settled: the two identity spaces are
171
171
  * separate tables again, and `app_user` is a row in `app_users`, belonging to
172
172
  * exactly one app. `end_user` is kept for the same reason `auditActor.kind`
@@ -192,10 +192,10 @@ export const jobActor = z.object({
192
192
  });
193
193
  export const jobRunKind = z.enum(['action', 'service']);
194
194
  /**
195
- * One durable record of one invocation (spec `2026-08-20-timeseries-and-run-history`,
196
- * D2). One row per run, never one per event: the per-event timeline's write rate
195
+ * One durable record of one invocation. One row per run, never one per event:
196
+ * the per-event timeline's write rate
197
197
  * is set by the bridge, and a throttled log that cannot say it was throttled is
198
- * the instrument this codebase refuses everywhere else. The live timeline is
198
+ * an instrument that cannot say what it does not know. The live timeline is
199
199
  * delivered in full by realtime, for as long as somebody is watching.
200
200
  */
201
201
  export const jobRun = z.object({
package/dist/mcp.d.ts CHANGED
@@ -36,7 +36,7 @@ export declare const MCP_PROTOCOL_VERSION: "2025-11-25";
36
36
  *
37
37
  * **Not parameterised, and that is now a statement rather than the absence of
38
38
  * one.** The central endpoint serves the org's team with the console tool
39
- * family (2026-09-05, D7); an app's users reach a different endpoint, whose
39
+ * family; an app's users reach a different endpoint, whose
40
40
  * path `mcpAppEndpointPath` builds. Two constants for two audiences, so a call
41
41
  * site says which it means instead of an argument deciding it.
42
42
  *
@@ -48,7 +48,7 @@ export declare const MCP_PROTOCOL_VERSION: "2025-11-25";
48
48
  */
49
49
  export declare const MCP_ENDPOINT_PATH: "/mcp";
50
50
  /**
51
- * The path of **one app's** MCP server (D7) — what an app user pastes into
51
+ * The path of **one app's** MCP server — what an app user pastes into
52
52
  * their AI tool, served only while the app's `appAuthConfig.mcp_enabled` is on.
53
53
  *
54
54
  * A helper rather than a template literal at four call sites, for
@@ -72,7 +72,7 @@ export declare const MCP_ENDPOINT_PATH: "/mcp";
72
72
  export declare function mcpAppEndpointPath(appIdentifier: string): string;
73
73
  /**
74
74
  * **Every path one app's MCP server answers on, built from its identifier
75
- * once** (D7).
75
+ * once**.
76
76
  *
77
77
  * Six strings, and each of them is spelled in at least three places that
78
78
  * cannot see one another: the cloud registers the route, the console renders a