@hyperscale0/udl 1.0.0-beta.1 → 1.0.0
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/CHANGELOG.md +78 -25
- package/README.md +37 -99
- package/conformance/README.md +44 -41
- package/conformance/evolution/action-contract.expected.json +10 -0
- package/conformance/evolution/action-contract.live.udl +44 -0
- package/conformance/evolution/action-contract.next.udl +45 -0
- package/conformance/evolution/product-identity.expected.json +10 -0
- package/conformance/evolution/product-identity.live.udl +55 -0
- package/conformance/evolution/product-identity.next.udl +55 -0
- package/conformance/evolution/version-required.expected.json +10 -0
- package/conformance/evolution/version-required.live.udl +55 -0
- package/conformance/evolution/version-required.next.udl +58 -0
- package/conformance/invalid/action-without-transition.expected.json +10 -0
- package/conformance/invalid/{verb-without-transition.udl → action-without-transition.udl} +7 -2
- package/conformance/invalid/agent-description-too-long.expected.json +10 -0
- package/conformance/invalid/agent-description-too-long.udl +57 -0
- package/conformance/invalid/blank-title.expected.json +1 -1
- package/conformance/invalid/blank-title.udl +6 -2
- package/conformance/invalid/composition-dial-duplicate-key.expected.json +10 -0
- package/conformance/invalid/composition-dial-duplicate-key.udl +73 -0
- package/conformance/invalid/depth-budget.expected.json +1 -1
- package/conformance/invalid/duplicate-subject.expected.json +10 -0
- package/conformance/invalid/duplicate-subject.udl +230 -0
- package/conformance/invalid/forged-effects.expected.json +10 -0
- package/conformance/invalid/forged-effects.udl +76 -0
- package/conformance/invalid/format-version.expected.json +1 -1
- package/conformance/invalid/format-version.udl +6 -2
- package/conformance/invalid/instrument-id-not-snake-case.expected.json +10 -0
- package/conformance/invalid/{noun-id-not-snake-case.udl → instrument-id-not-snake-case.udl} +6 -2
- package/conformance/invalid/invalid-aggregate-gate-shape.expected.json +10 -0
- package/conformance/invalid/invalid-aggregate-gate-shape.udl +1819 -0
- package/conformance/invalid/invalid-check-duration.expected.json +10 -0
- package/conformance/invalid/invalid-check-duration.udl +219 -0
- package/conformance/invalid/invalid-dial-anchor.expected.json +10 -0
- package/conformance/invalid/invalid-dial-anchor.udl +219 -0
- package/conformance/invalid/invalid-exception-parent-ref.expected.json +10 -0
- package/conformance/invalid/invalid-exception-parent-ref.udl +2487 -0
- package/conformance/invalid/invalid-exposure-shape.expected.json +10 -0
- package/conformance/invalid/invalid-exposure-shape.udl +1819 -0
- package/conformance/invalid/invalid-remainder.expected.json +10 -0
- package/conformance/invalid/invalid-remainder.udl +220 -0
- package/conformance/invalid/invalid-schema-keyword.expected.json +10 -0
- package/conformance/invalid/invalid-schema-keyword.udl +220 -0
- package/conformance/invalid/invalid-utf8.expected.json +1 -1
- package/conformance/invalid/malformed-json.expected.json +1 -1
- package/conformance/invalid/missing-create-action.expected.json +10 -0
- package/conformance/invalid/{missing-create-verb.udl → missing-create-action.udl} +5 -2
- package/conformance/invalid/missing-exception-amount-field.expected.json +10 -0
- package/conformance/invalid/missing-exception-amount-field.udl +2487 -0
- package/conformance/invalid/missing-exception-contract.expected.json +14 -0
- package/conformance/invalid/missing-exception-contract.udl +2523 -0
- package/conformance/invalid/missing-exception-reason-field.expected.json +10 -0
- package/conformance/invalid/missing-exception-reason-field.udl +2487 -0
- package/conformance/invalid/not-an-object.expected.json +1 -1
- package/conformance/invalid/payout-reconcile-not-a-bank-debit.expected.json +10 -0
- package/conformance/invalid/payout-reconcile-not-a-bank-debit.udl +259 -0
- package/conformance/invalid/quote-freeze-set-incomplete.expected.json +10 -0
- package/conformance/invalid/quote-freeze-set-incomplete.udl +261 -0
- package/conformance/invalid/quote-named-reference-gate.expected.json +10 -0
- package/conformance/invalid/quote-named-reference-gate.udl +50 -0
- package/conformance/invalid/reconcile-named-reference-gate.expected.json +10 -0
- package/conformance/invalid/reconcile-named-reference-gate.udl +50 -0
- package/conformance/invalid/unknown-key.expected.json +1 -1
- package/conformance/invalid/unknown-key.udl +6 -2
- package/conformance/invalid/unknown-reference-gate-field.expected.json +10 -0
- package/conformance/invalid/unknown-reference-gate-field.udl +1819 -0
- package/conformance/invalid/unknown-required-field.expected.json +10 -0
- package/conformance/invalid/unknown-required-field.udl +220 -0
- package/conformance/invalid/unreachable-state.expected.json +2 -2
- package/conformance/invalid/unreachable-state.udl +6 -2
- package/conformance/invalid/wrong-exception-amount-field.expected.json +10 -0
- package/conformance/invalid/wrong-exception-amount-field.udl +2487 -0
- package/conformance/invalid/wrong-exception-reason-field.expected.json +10 -0
- package/conformance/invalid/wrong-exception-reason-field.udl +2487 -0
- package/conformance/valid/agent-description.expected.json +6 -0
- package/conformance/valid/agent-description.udl +66 -0
- package/conformance/valid/cards.expected.json +1 -0
- package/conformance/valid/cards.udl +843 -356
- package/conformance/valid/commerce-escrow.expected.json +1 -0
- package/conformance/valid/commerce-escrow.udl +792 -291
- package/conformance/valid/compiled-crowdfunding.expected.json +6 -0
- package/conformance/valid/compiled-crowdfunding.udl +1843 -0
- package/conformance/valid/compiled-watch-club.expected.json +6 -0
- package/conformance/valid/compiled-watch-club.udl +2486 -0
- package/conformance/valid/complete-contract.expected.json +6 -0
- package/conformance/valid/complete-contract.udl +218 -0
- package/conformance/valid/effect-signatures.expected.json +6 -0
- package/conformance/valid/effect-signatures.udl +75 -0
- package/conformance/valid/hand-edited.expected.json +1 -0
- package/conformance/valid/hand-edited.udl +1 -1
- package/conformance/valid/insured-car-marketplace.expected.json +1 -0
- package/conformance/valid/insured-car-marketplace.udl +534 -315
- package/conformance/valid/insured-travel.expected.json +2 -1
- package/conformance/valid/insured-travel.udl +1489 -641
- package/conformance/valid/minimal.expected.json +1 -0
- package/conformance/valid/minimal.udl +18 -14
- package/conformance/valid/protection.expected.json +1 -0
- package/conformance/valid/protection.udl +719 -304
- package/conformance/valid/string-escaping.expected.json +6 -0
- package/conformance/valid/string-escaping.udl +54 -0
- package/dist/canonical.d.ts +2 -0
- package/dist/canonical.d.ts.map +1 -1
- package/dist/canonical.js +7 -0
- package/dist/canonical.js.map +1 -1
- package/dist/check-profiles.d.ts +57 -0
- package/dist/check-profiles.d.ts.map +1 -0
- package/dist/check-profiles.js +62 -0
- package/dist/check-profiles.js.map +1 -0
- package/dist/cli.js +48 -4
- package/dist/cli.js.map +1 -1
- package/dist/diagnostics.d.ts +168 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +164 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/effects.d.ts +41 -0
- package/dist/effects.d.ts.map +1 -0
- package/dist/effects.js +110 -0
- package/dist/effects.js.map +1 -0
- package/dist/evolution.d.ts +51 -18
- package/dist/evolution.d.ts.map +1 -1
- package/dist/evolution.js +244 -102
- package/dist/evolution.js.map +1 -1
- package/dist/finance.d.ts +17 -13
- package/dist/finance.d.ts.map +1 -1
- package/dist/finance.js +165 -109
- package/dist/finance.js.map +1 -1
- package/dist/index.d.ts +12 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -5
- package/dist/index.js.map +1 -1
- package/dist/limits.d.ts +2 -2
- package/dist/limits.d.ts.map +1 -1
- package/dist/limits.js +4 -3
- package/dist/limits.js.map +1 -1
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +6 -16
- package/dist/parser.js.map +1 -1
- package/dist/schema.d.ts +2059 -135
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +759 -73
- package/dist/schema.js.map +1 -1
- package/dist/validation.d.ts +22 -9
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +1463 -457
- package/dist/validation.js.map +1 -1
- package/docs/README.md +14 -0
- package/docs/guide/01-a-document.md +37 -0
- package/docs/guide/02-money-steps.md +23 -0
- package/docs/guide/03-laws.md +18 -0
- package/docs/guide/04-fees-and-remainder.md +15 -0
- package/docs/guide/05-checks-updates-dials.md +7 -0
- package/docs/guide/06-effects.md +11 -0
- package/docs/guide/07-evolution.md +11 -0
- package/docs/guide/08-implementing.md +13 -0
- package/docs/llms-full.txt +1241 -0
- package/docs/llms.txt +14 -0
- package/docs/reference/canonical.md +16 -0
- package/docs/reference/clauses.md +986 -0
- package/docs/reference/cli.md +22 -0
- package/docs/reference/diagnostics.md +32 -0
- package/package.json +6 -2
- package/skills/udl/SKILL.md +28 -0
- package/spec/README.md +82 -51
- package/spec/udl.schema.json +1191 -119
- package/src/canonical.ts +11 -0
- package/src/check-profiles.ts +80 -0
- package/src/cli.ts +49 -3
- package/src/diagnostics.ts +221 -0
- package/src/effects.ts +163 -0
- package/src/evolution.ts +375 -125
- package/src/finance.ts +255 -160
- package/src/index.ts +50 -14
- package/src/limits.ts +4 -3
- package/src/parser.ts +15 -18
- package/src/schema.ts +855 -81
- package/src/validation.ts +2666 -560
- package/conformance/invalid/missing-create-verb.expected.json +0 -10
- package/conformance/invalid/noun-id-not-snake-case.expected.json +0 -10
- package/conformance/invalid/verb-without-transition.expected.json +0 -10
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<!-- Generated by scripts/docs/build.ts from @hyperscale0/udl 1.0.0. Edit the source, not cli.md. -->
|
|
2
|
+
|
|
3
|
+
# Command reference
|
|
4
|
+
|
|
5
|
+
The installed `udl` binary exposes the following commands and exit codes.
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
udl - the Universal Domain Language toolchain
|
|
9
|
+
|
|
10
|
+
usage:
|
|
11
|
+
udl validate <file> parse <file> and report every issue found
|
|
12
|
+
udl fmt <file> [--write] print the canonical form, or rewrite the file
|
|
13
|
+
udl canon <file> [--digest] print canonical bytes, or their SHA-256 digest
|
|
14
|
+
udl diff <live> <next> check <next> against the append-only law
|
|
15
|
+
udl explain UDL#### explain one stable diagnostic code
|
|
16
|
+
udl help print this
|
|
17
|
+
|
|
18
|
+
exit codes:
|
|
19
|
+
0 the document is admissible, or the change is additive
|
|
20
|
+
1 the document was refused, or the change breaks the append-only law
|
|
21
|
+
2 the command line was wrong, or a file could not be read
|
|
22
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<!-- Generated by scripts/docs/build.ts from @hyperscale0/udl 1.0.0. Edit the source, not diagnostics.md. -->
|
|
2
|
+
|
|
3
|
+
# Diagnostic reference
|
|
4
|
+
|
|
5
|
+
Codes are stable. Titles and messages may become clearer without changing the code. Apply the listed fix, then validate the whole document again.
|
|
6
|
+
|
|
7
|
+
| Code | Family | Category | Title | Fix |
|
|
8
|
+
| --------- | --------- | ----------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
9
|
+
| `UDL1001` | admission | invalid_utf8 | Invalid UTF-8 | Encode the document as valid UTF-8. |
|
|
10
|
+
| `UDL1002` | admission | invalid_json | Invalid JSON | Repair the JSON syntax before validation. |
|
|
11
|
+
| `UDL1003` | admission | invalid_shape | Invalid document shape | Match the published UDL JSON Schema. |
|
|
12
|
+
| `UDL1004` | admission | resource_limit | Resource limit exceeded | Reduce the source size, nesting, values, strings, references, or financial paths named by the message. |
|
|
13
|
+
| `UDL2001` | document | invalid_semantics | Duplicate declaration | Give each declaration a unique name. |
|
|
14
|
+
| `UDL2002` | document | invalid_semantics | Document law violation | Repair the declaration, subject contract, or derived effects named by the message. |
|
|
15
|
+
| `UDL2005` | document | invalid_semantics | Derived effects mismatch | Regenerate the action effects from its clauses. |
|
|
16
|
+
| `UDL3001` | lifecycle | invalid_semantics | Lifecycle is not closed | Declare every state and action transition, and make every state reachable. |
|
|
17
|
+
| `UDL4001` | finance | invalid_semantics | Money graph violation | Balance every funded amount and close every hold on each lifecycle path. |
|
|
18
|
+
| `UDL5001` | gates | invalid_semantics | Reference gate violation | Point the gate at a declared instrument, action, state, field, and reference. |
|
|
19
|
+
| `UDL5002` | gates | invalid_semantics | Check requirement violation | Use a declared check with compatible evidence and recurrence. |
|
|
20
|
+
| `UDL5003` | gates | invalid_semantics | Exposure gate violation | Use declared account and money fields for the exposure gate. |
|
|
21
|
+
| `UDL5004` | gates | invalid_semantics | Aggregate law violation | Point the aggregate at compatible parent and child fields. |
|
|
22
|
+
| `UDL5005` | gates | invalid_semantics | Settlement or payout violation | Use a declared settlement account and a compatible payout statement line. |
|
|
23
|
+
| `UDL5006` | gates | invalid_semantics | Quote and commit violation | Declare one complete quote freeze set and one matching commit action. |
|
|
24
|
+
| `UDL5007` | gates | invalid_semantics | Reconcile exception child violation | Name a declared child whose reference points back to this instrument. |
|
|
25
|
+
| `UDL5008` | gates | invalid_semantics | Action clause violation | Repair the clause fields and keep incompatible clauses separate. |
|
|
26
|
+
| `UDL5009` | gates | invalid_semantics | Reconcile exception amount field is missing or optional | Name the exception child's required money field in amountField. |
|
|
27
|
+
| `UDL5010` | gates | invalid_semantics | Reconcile exception amount field has the wrong type | Point amountField at a money field declared by the exception child. |
|
|
28
|
+
| `UDL5011` | gates | invalid_semantics | Reconcile exception reason field is missing or optional | Name the exception child's required text field in reasonField. |
|
|
29
|
+
| `UDL5012` | gates | invalid_semantics | Reconcile exception reason field has the wrong type | Point reasonField at a required plain text field declared by the exception child. |
|
|
30
|
+
| `UDL6001` | schema | invalid_semantics | Unsupported JSON Schema | Use only the sealed UDL JSON Schema subset. |
|
|
31
|
+
| `UDL7001` | evolution | invalid_evolution | Stored contract changed | Keep stored identities and contracts unchanged, and add only allowed optional declarations. |
|
|
32
|
+
| `UDL7002` | evolution | invalid_evolution | Version was not increased | Increase the product version for every semantic change. |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperscale0/udl",
|
|
3
|
-
"version": "1.0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "The Universal Domain Language: format spec, parser, validator, canonical serializer, and evolution diff.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"udl",
|
|
@@ -47,7 +47,9 @@
|
|
|
47
47
|
"SECURITY.md",
|
|
48
48
|
"TRADEMARKS.md",
|
|
49
49
|
"conformance",
|
|
50
|
+
"docs",
|
|
50
51
|
"dist",
|
|
52
|
+
"skills",
|
|
51
53
|
"spec",
|
|
52
54
|
"src"
|
|
53
55
|
],
|
|
@@ -59,7 +61,9 @@
|
|
|
59
61
|
},
|
|
60
62
|
"scripts": {
|
|
61
63
|
"build": "tsc -p tsconfig.build.json",
|
|
62
|
-
"check": "bun run spec:check && bun test && tsc -p tsconfig.json && bun run build && bun scripts/check-bin.ts",
|
|
64
|
+
"check": "bun run spec:check && bun run docs:check && bun test && tsc -p tsconfig.json && bun run build && bun scripts/check-bin.ts",
|
|
65
|
+
"docs:build": "bun scripts/docs/build.ts --write",
|
|
66
|
+
"docs:check": "bun scripts/docs/build.ts --check",
|
|
63
67
|
"postpack": "bun scripts/pack-exports.ts restore",
|
|
64
68
|
"prepack": "bun run build && bun scripts/pack-exports.ts apply",
|
|
65
69
|
"spec": "bun scripts/emit-spec.ts --write",
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: udl
|
|
3
|
+
description: Read, validate, explain, or write Universal Domain Language documents directly. Use for canonical UDL JSON and format-level diagnostics. SDK and MCP consumers should use their generated contracts instead.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# UDL
|
|
7
|
+
|
|
8
|
+
Use UDL when the task concerns the canonical product document, format conformance, or a validator implementation. Use HSX when authoring a product from reusable modules.
|
|
9
|
+
|
|
10
|
+
## Read first
|
|
11
|
+
|
|
12
|
+
1. Read `docs/guide/01-a-document.md` for the document frame.
|
|
13
|
+
2. Read `docs/guide/03-laws.md` before changing lifecycle, money, gates, or references.
|
|
14
|
+
3. Look up exact fields in `spec/udl.schema.json` and clauses in `docs/reference/clauses.md`.
|
|
15
|
+
|
|
16
|
+
## Edit loop
|
|
17
|
+
|
|
18
|
+
1. Change the smallest complete clause.
|
|
19
|
+
2. Run `udl validate <file>`.
|
|
20
|
+
3. Look up each `UDL####` code with `udl explain UDL####` or `docs/reference/diagnostics.md`.
|
|
21
|
+
4. Apply the listed fix. Validate the whole document again.
|
|
22
|
+
5. Run `udl canon <file> --digest` before pinning bytes or an identity.
|
|
23
|
+
|
|
24
|
+
Never hand-author `effects`. Derive them from action clauses. Never represent money as a JSON number. Use an integer minor-unit string and its declared currency. Never add a money move without checking every terminal lifecycle path for a matching drain or unwind.
|
|
25
|
+
|
|
26
|
+
For a stored definition, validate both documents before `udl diff <live> <next>`. Treat any `UDL7xxx` result as a refused change. A data migration does not make an incompatible document edit additive.
|
|
27
|
+
|
|
28
|
+
Validator work must run the complete `conformance/` contract and follow `docs/reference/canonical.md` byte for byte.
|
package/spec/README.md
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
# The UDL specification
|
|
2
2
|
|
|
3
3
|
A UDL document describes one product in business terms: its subjects, its
|
|
4
|
-
|
|
4
|
+
instruments, each instrument's lifecycle, the actions that move instances through it, and how
|
|
5
5
|
money moves while they do. Everything generated from a document (SDKs, docs,
|
|
6
6
|
tool surfaces, the running engine) is downstream of what is written here.
|
|
7
7
|
|
|
8
|
+
UDL is the platform's header files and driver framework. Its grammar is the
|
|
9
|
+
complete instrument vocabulary and the ABI between authored programs and the
|
|
10
|
+
engine. An instrument definition can round-trip through UDL without dropping a
|
|
11
|
+
clause.
|
|
12
|
+
|
|
8
13
|
## The schema is the authority
|
|
9
14
|
|
|
10
15
|
`udl.schema.json` in this directory is JSON Schema 2020-12, generated from the
|
|
@@ -17,7 +22,7 @@ no grammar tables and no field lists. Where anything below disagrees with
|
|
|
17
22
|
`udl.schema.json`, the schema wins.
|
|
18
23
|
|
|
19
24
|
The schema is generated from the _input_ view of the grammar, so it describes a
|
|
20
|
-
document as an author writes it, before any default is filled in. A
|
|
25
|
+
document as an author writes it, before any default is filled in. A action may
|
|
21
26
|
omit `moves`; a parser hands it back as `[]`.
|
|
22
27
|
|
|
23
28
|
## The ten laws
|
|
@@ -28,12 +33,13 @@ refuses.
|
|
|
28
33
|
1. **One-sentence law.** Every concept in UDL is explainable in one sentence to
|
|
29
34
|
someone who has never seen it. A concept that needs a paragraph is
|
|
30
35
|
machinery, and machinery does not belong in the language.
|
|
31
|
-
2. **Purity law.** No bank or provider legacy enters UDL: no statement
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
2. **Purity law.** No bank or provider legacy enters UDL: no provider statement
|
|
37
|
+
schemas, file drops, polling, batch windows, cutoff times, scheme names,
|
|
38
|
+
currency reconciliation rules, or ISO or SWIFT message types. A `reconcile`
|
|
39
|
+
clause names settlement evidence against a declared provider-side row. It
|
|
40
|
+
does not model the provider file, transport, or matching machinery.
|
|
41
|
+
3. **Event law.** Every state change emits an event. Names derive from the instrument
|
|
42
|
+
and the action's past tense (`escrow_order.released`); the optional
|
|
37
43
|
`eventName` overrides only where the honest past tense is irregular.
|
|
38
44
|
4. **One-spine law.** Internal ledger money moves through four instructions and no others:
|
|
39
45
|
`internal_transfer.create`, `.reserve`, `.post`, `.void`. Three account
|
|
@@ -42,23 +48,40 @@ refuses.
|
|
|
42
48
|
a stored amount and beneficiary reference to the execution core. It is not
|
|
43
49
|
a kernel instruction and cannot disguise an internal ledger move.
|
|
44
50
|
5. **Uniform object law.** Every instance carries an opaque prefixed id (from
|
|
45
|
-
the
|
|
51
|
+
the instrument's `idPrefix`), a `status` drawn from its declared lifecycle, a
|
|
46
52
|
creation timestamp, and a caller-owned metadata bag. Amounts are
|
|
47
53
|
string-encoded integer minor units paired with a currency code, never JSON
|
|
48
54
|
numbers.
|
|
49
|
-
6. **Requirements-as-data law.** Anything a caller must satisfy before a
|
|
55
|
+
6. **Requirements-as-data law.** Anything a caller must satisfy before a action
|
|
50
56
|
unlocks is declared data: `due`, `deadline`, `requiresRefs`,
|
|
51
|
-
`
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
`requiresChecks`, `requiresExposure`, `requiresAggregate`, `remainder`,
|
|
58
|
+
`requiresDrainedAccount`, `commit`, `reconcile`. A reconcile declares one
|
|
59
|
+
expectation: the amount, the currency, `credit` or `debit`, the ref naming
|
|
60
|
+
the provider-side row, exactly one evidence source, a match law of `exact`,
|
|
61
|
+
`tolerance` bounded by a named dial, or `window`, and a window given as a
|
|
62
|
+
fixed duration or a stored deadline field. It ends matched or as a capped
|
|
63
|
+
exception child, never as a silent wait; the child is declared and validated
|
|
64
|
+
at admission rather than materialized, so past the window the transition
|
|
65
|
+
refuses naming it. Settlement evidence for a payout is one reconcile against
|
|
66
|
+
a debit statement line under any match law, reading the reference an earlier
|
|
67
|
+
payout intent captured. No caller may assert that match. An action that carries `quote` prices a base into a charge
|
|
68
|
+
and a net, names the fields the price depends on, and declares when the offer
|
|
69
|
+
dies, as a fixed duration or a stored deadline field. Exactly one other
|
|
70
|
+
action names it back through `commit`, and that action is the only one that
|
|
71
|
+
may move the net. A `commit` gate reads the offer the quoting action priced
|
|
72
|
+
and refuses once its deadline has passed or any frozen field has changed. It
|
|
73
|
+
spends what the quote wrote instead of pricing again, so the number a caller
|
|
74
|
+
is shown is the number they pay.
|
|
55
75
|
7. **Append-only evolution law.** Once a definition has live instances, adding
|
|
56
|
-
states, transitions, optional fields, and
|
|
76
|
+
states, transitions, optional fields, and actions is legal; removing,
|
|
57
77
|
renaming, tightening, or changing a money step is not.
|
|
58
78
|
`diffValidatedUdlEvolution` decides, on two documents the validator has
|
|
59
|
-
already admitted; `udl diff` parses both files and then calls it.
|
|
60
|
-
|
|
61
|
-
|
|
79
|
+
already admitted; `udl diff` parses both files and then calls it. Evolution
|
|
80
|
+
snapshots retain navigation, update examples, and parked-state reasons for
|
|
81
|
+
complete inspection. The diff treats their prose as editable presentation
|
|
82
|
+
and protects the parked state keys that carry lifecycle meaning.
|
|
83
|
+
8. **Naming law.** Instruments are `snake_case`, singular, plain business English.
|
|
84
|
+
Actions are single words in imperative present. Operations are `instrument.action`.
|
|
62
85
|
Fields are `camelCase`. The patterns live in the schema.
|
|
63
86
|
9. **Time law.** Delays the world imposes (settlement windows, activation
|
|
64
87
|
periods, renewal cycles, retries) surface as honest statuses and timestamps
|
|
@@ -68,6 +91,19 @@ refuses.
|
|
|
68
91
|
every gate names a state that exists, and every funded balance is drained
|
|
69
92
|
on every terminal path.
|
|
70
93
|
|
|
94
|
+
## Admission budgets and derived effects
|
|
95
|
+
|
|
96
|
+
The 10,000-node limit bounds authored program complexity. The compiler derives
|
|
97
|
+
`effects` rows from action clauses, so the node counter excludes every action
|
|
98
|
+
`effects` subtree. Admission still checks those subtrees for shape, exact
|
|
99
|
+
agreement with the clauses including row order, nesting depth, string limits,
|
|
100
|
+
JSON-only values, and cycles.
|
|
101
|
+
|
|
102
|
+
The canonical 33-instrument catalog measured 10,270 nodes with derived effects
|
|
103
|
+
and 9,321 authored nodes without the effect subtrees on 2026-09-02. The fixed
|
|
104
|
+
10,000-node limit therefore leaves 679 authored nodes of headroom. The full
|
|
105
|
+
effectful document validates as one document.
|
|
106
|
+
|
|
71
107
|
## What the schema cannot say
|
|
72
108
|
|
|
73
109
|
JSON Schema pins shape. It does not pin meaning, and four classes of law live
|
|
@@ -91,38 +127,21 @@ suite is what makes two implementations agree.
|
|
|
91
127
|
|
|
92
128
|
## Issue codes
|
|
93
129
|
|
|
94
|
-
A refusal reports one or more issues, each with a stable code
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
| ------------------- | ----------------------------------------------------------------------------------------- |
|
|
99
|
-
| `invalid_utf8` | The bytes are not valid UTF-8. |
|
|
100
|
-
| `invalid_json` | The bytes are UTF-8 but not JSON. |
|
|
101
|
-
| `invalid_shape` | The JSON does not match `udl.schema.json`, or fails a check the schema cannot express. |
|
|
102
|
-
| `invalid_semantics` | The shape is right and a whole-document law is broken. |
|
|
103
|
-
| `resource_limit` | The document exceeds an admission budget (size, depth, node count, pattern search space). |
|
|
130
|
+
A refusal reports one or more issues, each with a stable `UDL####` code, a
|
|
131
|
+
category, a fix, and a JSON path. Codes and paths form the conformance
|
|
132
|
+
contract. Messages may become clearer. The generated
|
|
133
|
+
[diagnostic reference](../docs/reference/diagnostics.md) lists every code.
|
|
104
134
|
|
|
105
135
|
Paths are `$`-rooted with dotted keys and bracketed array indices:
|
|
106
|
-
`$.
|
|
136
|
+
`$.instruments[0].lifecycle.states[2]`.
|
|
107
137
|
|
|
108
138
|
## Canonical form
|
|
109
139
|
|
|
110
|
-
Every document has
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
- Two spaces of indentation per level of nesting.
|
|
116
|
-
- One space after each `:`. Members separated by `,` then a newline.
|
|
117
|
-
- An empty object is `{}` and an empty array is `[]`, both on one line.
|
|
118
|
-
- Exactly one line feed at the end of the file, and no other trailing
|
|
119
|
-
whitespace.
|
|
120
|
-
- Non-ASCII characters are written literally, not escaped.
|
|
121
|
-
|
|
122
|
-
Two consequences worth stating outright. Serialization validates first, so an
|
|
123
|
-
invalid document has no canonical form. And the round trip is byte-stable:
|
|
124
|
-
canonicalizing canonical bytes returns them unchanged, which is what lets a
|
|
125
|
-
document be diffed, signed, and stored as its own identity.
|
|
140
|
+
Every admitted document has one canonical byte sequence. The normative
|
|
141
|
+
[canonical bytes law](../docs/reference/canonical.md) defines key and array
|
|
142
|
+
order, number and string encoding, empty containers, the trailing line feed,
|
|
143
|
+
and the SHA-256 digest. Serialization validates first, so an invalid document
|
|
144
|
+
has no canonical form.
|
|
126
145
|
|
|
127
146
|
## Two version numbers
|
|
128
147
|
|
|
@@ -133,9 +152,21 @@ that exists.
|
|
|
133
152
|
**Package version** is the semver of `@hyperscale0/udl`, declared in
|
|
134
153
|
`package.json`.
|
|
135
154
|
|
|
136
|
-
They move independently, under one rule: **format 1
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
155
|
+
They move independently, under one rule: **format 1 freezes when the package
|
|
156
|
+
reaches 1.0.0.** The release candidate may still change what format 1 accepts,
|
|
157
|
+
and every change appears in `../CHANGELOG.md`.
|
|
158
|
+
|
|
159
|
+
After 1.0.0, an incompatible grammar change uses a new format literal. Readers
|
|
160
|
+
keep an explicit decoder and validator for each supported old literal. A
|
|
161
|
+
stored format 1 document remains readable under the format 1 rules. It does
|
|
162
|
+
not acquire new required fields from the current package. Passing an old
|
|
163
|
+
document to an evolution comparison can raise the matching `UDL7xxx` removal,
|
|
164
|
+
tightening, lifecycle, or executable-change code, but a package upgrade alone
|
|
165
|
+
does not rewrite its bytes. A product migration must validate and store its new
|
|
166
|
+
document as a separate version before switching instances to it.
|
|
167
|
+
|
|
168
|
+
The evolution codes are explicit. `UDL7001` protects stored identities,
|
|
169
|
+
subjects, instruments, fields, lifecycles, actions, money clauses, gates, and
|
|
170
|
+
policy. `UDL7002` requires a version increase for a semantic change.
|
|
171
|
+
Evolution comparison admits the previous document first. A stored document
|
|
172
|
+
that fails admission is `invalid_previous`, not an evolution issue.
|