@blue-labs/language 4.1.1 → 5.0.0-rc.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/dist/Blue-B7SYp5QY.mjs +8237 -0
- package/dist/Blue-CTQkRrnu.js +98 -0
- package/dist/conformance.d.ts +3 -0
- package/dist/conformance.d.ts.map +1 -0
- package/dist/conformance.js +6 -0
- package/dist/conformance.mjs +1258 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -27
- package/dist/index.mjs +679 -6799
- package/dist/lib/Blue.d.ts +5 -2
- package/dist/lib/Blue.d.ts.map +1 -1
- package/dist/lib/conformance/BlueConformanceSuiteRunner.d.ts +68 -0
- package/dist/lib/conformance/BlueConformanceSuiteRunner.d.ts.map +1 -0
- package/dist/lib/conformance/BlueLanguageConformanceReport.d.ts +37 -0
- package/dist/lib/conformance/BlueLanguageConformanceReport.d.ts.map +1 -0
- package/dist/lib/conformance/JavaBlueIdCalculator.d.ts +19 -0
- package/dist/lib/conformance/JavaBlueIdCalculator.d.ts.map +1 -0
- package/dist/lib/conformance/conformance-expect.d.ts +17 -0
- package/dist/lib/conformance/conformance-expect.d.ts.map +1 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/.gitkeep +1 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_double_1e0.yaml +6 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_double_negative_zero.yaml +14 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_double_overflow_rejected.yaml +9 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_empty_list.yaml +6 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_empty_object_list_element_rejected.yaml +10 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_empty_placeholder.yaml +10 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_integer_1_vs_double_1_0.yaml +7 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_invalid_this_placeholder_rejected.yaml +7 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_large_integer_quoted_explicit_integer.yaml +10 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_list_sugar_equivalence.yaml +12 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_malformed_empty_rejected.yaml +8 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_null_list_element_rejected.yaml +10 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_object_field_null_removal.yaml +8 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_payload_only_scalar_typed_identity.yaml +11 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_plain_blueid_validation.yaml +7 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_pos_rejected.yaml +10 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_previous_invalid_blueid_rejected.yaml +11 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_replace_rejected.yaml +10 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_root_empty_object.yaml +6 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_root_list.yaml +8 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_root_null_rejected.yaml +6 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_root_pure_reference.yaml +7 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_root_scalar.yaml +6 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_scalar_sugar_equivalence.yaml +8 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_type_alias_rejected_in_direct_blueid_input.yaml +9 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/blueid/B_unquoted_large_integer_rejected.yaml +7 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/circular/C_circular_reference_set_ids.yaml +14 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/circular/C_duplicate_preliminary_ids_deterministic_or_rejected.yaml +12 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/circular/C_this_placeholder_rejected_outside_cyclic_api.yaml +7 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/circular/C_three_document_cycle_stable_order.yaml +18 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/circular/C_zero_blueid_rejected_in_final_input.yaml +7 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/lint/L_no_profile_era_language_conformance_terms.yaml +45 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/manifest.yaml +234 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/provider/F_collapse_does_not_produce_mixed_blueid.yaml +10 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/provider/F_collapse_nested_subtree_preserves_node_blueid.yaml +10 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/provider/F_collapse_preserves_node_blueid.yaml +9 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/provider/F_expand_missing_nested_content_fails.yaml +9 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/provider/F_expand_nested_reference_preserves_node_blueid.yaml +14 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/provider/F_expand_preserves_node_blueid.yaml +11 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/provider/F_expand_wrong_nested_provider_content_fails.yaml +12 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/provider/F_provider_missing_content_fails.yaml +9 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/provider/F_provider_wrong_blueid_rejected.yaml +13 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/registry/changingCoreTypeDescriptionChangesBlueId.yaml +9 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/registry/coreRegistryBooleanNodeHashesToPublishedBlueId.yaml +7 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/registry/coreRegistryDictionaryNodeHashesToPublishedBlueId.yaml +7 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/registry/coreRegistryDoubleNodeHashesToPublishedBlueId.yaml +7 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/registry/coreRegistryIntegerNodeHashesToPublishedBlueId.yaml +7 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/registry/coreRegistryListNodeHashesToPublishedBlueId.yaml +7 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/registry/coreRegistryTextNodeHashesToPublishedBlueId.yaml +7 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_blue_imports.yaml +15 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_blue_imports_type_itemType_keyType_valueType.yaml +24 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_canonical_overlay_no_previous_no_pos.yaml +18 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_canonicalization_deterministic_for_same_resolved_view.yaml +11 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_child_field_labels_materialize_until_overridden.yaml +26 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_contracts_canonicalization_deterministic.yaml +18 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_contracts_merge_as_content.yaml +21 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_core_type_compatibility_nominal_by_blueid.yaml +11 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_enum_integer_vs_double.yaml +14 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_inherited_append_only_policy.yaml +16 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_inherited_item_type.yaml +13 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_inherited_keyType_valueType.yaml +16 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_instance_field_kept.yaml +11 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_provider_reference_canonicalizes_back.yaml +13 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_provider_reference_with_overlay_keeps_overlay.yaml +16 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_schema_double_multiple_of_exact.yaml +17 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_schema_double_multiple_of_rejects_decimal_approximation.yaml +12 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_schema_enum_order_and_duplicates_canonical.yaml +26 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_schema_integer_multiple_of_lcm_merge.yaml +17 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_schema_large_integer_minimum_with_type_alias.yaml +15 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_schema_value_shapes.yaml +10 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_schema_wrong_kind_keywords_rejected.yaml +10 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_source_empty_object_list_to_empty.yaml +14 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_source_null_list_to_empty.yaml +14 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_source_recursive_empty_object_list_to_empty.yaml +15 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_top_level_type_name_description_not_inherited.yaml +21 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_type_aliases_removed_from_canonical_overlay.yaml +15 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_type_derived_field_removed.yaml +11 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/fixtures/resolver/R_view_path_root_is_empty_string.yaml +25 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/language/1.0/spec.md +2932 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/registry/blue-language-1.0/Boolean.blue +6 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/registry/blue-language-1.0/Dictionary.blue +17 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/registry/blue-language-1.0/Double.blue +12 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/registry/blue-language-1.0/Integer.blue +11 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/registry/blue-language-1.0/List.blue +14 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/registry/blue-language-1.0/Text.blue +9 -0
- package/dist/lib/conformance/fixtures/blue-language-1.0/registry/blue-language-1.0/manifest.yaml +8 -0
- package/dist/lib/errors/BlueError.d.ts +23 -1
- package/dist/lib/errors/BlueError.d.ts.map +1 -1
- package/dist/lib/identity/CyclicSetIdentityService.d.ts +1 -1
- package/dist/lib/identity/CyclicSetIdentityService.d.ts.map +1 -1
- package/dist/lib/identity/SemanticIdentityService.d.ts.map +1 -1
- package/dist/lib/index.d.ts +3 -0
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/mapping/ComplexObjectConverter.d.ts.map +1 -1
- package/dist/lib/mapping/ConverterFactory.d.ts.map +1 -1
- package/dist/lib/mapping/ValueConverter.d.ts.map +1 -1
- package/dist/lib/merge/Merger.d.ts +4 -0
- package/dist/lib/merge/Merger.d.ts.map +1 -1
- package/dist/lib/merge/MergingProcessor.d.ts +10 -0
- package/dist/lib/merge/MergingProcessor.d.ts.map +1 -1
- package/dist/lib/merge/processors/DictionaryProcessor.d.ts.map +1 -1
- package/dist/lib/merge/processors/ListProcessor.d.ts +2 -0
- package/dist/lib/merge/processors/ListProcessor.d.ts.map +1 -1
- package/dist/lib/merge/processors/SchemaPropagator.d.ts +13 -0
- package/dist/lib/merge/processors/SchemaPropagator.d.ts.map +1 -0
- package/dist/lib/merge/processors/SchemaVerifier.d.ts +16 -0
- package/dist/lib/merge/processors/SchemaVerifier.d.ts.map +1 -0
- package/dist/lib/merge/processors/SequentialMergingProcessor.d.ts +2 -0
- package/dist/lib/merge/processors/SequentialMergingProcessor.d.ts.map +1 -1
- package/dist/lib/merge/processors/TypeAssigner.d.ts.map +1 -1
- package/dist/lib/merge/processors/ValuePropagator.d.ts.map +1 -1
- package/dist/lib/merge/processors/index.d.ts +2 -0
- package/dist/lib/merge/processors/index.d.ts.map +1 -1
- package/dist/lib/merge/utils/default.d.ts.map +1 -1
- package/dist/lib/model/Node.d.ts +18 -1
- package/dist/lib/model/Node.d.ts.map +1 -1
- package/dist/lib/model/NodeDeserializer.d.ts +5 -0
- package/dist/lib/model/NodeDeserializer.d.ts.map +1 -1
- package/dist/lib/model/ResolvedNode.d.ts.map +1 -1
- package/dist/lib/model/Schema.d.ts +14 -0
- package/dist/lib/model/Schema.d.ts.map +1 -0
- package/dist/lib/model/index.d.ts +1 -0
- package/dist/lib/model/index.d.ts.map +1 -1
- package/dist/lib/preprocess/Preprocessor.d.ts +8 -1
- package/dist/lib/preprocess/Preprocessor.d.ts.map +1 -1
- package/dist/lib/provider/InMemoryNodeProvider.d.ts.map +1 -1
- package/dist/lib/provider/RepositoryBasedNodeProvider.d.ts +2 -0
- package/dist/lib/provider/RepositoryBasedNodeProvider.d.ts.map +1 -1
- package/dist/lib/provider/VerifyingNodeProvider.d.ts +14 -0
- package/dist/lib/provider/VerifyingNodeProvider.d.ts.map +1 -0
- package/dist/lib/repository/BuiltinRuntimeTypes.d.ts +360 -0
- package/dist/lib/repository/BuiltinRuntimeTypes.d.ts.map +1 -0
- package/dist/lib/repository/RepositoryContentCanonicalizer.d.ts.map +1 -1
- package/dist/lib/repository/RepositoryRuntime.d.ts +1 -1
- package/dist/lib/repository/RepositoryRuntime.d.ts.map +1 -1
- package/dist/lib/snapshot/CanonicalOverlayPatchEngine.d.ts +6 -0
- package/dist/lib/snapshot/CanonicalOverlayPatchEngine.d.ts.map +1 -0
- package/dist/lib/snapshot/FrozenNode.d.ts +80 -0
- package/dist/lib/snapshot/FrozenNode.d.ts.map +1 -0
- package/dist/lib/snapshot/FrozenNodeToBlueIdInput.d.ts +5 -0
- package/dist/lib/snapshot/FrozenNodeToBlueIdInput.d.ts.map +1 -0
- package/dist/lib/snapshot/ResolvedReferenceCache.d.ts +8 -0
- package/dist/lib/snapshot/ResolvedReferenceCache.d.ts.map +1 -0
- package/dist/lib/snapshot/ResolvedSnapshot.d.ts +8 -0
- package/dist/lib/snapshot/ResolvedSnapshot.d.ts.map +1 -0
- package/dist/lib/snapshot/index.d.ts +6 -0
- package/dist/lib/snapshot/index.d.ts.map +1 -0
- package/dist/lib/types/BlueRepository.d.ts +1 -1
- package/dist/lib/utils/BlueIdCalculator.d.ts +19 -1
- package/dist/lib/utils/BlueIdCalculator.d.ts.map +1 -1
- package/dist/lib/utils/BlueIds.d.ts +9 -1
- package/dist/lib/utils/BlueIds.d.ts.map +1 -1
- package/dist/lib/utils/BlueNumbers.d.ts +7 -0
- package/dist/lib/utils/BlueNumbers.d.ts.map +1 -0
- package/dist/lib/utils/ListControls.d.ts.map +1 -1
- package/dist/lib/utils/MergeReverser.d.ts +10 -0
- package/dist/lib/utils/MergeReverser.d.ts.map +1 -1
- package/dist/lib/utils/NodePatch/patch-utils.d.ts +1 -1
- package/dist/lib/utils/NodeProviderWrapper.d.ts +4 -0
- package/dist/lib/utils/NodeProviderWrapper.d.ts.map +1 -1
- package/dist/lib/utils/NodeToBlueIdInput.d.ts +34 -0
- package/dist/lib/utils/NodeToBlueIdInput.d.ts.map +1 -0
- package/dist/lib/utils/NodeToMapListOrValue.d.ts.map +1 -1
- package/dist/lib/utils/NodeTransformer.d.ts.map +1 -1
- package/dist/lib/utils/NodeTypeMatcher.d.ts +27 -1
- package/dist/lib/utils/NodeTypeMatcher.d.ts.map +1 -1
- package/dist/lib/utils/NodeTypes.d.ts +1 -0
- package/dist/lib/utils/NodeTypes.d.ts.map +1 -1
- package/dist/lib/utils/Properties.d.ts +97 -10
- package/dist/lib/utils/Properties.d.ts.map +1 -1
- package/dist/lib/utils/TypeSchema.d.ts +0 -1
- package/dist/lib/utils/TypeSchema.d.ts.map +1 -1
- package/dist/lib/utils/index.d.ts +4 -1
- package/dist/lib/utils/index.d.ts.map +1 -1
- package/dist/schema/jsonBlue.d.ts +1 -1
- package/dist/schema/utils.d.ts.map +1 -1
- package/dist/utils/yamlBlue/type/float.d.ts.map +1 -1
- package/package.json +8 -3
|
@@ -0,0 +1,2932 @@
|
|
|
1
|
+
# Blue Language Specification 1.0
|
|
2
|
+
|
|
3
|
+
> **Scope.** This document defines Blue's content language: the node model, Blue Graph, Blue Documents, typing, overlays, schema constraints, preprocessing, resolution, expansion, collapse, canonicalization, minimization, and BlueId. It does **not** define runtime execution, handlers, events, channels, gas, or contract processing. Those belong to the separate **Blue Contracts and Processor Specification**.
|
|
4
|
+
|
|
5
|
+
Where this document references core types such as **Text**, **Integer**, **Double**, **Boolean**, **Dictionary**, and **List**, their canonical type definitions and canonical BlueIds are supplied by the canonical Blue type registry. Appendix A defines their normative semantics and shows the intended canonical registry nodes. The registry is the authority for the exact node content and BlueIds.
|
|
6
|
+
|
|
7
|
+
Canonical core type nodes are identity-bearing Blue content. Their `description` fields define type semantics and affect BlueId. Editing a canonical description changes the type identity and therefore MUST be treated as a registry/versioning change, not as ordinary documentation editing.
|
|
8
|
+
|
|
9
|
+
The Blue Language 1.0 release is defined by this prose specification, the canonical Blue type registry, and the Blue Language 1.0 conformance fixture package together. If these artifacts conflict, the release process MUST be corrected; implementations MUST NOT guess.
|
|
10
|
+
|
|
11
|
+
## Conventions
|
|
12
|
+
|
|
13
|
+
The key words **MUST**, **MUST NOT**, **REQUIRED**, **SHOULD**, **SHOULD NOT**, **MAY**, and **OPTIONAL** are to be interpreted as normative requirement levels.
|
|
14
|
+
|
|
15
|
+
Sections marked **normative** define required behavior for conforming Blue Language 1.0 implementations. Sections marked **informative** explain intent, examples, or implementation guidance.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 0. Overview
|
|
20
|
+
|
|
21
|
+
Blue is a deterministic content language for describing a **content-addressed graph of typed nodes**.
|
|
22
|
+
|
|
23
|
+
A **Blue Graph** is the conceptual network of Blue nodes. Nodes are connected by ordinary object fields, list elements, type links, and `blueId` references. A **Blue Document** is a serialized rooted slice of that graph. It is **not required to contain the whole graph**: any pure `{ blueId: ... }` reference may point to content outside the selected document.
|
|
24
|
+
|
|
25
|
+
The **BlueId** of a document is the BlueId of its root node. BlueId is a content address. Equivalent source, expanded, collapsed, resolved, and canonical forms of the same content produce the same semantic identity when processed through the appropriate identity pipeline.
|
|
26
|
+
|
|
27
|
+
Blue supports several **views** of the same content. Implementations and authors MUST distinguish them.
|
|
28
|
+
|
|
29
|
+
| View / state | Purpose | Identity status |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| **Source Document** | Authored input. May use authoring sugar and the root `blue` directive. | Not necessarily direct BlueId Input. |
|
|
32
|
+
| **Preprocessed Document** | Source after preprocessing has applied authoring transforms and removed `blue`. | Eligible for resolution and, if otherwise valid, direct hashing. |
|
|
33
|
+
| **Expanded View** | Pure `{ blueId: X }` references materialized from a provider. | Preserves Node BlueId when provider content verifies. |
|
|
34
|
+
| **Collapsed View** | Materialized subtrees replaced by pure `{ blueId: X }` references. | Preserves Node BlueId. |
|
|
35
|
+
| **Resolved View** | Fully type-merged and schema-validated semantic view. | Carries semantic identity; not necessarily direct BlueId Input. |
|
|
36
|
+
| **Canonical Identity Input** | Deterministic identity form derived from a Resolved View. It may contain final canonical payloads that are not ordinary Source overlays. | Direct input to Node BlueId; produces Content BlueId. |
|
|
37
|
+
| **Minimized Overlay** | Author-facing reduced overlay that re-resolves to the same Resolved View. | Same Content BlueId when processed through the identity pipeline. |
|
|
38
|
+
|
|
39
|
+
The term **Canonical Overlay** is retained as a historical shorthand in some examples, but its normative role is **Canonical Identity Input**: the deterministic BlueId Input used to compute Content BlueId. It is not necessarily valid Source Document authoring form and is not required to re-resolve through ordinary Source overlay semantics.
|
|
40
|
+
|
|
41
|
+
A **Minimized Overlay** is the author-facing reduced form that re-resolves to the same Resolved View.
|
|
42
|
+
|
|
43
|
+
The identity pipeline for a Source Document is:
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
Source Document
|
|
47
|
+
-- preprocess --> Preprocessed Document
|
|
48
|
+
-- resolve --> Resolved View
|
|
49
|
+
-- canonicalize --> Canonical Identity Input
|
|
50
|
+
-- BlueId algorithm --> Node BlueId
|
|
51
|
+
= Content BlueId of the Source Document
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
A Blue Document is a rooted slice of a larger graph:
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
Selected document slice
|
|
58
|
+
+-----------------------------+
|
|
59
|
+
| root |
|
|
60
|
+
| +- local field |
|
|
61
|
+
| +- local list |
|
|
62
|
+
| +- type: { blueId: T } -----+----> external type node T
|
|
63
|
+
+-----------------------------+
|
|
64
|
+
\--> more graph reachable by BlueId
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
This specification defines content-language semantics only.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 1. Scope, Goals, Versioning, and Conformance
|
|
72
|
+
|
|
73
|
+
### 1.1 Goal
|
|
74
|
+
|
|
75
|
+
Blue is a universal, deterministic **content language** with:
|
|
76
|
+
|
|
77
|
+
- a strict, mergeable type system with overlay and subtyping rules;
|
|
78
|
+
- a content address called **BlueId** that is stable across equivalent content forms;
|
|
79
|
+
- a precise pipeline that maps an authored document to deterministic content identity;
|
|
80
|
+
- graph-slice semantics, so documents can contain local content and external `blueId` references.
|
|
81
|
+
|
|
82
|
+
### 1.2 Out of scope
|
|
83
|
+
|
|
84
|
+
The following are not defined by this specification:
|
|
85
|
+
|
|
86
|
+
- runtime execution;
|
|
87
|
+
- event processing;
|
|
88
|
+
- channels;
|
|
89
|
+
- handlers;
|
|
90
|
+
- gas accounting;
|
|
91
|
+
- document update listeners;
|
|
92
|
+
- processor lifecycle markers;
|
|
93
|
+
- contract execution.
|
|
94
|
+
|
|
95
|
+
The field `contracts` is reserved by the language because it is a possible field in Blue content and therefore can affect BlueId. Its runtime meaning is defined only by the separate Blue Contracts and Processor Specification.
|
|
96
|
+
|
|
97
|
+
### 1.3 Versioning
|
|
98
|
+
|
|
99
|
+
This document defines **Blue Language 1.0**.
|
|
100
|
+
|
|
101
|
+
A Blue node does not carry a required language-version field. A node's meaning is determined by this specification, its content, and the BlueIds of any referenced types.
|
|
102
|
+
|
|
103
|
+
Implementations MUST declare which Blue Language version they implement.
|
|
104
|
+
|
|
105
|
+
Blue Language 1.x revisions MUST preserve the meaning and BlueId of valid Blue Language 1.0 documents. Any incompatible change to the BlueId algorithm, node model, or resolution semantics requires a new major language version and an out-of-band version-selection mechanism. Such a mechanism MUST NOT require interpreting a node under the wrong BlueId algorithm before the version is known.
|
|
106
|
+
|
|
107
|
+
### 1.4 Conformance
|
|
108
|
+
|
|
109
|
+
A conforming Blue Language 1.0 implementation MUST implement all normative requirements in this specification.
|
|
110
|
+
|
|
111
|
+
A conforming implementation MUST support:
|
|
112
|
+
|
|
113
|
+
- parsing Blue Source Documents and BlueId Input;
|
|
114
|
+
- preprocessing, including the standard baseline preprocessing environment;
|
|
115
|
+
- type resolution and overlay merging;
|
|
116
|
+
- schema validation;
|
|
117
|
+
- list merge semantics and list control forms;
|
|
118
|
+
- provider-backed resolution when referenced content is required;
|
|
119
|
+
- expansion semantics, including provider-backed materialization when referenced content is required;
|
|
120
|
+
- collapse semantics if the implementation exposes a collapse API;
|
|
121
|
+
- canonicalization for Content BlueId calculation;
|
|
122
|
+
- author-facing minimization if the implementation exposes a minimization API;
|
|
123
|
+
- Node BlueId and Content BlueId calculation;
|
|
124
|
+
- circular reference set BlueIds;
|
|
125
|
+
- rejection of invalid Blue Language 1.0 documents and invalid BlueId Input;
|
|
126
|
+
- the Blue Language 1.0 conformance suite.
|
|
127
|
+
|
|
128
|
+
Implementations MAY expose smaller internal APIs, such as direct Node BlueId calculation, but such APIs do not define separate conformance levels.
|
|
129
|
+
|
|
130
|
+
A library or tool that implements only a subset of this specification may be useful, but it MUST NOT describe itself as a conforming Blue Language 1.0 implementation.
|
|
131
|
+
|
|
132
|
+
### 1.5 Core registry dependency
|
|
133
|
+
|
|
134
|
+
The canonical Blue type registry is part of the Blue Language 1.0 release surface. Its entries for `Text`, `Integer`, `Double`, `Boolean`, `Dictionary`, and `List` are content-addressed and versioned with this specification.
|
|
135
|
+
|
|
136
|
+
A conforming implementation MUST use the registry BlueIds for core type aliases. A different registry binding does not produce portable Blue Language 1.0 Content BlueIds.
|
|
137
|
+
|
|
138
|
+
Canonical registry nodes are self-describing Blue content.
|
|
139
|
+
|
|
140
|
+
A registry node's `name` and `description` fields are identity-bearing content under the Blue Language. A canonical registry entry SHOULD include a concise normative `description` that defines the semantics of the type. Changing that semantic description changes the node's BlueId and therefore defines a different type.
|
|
141
|
+
|
|
142
|
+
Non-normative examples, rationale, translations, tutorial material, implementation notes, and editorial commentary MUST NOT be included in canonical registry nodes unless intentionally made identity-bearing. Such material belongs in the prose specification, registry documentation, or examples outside the canonical node.
|
|
143
|
+
|
|
144
|
+
The registry file is the authority for the exact byte/string content of canonical nodes. Code blocks in this specification that claim to show canonical nodes SHOULD be generated from, or kept byte-equivalent to, the registry entries used to calculate the published BlueIds.
|
|
145
|
+
|
|
146
|
+
Practical editorial rule: if changing the text should change what the type means, put it in the canonical node. If changing the text only improves explanation, examples, formatting, translation, or teaching, keep it outside the canonical node.
|
|
147
|
+
|
|
148
|
+
The canonical registry entry for each core type MUST include:
|
|
149
|
+
|
|
150
|
+
- the exact canonical Blue node;
|
|
151
|
+
- the node's calculated BlueId;
|
|
152
|
+
- the Blue Language version that publishes it;
|
|
153
|
+
- the conformance fixture package identity that verifies it.
|
|
154
|
+
|
|
155
|
+
A conforming implementation MUST verify, at release or test time, that every bundled core type node hashes to the published registry BlueId.
|
|
156
|
+
|
|
157
|
+
The Blue Language 1.0 release is defined by three artifacts together:
|
|
158
|
+
|
|
159
|
+
1. this prose specification;
|
|
160
|
+
2. the canonical Blue type registry for Blue Language 1.0;
|
|
161
|
+
3. the Blue Language 1.0 conformance fixture package.
|
|
162
|
+
|
|
163
|
+
If these artifacts conflict, the release is inconsistent and MUST be corrected. Implementations MUST NOT guess which artifact wins.
|
|
164
|
+
|
|
165
|
+
The prose explains the rules, the registry supplies the exact identity-bearing type nodes and BlueIds, and the fixtures provide behavior-defining examples. These artifacts MUST be versioned and published together.
|
|
166
|
+
|
|
167
|
+
The fixture package is behavior-defining. It MUST publish exact expected BlueIds, canonical registry BlueIds, and fixture package identity.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## 2. Serialization and Data Model
|
|
172
|
+
|
|
173
|
+
### 2.1 JSON data model (normative)
|
|
174
|
+
|
|
175
|
+
Blue documents use the JSON data model:
|
|
176
|
+
|
|
177
|
+
- objects;
|
|
178
|
+
- arrays;
|
|
179
|
+
- strings;
|
|
180
|
+
- numbers;
|
|
181
|
+
- booleans;
|
|
182
|
+
- null.
|
|
183
|
+
|
|
184
|
+
YAML is an authoring syntax for this JSON data model. A YAML parser used for Blue MUST NOT introduce YAML-specific data types into the Blue data model.
|
|
185
|
+
|
|
186
|
+
### 2.2 YAML restrictions (normative)
|
|
187
|
+
|
|
188
|
+
When YAML is used for Blue serialization:
|
|
189
|
+
|
|
190
|
+
- duplicate object keys MUST be rejected;
|
|
191
|
+
- custom YAML tags MUST be rejected;
|
|
192
|
+
- Portable Blue YAML MUST reject YAML anchors, aliases, and merge keys. An implementation MAY expose a non-portable preprocessing mode that expands them deterministically before Blue parsing, but documents relying on that mode are not portable Blue Source Documents.
|
|
193
|
+
- non-JSON implicit types, including timestamps, binary blobs, sets, and ordered maps, MUST be disabled;
|
|
194
|
+
- timestamp-like values SHOULD be quoted by authors. Blue Language 1.0 defines no timestamp scalar.
|
|
195
|
+
|
|
196
|
+
Blue YAML 1.0 uses the YAML 1.2 JSON schema data model. Portable Blue YAML MUST reject custom tags, non-string object keys, binary tags, sets, ordered maps, and non-JSON implicit scalar types.
|
|
197
|
+
|
|
198
|
+
The parsed value of a YAML block scalar is the exact Text value. Blue performs no block-scalar normalization. Different YAML scalar styles, indentation, folding, chomping indicators, trailing newlines, or line endings that produce different parsed strings produce different BlueIds.
|
|
199
|
+
|
|
200
|
+
Examples:
|
|
201
|
+
|
|
202
|
+
```yaml
|
|
203
|
+
# Text, not a Date/Time type in Blue Language 1.0
|
|
204
|
+
ts: "2025-09-01T12:00:00Z"
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Blue Language 1.0 does not define a core Date or Timestamp scalar type.
|
|
208
|
+
|
|
209
|
+
### 2.3 Duplicate keys (normative)
|
|
210
|
+
|
|
211
|
+
Serialized Blue documents MUST NOT contain duplicate object keys. Parsers MUST reject duplicate keys. Later-key-wins behavior is not conforming.
|
|
212
|
+
|
|
213
|
+
### 2.4 Number tokens and large integers (normative)
|
|
214
|
+
|
|
215
|
+
Blue distinguishes the mathematical value of an integer from the JSON/YAML encoding used to carry it.
|
|
216
|
+
|
|
217
|
+
The interoperable **safe JSON numeric integer range** for Blue Language 1.0 is:
|
|
218
|
+
|
|
219
|
+
```text
|
|
220
|
+
[-9007199254740991, 9007199254740991]
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
JSON itself does not define a numeric range. Blue uses this safe range because it is exactly representable by JSON implementations that store numbers as IEEE 754 binary64 values.
|
|
224
|
+
|
|
225
|
+
Rules:
|
|
226
|
+
|
|
227
|
+
1. An unquoted integer token within this range MAY be used as an `Integer` value.
|
|
228
|
+
2. An integer value outside this range MUST be authored as a quoted canonical decimal string and MUST have explicit type `Integer` or a type that resolves to `Integer`.
|
|
229
|
+
3. In Canonical Identity Input and BlueId Input, an `Integer` value outside this range MUST be represented as its quoted canonical decimal string while retaining the explicit `Integer` type.
|
|
230
|
+
4. The canonical decimal string form is an optional leading `-` followed by decimal digits, with no leading zeros except the single digit `0`.
|
|
231
|
+
5. Quoted decimal text without an explicit `Integer` type is Text, not Integer.
|
|
232
|
+
|
|
233
|
+
A quoted canonical decimal string value is interpreted as an `Integer` when the node has an explicit effective type that resolves to `Integer`. The effective type may be authored locally or inherited from the resolved type chain.
|
|
234
|
+
|
|
235
|
+
If no effective type resolves to `Integer`, quoted decimal text is Text.
|
|
236
|
+
|
|
237
|
+
If an effective type resolves to `Integer` and the quoted value is not a valid canonical decimal integer string, resolution MUST fail.
|
|
238
|
+
|
|
239
|
+
Primitive scalar inference for quoted strings is provisional for Source Documents. Resolution MAY refine a quoted scalar's effective scalar type when an inherited or explicit type requires `Integer` and the quoted value is a valid canonical decimal integer string.
|
|
240
|
+
|
|
241
|
+
Examples:
|
|
242
|
+
|
|
243
|
+
```yaml
|
|
244
|
+
small:
|
|
245
|
+
type: Integer
|
|
246
|
+
value: 42
|
|
247
|
+
|
|
248
|
+
large:
|
|
249
|
+
type: Integer
|
|
250
|
+
value: "9007199254740992"
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
The same rule applies below the negative bound:
|
|
254
|
+
|
|
255
|
+
```yaml
|
|
256
|
+
veryNegative:
|
|
257
|
+
type: Integer
|
|
258
|
+
value: "-9007199254740992"
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Example with inherited Integer type:
|
|
262
|
+
|
|
263
|
+
```yaml
|
|
264
|
+
# Type
|
|
265
|
+
name: Account
|
|
266
|
+
accountId:
|
|
267
|
+
type: Integer
|
|
268
|
+
|
|
269
|
+
# Source instance
|
|
270
|
+
type: Account
|
|
271
|
+
accountId: "9007199254740992"
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
After preprocessing and resolution, `accountId` is an Integer value because the effective inherited type resolves to `Integer`.
|
|
275
|
+
|
|
276
|
+
Without the inherited or explicit Integer type, the same quoted value is Text.
|
|
277
|
+
|
|
278
|
+
Floating-point `Double` values MUST be finite. `NaN`, `Infinity`, and `-Infinity` are not valid Blue scalar values.
|
|
279
|
+
|
|
280
|
+
Double parsing MUST produce a finite IEEE 754 binary64 value using round-to-nearest, ties-to-even semantics. A numeric token that overflows to positive or negative Infinity, underflows to a non-finite value, or parses as NaN is invalid.
|
|
281
|
+
|
|
282
|
+
A parsed `-0.0` Double value compares equal to `0.0` and canonicalizes as JSON number `0` under RFC 8785. The node remains Double because its effective type is Double.
|
|
283
|
+
|
|
284
|
+
A Double whose RFC 8785 canonical JSON representation is integer-looking, such as `1`, remains Double because its effective type is represented in BlueId Input.
|
|
285
|
+
|
|
286
|
+
If a parser cannot deterministically parse a numeric token as binary64 with these semantics, the implementation MUST reject the token or require explicit authoring in a supported form.
|
|
287
|
+
|
|
288
|
+
### 2.5 Numeric token inference (normative)
|
|
289
|
+
|
|
290
|
+
When a numeric Source Document value has no explicit type:
|
|
291
|
+
|
|
292
|
+
- an unquoted integer token with no decimal point and no exponent infers `Integer`;
|
|
293
|
+
- an unquoted numeric token with a decimal point or exponent infers `Double`, even if its mathematical value is integral.
|
|
294
|
+
|
|
295
|
+
Examples:
|
|
296
|
+
|
|
297
|
+
```yaml
|
|
298
|
+
a: 1 # Integer
|
|
299
|
+
b: 1.0 # Double, canonical numeric payload may render as 1
|
|
300
|
+
c: -0.0 # Double, canonical numeric payload renders as 0
|
|
301
|
+
d: 1e999 # invalid Double
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
If a parser cannot preserve the lexical distinction between integer tokens and decimal/exponent tokens, it MUST require explicit type annotations for ambiguous numeric values or document that such inputs are not portable Source Documents.
|
|
305
|
+
|
|
306
|
+
### 2.6 String and multiline scalar identity (normative)
|
|
307
|
+
|
|
308
|
+
After parsing, a Blue string value is identity-bearing exactly as parsed. Blue Language performs no automatic whitespace normalization, line-ending normalization, trailing newline stripping, indentation rewriting, Unicode normalization, case folding, or YAML block-scalar canonicalization.
|
|
309
|
+
|
|
310
|
+
Different YAML scalar styles may produce different string values and therefore different BlueIds. In particular, YAML block scalar choices such as `|`, `|-`, `|+`, `>`, and `>-` may differ in line folding and trailing newline behavior.
|
|
311
|
+
|
|
312
|
+
Canonical registry nodes SHOULD be generated, fixture-checked, or otherwise protected against accidental string drift. Authors of identity-sensitive documents SHOULD treat edits to multiline `description` fields as content edits, not formatting edits.
|
|
313
|
+
|
|
314
|
+
Blue Language uses the parsed Unicode code-point sequence. Implementations MUST NOT normalize Text by default. Applications that need a normalization convention, such as NFC, SHOULD apply it explicitly at the application/preprocessing layer.
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## 3. Blue Graph, Blue Documents, and References
|
|
319
|
+
|
|
320
|
+
### 3.1 The Blue Graph (normative)
|
|
321
|
+
|
|
322
|
+
The **Blue Graph** is the conceptual content-addressed network of Blue nodes. Edges in the graph arise from:
|
|
323
|
+
|
|
324
|
+
- ordinary object fields, for example `address -> child node`;
|
|
325
|
+
- list elements;
|
|
326
|
+
- type links, for example `type: ...`;
|
|
327
|
+
- `blueId` references.
|
|
328
|
+
|
|
329
|
+
Nodes are identified by BlueId. The graph is global and content-addressed; it is not owned by any single document.
|
|
330
|
+
|
|
331
|
+
### 3.2 Blue Documents as graph slices (normative)
|
|
332
|
+
|
|
333
|
+
A **Blue Document** is a serialized rooted slice of the Blue Graph. It may contain:
|
|
334
|
+
|
|
335
|
+
- fully materialized child nodes;
|
|
336
|
+
- pure references to external nodes using `{ blueId: ... }`;
|
|
337
|
+
- a mixture of local content and external references.
|
|
338
|
+
|
|
339
|
+
A Blue Document is not required to be closed. A `{ blueId: X }` reference may point to content outside the selected document. Implementations may require a provider to expand references, resolve types, or canonicalize a view.
|
|
340
|
+
|
|
341
|
+
### 3.3 Pure references (normative)
|
|
342
|
+
|
|
343
|
+
A **pure reference** is exactly:
|
|
344
|
+
|
|
345
|
+
```yaml
|
|
346
|
+
blueId: <id>
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
or, as a field value:
|
|
350
|
+
|
|
351
|
+
```yaml
|
|
352
|
+
field:
|
|
353
|
+
blueId: <id>
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
A pure reference object MUST NOT carry sibling fields. The following is not a pure reference:
|
|
357
|
+
|
|
358
|
+
```yaml
|
|
359
|
+
blueId: <id>
|
|
360
|
+
name: Something
|
|
361
|
+
foo: bar
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Mixed `blueId` forms MUST be rejected in Source Documents, Preprocessed Documents, Canonical Identity Input, and BlueId Input. Provider metadata MUST be represented out-of-band or in a non-Blue envelope.
|
|
365
|
+
|
|
366
|
+
A non-Blue envelope is packaging metadata outside the Blue Document root. It is not part of the Blue node and is not included in BlueId calculation.
|
|
367
|
+
|
|
368
|
+
A pure reference cannot carry sibling fields. To refine or extend referenced content, the reference MUST appear in a type position or be resolved as an ancestor/type, and the overlay MUST be written as ordinary instance content outside the pure reference object.
|
|
369
|
+
|
|
370
|
+
Invalid:
|
|
371
|
+
|
|
372
|
+
```yaml
|
|
373
|
+
blueId: X
|
|
374
|
+
extra: value
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
Valid as a typed overlay:
|
|
378
|
+
|
|
379
|
+
```yaml
|
|
380
|
+
type:
|
|
381
|
+
blueId: X
|
|
382
|
+
extra: value
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### 3.4 Document identity (normative)
|
|
386
|
+
|
|
387
|
+
The BlueId of a Blue Document is the BlueId of its root node. There is no separate document-level identity above the root node.
|
|
388
|
+
|
|
389
|
+
A Blue Document root MAY be a scalar, list, object, or pure reference. Scalar and list roots follow the same wrapper-equivalence rules as field values. A Blue Document root MUST NOT be `null`.
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## 4. Node Model and Reserved Fields
|
|
394
|
+
|
|
395
|
+
### 4.1 Node anatomy (normative)
|
|
396
|
+
|
|
397
|
+
A **Blue node** consists of reserved language fields and, optionally, one primary payload kind.
|
|
398
|
+
|
|
399
|
+
```text
|
|
400
|
+
Node = reserved language fields + zero or one payload kind
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
The permitted payload kinds are:
|
|
404
|
+
|
|
405
|
+
- **scalar payload**: a `value` field carrying a string, number, or boolean;
|
|
406
|
+
- **list payload**: an `items` field carrying an ordered sequence;
|
|
407
|
+
- **object payload**: one or more ordinary child fields, where ordinary child fields are fields whose keys are not reserved language keys.
|
|
408
|
+
|
|
409
|
+
A node MUST NOT combine payload kinds. For example, a node MUST NOT contain both `value` and `items`, or both `value` and ordinary child fields.
|
|
410
|
+
|
|
411
|
+
A node MAY have no payload. Such a node is a metadata-only, type-only, schema-only, or overlay-only node. Examples include:
|
|
412
|
+
|
|
413
|
+
```yaml
|
|
414
|
+
age:
|
|
415
|
+
type: Integer
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
and:
|
|
419
|
+
|
|
420
|
+
```yaml
|
|
421
|
+
name: Person
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
A pure reference is a special metadata-only reference node. It is valid only when the object contains exactly `blueId`.
|
|
425
|
+
|
|
426
|
+
If a node has no payload and no retained reserved content after object-field cleaning, it may normalize to an empty map and be omitted when it appears as an object field. It MUST NOT be silently deleted when it appears as a list element; list element normalization is context-sensitive (§11.5, §14.2).
|
|
427
|
+
|
|
428
|
+
### 4.2 Reserved language keys (normative)
|
|
429
|
+
|
|
430
|
+
The following keys are reserved by the language:
|
|
431
|
+
|
|
432
|
+
```text
|
|
433
|
+
name, description,
|
|
434
|
+
type, itemType, keyType, valueType,
|
|
435
|
+
value, items,
|
|
436
|
+
blueId, blue,
|
|
437
|
+
schema, mergePolicy,
|
|
438
|
+
contracts
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
The following keys are reserved-invalid and MUST be rejected wherever they would appear as object fields:
|
|
442
|
+
|
|
443
|
+
```text
|
|
444
|
+
properties, constraints
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
Reserved fields are grouped as follows:
|
|
448
|
+
|
|
449
|
+
| Category | Fields |
|
|
450
|
+
|---|---|
|
|
451
|
+
| Identity labels | `name`, `description` |
|
|
452
|
+
| Type and constraint metadata | `type`, `itemType`, `keyType`, `valueType`, `schema`, `mergePolicy` |
|
|
453
|
+
| Payload wrappers | `value`, `items` |
|
|
454
|
+
| Reference and preprocessing controls | `blueId`, `blue` |
|
|
455
|
+
| Reserved extension field | `contracts` |
|
|
456
|
+
|
|
457
|
+
`contracts` is reserved by the language but semantically defined only by the Blue Contracts and Processor Specification.
|
|
458
|
+
|
|
459
|
+
The key `blue` is valid only as a preprocessing directive on the root of a Source Document. A conforming implementation MUST reject `blue` anywhere else. Direct Node BlueId calculation MUST reject any node containing `blue` as direct BlueId Input.
|
|
460
|
+
|
|
461
|
+
There is no `properties` field in the Blue Language. The key `properties` is reserved-invalid in Blue Language 1.0 and MUST NOT appear as an ordinary child field or language wrapper. Applications that need a data key literally named `properties` MUST use an escaped representation defined by the application's type.
|
|
462
|
+
|
|
463
|
+
Reserved language keys cannot be used as ordinary child-field names in direct object encoding. Direct object encoding can therefore represent only data keys that do not collide with reserved language keys.
|
|
464
|
+
Applications that need arbitrary user keys, including keys that equal reserved language keys, MUST use an escaped representation defined by the application's type.
|
|
465
|
+
|
|
466
|
+
### 4.3 Reserved field value types (normative)
|
|
467
|
+
|
|
468
|
+
Implementations MUST validate reserved field value types.
|
|
469
|
+
|
|
470
|
+
| Field | Required value shape |
|
|
471
|
+
|---|---|
|
|
472
|
+
| `name` | string, or absent |
|
|
473
|
+
| `description` | string, or absent |
|
|
474
|
+
| `type` | node, string alias in Source Documents before preprocessing, or pure reference |
|
|
475
|
+
| `itemType` | node, string alias in Source Documents before preprocessing, or pure reference |
|
|
476
|
+
| `keyType` | node, string alias in Source Documents before preprocessing, or pure reference |
|
|
477
|
+
| `valueType` | node, string alias in Source Documents before preprocessing, or pure reference |
|
|
478
|
+
| `value` | string, number, boolean, or absent |
|
|
479
|
+
| `items` | list, or absent |
|
|
480
|
+
| `blueId` | string BlueId, only in pure references |
|
|
481
|
+
| `blue` | string or object directive; root Source Document only |
|
|
482
|
+
| `schema` | object using only schema keywords from §9 |
|
|
483
|
+
| `mergePolicy` | `append-only`, `positional`, or absent |
|
|
484
|
+
| `contracts` | object; runtime semantics out of scope |
|
|
485
|
+
|
|
486
|
+
Wrong reserved-field types MUST be rejected. Implementations MUST NOT silently coerce reserved field values such as `blueId: 123` or `name: true` into strings.
|
|
487
|
+
|
|
488
|
+
### 4.4 `contracts` boundary (normative)
|
|
489
|
+
|
|
490
|
+
In Blue Language 1.0, `contracts` is a reserved identity-bearing content field. A language implementation MUST parse, preserve, resolve, canonicalize, and hash `contracts` as content. It MUST NOT execute `contracts`.
|
|
491
|
+
|
|
492
|
+
Unless a separate processor specification is explicitly being applied, `contracts` participates in language-level merge and canonicalization according to ordinary object-field rules. Runtime interpretation, reserved processor keys under `contracts`, processor lifecycle behavior, and contract capability handling are outside this specification.
|
|
493
|
+
|
|
494
|
+
Language-level merge of `contracts` is field-wise:
|
|
495
|
+
|
|
496
|
+
- If only the ancestor contributes a contract entry at key `k`, the entry is materialized in the Resolved View as type-derived content.
|
|
497
|
+
- If only the instance contributes a contract entry at key `k`, the entry is preserved as instance-supplied content.
|
|
498
|
+
- If both ancestor and instance contribute `contracts[k]`, the two contract nodes are merged recursively under the same fixed-value, type-compatibility, schema, and object-field rules used for ordinary child fields.
|
|
499
|
+
- A descendant MUST NOT remove an inherited contract entry during language resolution. Runtime removal or mutation of contracts, if allowed, belongs to the Blue Contracts and Processor Specification.
|
|
500
|
+
- The language resolver MUST NOT interpret, execute, sort, dispatch, or validate processor-specific contract behavior.
|
|
501
|
+
|
|
502
|
+
Processor-reserved keys inside `contracts` have no runtime effect in this specification. They are still parsed, resolved, canonicalized, and hashed as content.
|
|
503
|
+
|
|
504
|
+
### 4.5 `name` and `description`: identity vs field semantics (normative)
|
|
505
|
+
|
|
506
|
+
`name` and `description` are content on the node. They affect BlueId.
|
|
507
|
+
|
|
508
|
+
They are also matcher-neutral. Matchers MUST ignore `name` and `description` for:
|
|
509
|
+
|
|
510
|
+
- type conformance checks;
|
|
511
|
+
- subtype compatibility checks;
|
|
512
|
+
- structural or shape matching;
|
|
513
|
+
- resolution matching.
|
|
514
|
+
|
|
515
|
+
Identity equality includes `name` and `description`. Structural and type equality ignore them.
|
|
516
|
+
|
|
517
|
+
### 4.6 Document identity vs field semantics for labels (normative)
|
|
518
|
+
|
|
519
|
+
A node whose `type` is `T` is not `T`; it is a new entity. The resolved node's top-level `name` and `description` come only from the instance and MUST NOT be inherited from the type. The embedded type object may carry its own `name` and `description` inside `node.type`.
|
|
520
|
+
|
|
521
|
+
When a type materializes declaration-only fields or list elements into an instance, those child nodes carry the type's `name` and `description` as inherited labels until the instance explicitly overrides them.
|
|
522
|
+
|
|
523
|
+
However, when the inherited child node contains a fixed payload value, fixed list payload, fixed object subtree, or pure reference, the labels on that node are part of the inherited fixed value's identity. A descendant MUST NOT change `name` or `description` on such a fixed-value node unless the inherited type leaves that label absent or the change is otherwise allowed by an explicit resolution rule.
|
|
524
|
+
|
|
525
|
+
Dereferencing `{ blueId: X }` to materialize a node may copy the referenced node's `name` and `description` onto that materialized node, because the node itself is being materialized. This is expansion, not type inheritance.
|
|
526
|
+
|
|
527
|
+
---
|
|
528
|
+
|
|
529
|
+
## 5. Authoring Forms and Wrapper Equivalence
|
|
530
|
+
|
|
531
|
+
### 5.1 Wrapper equivalence (normative)
|
|
532
|
+
|
|
533
|
+
To improve ergonomics, Blue admits equivalent authoring forms for scalars and lists, provided the wrapper has no other keys.
|
|
534
|
+
|
|
535
|
+
Scalar sugar:
|
|
536
|
+
|
|
537
|
+
```yaml
|
|
538
|
+
x: 1
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
is equivalent to the wrapped form:
|
|
542
|
+
|
|
543
|
+
```yaml
|
|
544
|
+
x:
|
|
545
|
+
value: 1
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
List sugar:
|
|
549
|
+
|
|
550
|
+
```yaml
|
|
551
|
+
x: [a, b]
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
is equivalent to:
|
|
555
|
+
|
|
556
|
+
```yaml
|
|
557
|
+
x:
|
|
558
|
+
items: [a, b]
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
### 5.2 Sugar vs explicit metadata (normative)
|
|
562
|
+
|
|
563
|
+
The sugar rule applies only when the wrapper has no other keys. Therefore:
|
|
564
|
+
|
|
565
|
+
```yaml
|
|
566
|
+
x: 1
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
is sugar for:
|
|
570
|
+
|
|
571
|
+
```yaml
|
|
572
|
+
x:
|
|
573
|
+
value: 1
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
but:
|
|
577
|
+
|
|
578
|
+
```yaml
|
|
579
|
+
x:
|
|
580
|
+
type: Integer
|
|
581
|
+
value: 1
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
is not sugar. It is the explicit scalar node form with metadata.
|
|
585
|
+
|
|
586
|
+
A node may carry metadata such as `type`, `description`, `schema`, or `mergePolicy` alongside a payload kind. Metadata is not a payload kind.
|
|
587
|
+
|
|
588
|
+
### 5.3 Object nodes (normative)
|
|
589
|
+
|
|
590
|
+
Object payloads are written directly as ordinary child fields:
|
|
591
|
+
|
|
592
|
+
```yaml
|
|
593
|
+
x:
|
|
594
|
+
a: 1
|
|
595
|
+
b: 2
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
There is no `properties` wrapper. The key `properties` is reserved-invalid (§4.2).
|
|
599
|
+
|
|
600
|
+
### 5.4 Identity over forms (normative)
|
|
601
|
+
|
|
602
|
+
Equivalent authoring forms of the same semantic content MUST produce the same Content BlueId.
|
|
603
|
+
|
|
604
|
+
The BlueId algorithm operates on the abstract node model after canonical input normalization, not on authoring syntax. In particular, a bare scalar and its `{ value: ... }` wrapped form normalize identically. A bare list and its `{ items: ... }` wrapped form normalize identically.
|
|
605
|
+
|
|
606
|
+
---
|
|
607
|
+
|
|
608
|
+
## 6. Preprocessing and the `blue` Directive
|
|
609
|
+
|
|
610
|
+
### 6.1 Purpose (normative)
|
|
611
|
+
|
|
612
|
+
The root of a Source Document MAY contain a `blue` field. The `blue` directive declares preprocessing transforms that normalize authoring conveniences before the document is treated as identity-bearing content.
|
|
613
|
+
|
|
614
|
+
A string-valued `blue` directive identifies a preprocessing environment or import document according to the implementation's declared preprocessing configuration.
|
|
615
|
+
An object-valued `blue` directive declares imports and preprocessing transforms directly. The exact object fields supported by a preprocessing environment MUST be deterministic and documented by that environment.
|
|
616
|
+
|
|
617
|
+
Preprocessing is part of Content BlueId calculation. It is not part of direct Node BlueId calculation, because direct Node BlueId accepts only BlueId Input.
|
|
618
|
+
|
|
619
|
+
A conforming implementation MUST support this portable `blue.imports` shape:
|
|
620
|
+
|
|
621
|
+
```yaml
|
|
622
|
+
blue:
|
|
623
|
+
imports:
|
|
624
|
+
AliasName:
|
|
625
|
+
blueId: <BlueId>
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
Each key under `imports` is an authoring alias. Each value MUST be a pure reference object. During preprocessing, occurrences of that alias in `type`, `itemType`, `keyType`, or `valueType` positions are replaced by the corresponding pure reference.
|
|
629
|
+
|
|
630
|
+
Aliases declared in `blue.imports` are scoped to the Source Document being preprocessed. They are removed with the `blue` directive and are not identity content after preprocessing.
|
|
631
|
+
|
|
632
|
+
An alias name MUST NOT be declared more than once in the same `imports` object. An alias declared in `blue.imports` MUST NOT redefine a built-in core type name unless it maps to the same canonical BlueId.
|
|
633
|
+
|
|
634
|
+
### 6.2 Standard baseline preprocessing (normative)
|
|
635
|
+
|
|
636
|
+
A conforming implementation MUST support the standard baseline preprocessing environment:
|
|
637
|
+
|
|
638
|
+
1. **Core type aliases to BlueIds.** Core aliases such as `Text`, `Integer`, `Double`, `Boolean`, `Dictionary`, and `List` are replaced by canonical type references supplied by the canonical Blue type registry.
|
|
639
|
+
2. **Document-declared aliases to BlueIds.** Aliases other than the built-in core type names MUST be declared by the Source Document, for example through the root `blue` directive, or by content-addressed import documents referenced from it.
|
|
640
|
+
3. **Primitive scalar inference.** Bare scalar payloads with no explicit type are assigned the corresponding core primitive type: `Text`, `Integer`, `Double`, or `Boolean`.
|
|
641
|
+
4. **Wrapper normalization.** Scalar and list sugar are normalized into the abstract node model.
|
|
642
|
+
5. **List placeholder normalization.** In Source Documents, list elements that are `null`, `{}`, or that recursively normalize to an empty object after object-field cleaning are normalized to `$empty: true` (§11.5).
|
|
643
|
+
|
|
644
|
+
If the root `blue` directive is omitted, conforming implementations MUST still apply the standard baseline preprocessing environment. If a `blue` directive is present, it MAY configure imports and additional declared supported transforms, but it MUST NOT disable the mandatory baseline transforms required for interoperability.
|
|
645
|
+
|
|
646
|
+
Implementation-local alias configuration MAY be used for authoring convenience, but documents depending on undeclared implementation-local aliases do not have portable Content BlueIds.
|
|
647
|
+
|
|
648
|
+
### 6.3 Additional preprocessing transforms (normative)
|
|
649
|
+
|
|
650
|
+
Additional preprocessing transforms MAY be used only when they are explicitly declared by the root `blue` directive and supported by the implementation.
|
|
651
|
+
Such transforms MUST be deterministic. If a Source Document requires a transform that the implementation does not support, preprocessing MUST fail.
|
|
652
|
+
Any imported preprocessing document that affects Content BlueId MUST itself be identified by BlueId or by a deterministic registry binding declared by the Source Document.
|
|
653
|
+
A document that depends on implementation-local transforms not declared by the Source Document does not have a portable Content BlueId.
|
|
654
|
+
|
|
655
|
+
### 6.4 Preprocessing rules (normative)
|
|
656
|
+
|
|
657
|
+
- The `blue` directive is valid only on the root of a Source Document.
|
|
658
|
+
- The `blue` directive is not semantic content.
|
|
659
|
+
- A document containing `blue` is not valid BlueId Input.
|
|
660
|
+
- Preprocessing MUST remove the `blue` directive after applying it.
|
|
661
|
+
- Direct Node BlueId calculation MUST reject a node containing `blue`.
|
|
662
|
+
- Content BlueId calculation MUST preprocess the document and remove `blue` before hashing.
|
|
663
|
+
|
|
664
|
+
Simply ignoring `blue` is not correct. The directive may define aliases and transforms that change the canonical content. A direct hasher that sees `blue` MUST reject the input rather than hash a partially processed structure.
|
|
665
|
+
|
|
666
|
+
### 6.5 Security (normative)
|
|
667
|
+
|
|
668
|
+
Remote fetch of preprocessing imports or transforms is DISABLED by default. Implementations MAY support remote preprocessing documents only through explicit opt-in configuration and deterministic caching rules.
|
|
669
|
+
|
|
670
|
+
Any preprocessing import document or transform document fetched by BlueId MUST be verified against that BlueId before use. If verification fails, preprocessing MUST fail deterministically.
|
|
671
|
+
|
|
672
|
+
A preprocessing import that is not identified by BlueId MUST be supplied by a deterministic registry binding declared by the Source Document or by the implementation's declared preprocessing configuration. Such bindings are outside the portable Source Document unless their identity is included in the conformance fixture or release artifact.
|
|
673
|
+
|
|
674
|
+
---
|
|
675
|
+
|
|
676
|
+
## 7. BlueId and Content Identity
|
|
677
|
+
|
|
678
|
+
### 7.1 BlueId summary (normative)
|
|
679
|
+
|
|
680
|
+
Every Blue node has a content identity called its **BlueId**. The BlueId of a Blue Document is the BlueId of its root node.
|
|
681
|
+
|
|
682
|
+
BlueId is a content address: equivalent representations of the same content produce the same identity after the relevant view transformations have been applied.
|
|
683
|
+
|
|
684
|
+
This section defines BlueId conceptually. The algorithmic details are in §14.
|
|
685
|
+
|
|
686
|
+
### 7.2 Node BlueId and Content BlueId (normative)
|
|
687
|
+
|
|
688
|
+
Blue defines two related identities.
|
|
689
|
+
|
|
690
|
+
**Node BlueId** is the result of applying the BlueId algorithm directly to valid **BlueId Input**.
|
|
691
|
+
|
|
692
|
+
**Content BlueId** is the semantic identity of a Source Document. It is calculated as:
|
|
693
|
+
|
|
694
|
+
1. preprocess the Source Document (§6);
|
|
695
|
+
2. resolve type chains and validate constraints (§10), producing a Resolved View;
|
|
696
|
+
3. canonicalize the Resolved View into a Canonical Identity Input (§13);
|
|
697
|
+
4. compute the Node BlueId of the Canonical Identity Input (§14).
|
|
698
|
+
|
|
699
|
+
All conforming implementations MUST produce the same Content BlueId for equivalent Source Documents, given the same provider state required for resolution.
|
|
700
|
+
|
|
701
|
+
### 7.3 Identity preservation across views (normative)
|
|
702
|
+
|
|
703
|
+
Expansion preserves Node BlueId when the provider returns verified content. Pure references hash to their target BlueId; materializing a reference into content does not change the surrounding node's Node BlueId if the materialized content has that BlueId.
|
|
704
|
+
|
|
705
|
+
Collapse preserves Node BlueId. Replacing materialized content with a pure reference to its known BlueId yields the same Node BlueId.
|
|
706
|
+
|
|
707
|
+
Resolution preserves semantic identity. A Source Document and its Resolved View have the same Content BlueId when the Resolved View is canonicalized.
|
|
708
|
+
|
|
709
|
+
A Resolved View is not generally direct BlueId Input. It may contain inherited or materialized fields that are derivable from the type chain. Directly hashing a Resolved View is not guaranteed to produce the Content BlueId.
|
|
710
|
+
|
|
711
|
+
### 7.4 BlueId Input (normative)
|
|
712
|
+
|
|
713
|
+
**BlueId Input** is any node valid for direct application of the BlueId algorithm after BlueId input normalization.
|
|
714
|
+
|
|
715
|
+
BlueId Input MUST NOT contain:
|
|
716
|
+
|
|
717
|
+
- the `blue` directive;
|
|
718
|
+
- unresolved aliases introduced only for authoring convenience;
|
|
719
|
+
- illegal payload combinations;
|
|
720
|
+
- invalid list-control forms;
|
|
721
|
+
- mixed `blueId` reference shapes;
|
|
722
|
+
- unresolved cyclic placeholders such as `this#0`, except inside the explicit cyclic-set calculation API defined in §15;
|
|
723
|
+
- `$pos` overlays;
|
|
724
|
+
- `null` list elements;
|
|
725
|
+
- empty-object list elements that have not been normalized to `$empty: true`.
|
|
726
|
+
|
|
727
|
+
A node containing `blue` MUST NOT be accepted as direct BlueId Input. The `blue` directive is never identity content.
|
|
728
|
+
|
|
729
|
+
### 7.5 Allowed BlueId forms (normative)
|
|
730
|
+
|
|
731
|
+
A **plain BlueId** is the Base58 encoding of a SHA-256 digest using the following alphabet:
|
|
732
|
+
|
|
733
|
+
```text
|
|
734
|
+
123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
Blue Language 1.0 does not define alternative BlueId alphabets. A registry MAY define aliases or packaging metadata, but MUST NOT redefine the BlueId hash alphabet.
|
|
738
|
+
|
|
739
|
+
A plain BlueId MUST be the canonical Base58 encoding of exactly 32 bytes, the output length of SHA-256. Implementations MUST reject non-canonical Base58 encodings, strings containing characters outside the BlueId alphabet, and strings that decode to any length other than 32 bytes.
|
|
740
|
+
|
|
741
|
+
A plain BlueId MUST NOT contain `#`. The `#` suffix syntax is reserved for cyclic-set member BlueIds.
|
|
742
|
+
|
|
743
|
+
The ZERO_BLUEID sentinel defined in §15.2 is not a plain BlueId because the character `0` is not in the BlueId alphabet.
|
|
744
|
+
|
|
745
|
+
A **cyclic-set member BlueId** has the form:
|
|
746
|
+
|
|
747
|
+
```text
|
|
748
|
+
<MASTER>#<index>
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
where `MASTER` is the plain BlueId of the ordered cyclic set list and `index` is a non-negative decimal integer.
|
|
752
|
+
|
|
753
|
+
`this#<index>` is an algorithm-internal placeholder accepted only by the explicit cyclic-set calculation API defined in §15. It MUST NOT appear in ordinary BlueId Input or provider-stored content.
|
|
754
|
+
|
|
755
|
+
---
|
|
756
|
+
|
|
757
|
+
## 8. Types, Overlays, and Subtyping
|
|
758
|
+
|
|
759
|
+
### 8.1 Any node can be a type (normative)
|
|
760
|
+
|
|
761
|
+
There is no schema-versus-instance bifurcation in Blue. Any node can appear under `type`.
|
|
762
|
+
|
|
763
|
+
If `T` is used in `type: T`, then `T` contributes:
|
|
764
|
+
|
|
765
|
+
- structure;
|
|
766
|
+
- nested type chains;
|
|
767
|
+
- schema constraints;
|
|
768
|
+
- fixed values.
|
|
769
|
+
|
|
770
|
+
A type is an **overlay source**, not a class declaration.
|
|
771
|
+
|
|
772
|
+
### 8.2 Fixed-value invariant (normative)
|
|
773
|
+
|
|
774
|
+
A concrete value embedded in a type is immutable in descendants at that path. A descendant MUST NOT replace, remove, or contradict that value. Any attempted override MUST fail resolution.
|
|
775
|
+
|
|
776
|
+
For example, if a type fixes:
|
|
777
|
+
|
|
778
|
+
```yaml
|
|
779
|
+
country:
|
|
780
|
+
value: PL
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
then a descendant cannot resolve with:
|
|
784
|
+
|
|
785
|
+
```yaml
|
|
786
|
+
country:
|
|
787
|
+
value: US
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
### 8.3 Fixed-value equality (normative)
|
|
791
|
+
|
|
792
|
+
Fixed-value equality is evaluated after preprocessing and wrapper normalization.
|
|
793
|
+
|
|
794
|
+
- Scalar equality compares the parsed scalar value and effective scalar type.
|
|
795
|
+
- Object and list equality compares the Node BlueId of the normalized subtree.
|
|
796
|
+
- `name` and `description` are content for fixed-value equality. Matcher neutrality applies to type/shape matching, not to identity equality of fixed values.
|
|
797
|
+
|
|
798
|
+
Scalar payload equality compares parsed scalar value and effective scalar type. Full fixed-node equality compares the normalized Blue node identity, including `name`, `description`, metadata, and payload. Thus a descendant may not change labels on an inherited fixed-value node, because doing so changes the fixed node's identity.
|
|
799
|
+
|
|
800
|
+
Therefore these are equal after wrapper normalization:
|
|
801
|
+
|
|
802
|
+
```yaml
|
|
803
|
+
city: Warsaw
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
```yaml
|
|
807
|
+
city:
|
|
808
|
+
value: Warsaw
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
but these are different fixed values because labels are identity content:
|
|
812
|
+
|
|
813
|
+
```yaml
|
|
814
|
+
city:
|
|
815
|
+
name: City
|
|
816
|
+
value: Warsaw
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
```yaml
|
|
820
|
+
city:
|
|
821
|
+
name: Location
|
|
822
|
+
value: Warsaw
|
|
823
|
+
```
|
|
824
|
+
|
|
825
|
+
Valid label override on declaration-only field:
|
|
826
|
+
|
|
827
|
+
```yaml
|
|
828
|
+
# Parent type
|
|
829
|
+
city:
|
|
830
|
+
name: City
|
|
831
|
+
type: Text
|
|
832
|
+
|
|
833
|
+
# Descendant
|
|
834
|
+
city:
|
|
835
|
+
name: Location
|
|
836
|
+
value: Warsaw
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
Invalid label override on fixed-value field:
|
|
840
|
+
|
|
841
|
+
```yaml
|
|
842
|
+
# Parent type
|
|
843
|
+
city:
|
|
844
|
+
name: City
|
|
845
|
+
value: Warsaw
|
|
846
|
+
|
|
847
|
+
# Descendant
|
|
848
|
+
city:
|
|
849
|
+
name: Location
|
|
850
|
+
value: Warsaw
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
The second case fails because the inherited fixed node includes the label `name: City` as identity content.
|
|
854
|
+
|
|
855
|
+
### 8.4 Subtyping and Liskov substitutability (normative)
|
|
856
|
+
|
|
857
|
+
When resolving, descendants MUST satisfy:
|
|
858
|
+
|
|
859
|
+
1. **No fixed-value override.** Immutable values inherited from types cannot be changed.
|
|
860
|
+
2. **Type compatibility.** A descendant type at a path must be equal to or a subtype of the inherited type at that path (§8.4.1).
|
|
861
|
+
3. **Additive structure.** Guaranteed fields cannot be deleted.
|
|
862
|
+
4. **Collection compatibility.** `itemType`, `keyType`, and `valueType` compatibility must be preserved.
|
|
863
|
+
|
|
864
|
+
Every instance of a subtype MUST be substitutable for its parent.
|
|
865
|
+
|
|
866
|
+
If `itemType`, `keyType`, or `valueType` is inherited at a path, a descendant that omits the field inherits it. A descendant MAY narrow the inherited type by supplying an equal type or subtype. A descendant MUST NOT widen, remove, or replace the inherited type with an incompatible type.
|
|
867
|
+
|
|
868
|
+
Omitting `itemType`, `keyType`, or `valueType` means unconstrained only when there is no inherited effective type constraint at that path.
|
|
869
|
+
|
|
870
|
+
### 8.4.1 Formal subtype relation (normative)
|
|
871
|
+
|
|
872
|
+
For Blue Language 1.0, `T <: P` ("T is a subtype of P") iff resolving `T` as a descendant overlay of `P` succeeds under the resolution rules in §10, and every valid instance of `T` is substitutable where an instance of `P` is required.
|
|
873
|
+
|
|
874
|
+
A subtype check MUST ignore `name` and `description` for matcher/type-shape purposes, but fixed-value equality still includes `name` and `description` because they are identity content (§8.3).
|
|
875
|
+
|
|
876
|
+
For each path contributed by parent type `P`, subtype `T` MUST satisfy all of the following:
|
|
877
|
+
|
|
878
|
+
1. **Fixed values preserved.** If `P` fixes a scalar, object, list, or subtree value at a path, `T` MUST preserve the same fixed value under §8.3.
|
|
879
|
+
2. **Guaranteed structure preserved.** If `P` guarantees a field or list prefix element, `T` MUST keep it present in all valid instances unless a specific list merge rule explicitly refines it without removal.
|
|
880
|
+
3. **Schema constraints compatible.** Every schema constraint contributed by `P` MUST remain satisfied by `T`. Additional constraints in `T` are allowed only when their intersection with inherited constraints is non-empty and not weaker.
|
|
881
|
+
4. **Type constraints narrowed only.** If `P` declares `type`, `itemType`, `keyType`, or `valueType` at a path, `T` may repeat the same type or provide a subtype. It MUST NOT omit, widen, or replace the inherited effective type constraint with an incompatible type.
|
|
882
|
+
5. **Payload kind compatible.** Scalar, list, and object payload kinds MUST remain compatible with inherited guarantees. A subtype MUST NOT turn an inherited scalar requirement into a list/object requirement, or vice versa, unless resolution can prove the inherited requirement is not applicable.
|
|
883
|
+
6. **List policies preserved.** An inherited `mergePolicy: append-only` MUST remain append-only. A descendant MUST NOT weaken append-only to positional. If no merge policy is inherited and none is authored, the effective default is positional.
|
|
884
|
+
|
|
885
|
+
Equivalently, `T <: P` when the Resolved View produced by resolving `T` over `P` is valid and does not violate any invariant or guarantee of `P`.
|
|
886
|
+
|
|
887
|
+
If checking `T <: P` requires resolving a type chain that revisits a type already on the active resolution stack, resolution MUST fail with a type-cycle error (§10.2.1).
|
|
888
|
+
|
|
889
|
+
### 8.4.2 Nominal core type identity (normative)
|
|
890
|
+
|
|
891
|
+
The canonical core primitive and collection types `Text`, `Integer`, `Double`, `Boolean`, `Dictionary`, and `List` are **nominal** Blue Language types identified by their canonical registry BlueIds.
|
|
892
|
+
|
|
893
|
+
A type resolving to one of these canonical core types is compatible with another such type only when the canonical registry BlueId is equal, unless the canonical registry explicitly declares a subtype relationship. Blue Language 1.0 declares no implicit subtype relationship between distinct core types.
|
|
894
|
+
|
|
895
|
+
Matcher-neutral treatment of `name` and `description` applies to structural field matching and subtype shape checks. It does **not** make two different canonical registry type identities interchangeable. If a core type description changes and therefore the type BlueId changes, it is a different nominal type.
|
|
896
|
+
|
|
897
|
+
Examples:
|
|
898
|
+
|
|
899
|
+
- The canonical `Integer` type is compatible with itself by registry BlueId.
|
|
900
|
+
- A node named `Integer` with a different description and different BlueId is not the canonical `Integer` type.
|
|
901
|
+
- `Integer` and `Double` are not subtypes of each other in Blue Language 1.0.
|
|
902
|
+
|
|
903
|
+
### 8.5 Instance-as-type (normative)
|
|
904
|
+
|
|
905
|
+
Nodes representing individuals can be used as types.
|
|
906
|
+
|
|
907
|
+
For example:
|
|
908
|
+
|
|
909
|
+
- `Alice` may have `type: Person`.
|
|
910
|
+
- `Alice Smith` may have `type: Alice`.
|
|
911
|
+
|
|
912
|
+
All fixed values in `Alice` become invariants in `Alice Smith`. Alice's top-level `name` and `description` do not flow to Alice Smith (§4.6).
|
|
913
|
+
|
|
914
|
+
### 8.6 Requirement overlays (normative)
|
|
915
|
+
|
|
916
|
+
An ancestor may partially constrain a subtree without binding a concrete type at that path.
|
|
917
|
+
|
|
918
|
+
Example:
|
|
919
|
+
|
|
920
|
+
```yaml
|
|
921
|
+
# Parent
|
|
922
|
+
name: A
|
|
923
|
+
prop1:
|
|
924
|
+
x: 1
|
|
925
|
+
schema:
|
|
926
|
+
minFields: 1
|
|
927
|
+
```
|
|
928
|
+
|
|
929
|
+
A descendant may later set:
|
|
930
|
+
|
|
931
|
+
```yaml
|
|
932
|
+
name: B
|
|
933
|
+
type: A
|
|
934
|
+
prop1:
|
|
935
|
+
type: Some
|
|
936
|
+
```
|
|
937
|
+
|
|
938
|
+
This is valid only if the merged result still satisfies all overlay obligations, including fixed values and schema constraints. If the overlay had a type, the descendant's type must be equal to or a subtype of that type.
|
|
939
|
+
|
|
940
|
+
If the overlay forces `x = 1` but `Some` forces `x = 2`, resolution MUST fail.
|
|
941
|
+
|
|
942
|
+
---
|
|
943
|
+
|
|
944
|
+
## 9. Schema Constraints
|
|
945
|
+
|
|
946
|
+
### 9.1 Attaching schema (normative)
|
|
947
|
+
|
|
948
|
+
A `schema` object MAY be attached to any node.
|
|
949
|
+
|
|
950
|
+
All schema constraints accumulate along the type chain. Compatible constraints are intersected according to §9.9. Irreconcilable constraints MUST fail resolution.
|
|
951
|
+
|
|
952
|
+
### 9.2 Schema vocabulary (normative)
|
|
953
|
+
|
|
954
|
+
Only the keywords listed in §9.3-§9.8 are valid inside a `schema` object. Implementations MUST reject any other key inside `schema`.
|
|
955
|
+
|
|
956
|
+
The valid schema keywords are:
|
|
957
|
+
|
|
958
|
+
```text
|
|
959
|
+
required,
|
|
960
|
+
minItems, maxItems, uniqueItems,
|
|
961
|
+
minFields, maxFields,
|
|
962
|
+
minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf,
|
|
963
|
+
minLength, maxLength,
|
|
964
|
+
enum
|
|
965
|
+
```
|
|
966
|
+
|
|
967
|
+
A schema object MUST NOT contain any key outside this list.
|
|
968
|
+
|
|
969
|
+
### 9.2.1 Schema keyword value types (normative)
|
|
970
|
+
|
|
971
|
+
| Keyword | Required value shape |
|
|
972
|
+
|---|---|
|
|
973
|
+
| `required` | boolean |
|
|
974
|
+
| `minItems`, `maxItems`, `minFields`, `maxFields`, `minLength`, `maxLength` | non-negative integer in the safe JSON numeric integer range |
|
|
975
|
+
| `uniqueItems` | boolean |
|
|
976
|
+
| `minimum`, `maximum`, `exclusiveMinimum`, `exclusiveMaximum`, `multipleOf` | numeric scalar or explicit numeric scalar node |
|
|
977
|
+
| `enum` | list of scalar values or explicit scalar nodes |
|
|
978
|
+
|
|
979
|
+
A schema keyword value with the wrong shape MUST be rejected. Implementations MUST NOT coerce schema keyword values across scalar types.
|
|
980
|
+
|
|
981
|
+
### 9.2.2 Schema applicability (normative)
|
|
982
|
+
|
|
983
|
+
Each schema keyword applies only to the effective node kind for which it is defined.
|
|
984
|
+
|
|
985
|
+
- String constraints apply only to effective Text values.
|
|
986
|
+
- Numeric constraints apply only to effective Integer or Double values.
|
|
987
|
+
- List constraints apply only to effective list payloads.
|
|
988
|
+
- Object field-count constraints apply only to effective object payloads.
|
|
989
|
+
- `enum` applies to scalar values unless an explicit scalar-node enum entry is used.
|
|
990
|
+
- `required` applies to the child field declaration at the path where it appears.
|
|
991
|
+
|
|
992
|
+
If a schema keyword is evaluated against an incompatible effective node kind, validation MUST fail with a schema violation. Implementations MUST NOT silently ignore incompatible schema keywords.
|
|
993
|
+
|
|
994
|
+
### 9.2.3 Required fields (normative)
|
|
995
|
+
|
|
996
|
+
`required: true` on a child field declaration requires that the field be semantically present in resolved descendants.
|
|
997
|
+
|
|
998
|
+
A required field is satisfied only if the resolved child node contains at least one of:
|
|
999
|
+
|
|
1000
|
+
- a scalar payload `value`;
|
|
1001
|
+
- a list payload `items`, including an empty list;
|
|
1002
|
+
- an object payload with at least one ordinary child field;
|
|
1003
|
+
- a pure reference;
|
|
1004
|
+
- a fixed payload or fixed subtree inherited from an ancestor type.
|
|
1005
|
+
|
|
1006
|
+
A metadata-only child declaration, such as a node containing only `type`, `schema`, `name`, or `description`, does not by itself satisfy `required: true`.
|
|
1007
|
+
|
|
1008
|
+
If a field is required but has no semantic payload or fixed inherited content after resolution and cleaning, validation MUST fail.
|
|
1009
|
+
|
|
1010
|
+
### 9.2.4 Field counting (normative)
|
|
1011
|
+
|
|
1012
|
+
`minFields` and `maxFields` count ordinary child fields of the effective object payload after resolution and object-field cleaning.
|
|
1013
|
+
|
|
1014
|
+
Reserved language fields such as `name`, `description`, `type`, `schema`, `contracts`, `value`, and `items` do not count as ordinary fields.
|
|
1015
|
+
|
|
1016
|
+
Fields removed by object-field cleaning do not count. Inherited ordinary child fields that are materialized in the Resolved View do count.
|
|
1017
|
+
|
|
1018
|
+
### 9.3 Presence
|
|
1019
|
+
|
|
1020
|
+
```yaml
|
|
1021
|
+
required: true
|
|
1022
|
+
```
|
|
1023
|
+
|
|
1024
|
+
When a schema with `required: true` is attached to a child field in a type or object overlay, that field MUST be semantically present in resolved descendants according to §9.2.3. If used at a document root, `required` is trivially satisfied by the existence of the root node.
|
|
1025
|
+
|
|
1026
|
+
### 9.4 Lists
|
|
1027
|
+
|
|
1028
|
+
```yaml
|
|
1029
|
+
minItems: <non-negative integer>
|
|
1030
|
+
maxItems: <non-negative integer>
|
|
1031
|
+
uniqueItems: true | false
|
|
1032
|
+
```
|
|
1033
|
+
|
|
1034
|
+
`maxItems` MUST be greater than or equal to `minItems` when both are present.
|
|
1035
|
+
|
|
1036
|
+
`uniqueItems: true` compares items by item BlueId, not by textual rendering.
|
|
1037
|
+
|
|
1038
|
+
### 9.5 Objects
|
|
1039
|
+
|
|
1040
|
+
```yaml
|
|
1041
|
+
minFields: <non-negative integer>
|
|
1042
|
+
maxFields: <non-negative integer>
|
|
1043
|
+
```
|
|
1044
|
+
|
|
1045
|
+
`maxFields` MUST be greater than or equal to `minFields` when both are present.
|
|
1046
|
+
|
|
1047
|
+
The term **fields** is used because Blue objects have direct ordinary fields and no `properties` wrapper.
|
|
1048
|
+
|
|
1049
|
+
### 9.5.1 Dictionary direct encoding validation (normative)
|
|
1050
|
+
|
|
1051
|
+
For direct Dictionary object encoding, each direct key MUST be valid under the effective `keyType`.
|
|
1052
|
+
|
|
1053
|
+
For direct object encoding, `keyType` MUST resolve to one of the scalar key types with a canonical textual representation: Text, Integer, Double, or Boolean. If `keyType` is omitted and no effective `keyType` is inherited, it defaults to Text.
|
|
1054
|
+
|
|
1055
|
+
A key's serialized object-member name MUST be exactly the canonical textual form of the parsed key value. If two key values canonicalize to the same object-member string, the document has a duplicate key conflict and MUST be rejected.
|
|
1056
|
+
|
|
1057
|
+
Every value in a Dictionary with an effective `valueType` MUST resolve as an instance of, or subtype-compatible with, the effective `valueType`.
|
|
1058
|
+
|
|
1059
|
+
Applications needing arbitrary non-scalar keys or reserved-key collisions MUST use an application-defined escaped representation rather than direct object encoding.
|
|
1060
|
+
|
|
1061
|
+
### 9.6 Numerics
|
|
1062
|
+
|
|
1063
|
+
```yaml
|
|
1064
|
+
minimum: number
|
|
1065
|
+
maximum: number
|
|
1066
|
+
exclusiveMinimum: number
|
|
1067
|
+
exclusiveMaximum: number
|
|
1068
|
+
multipleOf: number
|
|
1069
|
+
```
|
|
1070
|
+
|
|
1071
|
+
Numeric schema keyword values MAY be authored in either scalar form or explicit scalar-node form.
|
|
1072
|
+
|
|
1073
|
+
Scalar form:
|
|
1074
|
+
|
|
1075
|
+
```yaml
|
|
1076
|
+
schema:
|
|
1077
|
+
minimum: 5
|
|
1078
|
+
```
|
|
1079
|
+
|
|
1080
|
+
Explicit scalar-node form:
|
|
1081
|
+
|
|
1082
|
+
```yaml
|
|
1083
|
+
schema:
|
|
1084
|
+
minimum:
|
|
1085
|
+
type: Integer
|
|
1086
|
+
value: "9007199254740992"
|
|
1087
|
+
```
|
|
1088
|
+
|
|
1089
|
+
A quoted decimal string without explicit `type: Integer` is Text and MUST NOT be accepted as a numeric constraint.
|
|
1090
|
+
|
|
1091
|
+
Rules:
|
|
1092
|
+
|
|
1093
|
+
- `minimum: m` means the numeric value must be greater than or equal to `m`.
|
|
1094
|
+
- `maximum: m` means the numeric value must be less than or equal to `m`.
|
|
1095
|
+
- `exclusiveMinimum: m` means the numeric value must be strictly greater than `m`.
|
|
1096
|
+
- `exclusiveMaximum: m` means the numeric value must be strictly less than `m`.
|
|
1097
|
+
- `multipleOf` must be greater than zero.
|
|
1098
|
+
|
|
1099
|
+
If multiple numeric constraints appear in the type chain, the value must satisfy all of them. For integer `multipleOf` constraints, implementations MUST combine compatible constraints using least common multiple (LCM). The effective merged schema MUST contain one `multipleOf` value equal to that LCM, and the Resolved View and Canonical Identity Input MUST NOT preserve an implementation-specific list of equivalent integer `multipleOf` constraints.
|
|
1100
|
+
|
|
1101
|
+
For `Double` `multipleOf`, both the tested value and the `multipleOf` constraint are interpreted as their exact IEEE 754 binary64 rational values after parsing. A Double value `v` satisfies `multipleOf: m` iff `m > 0` and the exact rational quotient `v / m` is an integer. Implementations MUST NOT use epsilon comparisons, decimal string rounding, host-language modulo on binary floating point, or implementation-specific approximation.
|
|
1102
|
+
|
|
1103
|
+
For cross-type numeric comparisons, an `Integer` value is interpreted as an exact rational integer. A `Double` bound or value is interpreted as its exact IEEE 754 binary64 rational value. Comparison between Integer and Double uses exact rational comparison.
|
|
1104
|
+
|
|
1105
|
+
A numeric token that cannot be parsed to a finite IEEE 754 binary64 value under §2.4 is invalid before schema evaluation.
|
|
1106
|
+
|
|
1107
|
+
Implementations MAY use arbitrary-precision rational arithmetic internally to implement these predicates. They MUST NOT expose host floating-point rounding differences in conformance behavior.
|
|
1108
|
+
|
|
1109
|
+
Numeric schema keyword values follow the same numeric representation rules as scalar values (§2.4). Integer constraints outside the safe JSON numeric integer range MUST be represented as typed Integer scalar nodes that preserve exact integer identity. Quoted decimal text without explicit Integer typing is Text and MUST NOT be treated as a numeric schema constraint.
|
|
1110
|
+
|
|
1111
|
+
### 9.7 Strings
|
|
1112
|
+
|
|
1113
|
+
```yaml
|
|
1114
|
+
minLength: <non-negative integer>
|
|
1115
|
+
maxLength: <non-negative integer>
|
|
1116
|
+
```
|
|
1117
|
+
|
|
1118
|
+
Length is measured in Unicode code points. `maxLength` MUST be greater than or equal to `minLength` when both are present.
|
|
1119
|
+
|
|
1120
|
+
### 9.8 Enumerations
|
|
1121
|
+
|
|
1122
|
+
```yaml
|
|
1123
|
+
enum: [v1, v2, ...]
|
|
1124
|
+
```
|
|
1125
|
+
|
|
1126
|
+
Enumeration values are scalar Blue values. They MAY be authored as bare scalars when unambiguous, or as explicit scalar nodes with `type` and `value` when type disambiguation is required, for example for large integers represented as quoted canonical decimal text. Equality is by parsed scalar value, effective scalar type, and canonical JSON value semantics, not by textual rendering.
|
|
1127
|
+
|
|
1128
|
+
`enum` comparison is performed after preprocessing and scalar type inference. Therefore the untyped enum entry `1` is an `Integer`, while `1.0` and `1e0` are `Double`. A quoted decimal string is Text unless authored as an explicit `Integer` scalar node.
|
|
1129
|
+
|
|
1130
|
+
Example with a large integer enum value:
|
|
1131
|
+
|
|
1132
|
+
```yaml
|
|
1133
|
+
schema:
|
|
1134
|
+
enum:
|
|
1135
|
+
- 1
|
|
1136
|
+
- 1.0
|
|
1137
|
+
- type: Integer
|
|
1138
|
+
value: "9007199254740992"
|
|
1139
|
+
```
|
|
1140
|
+
|
|
1141
|
+
The first two enum entries above are distinct because their effective scalar types are different.
|
|
1142
|
+
|
|
1143
|
+
There is no separate `const` keyword. A fixed value in a type enforces a constant.
|
|
1144
|
+
|
|
1145
|
+
### 9.8.1 Enumeration normalization (normative)
|
|
1146
|
+
|
|
1147
|
+
`enum` is a set of allowed scalar identities. Authoring order is not semantic.
|
|
1148
|
+
|
|
1149
|
+
During schema validation, schema merge, and canonicalization, each enum entry MUST be normalized to its typed scalar identity: effective scalar type plus canonical scalar value. Duplicate entries with the same typed scalar identity are redundant and MUST be removed in the effective schema.
|
|
1150
|
+
|
|
1151
|
+
The canonical enum representation MUST sort entries by the RFC 8785 canonical JSON byte sequence of their typed scalar identity form. If two entries have identical canonical bytes, they are duplicates and only one is retained.
|
|
1152
|
+
|
|
1153
|
+
Therefore these schemas are semantically equivalent and MUST canonicalize identically:
|
|
1154
|
+
|
|
1155
|
+
```yaml
|
|
1156
|
+
schema:
|
|
1157
|
+
enum: [A, B]
|
|
1158
|
+
```
|
|
1159
|
+
|
|
1160
|
+
```yaml
|
|
1161
|
+
schema:
|
|
1162
|
+
enum: [B, A, A]
|
|
1163
|
+
```
|
|
1164
|
+
|
|
1165
|
+
The effective canonical enum contains `A` and `B` once each, in the canonical ordering defined above.
|
|
1166
|
+
|
|
1167
|
+
### 9.9 Schema merge rules (normative)
|
|
1168
|
+
|
|
1169
|
+
When schemas accumulate along the type chain, implementations MUST merge keyword constraints as follows:
|
|
1170
|
+
|
|
1171
|
+
| Keyword | Merge rule | Failure case |
|
|
1172
|
+
|---|---|---|
|
|
1173
|
+
| `required` | logical OR | never, for the keyword itself |
|
|
1174
|
+
| `minItems` | maximum | merged `minItems > maxItems` |
|
|
1175
|
+
| `maxItems` | minimum | merged `maxItems < minItems` |
|
|
1176
|
+
| `uniqueItems` | logical OR | never, for the keyword itself |
|
|
1177
|
+
| `minFields` | maximum | merged `minFields > maxFields` |
|
|
1178
|
+
| `maxFields` | minimum | merged `maxFields < minFields` |
|
|
1179
|
+
| `minimum` | strongest lower bound | incompatible with upper bounds |
|
|
1180
|
+
| `maximum` | strongest upper bound | incompatible with lower bounds |
|
|
1181
|
+
| `exclusiveMinimum` | strongest exclusive lower bound | incompatible with upper bounds |
|
|
1182
|
+
| `exclusiveMaximum` | strongest exclusive upper bound | incompatible with lower bounds |
|
|
1183
|
+
| `multipleOf` | all constraints must hold; integer constraints MUST be merged to their LCM; Double constraints MUST be evaluated by exact rational arithmetic over IEEE 754 binary64 values under §9.6 | no possible numeric value satisfies all constraints |
|
|
1184
|
+
| `minLength` | maximum | merged `minLength > maxLength` |
|
|
1185
|
+
| `maxLength` | minimum | merged `maxLength < minLength` |
|
|
1186
|
+
| `enum` | normalize both sides under §9.8.1, then intersect by typed scalar identity; canonical effective enum is duplicate-free and sorted under §9.8.1 | empty intersection |
|
|
1187
|
+
|
|
1188
|
+
For lower/upper-bound interactions, an exclusive bound at the same numeric value is stricter than an inclusive bound. For example, `minimum: 5` merged with `exclusiveMinimum: 5` yields `exclusiveMinimum: 5`.
|
|
1189
|
+
|
|
1190
|
+
---
|
|
1191
|
+
|
|
1192
|
+
## 10. Resolution and Resolved Views
|
|
1193
|
+
|
|
1194
|
+
### 10.1 Goal (normative)
|
|
1195
|
+
|
|
1196
|
+
Resolution produces a **Resolved View**: a fully materialized, type-merged, schema-validated semantic view of a Source Node.
|
|
1197
|
+
|
|
1198
|
+
A Resolved View is the correct input for type checks and semantic validation. It is not necessarily direct BlueId Input because it may contain inherited or materialized fields that are derivable from the type chain.
|
|
1199
|
+
|
|
1200
|
+
To compute Content BlueId, the Resolved View MUST be canonicalized into a Canonical Identity Input (§13) and then hashed (§14).
|
|
1201
|
+
|
|
1202
|
+
### 10.2 Resolution algorithm (normative)
|
|
1203
|
+
|
|
1204
|
+
Given a Source Node `S`, a conforming implementation performs:
|
|
1205
|
+
|
|
1206
|
+
1. **Preprocess** `S` (§6), producing a Preprocessed Document.
|
|
1207
|
+
2. **Resolve type chain.** If `S.type` exists, recursively resolve it. If the type is a pure reference, follow it through a provider and verify the fetched content (§12.4). The result is the ancestor Resolved View `A`.
|
|
1208
|
+
3. **Merge ancestor and source.** Merge `A` into target `T`, then merge `S` into `T`:
|
|
1209
|
+
- **Root labels:** when merging a type into an instance root, do not copy the type root's `name` or `description` onto the instance root (§4.6).
|
|
1210
|
+
- **Values:** copy if absent; if both are present, they must be equal under fixed-value equality (§8.3).
|
|
1211
|
+
- **Types:** assign and propagate under §8.
|
|
1212
|
+
- **Schema:** accumulate under §9.
|
|
1213
|
+
- **Object fields:** merge recursively; children must remain compatible.
|
|
1214
|
+
- **Lists:** merge under §11.
|
|
1215
|
+
- **Contracts:** preserve and merge as identity-bearing content under §4.4; do not execute.
|
|
1216
|
+
4. **Validate schema** after merging.
|
|
1217
|
+
5. **Produce the Resolved View.** Implementations MAY freeze it into a **Resolved Snapshot** when immutability matters.
|
|
1218
|
+
|
|
1219
|
+
Schema validation is performed after inherited and instance values are merged at a node. Therefore an inherited schema applies to inherited fixed values, type-derived fields, and instance-supplied values in the final Resolved View.
|
|
1220
|
+
|
|
1221
|
+
Type-chain resolution is depth-first: the effective ancestor type is resolved before it is merged into the descendant target. A resolver MUST track the active type-resolution stack for cycle detection.
|
|
1222
|
+
|
|
1223
|
+
### 10.2.1 Type-chain cycle detection (normative)
|
|
1224
|
+
|
|
1225
|
+
Type-chain cycles are invalid for Blue Language 1.0 resolution.
|
|
1226
|
+
|
|
1227
|
+
If resolving a node requires resolving a type that is already present on the active type-resolution stack, resolution MUST fail deterministically with a type-cycle error.
|
|
1228
|
+
|
|
1229
|
+
Example invalid cycle:
|
|
1230
|
+
|
|
1231
|
+
```yaml
|
|
1232
|
+
# A
|
|
1233
|
+
name: A
|
|
1234
|
+
type:
|
|
1235
|
+
blueId: <B>
|
|
1236
|
+
|
|
1237
|
+
# B
|
|
1238
|
+
name: B
|
|
1239
|
+
type:
|
|
1240
|
+
blueId: <A>
|
|
1241
|
+
```
|
|
1242
|
+
|
|
1243
|
+
Circular-set BlueIds (§15) identify cyclic document sets. They do not make cyclic inheritance or cyclic type chains resolvable. Blue Language 1.0 does not define fixed-point type semantics.
|
|
1244
|
+
|
|
1245
|
+
### 10.2.2 Reference resolution pseudocode (informative)
|
|
1246
|
+
|
|
1247
|
+
The following pseudocode is informative, but illustrates the required order of operations.
|
|
1248
|
+
|
|
1249
|
+
```text
|
|
1250
|
+
resolve(source, provider):
|
|
1251
|
+
S = preprocess(source)
|
|
1252
|
+
if S.type exists:
|
|
1253
|
+
T_ref = normalize_type_reference(S.type)
|
|
1254
|
+
T_node = materialize_if_reference(T_ref, provider)
|
|
1255
|
+
A = resolve(T_node, provider)
|
|
1256
|
+
else:
|
|
1257
|
+
A = empty node
|
|
1258
|
+
R = merge_as_instance(ancestor=A, instance=S, path="/")
|
|
1259
|
+
validate_schema_recursively(R)
|
|
1260
|
+
return ResolvedView(R, provenance)
|
|
1261
|
+
|
|
1262
|
+
merge_as_instance(ancestor, instance, path):
|
|
1263
|
+
T = copy_type_derived_content(ancestor, path)
|
|
1264
|
+
if path == "/" and ancestor is the effective type of instance:
|
|
1265
|
+
do not copy ancestor.name or ancestor.description to T
|
|
1266
|
+
merge reserved metadata using field-specific rules
|
|
1267
|
+
merge ordinary child fields recursively
|
|
1268
|
+
merge lists using §11
|
|
1269
|
+
merge contracts using §4.4
|
|
1270
|
+
reject fixed-value, type, schema, or payload-kind conflicts
|
|
1271
|
+
record provenance for each retained contribution
|
|
1272
|
+
return T
|
|
1273
|
+
```
|
|
1274
|
+
|
|
1275
|
+
Precise implementation structure is not normative. The observable Resolved View, provenance sufficient for canonicalization, validation behavior, and resulting Content BlueId are normative.
|
|
1276
|
+
|
|
1277
|
+
### 10.3 Resolution provenance (normative)
|
|
1278
|
+
|
|
1279
|
+
A conforming implementation MUST track enough provenance to canonicalize deterministically. For each resolved path, the implementation MUST be able to determine whether the content was:
|
|
1280
|
+
|
|
1281
|
+
- **instance-supplied** by the Source Document after preprocessing;
|
|
1282
|
+
- **type-derived** from an ancestor type;
|
|
1283
|
+
- **provider-materialized** from a `blueId` reference;
|
|
1284
|
+
- **preprocessing-derived** from mandatory or declared preprocessing;
|
|
1285
|
+
- **merge-derived** from compatible instance and type contributions.
|
|
1286
|
+
|
|
1287
|
+
The exact internal representation is implementation-defined, but the canonicalization result MUST be deterministic and conform to §13.
|
|
1288
|
+
|
|
1289
|
+
### 10.4 Identity guarantee (normative)
|
|
1290
|
+
|
|
1291
|
+
Resolution preserves semantic identity. A Source Document and its Resolved View have the same Content BlueId when the Resolved View is canonicalized.
|
|
1292
|
+
|
|
1293
|
+
Implementations MUST NOT assume that directly hashing a Resolved View produces the Content BlueId.
|
|
1294
|
+
|
|
1295
|
+
### 10.5 Provider failures (normative)
|
|
1296
|
+
|
|
1297
|
+
A conforming implementation MUST materialize referenced content when that content is required for resolution, canonicalization, expansion, collapse, or validation. If required content is unavailable, the operation MUST fail deterministically. Implementations MUST NOT silently substitute empty content for missing references.
|
|
1298
|
+
|
|
1299
|
+
### 10.6 Limits (normative)
|
|
1300
|
+
|
|
1301
|
+
Implementations SHOULD support path and depth limits to bound materialization of large graphs. Limits affect materialization, not semantic meaning. If a limit prevents content required for resolution, resolution MUST fail or return an explicitly incomplete view, depending on the declared API. An incomplete view MUST NOT be used for Content BlueId.
|
|
1302
|
+
|
|
1303
|
+
---
|
|
1304
|
+
|
|
1305
|
+
## 11. Lists, Merge Policies, and List Control Forms
|
|
1306
|
+
|
|
1307
|
+
### 11.1 Authoring model (normative)
|
|
1308
|
+
|
|
1309
|
+
A list field SHOULD be authored in typed form when list semantics matter:
|
|
1310
|
+
|
|
1311
|
+
```yaml
|
|
1312
|
+
<field>:
|
|
1313
|
+
type: List
|
|
1314
|
+
itemType: <Type>
|
|
1315
|
+
mergePolicy: append-only | positional
|
|
1316
|
+
items:
|
|
1317
|
+
- ...elements...
|
|
1318
|
+
```
|
|
1319
|
+
|
|
1320
|
+
A surface list is permitted for simple cases:
|
|
1321
|
+
|
|
1322
|
+
```yaml
|
|
1323
|
+
tags: [a, b, c]
|
|
1324
|
+
```
|
|
1325
|
+
|
|
1326
|
+
Typed form is REQUIRED when `mergePolicy`, anchors, or overlays are used.
|
|
1327
|
+
|
|
1328
|
+
Every element of a resolved list with an effective `itemType` MUST resolve as an instance of, or subtype-compatible with, the effective `itemType`. If an item cannot be resolved or is incompatible with `itemType`, validation MUST fail.
|
|
1329
|
+
|
|
1330
|
+
If `itemType` is omitted and no effective inherited `itemType` exists, list elements are unconstrained by item type.
|
|
1331
|
+
|
|
1332
|
+
### 11.2 Allowed item forms inside `items` (normative)
|
|
1333
|
+
|
|
1334
|
+
Each item inside `items` MUST be exactly one of the following forms after Source Document preprocessing.
|
|
1335
|
+
|
|
1336
|
+
#### Normal element
|
|
1337
|
+
|
|
1338
|
+
```yaml
|
|
1339
|
+
- <scalar | object | list | pure reference>
|
|
1340
|
+
```
|
|
1341
|
+
|
|
1342
|
+
A normal element is content.
|
|
1343
|
+
|
|
1344
|
+
#### Append anchor
|
|
1345
|
+
|
|
1346
|
+
```yaml
|
|
1347
|
+
- $previous:
|
|
1348
|
+
blueId: <PrevListBlueId>
|
|
1349
|
+
```
|
|
1350
|
+
|
|
1351
|
+
Rules:
|
|
1352
|
+
|
|
1353
|
+
- `$previous` is allowed only as the first item.
|
|
1354
|
+
- The shape MUST be exactly one top-level `$previous` key whose value is an object with exactly one `blueId` key.
|
|
1355
|
+
- `$previous` is never content.
|
|
1356
|
+
|
|
1357
|
+
#### Positional overlay
|
|
1358
|
+
|
|
1359
|
+
Map overlay:
|
|
1360
|
+
|
|
1361
|
+
```yaml
|
|
1362
|
+
- $pos: 1
|
|
1363
|
+
...overlay fields...
|
|
1364
|
+
```
|
|
1365
|
+
|
|
1366
|
+
Replacement overlay for an object:
|
|
1367
|
+
|
|
1368
|
+
```yaml
|
|
1369
|
+
- $pos: 1
|
|
1370
|
+
$replace:
|
|
1371
|
+
type: Address
|
|
1372
|
+
city: Warsaw
|
|
1373
|
+
```
|
|
1374
|
+
|
|
1375
|
+
Replacement overlay for a list:
|
|
1376
|
+
|
|
1377
|
+
```yaml
|
|
1378
|
+
- $pos: 1
|
|
1379
|
+
$replace:
|
|
1380
|
+
items:
|
|
1381
|
+
- A
|
|
1382
|
+
- B
|
|
1383
|
+
```
|
|
1384
|
+
|
|
1385
|
+
Replacement overlay for a pure reference:
|
|
1386
|
+
|
|
1387
|
+
```yaml
|
|
1388
|
+
- $pos: 1
|
|
1389
|
+
$replace:
|
|
1390
|
+
blueId: X
|
|
1391
|
+
```
|
|
1392
|
+
|
|
1393
|
+
Rules:
|
|
1394
|
+
|
|
1395
|
+
- `$pos` MUST be a non-negative integer using zero-based indexing.
|
|
1396
|
+
- `$pos` is valid only when `mergePolicy: positional`.
|
|
1397
|
+
- A `$pos` item without `$replace` is a map overlay. It is valid only when the inherited element at that index is an object-compatible node. If the inherited element is scalar, list, or pure reference, the overlay MUST use `$replace` and remain type-compatible.
|
|
1398
|
+
- `$pos` overlays are consumed by resolution and do not appear as content in the final list.
|
|
1399
|
+
- `$replace` is valid only inside a `$pos` item. Its value is a full Blue node used to replace the inherited element, subject to type and schema compatibility.
|
|
1400
|
+
- For scalar replacement, the concise form below is equivalent to `$replace: { value: B }`:
|
|
1401
|
+
|
|
1402
|
+
```yaml
|
|
1403
|
+
- $pos: 1
|
|
1404
|
+
value: B
|
|
1405
|
+
```
|
|
1406
|
+
|
|
1407
|
+
The `value` form MUST NOT be used to carry list or object replacements. Use `$replace` for non-scalar replacements.
|
|
1408
|
+
|
|
1409
|
+
#### Placeholder element
|
|
1410
|
+
|
|
1411
|
+
```yaml
|
|
1412
|
+
- $empty: true
|
|
1413
|
+
```
|
|
1414
|
+
|
|
1415
|
+
`$empty: true` is content. It is a real element that occupies a position and affects BlueId. It is distinct from `null`, `{}`, and `[]`.
|
|
1416
|
+
|
|
1417
|
+
The shape MUST be exactly one top-level `$empty` key whose value is the boolean `true`. `$empty: false`, `$empty: null`, and `$empty` with sibling fields are invalid as list placeholder elements.
|
|
1418
|
+
|
|
1419
|
+
### 11.3 Scope of list control keys (normative)
|
|
1420
|
+
|
|
1421
|
+
The special keys `$previous`, `$pos`, `$replace`, and `$empty` are recognized only as top-level keys of elements inside a list payload.
|
|
1422
|
+
|
|
1423
|
+
`$empty` is valid in any list payload.
|
|
1424
|
+
|
|
1425
|
+
`$previous`, `$pos`, and `$replace` are list overlay controls. They are valid only when the list is being resolved as a typed or overlay-capable list. Authors SHOULD use the typed list form when using these controls.
|
|
1426
|
+
|
|
1427
|
+
Outside list-control position, `$previous`, `$pos`, `$replace`, and `$empty` are ordinary field names unless another specification gives them meaning. They do not act as list controls outside list elements.
|
|
1428
|
+
|
|
1429
|
+
### 11.4 Default merge policy (normative)
|
|
1430
|
+
|
|
1431
|
+
If no effective `mergePolicy` is inherited and no `mergePolicy` is authored on the list, resolvers MUST assume:
|
|
1432
|
+
|
|
1433
|
+
```yaml
|
|
1434
|
+
mergePolicy: positional
|
|
1435
|
+
```
|
|
1436
|
+
|
|
1437
|
+
If an inherited list has an effective `mergePolicy`, a descendant list overlay that omits `mergePolicy` inherits that effective policy. A descendant MAY repeat the same `mergePolicy`.
|
|
1438
|
+
|
|
1439
|
+
A descendant MUST NOT change an inherited `mergePolicy`. If an effective `mergePolicy` is inherited, omission by the descendant means inheritance, not defaulting. If no policy is inherited and no policy is authored, the effective default is `positional`.
|
|
1440
|
+
|
|
1441
|
+
In particular, `append-only` MUST NOT be weakened to `positional`.
|
|
1442
|
+
|
|
1443
|
+
For histories, ledgers, timelines, and append-only logs, authors MUST specify:
|
|
1444
|
+
|
|
1445
|
+
```yaml
|
|
1446
|
+
mergePolicy: append-only
|
|
1447
|
+
```
|
|
1448
|
+
|
|
1449
|
+
### 11.5 Semantics of `null`, `{}`, `[]`, and `$empty` (normative)
|
|
1450
|
+
|
|
1451
|
+
Blue distinguishes object-field absence from list position.
|
|
1452
|
+
|
|
1453
|
+
#### Object fields
|
|
1454
|
+
|
|
1455
|
+
In object fields, `null` means no information. Before hashing:
|
|
1456
|
+
|
|
1457
|
+
- fields whose value is `null` MUST be omitted;
|
|
1458
|
+
- fields whose value normalizes to an empty object `{}` MUST be omitted;
|
|
1459
|
+
- empty lists `[]` MUST be preserved.
|
|
1460
|
+
|
|
1461
|
+
This removal is recursive and may cascade.
|
|
1462
|
+
|
|
1463
|
+
#### List elements
|
|
1464
|
+
|
|
1465
|
+
List elements are positional. Implementations MUST NOT delete list elements during cleaning, because doing so changes list length and shifts later indices.
|
|
1466
|
+
|
|
1467
|
+
In Source Documents, a list element that is `null`, an empty object `{}`, or an object that recursively normalizes to an empty object after object-field cleaning MUST be normalized to:
|
|
1468
|
+
|
|
1469
|
+
```yaml
|
|
1470
|
+
$empty: true
|
|
1471
|
+
```
|
|
1472
|
+
|
|
1473
|
+
It MUST NOT be deleted from the list, because list position is content.
|
|
1474
|
+
|
|
1475
|
+
In Canonical Identity Input and BlueId Input, `null` list elements and empty-object list elements MUST NOT appear. They MUST already have been normalized to `$empty: true` or rejected.
|
|
1476
|
+
|
|
1477
|
+
The marker `$empty: true` is content. It occupies a list position and affects BlueId.
|
|
1478
|
+
|
|
1479
|
+
Empty lists `[]` are preserved as list elements and are distinct from `$empty: true`.
|
|
1480
|
+
|
|
1481
|
+
Consequences:
|
|
1482
|
+
|
|
1483
|
+
```text
|
|
1484
|
+
id([A, null, B] after preprocessing) == id([A, {$empty: true}, B])
|
|
1485
|
+
id([A, null, B] after preprocessing) != id([A, B])
|
|
1486
|
+
id([A, {}, B] after preprocessing) == id([A, {$empty: true}, B])
|
|
1487
|
+
id([A, [], B]) != id([A, {$empty: true}, B])
|
|
1488
|
+
```
|
|
1489
|
+
|
|
1490
|
+
### 11.6 Merge semantics (normative)
|
|
1491
|
+
|
|
1492
|
+
Let `P` be the resolved parent list and `C` be the child overlay list.
|
|
1493
|
+
|
|
1494
|
+
#### `append-only`
|
|
1495
|
+
|
|
1496
|
+
For `mergePolicy: append-only`:
|
|
1497
|
+
|
|
1498
|
+
- inherited indices `< length(P)` MUST NOT be modified or deleted;
|
|
1499
|
+
- `$pos` overlays are forbidden;
|
|
1500
|
+
- normal items after the inherited prefix are appended;
|
|
1501
|
+
- an optional `$previous` anchor may appear as the first child item.
|
|
1502
|
+
|
|
1503
|
+
Errors:
|
|
1504
|
+
|
|
1505
|
+
- any `$pos` overlay;
|
|
1506
|
+
- malformed `$previous`;
|
|
1507
|
+
- `$previous` not first;
|
|
1508
|
+
- repeated `$previous`;
|
|
1509
|
+
- attempted modification, removal, or reordering of the inherited prefix.
|
|
1510
|
+
|
|
1511
|
+
#### `positional`
|
|
1512
|
+
|
|
1513
|
+
For `mergePolicy: positional`:
|
|
1514
|
+
|
|
1515
|
+
- `$pos: i` refines inherited index `i`, where `0 <= i < length(P)`;
|
|
1516
|
+
- map overlays merge field-wise, subject to type and schema compatibility;
|
|
1517
|
+
- `$replace` overlays replace the inherited element, subject to compatibility;
|
|
1518
|
+
- scalar `value` overlays replace the inherited element with a scalar node, subject to compatibility;
|
|
1519
|
+
- normal items without `$pos` are appended after the inherited prefix in author order;
|
|
1520
|
+
- reordering, removal, and gaps within the inherited prefix are forbidden.
|
|
1521
|
+
|
|
1522
|
+
Errors:
|
|
1523
|
+
|
|
1524
|
+
- `$pos` missing or non-integer;
|
|
1525
|
+
- `$pos` out of range;
|
|
1526
|
+
- duplicate overlays for the same index;
|
|
1527
|
+
- type or schema incompatibility at the index;
|
|
1528
|
+
- attempted reordering or removal of parent elements;
|
|
1529
|
+
- `value` used as a non-scalar positional replacement.
|
|
1530
|
+
|
|
1531
|
+
### 11.7 `$previous` validation (normative)
|
|
1532
|
+
|
|
1533
|
+
`$previous` is a resolution-time anchor.
|
|
1534
|
+
|
|
1535
|
+
During resolution, the resolver MUST verify that the inherited prefix hashes to `$previous.blueId`. If it does not match, resolution MUST fail.
|
|
1536
|
+
|
|
1537
|
+
During direct Node BlueId calculation of valid BlueId Input that already contains a leading `$previous`, the anchor MAY be used as a list-fold seed (§14.8). Validity of the anchor is a precondition of the input. An implementation performing direct Node BlueId calculation without resolution context MAY reject `$previous` inputs.
|
|
1538
|
+
|
|
1539
|
+
A direct hasher MUST NOT silently ignore `$previous` and recompute when it cannot verify the prefix. A direct hasher has no provider or inheritance context and therefore cannot determine whether an anchor is stale.
|
|
1540
|
+
|
|
1541
|
+
### 11.8 List conformance checklist (normative)
|
|
1542
|
+
|
|
1543
|
+
Implementations supporting lists MUST satisfy:
|
|
1544
|
+
|
|
1545
|
+
- `id([])` is defined and distinct from absent values and cleaned object fields;
|
|
1546
|
+
- `[A]` hashes differently from `A`;
|
|
1547
|
+
- `[[A, B], C]` hashes differently from `[A, B, C]`;
|
|
1548
|
+
- Source list `[A, null, B]` normalizes to `[A, {$empty: true}, B]`, not `[A, B]`;
|
|
1549
|
+
- Source list `[A, {}, B]` normalizes to `[A, {$empty: true}, B]`, not `[A, B]`;
|
|
1550
|
+
- Source list `[A, {x: null}, B]` normalizes to `[A, {$empty: true}, B]`, not `[A, B]`;
|
|
1551
|
+
- `$previous` is recognized only as the first item;
|
|
1552
|
+
- `$previous` mismatch fails resolution;
|
|
1553
|
+
- `append-only` rejects `$pos`;
|
|
1554
|
+
- inherited `append-only` remains effective when a child overlay omits `mergePolicy`;
|
|
1555
|
+
- `positional` accepts valid `$pos` overlays and rejects duplicate or out-of-range overlays;
|
|
1556
|
+
- `$empty: true` remains content and affects BlueId;
|
|
1557
|
+
- malformed `$empty` placeholder items are rejected;
|
|
1558
|
+
- object-field cleaning removes `null` and object fields that normalize to `{}`, but does not delete list positions.
|
|
1559
|
+
|
|
1560
|
+
### 11.9 Worked examples (informative)
|
|
1561
|
+
|
|
1562
|
+
Present-empty vs absent:
|
|
1563
|
+
|
|
1564
|
+
```yaml
|
|
1565
|
+
# Absent
|
|
1566
|
+
doc: {}
|
|
1567
|
+
|
|
1568
|
+
# Present-empty
|
|
1569
|
+
doc:
|
|
1570
|
+
list:
|
|
1571
|
+
type: List
|
|
1572
|
+
items: []
|
|
1573
|
+
```
|
|
1574
|
+
|
|
1575
|
+
Append-only timeline:
|
|
1576
|
+
|
|
1577
|
+
```yaml
|
|
1578
|
+
# Parent
|
|
1579
|
+
entries:
|
|
1580
|
+
type: List
|
|
1581
|
+
itemType: Timeline Entry
|
|
1582
|
+
mergePolicy: append-only
|
|
1583
|
+
items:
|
|
1584
|
+
- { type: Timeline Entry, ts: "2025-09-01T12:00:00Z", message: A }
|
|
1585
|
+
- { type: Timeline Entry, ts: "2025-09-01T12:05:00Z", message: B }
|
|
1586
|
+
|
|
1587
|
+
# Child
|
|
1588
|
+
entries:
|
|
1589
|
+
type: List
|
|
1590
|
+
itemType: Timeline Entry
|
|
1591
|
+
mergePolicy: append-only
|
|
1592
|
+
items:
|
|
1593
|
+
- $previous: { blueId: PrevId }
|
|
1594
|
+
- { type: Timeline Entry, ts: "2025-09-01T12:10:00Z", message: C }
|
|
1595
|
+
```
|
|
1596
|
+
|
|
1597
|
+
Positional hole and refinement:
|
|
1598
|
+
|
|
1599
|
+
```yaml
|
|
1600
|
+
# Parent
|
|
1601
|
+
entries:
|
|
1602
|
+
type: List
|
|
1603
|
+
mergePolicy: positional
|
|
1604
|
+
items:
|
|
1605
|
+
- A
|
|
1606
|
+
- $empty: true
|
|
1607
|
+
- C
|
|
1608
|
+
|
|
1609
|
+
# Child
|
|
1610
|
+
entries:
|
|
1611
|
+
type: List
|
|
1612
|
+
mergePolicy: positional
|
|
1613
|
+
items:
|
|
1614
|
+
- $pos: 1
|
|
1615
|
+
value: B
|
|
1616
|
+
# Resolved: [A, B, C]
|
|
1617
|
+
```
|
|
1618
|
+
|
|
1619
|
+
---
|
|
1620
|
+
|
|
1621
|
+
## 12. References, Providers, Expansion, and Collapse
|
|
1622
|
+
|
|
1623
|
+
### 12.1 Providers (informative)
|
|
1624
|
+
|
|
1625
|
+
A **provider** is any mechanism that resolves a BlueId to node content. Examples include an in-memory map, a local registry, a database, or a content-addressed network store.
|
|
1626
|
+
|
|
1627
|
+
This specification defines only the semantic role of providers. It does not define transport, trust, availability, or persistence protocols.
|
|
1628
|
+
|
|
1629
|
+
### 12.2 Provider trust model (normative/informative)
|
|
1630
|
+
|
|
1631
|
+
A provider MAY be untrusted. A conforming implementation MUST verify provider-returned content against the requested BlueId before using it for expansion, resolution, or canonicalization.
|
|
1632
|
+
|
|
1633
|
+
BlueId verification provides content integrity: the returned content matches the requested content address. It does not provide authenticity, authorization, availability, freshness, confidentiality, or provenance of the provider itself.
|
|
1634
|
+
|
|
1635
|
+
If a provider returns missing content, malformed content, content that does not verify under the declared provider mode, or content that requires unsupported resolution, the operation MUST fail deterministically.
|
|
1636
|
+
|
|
1637
|
+
### 12.3 Provider content form (normative)
|
|
1638
|
+
|
|
1639
|
+
A provider used to dereference a plain `blueId: X` in expansion, resolution, or canonicalization MUST return content whose direct Node BlueId is `X`, unless the provider is explicitly declared as a Source Document provider.
|
|
1640
|
+
|
|
1641
|
+
The portable provider model for Blue Language 1.0 is a verified BlueId provider: provider content is already valid BlueId Input or canonical content. Implementations MUST verify the returned content by direct Node BlueId before using it.
|
|
1642
|
+
|
|
1643
|
+
A Source Document provider MAY be supported as an implementation extension or registry mode. Such a provider verifies returned content by Content BlueId, not direct Node BlueId. This requires declaring the Blue Language version, preprocessing environment, provider state, and registry bindings used for Content BlueId calculation. A Source Document provider is not the default portable provider model.
|
|
1644
|
+
|
|
1645
|
+
A conforming implementation MUST NOT silently accept Source Document provider content under the ordinary BlueId provider model.
|
|
1646
|
+
|
|
1647
|
+
### 12.4 Plain BlueId provider verification (normative)
|
|
1648
|
+
|
|
1649
|
+
When a provider returns materialized content for `blueId: X`, the implementation MUST verify that the returned content has Node BlueId `X`. If verification fails, expansion or resolution MUST fail deterministically.
|
|
1650
|
+
|
|
1651
|
+
Implementations MUST NOT silently use provider content whose computed BlueId differs from the requested BlueId.
|
|
1652
|
+
|
|
1653
|
+
### 12.5 Cyclic-set member provider verification (normative)
|
|
1654
|
+
|
|
1655
|
+
A cyclic-set member BlueId of the form `<MASTER>#<index>` cannot be verified by ordinary single-node Node BlueId calculation.
|
|
1656
|
+
|
|
1657
|
+
A provider that returns content for a cyclic-set member BlueId MUST either:
|
|
1658
|
+
|
|
1659
|
+
1. return a verified cyclic-set envelope containing the full ordered set needed to recompute `MASTER` and select member `index`;
|
|
1660
|
+
2. be a trusted registry binding whose cyclic-set membership and `MASTER` were verified as part of the release artifact; or
|
|
1661
|
+
3. fail deterministically.
|
|
1662
|
+
|
|
1663
|
+
An implementation MUST NOT verify `<MASTER>#<index>` by hashing the returned member alone.
|
|
1664
|
+
|
|
1665
|
+
### 12.6 Expansion (normative)
|
|
1666
|
+
|
|
1667
|
+
**Expansion** materializes content referenced by `blueId` from a provider without changing identity.
|
|
1668
|
+
|
|
1669
|
+
Given:
|
|
1670
|
+
|
|
1671
|
+
```yaml
|
|
1672
|
+
field:
|
|
1673
|
+
blueId: X
|
|
1674
|
+
```
|
|
1675
|
+
|
|
1676
|
+
expansion fetches the content for `X`, verifies it (§12.4), and materializes it in place or side-by-side, enabling nested references to expand recursively.
|
|
1677
|
+
|
|
1678
|
+
Expansion is a view operation. It changes representation, not meaning.
|
|
1679
|
+
|
|
1680
|
+
Expansion MUST NOT change Node BlueId. A pure reference hashes to its target BlueId. Materialized content contributes the same identity when the materialized content verifies to that BlueId.
|
|
1681
|
+
|
|
1682
|
+
Implementations SHOULD support path and depth limits to avoid runaway traversal of large graphs. Limits affect only materialization, not identity.
|
|
1683
|
+
|
|
1684
|
+
### 12.7 Collapse (normative)
|
|
1685
|
+
|
|
1686
|
+
**Collapse** is the inverse of expansion. It replaces a materialized subtree with a pure reference `{ blueId: X }` when the subtree's Node BlueId is known to be `X`.
|
|
1687
|
+
|
|
1688
|
+
Collapse is optional as an exposed view operation. If an implementation exposes collapse, the operation MUST satisfy this section and MUST preserve Node BlueId. A collapsed result MUST be a pure reference and MUST NOT produce mixed `blueId` forms.
|
|
1689
|
+
|
|
1690
|
+
Minimized Overlays MAY use collapse when the minimization rules permit it (§13). Canonical Identity Input MUST follow the deterministic canonicalization rules.
|
|
1691
|
+
|
|
1692
|
+
### 12.8 Graph boundary (normative)
|
|
1693
|
+
|
|
1694
|
+
A Blue Document need not be a closed tree. A `{ blueId: ... }` reference may point outside the selected document. Implementations materialize referenced content only as needed and within configured limits.
|
|
1695
|
+
|
|
1696
|
+
### 12.9 Blue Language view paths (normative when exposed)
|
|
1697
|
+
|
|
1698
|
+
Blue Language view paths are implementation-facing selectors used for expansion limits, collapse limits, diagnostics, and provenance. They are not Blue content and do not affect BlueId.
|
|
1699
|
+
|
|
1700
|
+
A conforming implementation that exposes path-limited expansion, collapse, or diagnostics MUST support RFC 6901 JSON Pointer paths over the abstract Blue node model:
|
|
1701
|
+
|
|
1702
|
+
- the empty string `""` selects the root node;
|
|
1703
|
+
- `/field` selects an object field named `field`;
|
|
1704
|
+
- `/items/0` selects list payload item index `0` in the abstract node model;
|
|
1705
|
+
- `~0` represents `~`, and `~1` represents `/`, following RFC 6901.
|
|
1706
|
+
|
|
1707
|
+
The path `/` selects an object field whose key is the empty string. Since empty object-field names are valid JSON member names but are not recommended in portable Blue documents, implementations MUST still treat `/` according to RFC 6901 if exposed.
|
|
1708
|
+
|
|
1709
|
+
The wildcard `*`, such as `/spent/*`, is not part of the required Blue Language 1.0 path grammar. Implementations MAY support wildcards as an extension, but portable conformance fixtures MUST use RFC 6901 paths unless a future path-selector specification defines more.
|
|
1710
|
+
|
|
1711
|
+
---
|
|
1712
|
+
|
|
1713
|
+
## 13. Canonicalization and Minimization
|
|
1714
|
+
|
|
1715
|
+
### 13.1 Distinction (normative)
|
|
1716
|
+
|
|
1717
|
+
Blue defines two related but different operations on a Resolved View.
|
|
1718
|
+
|
|
1719
|
+
**Minimization** is any semantics-preserving reduction of a Resolved View into a smaller overlay. Different minimizers MAY produce different serialized forms.
|
|
1720
|
+
|
|
1721
|
+
**Canonicalization** is the deterministic identity-input derivation used to compute Content BlueId. For a given Resolved View and the same provider state required by resolution, there is exactly one Canonical Identity Input.
|
|
1722
|
+
|
|
1723
|
+
### 13.2 Canonical Identity Input (normative)
|
|
1724
|
+
|
|
1725
|
+
A **Canonical Identity Input** is the deterministic identity form derived from a Resolved View. It contains the deterministic identity-bearing content needed for BlueId calculation. It may contain final canonical payloads, including final list payloads, that are not ordinary Source overlays. A Canonical Identity Input MUST be valid BlueId Input. It is not required to be accepted as a Source Document or to re-resolve under ordinary Source overlay semantics.
|
|
1726
|
+
|
|
1727
|
+
The Content BlueId of a Source Document is the Node BlueId of its Canonical Identity Input.
|
|
1728
|
+
|
|
1729
|
+
A Canonical Identity Input MUST NOT contain `blue`, unresolved aliases, `$previous`, `$pos`, `null` list elements, or empty-object list elements.
|
|
1730
|
+
|
|
1731
|
+
The re-resolution guarantee belongs to Minimized Overlay (§13.3). A Canonical Identity Input and a Minimized Overlay MAY have different serialized forms and different direct Node BlueIds when hashed outside the full Source identity pipeline.
|
|
1732
|
+
|
|
1733
|
+
### 13.3 Minimized Overlay (normative)
|
|
1734
|
+
|
|
1735
|
+
A **Minimized Overlay** is an author-facing reduced overlay that re-resolves to the same Resolved View.
|
|
1736
|
+
|
|
1737
|
+
A conforming implementation MUST implement canonicalization. A conforming implementation MAY expose author-facing minimization. If it does, every Minimized Overlay it produces MUST re-resolve to the same Resolved View and MUST produce the same Content BlueId through the full identity pipeline.
|
|
1738
|
+
|
|
1739
|
+
Optional author-facing minimizers MAY produce different Minimized Overlays. Such overlays MAY have different direct Node BlueIds, but when processed through the full identity pipeline they MUST produce the same Content BlueId.
|
|
1740
|
+
|
|
1741
|
+
Unlike Canonical Identity Input, a Minimized Overlay MAY contain authoring conveniences such as `$previous`, `$pos`, and `$replace` when those controls are valid Source overlay controls.
|
|
1742
|
+
|
|
1743
|
+
### 13.4 Canonicalization requirements (normative)
|
|
1744
|
+
|
|
1745
|
+
Given a Resolved View `R`, canonicalization MUST:
|
|
1746
|
+
|
|
1747
|
+
- preserve all instance contributions that are not derivable from the type chain;
|
|
1748
|
+
- remove fields fully derivable from the type chain;
|
|
1749
|
+
- preserve instance-level `name` and `description` when present on the instance;
|
|
1750
|
+
- not inherit top-level `name` or `description` from the type;
|
|
1751
|
+
- preserve instance-fixed values that are not derivable from the type chain;
|
|
1752
|
+
- replace materialized type objects with canonical `type: { blueId: ... }` references when their BlueId is known;
|
|
1753
|
+
- ensure the Canonical Identity Input contains no type aliases; if an instance supplied a type alias, preprocessing MUST replace it with the canonical `type: { blueId: ... }` reference before resolution;
|
|
1754
|
+
- for provider-materialized content, preserve the original pure reference when that reference is an instance contribution and the materialized subtree contributes no additional instance-supplied content;
|
|
1755
|
+
- remove the `blue` directive if present, because it is invalid after preprocessing;
|
|
1756
|
+
- normalize list placeholders so that list `null` and empty-object elements become `$empty: true`;
|
|
1757
|
+
- consume all `$pos` overlays and produce final canonical list content;
|
|
1758
|
+
- produce valid BlueId Input.
|
|
1759
|
+
|
|
1760
|
+
Schema objects included in Canonical Identity Input MUST use normalized effective schema form. In particular, `enum` values are duplicate-free and sorted under §9.8.1, and integer `multipleOf` constraints are represented by the merged LCM value rather than by raw inherited/descendant contributions.
|
|
1761
|
+
|
|
1762
|
+
### 13.5 Canonicalization as deterministic diff (normative)
|
|
1763
|
+
|
|
1764
|
+
Canonicalization can be understood as a deterministic diff between the Resolved View and the resolved ancestor view contributed by the effective type chain.
|
|
1765
|
+
|
|
1766
|
+
For each node:
|
|
1767
|
+
|
|
1768
|
+
1. If the node has an effective type, include the canonical type reference unless the type reference itself is fully derivable at that path and not required by the canonical identity form.
|
|
1769
|
+
2. For each reserved metadata field other than `type`, include it only when it is an instance contribution that is not derivable from the ancestor view, except where this specification requires preservation.
|
|
1770
|
+
3. For each ordinary child field, omit it when the child is fully derivable from the ancestor view. Otherwise include the canonical identity input of the child.
|
|
1771
|
+
4. For scalar values, omit an inherited fixed value and include an instance value not derivable from the ancestor.
|
|
1772
|
+
5. For lists, use the canonical list rules in §13.6.
|
|
1773
|
+
6. After the identity input is constructed, apply BlueId input normalization and object-field cleaning. Empty object fields are omitted. Empty lists are preserved.
|
|
1774
|
+
|
|
1775
|
+
Implementations MUST make all tie-breakers deterministic and covered by conformance vectors.
|
|
1776
|
+
|
|
1777
|
+
### 13.5.1 Canonicalization tie-breakers (normative)
|
|
1778
|
+
|
|
1779
|
+
When multiple candidate identity inputs would represent the same Resolved View, the Canonical Identity Input MUST be selected by the following tie-breakers, in order:
|
|
1780
|
+
|
|
1781
|
+
1. **Omit derivable non-list content.** A field, metadata entry, or non-list subtree that is fully derivable from the effective type chain MUST be omitted from the Canonical Identity Input, unless another rule in this section explicitly requires it. **List payloads are special:** for list nodes, §13.6 overrides this general omission rule. Canonicalization of a list produces the final canonical list payload for identity calculation, including inherited prefix elements, positional refinements, append-only appends, and `$empty` placeholders after normalization.
|
|
1782
|
+
2. **Preserve non-derivable instance content.** Content supplied by the instance or Source Document and not derivable from the type chain MUST be preserved.
|
|
1783
|
+
3. **Use pure references for referenced ancestors/types.** A materialized type or referenced ancestor whose BlueId is known MUST be represented as `{ blueId: X }` in type positions and other reference-preserving positions.
|
|
1784
|
+
4. **Preserve source pure references materialized only for resolution.** If a Source Document provided a pure reference and the provider materialized it only to resolve or validate content, the Canonical Identity Input MUST prefer the original pure reference form unless the instance supplied an overlay that must be represented.
|
|
1785
|
+
5. **Consume overlay controls.** `$pos`, `$replace`, `$previous`, source list `null`, and empty-object list elements MUST NOT appear in Canonical Identity Input. Their effects must be represented as ordinary canonical content.
|
|
1786
|
+
6. **No authoring aliases.** Type aliases and `blue` preprocessing directives MUST NOT appear in Canonical Identity Input.
|
|
1787
|
+
7. **Deterministic map ordering.** When serializing helper maps or canonical JSON, property order is the order defined by RFC 8785 canonical JSON. No locale-sensitive ordering, implementation insertion order, or host map order is permitted.
|
|
1788
|
+
8. **Smallest semantic identity input wins.** If two candidate identity inputs both satisfy the rules above, the one with fewer non-derivable fields and fewer materialized subtrees wins. If still tied, the RFC 8785 canonical JSON byte sequence of the candidate identity input is compared lexicographically and the smaller byte sequence wins.
|
|
1789
|
+
|
|
1790
|
+
These rules are part of the Blue Language 1.0 identity definition and MUST be implemented consistently. The conformance fixture suite provides examples but does not replace these rules.
|
|
1791
|
+
|
|
1792
|
+
### 13.6 Canonical list rules (normative)
|
|
1793
|
+
|
|
1794
|
+
Canonical list rules produce final list payload content for identity calculation.
|
|
1795
|
+
|
|
1796
|
+
For list payloads, final canonical list content is the canonical identity form. This rule overrides the general "omit derivable content" tie-breaker in §13.5.1. Blue Language 1.0 does not define a canonical list-diff representation.
|
|
1797
|
+
|
|
1798
|
+
For a list with no inherited prefix, the Canonical Identity Input contains the canonicalized full list.
|
|
1799
|
+
|
|
1800
|
+
For an inherited list under `mergePolicy: append-only`, a Minimized Overlay MAY use a valid `$previous` anchor followed by appended elements. A Canonical Identity Input MUST NOT contain `$previous`. Canonicalization MUST produce the final canonical list payload before hashing. Implementations MAY internally optimize list hashing by using a verified inherited-prefix BlueId, but that optimization is not part of the serialized Canonical Identity Input.
|
|
1801
|
+
|
|
1802
|
+
For an inherited list under `mergePolicy: positional`, a Minimized Overlay MAY represent inherited-index refinements using `$pos` overlays. A Canonical Identity Input MUST NOT contain `$pos`. Canonicalization MUST apply all positional overlays and produce the final canonical list payload before hashing.
|
|
1803
|
+
|
|
1804
|
+
A final canonical list payload in Canonical Identity Input is identity input, not an instruction to append to or refine an inherited list under ordinary Source overlay semantics.
|
|
1805
|
+
|
|
1806
|
+
### 13.7 Deterministic collapse during minimization (normative)
|
|
1807
|
+
|
|
1808
|
+
A Minimized Overlay MAY collapse a subtree to `{ blueId: X }` only when:
|
|
1809
|
+
|
|
1810
|
+
1. the subtree's Node BlueId is known to be `X`;
|
|
1811
|
+
2. provider verification has established that `X` identifies that content if the subtree came from a provider;
|
|
1812
|
+
3. collapse at that path is deterministic under the implementation's declared minimization rules;
|
|
1813
|
+
4. the collapsed overlay re-resolves to the same Resolved View.
|
|
1814
|
+
|
|
1815
|
+
A Canonical Identity Input MUST follow the deterministic canonicalization rules. Unless this specification explicitly requires collapse at a path, Canonical Identity Input MUST prefer the materialized canonical identity form. Optional collapse is an author-facing minimization feature, not a source of variation in Content BlueId.
|
|
1816
|
+
|
|
1817
|
+
A Canonical Identity Input MUST NOT depend on implementation-local collapse preferences.
|
|
1818
|
+
|
|
1819
|
+
---
|
|
1820
|
+
|
|
1821
|
+
## 14. BlueId Algorithm
|
|
1822
|
+
|
|
1823
|
+
### 14.1 Hash function (normative)
|
|
1824
|
+
|
|
1825
|
+
Let:
|
|
1826
|
+
|
|
1827
|
+
```text
|
|
1828
|
+
H(x) = Base58(SHA-256(RFC 8785 canonical JSON of x))
|
|
1829
|
+
```
|
|
1830
|
+
|
|
1831
|
+
BlueId is computed bottom-up over canonical BlueId Input using `H`.
|
|
1832
|
+
|
|
1833
|
+
### 14.2 Context-sensitive cleaning and placeholder normalization (normative)
|
|
1834
|
+
|
|
1835
|
+
Before hashing, implementations MUST normalize BlueId Input context-sensitively.
|
|
1836
|
+
|
|
1837
|
+
#### Object-field cleaning
|
|
1838
|
+
|
|
1839
|
+
For object fields:
|
|
1840
|
+
|
|
1841
|
+
- remove fields whose value is `null`;
|
|
1842
|
+
- remove fields whose value normalizes to an empty object `{}`;
|
|
1843
|
+
- preserve fields whose value is an empty list `[]`;
|
|
1844
|
+
|
|
1845
|
+
This removal is recursive and may cascade.
|
|
1846
|
+
|
|
1847
|
+
#### List-element rules
|
|
1848
|
+
|
|
1849
|
+
For list elements:
|
|
1850
|
+
|
|
1851
|
+
- list elements MUST NOT be deleted merely because they are `null` or `{}`;
|
|
1852
|
+
- in Source Documents, `null`, `{}`, and elements that recursively clean to empty objects MUST have been normalized to `$empty: true` before BlueId calculation;
|
|
1853
|
+
- in BlueId Input, `null` and `{}` list elements are invalid;
|
|
1854
|
+
- `[]` is preserved as an empty list element;
|
|
1855
|
+
- `$empty: true` is preserved as placeholder content.
|
|
1856
|
+
|
|
1857
|
+
This rule preserves list length, order, and positional meaning.
|
|
1858
|
+
|
|
1859
|
+
In object-field context, an object that becomes empty after cleaning is omitted. In list-element context, a Source element that becomes empty after recursive cleaning is normalized to `$empty: true` before BlueId Input is produced. Direct BlueId Input MUST NOT contain raw empty-object list elements.
|
|
1860
|
+
|
|
1861
|
+
#### Root normalization
|
|
1862
|
+
|
|
1863
|
+
The root of BlueId Input is never omitted by cleaning.
|
|
1864
|
+
|
|
1865
|
+
If the root is an empty object `{}`, its Node BlueId is `H({})`.
|
|
1866
|
+
|
|
1867
|
+
If object-field cleaning causes the root object to become empty, the root remains `{}` and hashes as `H({})`.
|
|
1868
|
+
|
|
1869
|
+
A root `null` value is not valid BlueId Input. Source Documents whose root is `null` MUST be rejected. Authors who intend an empty object document MUST write `{}`; authors who intend an empty list document MUST write `[]`.
|
|
1870
|
+
|
|
1871
|
+
### 14.3 Canonical BlueId input normalization (normative)
|
|
1872
|
+
|
|
1873
|
+
The BlueId algorithm hashes the abstract node model, not authoring syntax.
|
|
1874
|
+
|
|
1875
|
+
Direct Node BlueId calculation does not run the full Source Document preprocessing pipeline. However, BlueId input normalization includes the mandatory primitive scalar inference needed to make bare scalar nodes identity-stable across conforming implementations. This inference is limited to the core primitive types listed below and does not apply aliases, imports, `blue` directives, or declared preprocessing transforms.
|
|
1876
|
+
|
|
1877
|
+
Before hashing a Node value:
|
|
1878
|
+
|
|
1879
|
+
- scalar sugar is normalized to scalar payload;
|
|
1880
|
+
- list sugar is normalized to list payload;
|
|
1881
|
+
- bare scalar payloads with no explicit type are assigned the corresponding core primitive type reference;
|
|
1882
|
+
- integer values outside the safe JSON numeric integer range are represented as quoted canonical decimal text while retaining explicit `Integer` type (§2.4);
|
|
1883
|
+
- finite `Double` values are converted to their canonical scalar representation;
|
|
1884
|
+
- pure references are represented exactly as `{ blueId: X }`;
|
|
1885
|
+
- `blue` is rejected;
|
|
1886
|
+
- `$pos` is rejected;
|
|
1887
|
+
- list `null` and empty-object elements are rejected unless already normalized to `$empty: true`.
|
|
1888
|
+
|
|
1889
|
+
Primitive scalar inference for BlueId input normalization uses:
|
|
1890
|
+
|
|
1891
|
+
| Parsed value kind | Inferred type |
|
|
1892
|
+
|---|---|
|
|
1893
|
+
| string | `Text` |
|
|
1894
|
+
| integer numeric token with no decimal point or exponent, or explicitly typed canonical integer text | `Integer` |
|
|
1895
|
+
| numeric token with a decimal point or exponent, or other non-integer finite number | `Double` |
|
|
1896
|
+
| boolean | `Boolean` |
|
|
1897
|
+
|
|
1898
|
+
A scalar payload with explicit type uses the explicit type, subject to resolution and validation.
|
|
1899
|
+
|
|
1900
|
+
### 14.4 Scalars (normative)
|
|
1901
|
+
|
|
1902
|
+
For BlueId calculation, every scalar payload node is normalized to a **typed scalar identity form** before hashing. If no explicit effective type is present, the inferred primitive type from §14.3 is inserted. Therefore an untyped Source scalar token `1` hashes as a scalar node with effective type `Integer`, while source tokens `1.0` and `1e0` hash as scalar nodes with effective type `Double`. The effective scalar type is part of identity.
|
|
1903
|
+
|
|
1904
|
+
A bare scalar payload is represented as the canonical scalar value and, when converted to canonical BlueId input as a node, includes its inferred primitive type unless an explicit type is already present.
|
|
1905
|
+
|
|
1906
|
+
Scalar values are encoded using RFC 8785 canonical JSON value rules after Blue scalar normalization.
|
|
1907
|
+
|
|
1908
|
+
For `Integer`, implementations MUST preserve mathematical integer identity. Integer values outside the safe JSON numeric integer range MUST be encoded as canonical decimal text while retaining `type: Integer` in the canonical BlueId input (§2.4).
|
|
1909
|
+
|
|
1910
|
+
For `Double`, only finite numbers are valid. `NaN`, `Infinity`, and `-Infinity` are invalid Blue scalar values.
|
|
1911
|
+
|
|
1912
|
+
A `Double` value whose canonical JSON number renders as an integer-looking number, such as `1`, remains distinct from `Integer` because the canonical BlueId input retains `type: Double`. Numeric rendering alone does not determine scalar type after preprocessing.
|
|
1913
|
+
|
|
1914
|
+
### 14.4.1 Payload normalization before hashing (normative)
|
|
1915
|
+
|
|
1916
|
+
The BlueId algorithm hashes the abstract Blue node model, not raw JSON/YAML syntax.
|
|
1917
|
+
|
|
1918
|
+
Before map hashing is applied, each node is classified as one of:
|
|
1919
|
+
|
|
1920
|
+
1. pure reference;
|
|
1921
|
+
2. scalar payload node;
|
|
1922
|
+
3. list payload node;
|
|
1923
|
+
4. object payload node;
|
|
1924
|
+
5. metadata-bearing node.
|
|
1925
|
+
|
|
1926
|
+
A node with a scalar payload and no retained metadata other than its effective scalar type and value hashes as the typed scalar identity form. "Payload-only scalar" does not mean hashing the raw JSON scalar alone; it means hashing the canonical Blue scalar node consisting of the effective primitive type reference and the canonical scalar value. If no explicit effective type is present, the inferred primitive type is inserted before hashing.
|
|
1927
|
+
|
|
1928
|
+
A node with a list payload and no retained metadata other than the payload itself hashes as the list payload.
|
|
1929
|
+
|
|
1930
|
+
Therefore these forms hash identically:
|
|
1931
|
+
|
|
1932
|
+
```yaml
|
|
1933
|
+
x: 1
|
|
1934
|
+
```
|
|
1935
|
+
|
|
1936
|
+
```yaml
|
|
1937
|
+
x:
|
|
1938
|
+
value: 1
|
|
1939
|
+
```
|
|
1940
|
+
|
|
1941
|
+
and these forms hash identically:
|
|
1942
|
+
|
|
1943
|
+
```yaml
|
|
1944
|
+
x: [a, b]
|
|
1945
|
+
```
|
|
1946
|
+
|
|
1947
|
+
```yaml
|
|
1948
|
+
x:
|
|
1949
|
+
items: [a, b]
|
|
1950
|
+
```
|
|
1951
|
+
|
|
1952
|
+
Thus these Source scalar tokens do not all have the same typed scalar identity unless an explicit type or schema says otherwise:
|
|
1953
|
+
|
|
1954
|
+
```yaml
|
|
1955
|
+
1 # effective type Integer, value 1
|
|
1956
|
+
1.0 # effective type Double, canonical numeric payload may render as 1
|
|
1957
|
+
1e0 # effective type Double, canonical numeric payload may render as 1
|
|
1958
|
+
```
|
|
1959
|
+
|
|
1960
|
+
`1.0` and `1e0` are equivalent Double values, but they are not equivalent to Integer `1` because the effective type differs.
|
|
1961
|
+
|
|
1962
|
+
When a node has retained metadata such as `type`, `schema`, `name`, `description`, `itemType`, `mergePolicy`, or `contracts`, it hashes as a metadata-bearing map. In that case, `value` or `items` is the payload field of that metadata-bearing node and participates in map hashing as defined below.
|
|
1963
|
+
|
|
1964
|
+
A node MUST NOT contain more than one payload kind.
|
|
1965
|
+
|
|
1966
|
+
### 14.5 Map hashing (normative)
|
|
1967
|
+
|
|
1968
|
+
Map hashing applies only after payload-only scalar and payload-only list nodes have been normalized as described above.
|
|
1969
|
+
|
|
1970
|
+
If and only if a map is exactly:
|
|
1971
|
+
|
|
1972
|
+
```json
|
|
1973
|
+
{ "blueId": "<id>" }
|
|
1974
|
+
```
|
|
1975
|
+
|
|
1976
|
+
then its BlueId is `<id>`. This is the pure reference short-circuit.
|
|
1977
|
+
|
|
1978
|
+
A map containing `blueId` together with sibling fields is not a pure reference and MUST NOT appear in BlueId Input.
|
|
1979
|
+
|
|
1980
|
+
Otherwise, build the helper map `M` conceptually. Its serialized property order is the order defined by RFC 8785 canonical JSON. Implementations MUST NOT use locale-sensitive collation or implementation insertion order.
|
|
1981
|
+
|
|
1982
|
+
- for `name`, `description`, and `value`, inline their cleaned scalar values;
|
|
1983
|
+
- for every other key `k` with value `v`, include:
|
|
1984
|
+
|
|
1985
|
+
```json
|
|
1986
|
+
"k": { "blueId": id(v) }
|
|
1987
|
+
```
|
|
1988
|
+
|
|
1989
|
+
Then compute:
|
|
1990
|
+
|
|
1991
|
+
```text
|
|
1992
|
+
id(map) = H(M)
|
|
1993
|
+
```
|
|
1994
|
+
|
|
1995
|
+
This rule ensures nested structure contributes through BlueId rather than through byte shape. It also makes materialized subtrees and pure references identity-equivalent when they have the same BlueId.
|
|
1996
|
+
|
|
1997
|
+
### 14.6 Object fields with `null` (normative)
|
|
1998
|
+
|
|
1999
|
+
Object fields with `null` values are omitted before map hashing:
|
|
2000
|
+
|
|
2001
|
+
```yaml
|
|
2002
|
+
a: null
|
|
2003
|
+
b: 1
|
|
2004
|
+
```
|
|
2005
|
+
|
|
2006
|
+
normalizes as:
|
|
2007
|
+
|
|
2008
|
+
```yaml
|
|
2009
|
+
b: 1
|
|
2010
|
+
```
|
|
2011
|
+
|
|
2012
|
+
If recursive cleaning makes a child object empty, the child field is also omitted. Empty lists are preserved.
|
|
2013
|
+
|
|
2014
|
+
### 14.7 List hashing (normative)
|
|
2015
|
+
|
|
2016
|
+
Lists are hashed using a domain-separated streaming fold over element BlueIds.
|
|
2017
|
+
|
|
2018
|
+
Empty list seed:
|
|
2019
|
+
|
|
2020
|
+
```text
|
|
2021
|
+
id([]) = H({ "$list": "empty" })
|
|
2022
|
+
```
|
|
2023
|
+
|
|
2024
|
+
Fold step:
|
|
2025
|
+
|
|
2026
|
+
```text
|
|
2027
|
+
fold(prevId, x) =
|
|
2028
|
+
H({
|
|
2029
|
+
"$listCons": {
|
|
2030
|
+
"prev": { "blueId": prevId },
|
|
2031
|
+
"elem": { "blueId": id(x) }
|
|
2032
|
+
}
|
|
2033
|
+
})
|
|
2034
|
+
```
|
|
2035
|
+
|
|
2036
|
+
The object passed to `H` in the fold step is serialized by RFC 8785; therefore property serialization order is determined by RFC 8785, not by the order shown in pseudocode.
|
|
2037
|
+
|
|
2038
|
+
Whole list:
|
|
2039
|
+
|
|
2040
|
+
```text
|
|
2041
|
+
id([a1, ..., an]) = fold(fold(...fold(id([]), a1)...), an)
|
|
2042
|
+
```
|
|
2043
|
+
|
|
2044
|
+
Properties:
|
|
2045
|
+
|
|
2046
|
+
- order is significant;
|
|
2047
|
+
- multiplicity is preserved;
|
|
2048
|
+
- lists are not flattened;
|
|
2049
|
+
- `[A]` is distinct from `A`;
|
|
2050
|
+
- `[]` is distinct from absent values and cleaned object fields;
|
|
2051
|
+
- `[A, {$empty: true}, B]` is distinct from `[A, B]`;
|
|
2052
|
+
- append hashing can be O(delta) when seeded by a valid `$previous` anchor.
|
|
2053
|
+
|
|
2054
|
+
### 14.8 List control normalization before hashing (normative)
|
|
2055
|
+
|
|
2056
|
+
For direct anchored BlueId Input:
|
|
2057
|
+
|
|
2058
|
+
- `$previous` MAY appear only as the first item.
|
|
2059
|
+
- If present and well-formed, `$previous.blueId` MAY seed the list fold.
|
|
2060
|
+
- Anchor validity is a precondition of direct anchored BlueId Input.
|
|
2061
|
+
- A Canonical Identity Input produced by the Content BlueId pipeline MUST NOT contain `$previous`.
|
|
2062
|
+
- Implementations MAY use a verified prefix BlueId as an internal hashing optimization.
|
|
2063
|
+
|
|
2064
|
+
`$pos` and `$replace` MUST NOT appear in BlueId Input. `$empty: true` remains content and hashes as a normal object element.
|
|
2065
|
+
|
|
2066
|
+
Malformed list controls MUST be rejected.
|
|
2067
|
+
|
|
2068
|
+
### 14.8.1 Canonical JSON examples (informative but behavior-defining through referenced rules)
|
|
2069
|
+
|
|
2070
|
+
#### Large Integer scalar node
|
|
2071
|
+
|
|
2072
|
+
An Integer outside the safe JSON numeric integer range is represented as quoted canonical decimal text with explicit Integer type.
|
|
2073
|
+
|
|
2074
|
+
Canonical BlueId Input shape:
|
|
2075
|
+
|
|
2076
|
+
```yaml
|
|
2077
|
+
type:
|
|
2078
|
+
blueId: <IntegerTypeBlueId>
|
|
2079
|
+
value: "9007199254740992"
|
|
2080
|
+
```
|
|
2081
|
+
|
|
2082
|
+
Map hashing builds helper map `M` conceptually:
|
|
2083
|
+
|
|
2084
|
+
```json
|
|
2085
|
+
{
|
|
2086
|
+
"type": { "blueId": "<IntegerTypeBlueId>" },
|
|
2087
|
+
"value": "9007199254740992"
|
|
2088
|
+
}
|
|
2089
|
+
```
|
|
2090
|
+
|
|
2091
|
+
The RFC 8785 canonical JSON byte sequence is the UTF-8 encoding of:
|
|
2092
|
+
|
|
2093
|
+
```json
|
|
2094
|
+
{"type":{"blueId":"<IntegerTypeBlueId>"},"value":"9007199254740992"}
|
|
2095
|
+
```
|
|
2096
|
+
|
|
2097
|
+
#### Double negative zero
|
|
2098
|
+
|
|
2099
|
+
`Double` values use finite IEEE 754 binary64 semantics. Negative zero and positive zero compare as the same numeric value. Under RFC 8785 canonical JSON, the numeric value canonicalizes as JSON number `0`.
|
|
2100
|
+
|
|
2101
|
+
A Source token such as `-0.0` infers `Double` if no explicit type is provided, but the canonical scalar numeric payload is `0` and the effective `type: Double` preserves the fact that the node is a Double rather than an Integer.
|
|
2102
|
+
|
|
2103
|
+
#### Integer-looking Double
|
|
2104
|
+
|
|
2105
|
+
A Source token such as `1.0` or `1e0` infers `Double`. The canonical JSON representation of the numeric payload may render as `1`, but the effective `type: Double` remains part of canonical BlueId input. Therefore `1` as Integer and `1.0` as Double are distinct Blue values unless an explicit type or schema says otherwise.
|
|
2106
|
+
|
|
2107
|
+
#### List fold helper map ordering
|
|
2108
|
+
|
|
2109
|
+
The list fold step uses the exact object keys `$listCons`, `prev`, and `elem`:
|
|
2110
|
+
|
|
2111
|
+
```json
|
|
2112
|
+
{"$listCons":{"elem":{"blueId":"<ElemId>"},"prev":{"blueId":"<PrevId>"}}}
|
|
2113
|
+
```
|
|
2114
|
+
|
|
2115
|
+
The example shows the RFC 8785 canonical JSON serialization for these keys. Implementations MUST NOT rely on insertion order or host map order.
|
|
2116
|
+
|
|
2117
|
+
### 14.9 Storage rule (normative)
|
|
2118
|
+
|
|
2119
|
+
A node MUST NOT store its own BlueId as authoritative content.
|
|
2120
|
+
|
|
2121
|
+
Using `{ blueId: ... }` to reference other nodes is permitted and encouraged. A provider or envelope MAY store a node's BlueId out-of-band, but the self-BlueId MUST NOT be treated as part of the node's own content.
|
|
2122
|
+
|
|
2123
|
+
### 14.10 Inputs containing `blue` (normative)
|
|
2124
|
+
|
|
2125
|
+
BlueId Input MUST NOT contain `blue`. A direct hasher MUST reject such input.
|
|
2126
|
+
|
|
2127
|
+
---
|
|
2128
|
+
|
|
2129
|
+
## 15. Circular Reference Sets
|
|
2130
|
+
|
|
2131
|
+
### 15.1 Purpose
|
|
2132
|
+
|
|
2133
|
+
Some authoring graphs contain direct cycles across documents, for example `Person` references `Dog` and `Dog` references `Person`. Blue supports a combined BlueId for a cyclic set, with stable per-document suffixes.
|
|
2134
|
+
|
|
2135
|
+
### 15.2 ZERO_BLUEID sentinel (normative)
|
|
2136
|
+
|
|
2137
|
+
During cyclic-set calculation, each direct cyclic reference is temporarily replaced with the **ZERO_BLUEID** sentinel: forty-four ASCII `0` characters.
|
|
2138
|
+
|
|
2139
|
+
ZERO_BLUEID is a sentinel only. It MUST NOT appear in finalized BlueId Input.
|
|
2140
|
+
|
|
2141
|
+
During cyclic-set calculation, ZERO_BLUEID and `this#<index>` are permitted only in positions where a BlueId string is expected inside the temporary cyclic-set calculation input.
|
|
2142
|
+
|
|
2143
|
+
They are not valid ordinary BlueId Input and MUST NOT appear in finalized provider-stored content.
|
|
2144
|
+
|
|
2145
|
+
### 15.3 Cyclic-set input (normative)
|
|
2146
|
+
|
|
2147
|
+
The input to the cyclic-set algorithm is a finite set of document roots plus explicit internal reference markers indicating which references point to documents within the set.
|
|
2148
|
+
|
|
2149
|
+
The algorithm applies to a strongly connected cyclic set. Independent strongly connected components SHOULD be processed separately.
|
|
2150
|
+
|
|
2151
|
+
A cyclic-set calculation input MUST contain at least one internal cyclic reference. A set with no internal cyclic references SHOULD be treated as ordinary independent documents rather than as a cyclic set.
|
|
2152
|
+
|
|
2153
|
+
If two cyclic-set members have identical preliminary BlueIds, implementations MUST compare the RFC 8785 canonical JSON byte sequence of their preliminary BlueId input as a deterministic tie-breaker.
|
|
2154
|
+
|
|
2155
|
+
If the tie remains equal, the cyclic-set input is invalid in Blue Language 1.0 unless the members contain an explicit identity-bearing disambiguator before preliminary hashing. Implementations MUST fail cyclic-set calculation with `CircularSetError` rather than assigning arbitrary positions.
|
|
2156
|
+
|
|
2157
|
+
Blue Language 1.0 does not define graph-isomorphism rules for duplicate preliminary cyclic members.
|
|
2158
|
+
|
|
2159
|
+
### 15.4 Cyclic-set algorithm (normative)
|
|
2160
|
+
|
|
2161
|
+
Given a finite set of documents participating in a direct cycle:
|
|
2162
|
+
|
|
2163
|
+
1. Temporarily replace each internal cyclic `blueId` reference with ZERO_BLUEID.
|
|
2164
|
+
2. Calculate preliminary BlueIds for each document in isolation.
|
|
2165
|
+
3. Sort documents lexicographically by preliminary BlueId, with the tie-breaking rule from §15.3.
|
|
2166
|
+
4. Assign positions `#0` through `#(n-1)` according to that order.
|
|
2167
|
+
5. Rewrite each internal cyclic reference as:
|
|
2168
|
+
|
|
2169
|
+
```yaml
|
|
2170
|
+
blueId: this#<index>
|
|
2171
|
+
```
|
|
2172
|
+
|
|
2173
|
+
where `<index>` is the assigned position of the target document.
|
|
2174
|
+
|
|
2175
|
+
6. Build a list:
|
|
2176
|
+
|
|
2177
|
+
```text
|
|
2178
|
+
L = [doc#0, doc#1, ..., doc#(n-1)]
|
|
2179
|
+
```
|
|
2180
|
+
|
|
2181
|
+
with `this#<index>` references in place.
|
|
2182
|
+
|
|
2183
|
+
7. Compute:
|
|
2184
|
+
|
|
2185
|
+
```text
|
|
2186
|
+
MASTER = id(L)
|
|
2187
|
+
```
|
|
2188
|
+
|
|
2189
|
+
8. The final BlueId of document `i` is:
|
|
2190
|
+
|
|
2191
|
+
```text
|
|
2192
|
+
MASTER#i
|
|
2193
|
+
```
|
|
2194
|
+
|
|
2195
|
+
The **preliminary BlueId input** for each document is the document after replacing each direct internal cyclic `blueId` reference with ZERO_BLUEID and before rewriting those references to `this#<index>`.
|
|
2196
|
+
|
|
2197
|
+
`this#<index>` is accepted only by the cyclic-set calculation API. It MUST NOT appear in stored provider content, ordinary BlueId Input, Source Documents outside explicit cyclic-set serialization, or Canonical Identity Input.
|
|
2198
|
+
|
|
2199
|
+
During preliminary BlueId calculation with ZERO_BLUEID placeholders, a pure reference `{ blueId: ZERO_BLUEID }` is treated as a temporary pure reference whose identity contribution is the sentinel value for the purpose of preliminary ordering only. ZERO_BLUEID MUST NOT be returned as a finalized BlueId.
|
|
2200
|
+
|
|
2201
|
+
During MASTER calculation, pure references `{ blueId: "this#<index>" }` are treated as internal cyclic placeholders as defined by the cyclic-set algorithm, not as ordinary provider references.
|
|
2202
|
+
|
|
2203
|
+
Cyclic-set identity flow:
|
|
2204
|
+
|
|
2205
|
+
```text
|
|
2206
|
+
authoring refs
|
|
2207
|
+
|
|
|
2208
|
+
v
|
|
2209
|
+
replace internal refs with ZERO_BLUEID
|
|
2210
|
+
|
|
|
2211
|
+
v
|
|
2212
|
+
preliminary ids -> sort -> assign #0..#(n-1)
|
|
2213
|
+
|
|
|
2214
|
+
v
|
|
2215
|
+
rewrite internal refs to this#k
|
|
2216
|
+
|
|
|
2217
|
+
v
|
|
2218
|
+
MASTER = id([doc#0, doc#1, ...])
|
|
2219
|
+
|
|
|
2220
|
+
v
|
|
2221
|
+
final ids = MASTER#0, MASTER#1, ...
|
|
2222
|
+
```
|
|
2223
|
+
|
|
2224
|
+
### 15.5 BlueId grammar for cyclic sets (normative)
|
|
2225
|
+
|
|
2226
|
+
A cyclic-set member BlueId has the form:
|
|
2227
|
+
|
|
2228
|
+
```text
|
|
2229
|
+
<MASTER>#<index>
|
|
2230
|
+
```
|
|
2231
|
+
|
|
2232
|
+
where `MASTER` is a plain BlueId and `index` is a non-negative decimal integer with no leading zeros, except for the single digit `0`.
|
|
2233
|
+
|
|
2234
|
+
`this#<index>` is an algorithm-internal placeholder. It is accepted only by an implementation API explicitly performing cyclic-set calculation over a declared finite cyclic set. It MUST be rejected by ordinary parsing, preprocessing, resolution, provider storage, expansion, canonicalization, and direct BlueId calculation outside that cyclic-set calculation API.
|
|
2235
|
+
|
|
2236
|
+
### 15.6 Example (informative)
|
|
2237
|
+
|
|
2238
|
+
```yaml
|
|
2239
|
+
# Dog (#0 after sorting)
|
|
2240
|
+
name: Dog
|
|
2241
|
+
owner:
|
|
2242
|
+
type:
|
|
2243
|
+
blueId: this#1
|
|
2244
|
+
breed:
|
|
2245
|
+
type: Text
|
|
2246
|
+
|
|
2247
|
+
# Person (#1 after sorting)
|
|
2248
|
+
name: Person
|
|
2249
|
+
pet:
|
|
2250
|
+
type:
|
|
2251
|
+
blueId: this#0
|
|
2252
|
+
```
|
|
2253
|
+
|
|
2254
|
+
If `MASTER = 12345...`, then:
|
|
2255
|
+
|
|
2256
|
+
```text
|
|
2257
|
+
Dog = 12345...#0
|
|
2258
|
+
Person = 12345...#1
|
|
2259
|
+
```
|
|
2260
|
+
|
|
2261
|
+
---
|
|
2262
|
+
|
|
2263
|
+
## 16. Conformance Vectors
|
|
2264
|
+
|
|
2265
|
+
The Blue Language 1.0 conformance suite, canonical core registry, and this prose specification jointly define Blue Language 1.0. The prose rules are normative, the registry supplies exact identity-bearing core type nodes and BlueIds, and the fixtures provide behavior-defining executable examples.
|
|
2266
|
+
|
|
2267
|
+
A fixture package identity MUST be published with the Blue Language 1.0 release. A conforming implementation MUST report which fixture package identity it passes.
|
|
2268
|
+
|
|
2269
|
+
If the prose specification, registry, and fixture package conflict, the release artifact is invalid and MUST be corrected. Implementations MUST NOT guess which artifact wins.
|
|
2270
|
+
|
|
2271
|
+
Conformance vectors are behavior-defining. A conforming Blue Language 1.0 implementation MUST pass all vectors in this section and all machine-readable fixtures in the Blue Language 1.0 conformance suite.
|
|
2272
|
+
|
|
2273
|
+
The labels `B`, `R`, and `F` identify fixture categories: BlueId algorithm, resolution/canonicalization, and provider/full-graph behavior. They do not define separate conformance levels.
|
|
2274
|
+
|
|
2275
|
+
### 16.1 BlueId algorithm vectors
|
|
2276
|
+
|
|
2277
|
+
- **B1.** `id([])` is defined and distinct from absent values and cleaned object fields.
|
|
2278
|
+
- **B2.** `[A]` hashes differently from `A`.
|
|
2279
|
+
- **B3.** `[[A, B], C]` hashes differently from `[A, B, C]`.
|
|
2280
|
+
- **B4.** `x: 1` and `x: { value: 1 }` produce the same Node BlueId after canonical input normalization.
|
|
2281
|
+
- **B5.** `x: [a, b]` and `x: { items: [a, b] }` produce the same Node BlueId.
|
|
2282
|
+
- **B6.** A map exactly `{ blueId: X }` hashes to `X`.
|
|
2283
|
+
- **B7.** Object-field cleaning removes `null` fields and fields that normalize to empty objects.
|
|
2284
|
+
- **B8.** Cleaning preserves `[]`.
|
|
2285
|
+
- **B9.** A node containing `blue` is rejected as direct BlueId Input.
|
|
2286
|
+
- **B10.** A map mixing `blueId` with sibling fields is rejected as BlueId Input.
|
|
2287
|
+
- **B11.** Primitive scalar inference assigns `Text`, `Integer`, `Double`, and `Boolean` deterministically.
|
|
2288
|
+
- **B12.** `$empty: true` remains content and affects BlueId.
|
|
2289
|
+
- **B13.** Direct BlueId Input containing a `null` list element is rejected.
|
|
2290
|
+
- **B14.** Direct BlueId Input containing an empty-object list element is rejected unless it has already been normalized to `$empty: true` before direct hashing.
|
|
2291
|
+
- **B15.** `[A, {$empty: true}, B]` hashes differently from `[A, B]`.
|
|
2292
|
+
- **B16.** Integer values above `9007199254740991` or below `-9007199254740991` are represented as quoted canonical decimal text with explicit `Integer` type.
|
|
2293
|
+
- **B17.** `this#<index>` is rejected outside the explicit cyclic-set calculation API.
|
|
2294
|
+
- **B18.** A source numeric token `1` infers `Integer`; source numeric tokens `1.0` and `1e0` infer `Double`; explicit `type: Double` remains Double even when the canonical JSON number renders as `1`.
|
|
2295
|
+
- **B19.** Root `{}` is valid BlueId Input and hashes as an empty object; it is not omitted.
|
|
2296
|
+
- **B20.** Root `null` is invalid as Source Document root and as BlueId Input.
|
|
2297
|
+
- **B21.** Plain BlueIds validate as canonical Base58 encodings of exactly 32 bytes; invalid alphabet characters, non-canonical encodings, wrong decoded length, and plain ID strings containing `#` are rejected.
|
|
2298
|
+
- **B22.** `$empty` list placeholder shape is exactly `{ "$empty": true }`; malformed `$empty` items are rejected.
|
|
2299
|
+
- **B23.** `Double` negative zero canonicalizes to numeric payload `0` while retaining Double type.
|
|
2300
|
+
- **B24.** `Double` overflow is rejected.
|
|
2301
|
+
- **B25.** Integer-looking Double canonical rendering retains Double type.
|
|
2302
|
+
- **B26.** Payload-only scalar hashing uses typed scalar identity form, not raw JSON scalar hashing.
|
|
2303
|
+
- **B27.** Enum order and duplicate entries do not affect effective canonical schema identity.
|
|
2304
|
+
- **B28.** `Double` `multipleOf` is evaluated by exact rational arithmetic over IEEE 754 binary64 values.
|
|
2305
|
+
- **B29.** A cyclic-set input with duplicate preliminary member inputs fails unless the members contain identity-bearing disambiguators before preliminary hashing.
|
|
2306
|
+
|
|
2307
|
+
### 16.2 Resolution and canonicalization vectors
|
|
2308
|
+
|
|
2309
|
+
- **R1.** Preprocessing removes `blue` and applies baseline transforms before resolution.
|
|
2310
|
+
- **R2.** Source list `[A, null, B]` preprocesses to `[A, {$empty: true}, B]`, not `[A, B]`.
|
|
2311
|
+
- **R3.** Source list `[A, {}, B]` preprocesses to `[A, {$empty: true}, B]`, not `[A, B]`.
|
|
2312
|
+
- **R4.** Type chains merge according to the overlay and subtyping rules.
|
|
2313
|
+
- **R5.** Fixed-value invariants cannot be overridden.
|
|
2314
|
+
- **R6.** Schema constraints accumulate; irreconcilable constraints fail resolution.
|
|
2315
|
+
- **R7.** Schema objects containing keys outside §9.2 are rejected.
|
|
2316
|
+
- **R8.** `name` and `description` are ignored by matchers and subtype checks.
|
|
2317
|
+
- **R9.** Type root `name` and `description` are not inherited onto the instance root.
|
|
2318
|
+
- **R10.** A Source Document and its Resolved View, after canonicalization, produce the same Content BlueId.
|
|
2319
|
+
- **R11.** Requirement overlays bind valid type completions and reject conflicting completions.
|
|
2320
|
+
- **R12.** `$previous` is validated against the resolved inherited prefix; mismatch fails resolution.
|
|
2321
|
+
- **R13.** `mergePolicy` defaults to `positional` only when there is no inherited effective `mergePolicy`.
|
|
2322
|
+
- **R14.** Append-only lists reject `$pos`.
|
|
2323
|
+
- **R15.** Positional lists reject inherited-prefix reordering and removal.
|
|
2324
|
+
- **R16.** A Minimized Overlay re-resolves to the same Resolved View.
|
|
2325
|
+
- **R17.** Canonical Identity Input does not contain `$previous`, `$pos`, `blue`, unresolved aliases, `null` list elements, or empty-object list elements.
|
|
2326
|
+
- **R18.** Direct hashing of a Resolved View is not used as Content BlueId unless the Resolved View is already identical to its Canonical Identity Input.
|
|
2327
|
+
- **R19.** Canonical Identity Input for append-only lists does not serialize `$previous`; `$previous` may appear only in Minimized Overlay or direct anchored BlueId Input.
|
|
2328
|
+
- **R20.** Canonical Identity Input contains no type aliases; all type references are canonical BlueId references.
|
|
2329
|
+
- **R21.** A source pure reference that is materialized only for resolution canonicalizes back to the pure reference unless the source overlays additional instance content onto it.
|
|
2330
|
+
- **R22.** A child overlay of an inherited `append-only` list that omits `mergePolicy` remains `append-only`; `$pos` is still rejected.
|
|
2331
|
+
- **R23.** A descendant collection that omits inherited `itemType`, `keyType`, or `valueType` retains the inherited constraint.
|
|
2332
|
+
- **R24.** Canonical positional list refinements produce final canonical list payloads, not Source overlay instructions.
|
|
2333
|
+
- **R25.** Minimized positional list overlays may use `$pos` and re-resolve to the same Resolved View.
|
|
2334
|
+
- **R26.** Canonical append-only list overlays do not contain `$previous`; minimized append-only overlays may use `$previous`.
|
|
2335
|
+
- **R27.** Inherited effective Integer type accepts quoted canonical large decimal text.
|
|
2336
|
+
- **R28.** Quoted decimal text without effective Integer type remains Text.
|
|
2337
|
+
- **R29.** Inherited effective Integer type rejects non-canonical decimal text.
|
|
2338
|
+
- **R30.** Declaration-only label overrides are allowed, but label overrides on inherited fixed-value nodes are rejected.
|
|
2339
|
+
- **R31.** Type-chain cycles and self-type cycles are rejected.
|
|
2340
|
+
- **R32.** Required metadata-only fields fail, while required instance payloads and inherited fixed payloads pass.
|
|
2341
|
+
- **R33.** `minFields` and `maxFields` count ordinary fields only.
|
|
2342
|
+
- **R34.** Wrong-kind schema keywords fail schema validation.
|
|
2343
|
+
- **R35.** `itemType`, `keyType`, and `valueType` validate resolved collection members.
|
|
2344
|
+
- **R36.** Direct Dictionary integer keys use canonical textual form and reject duplicate key conflicts after canonicalization.
|
|
2345
|
+
- **R37.** Source list `[A, { x: null }, B]` preprocesses to `[A, { $empty: true }, B]`.
|
|
2346
|
+
- **R38.** Canonical core type compatibility is nominal by registry BlueId.
|
|
2347
|
+
- **R39.** Blue Language view path root is the empty string under RFC 6901; `/` selects the empty-key member.
|
|
2348
|
+
|
|
2349
|
+
### 16.3 Provider, expansion, and collapse vectors
|
|
2350
|
+
|
|
2351
|
+
- **F1.** All B-vectors and R-vectors pass.
|
|
2352
|
+
- **F2.** Expansion preserves Node BlueId.
|
|
2353
|
+
- **F3.** If the implementation exposes collapse, collapse preserves Node BlueId and produces only valid pure references.
|
|
2354
|
+
- **F4.** Expansion supports configurable depth or path limits that do not affect identity.
|
|
2355
|
+
- **F5.** Cross-document references resolve through a provider without changing identity.
|
|
2356
|
+
- **F6.** Missing provider content required for resolution fails deterministically.
|
|
2357
|
+
- **F7.** Ordinary BlueId provider content whose computed Node BlueId does not equal the requested BlueId is rejected.
|
|
2358
|
+
- **F8.** Source Document provider content requires a declared Source Document provider mode and Content BlueId verification.
|
|
2359
|
+
- **F9.** Cyclic-set member provider content requires cyclic-set-aware verification context.
|
|
2360
|
+
|
|
2361
|
+
### 16.4 Machine-readable fixtures (normative)
|
|
2362
|
+
|
|
2363
|
+
The Blue Language 1.0 conformance suite MUST publish machine-readable fixtures with exact expected BlueIds.
|
|
2364
|
+
|
|
2365
|
+
The canonical fixture package is part of the Blue Language 1.0 release artifact and is versioned with this specification.
|
|
2366
|
+
|
|
2367
|
+
The Blue Language 1.0 release authority MUST publish the fixture package identity, either as a BlueId or as a content-addressed release artifact digest.
|
|
2368
|
+
|
|
2369
|
+
The fixture package identity for this Blue Language 1.0 publication is:
|
|
2370
|
+
|
|
2371
|
+
```text
|
|
2372
|
+
sha256:8b79cdbba2167db7e24badcd55467819cd3c24b9caf256e8af08e093b9b564db
|
|
2373
|
+
```
|
|
2374
|
+
|
|
2375
|
+
No inline reference BlueIds are included in this prose specification. Exact hashes live in the canonical fixture package.
|
|
2376
|
+
|
|
2377
|
+
Each fixture SHOULD use this shape:
|
|
2378
|
+
|
|
2379
|
+
```yaml
|
|
2380
|
+
id: B4
|
|
2381
|
+
category: BlueId
|
|
2382
|
+
description: scalar sugar and wrapped scalar are equivalent
|
|
2383
|
+
input:
|
|
2384
|
+
x: 1
|
|
2385
|
+
expectedNodeBlueId: "<blueId>"
|
|
2386
|
+
alsoEquivalentTo:
|
|
2387
|
+
x:
|
|
2388
|
+
value: 1
|
|
2389
|
+
```
|
|
2390
|
+
|
|
2391
|
+
Fixtures involving Content BlueId SHOULD include:
|
|
2392
|
+
|
|
2393
|
+
```yaml
|
|
2394
|
+
id: R10
|
|
2395
|
+
category: Resolution
|
|
2396
|
+
source: ...
|
|
2397
|
+
provider: ...
|
|
2398
|
+
expectedCanonicalIdentityInput: ...
|
|
2399
|
+
expectedContentBlueId: "<blueId>"
|
|
2400
|
+
```
|
|
2401
|
+
|
|
2402
|
+
Error fixtures MAY include:
|
|
2403
|
+
|
|
2404
|
+
```yaml
|
|
2405
|
+
expectedErrorCategory: SchemaViolation
|
|
2406
|
+
```
|
|
2407
|
+
|
|
2408
|
+
or, for multiple valid categories:
|
|
2409
|
+
|
|
2410
|
+
```yaml
|
|
2411
|
+
expectedErrorCategories: [InvalidBlueId, InvalidReferenceShape]
|
|
2412
|
+
```
|
|
2413
|
+
|
|
2414
|
+
The expected BlueIds are part of the specification test surface. Changing one requires either correcting an error in the specification or declaring a new incompatible language version.
|
|
2415
|
+
|
|
2416
|
+
The fixture suite MUST cover:
|
|
2417
|
+
|
|
2418
|
+
- scalar values;
|
|
2419
|
+
- large integers represented as quoted canonical decimal strings;
|
|
2420
|
+
- wrapped vs sugar forms;
|
|
2421
|
+
- pure references;
|
|
2422
|
+
- root scalar, list, object, and pure reference forms;
|
|
2423
|
+
- empty list;
|
|
2424
|
+
- empty object root;
|
|
2425
|
+
- root null rejection;
|
|
2426
|
+
- plain BlueId validation;
|
|
2427
|
+
- portable `blue.imports` alias resolution;
|
|
2428
|
+
- portable YAML rejection of anchors, aliases, merge keys, custom tags, YAML-only types, and implicit timestamp typing;
|
|
2429
|
+
- YAML multiline block scalar identity;
|
|
2430
|
+
- schema keyword value-shape validation;
|
|
2431
|
+
- schema wrong-kind validation;
|
|
2432
|
+
- enum order and duplicate normalization;
|
|
2433
|
+
- exact `Double` `multipleOf` validation using rational binary64 semantics;
|
|
2434
|
+
- required field semantic-presence validation;
|
|
2435
|
+
- field counting for ordinary object fields only;
|
|
2436
|
+
- deterministic integer `multipleOf` LCM merge;
|
|
2437
|
+
- enum scalar type inference;
|
|
2438
|
+
- typed scalar identity for payload-only scalar hashing;
|
|
2439
|
+
- object-field null removal;
|
|
2440
|
+
- list null placeholder normalization;
|
|
2441
|
+
- list empty-object placeholder normalization;
|
|
2442
|
+
- recursive list element placeholder normalization after object-field cleaning;
|
|
2443
|
+
- `$empty`;
|
|
2444
|
+
- malformed `$empty` rejection;
|
|
2445
|
+
- `$pos` map overlay and `$replace` compatibility;
|
|
2446
|
+
- append-only `$previous`;
|
|
2447
|
+
- Canonical Identity Input final list payloads are identity input, not ordinary Source overlays;
|
|
2448
|
+
- Minimized Overlay re-resolution for `$pos` and `$previous` list controls;
|
|
2449
|
+
- inherited `mergePolicy`;
|
|
2450
|
+
- inherited collection type constraints;
|
|
2451
|
+
- `itemType`, `keyType`, and `valueType` validation;
|
|
2452
|
+
- direct Dictionary key canonicalization and duplicate conflict rejection;
|
|
2453
|
+
- reserved-invalid `properties` rejection;
|
|
2454
|
+
- materialized subtree vs pure reference;
|
|
2455
|
+
- provider Node BlueId verification, declared Source provider verification, and cyclic-set member verification;
|
|
2456
|
+
- RFC 6901 Blue Language view paths, including empty-string root and `/` empty-key member behavior;
|
|
2457
|
+
- type alias preprocessing;
|
|
2458
|
+
- type-chain cycle detection;
|
|
2459
|
+
- nominal core type compatibility by registry BlueId;
|
|
2460
|
+
- primitive inference;
|
|
2461
|
+
- core registry Text node hashes to its published BlueId;
|
|
2462
|
+
- core registry Integer node hashes to its published BlueId;
|
|
2463
|
+
- core registry Double node hashes to its published BlueId;
|
|
2464
|
+
- core registry Boolean node hashes to its published BlueId;
|
|
2465
|
+
- core registry Dictionary node hashes to its published BlueId;
|
|
2466
|
+
- core registry List node hashes to its published BlueId;
|
|
2467
|
+
- changing a core type `description` changes the node BlueId;
|
|
2468
|
+
- circular references;
|
|
2469
|
+
- duplicate preliminary cyclic-set member rejection unless identity-bearing disambiguators are present before preliminary hashing;
|
|
2470
|
+
- error category classification;
|
|
2471
|
+
- publication lint that rejects obsolete conformance terminology in publishable Blue Language 1.0 files and requires the §1 heading used by this specification.
|
|
2472
|
+
|
|
2473
|
+
The Blue Language core registry manifest MUST make identity-bearing descriptions explicit. Each entry in the registry manifest MUST identify the registry kind, specification version, entry key, canonical node path, published BlueId, and `semanticDescriptionIdentityBearing: true`.
|
|
2474
|
+
|
|
2475
|
+
Release checks MUST verify that:
|
|
2476
|
+
|
|
2477
|
+
- registry nodes are loaded from files, not reconstructed from implementation constants;
|
|
2478
|
+
- registry file content hashes to the published BlueIds;
|
|
2479
|
+
- core type alias constants equal the calculated registry BlueIds;
|
|
2480
|
+
- no canonical registry node is edited without updating its BlueId and fixture package identity;
|
|
2481
|
+
- generated documentation is derived from registry nodes, or explicitly marked non-canonical;
|
|
2482
|
+
- publishable Blue Language files pass the documentation lint before release.
|
|
2483
|
+
|
|
2484
|
+
---
|
|
2485
|
+
|
|
2486
|
+
## 17. Worked Examples
|
|
2487
|
+
|
|
2488
|
+
BlueIds ending in `...` in this section are illustrative placeholders, not conformance vectors. Exact expected BlueIds are defined by the machine-readable fixture suite (§16.4).
|
|
2489
|
+
|
|
2490
|
+
### 17.1 Content-addressable types (informative)
|
|
2491
|
+
|
|
2492
|
+
```yaml
|
|
2493
|
+
name: Simple Amount
|
|
2494
|
+
amount:
|
|
2495
|
+
type: Double
|
|
2496
|
+
currency:
|
|
2497
|
+
type: Text
|
|
2498
|
+
# => blueId: FgHZjS...
|
|
2499
|
+
|
|
2500
|
+
name: Person
|
|
2501
|
+
age:
|
|
2502
|
+
type: Integer
|
|
2503
|
+
spent:
|
|
2504
|
+
type:
|
|
2505
|
+
blueId: FgHZjS... # Simple Amount
|
|
2506
|
+
# => blueId: GRwTYs...
|
|
2507
|
+
```
|
|
2508
|
+
|
|
2509
|
+
Instance:
|
|
2510
|
+
|
|
2511
|
+
```yaml
|
|
2512
|
+
name: Alice
|
|
2513
|
+
type:
|
|
2514
|
+
blueId: GRwTYs... # Person
|
|
2515
|
+
age: 25
|
|
2516
|
+
spent:
|
|
2517
|
+
amount: 27.15
|
|
2518
|
+
currency: USD
|
|
2519
|
+
# => Content BlueId: 3JTd8s...
|
|
2520
|
+
```
|
|
2521
|
+
|
|
2522
|
+
Expanding the type chain produces an Expanded View. Resolving produces a Resolved View. Canonicalizing the Resolved View produces a Canonical Identity Input whose Node BlueId is the Content BlueId of the instance.
|
|
2523
|
+
|
|
2524
|
+
### 17.2 `blue` directive (informative)
|
|
2525
|
+
|
|
2526
|
+
```yaml
|
|
2527
|
+
blue:
|
|
2528
|
+
imports:
|
|
2529
|
+
Person:
|
|
2530
|
+
blueId: GRwTYs...
|
|
2531
|
+
name: Alice
|
|
2532
|
+
type: Person
|
|
2533
|
+
age: 25
|
|
2534
|
+
```
|
|
2535
|
+
|
|
2536
|
+
Preprocessing replaces `Person` with its BlueId reference, infers primitive scalar types, and removes `blue` before hashing.
|
|
2537
|
+
|
|
2538
|
+
### 17.3 Large integer (informative)
|
|
2539
|
+
|
|
2540
|
+
```yaml
|
|
2541
|
+
accountId:
|
|
2542
|
+
type: Integer
|
|
2543
|
+
value: "9007199254740992"
|
|
2544
|
+
```
|
|
2545
|
+
|
|
2546
|
+
The value is quoted because it is outside the safe JSON numeric integer range. The explicit `Integer` type distinguishes it from Text.
|
|
2547
|
+
|
|
2548
|
+
Numeric token inference:
|
|
2549
|
+
|
|
2550
|
+
```yaml
|
|
2551
|
+
a: 1 # inferred Integer
|
|
2552
|
+
b: 1.0 # inferred Double
|
|
2553
|
+
c: 1e0 # inferred Double
|
|
2554
|
+
d:
|
|
2555
|
+
type: Double
|
|
2556
|
+
value: 1
|
|
2557
|
+
```
|
|
2558
|
+
|
|
2559
|
+
`b`, `c`, and `d` are Double values even when their canonical JSON number renders as `1`.
|
|
2560
|
+
|
|
2561
|
+
### 17.4 Same image, different meaning (informative)
|
|
2562
|
+
|
|
2563
|
+
```yaml
|
|
2564
|
+
# A
|
|
2565
|
+
name: Person to Avoid
|
|
2566
|
+
description: This guy will kill you today
|
|
2567
|
+
type: Image
|
|
2568
|
+
image:
|
|
2569
|
+
blueId: 123...456
|
|
2570
|
+
|
|
2571
|
+
# B
|
|
2572
|
+
name: Family Member
|
|
2573
|
+
description: Trust this person
|
|
2574
|
+
type: Image
|
|
2575
|
+
image:
|
|
2576
|
+
blueId: 123...456
|
|
2577
|
+
```
|
|
2578
|
+
|
|
2579
|
+
These have different Content BlueIds because `name` and `description` are identity content. Structural and type matchers ignore those labels.
|
|
2580
|
+
|
|
2581
|
+
### 17.5 Requirement overlay followed by type binding (informative)
|
|
2582
|
+
|
|
2583
|
+
```yaml
|
|
2584
|
+
# Parent
|
|
2585
|
+
name: A
|
|
2586
|
+
prop1:
|
|
2587
|
+
x: 1
|
|
2588
|
+
|
|
2589
|
+
# Child
|
|
2590
|
+
name: B
|
|
2591
|
+
type: A
|
|
2592
|
+
prop1:
|
|
2593
|
+
type: Some
|
|
2594
|
+
```
|
|
2595
|
+
|
|
2596
|
+
The child is valid only if `Some` can resolve while preserving `x = 1`. If `Some` forces `x = 2`, resolution fails.
|
|
2597
|
+
|
|
2598
|
+
### 17.6 Lists: refine and append (informative)
|
|
2599
|
+
|
|
2600
|
+
```yaml
|
|
2601
|
+
# Parent
|
|
2602
|
+
name: Trip
|
|
2603
|
+
segments:
|
|
2604
|
+
type: List
|
|
2605
|
+
itemType: Flight Segment
|
|
2606
|
+
items:
|
|
2607
|
+
- type: Flight Segment
|
|
2608
|
+
carrier: BA
|
|
2609
|
+
|
|
2610
|
+
# Child
|
|
2611
|
+
name: Trip LHR to SFO
|
|
2612
|
+
type: Trip
|
|
2613
|
+
segments:
|
|
2614
|
+
items:
|
|
2615
|
+
- $pos: 0
|
|
2616
|
+
from: LHR
|
|
2617
|
+
to: JFK
|
|
2618
|
+
- type: Flight Segment
|
|
2619
|
+
carrier: BA
|
|
2620
|
+
from: JFK
|
|
2621
|
+
to: SFO
|
|
2622
|
+
```
|
|
2623
|
+
|
|
2624
|
+
The child refines inherited index `0` and appends a second segment. Reordering or deleting the inherited prefix would be invalid.
|
|
2625
|
+
|
|
2626
|
+
### 17.7 Null list element as placeholder (informative)
|
|
2627
|
+
|
|
2628
|
+
```yaml
|
|
2629
|
+
items:
|
|
2630
|
+
- A
|
|
2631
|
+
- null
|
|
2632
|
+
- B
|
|
2633
|
+
```
|
|
2634
|
+
|
|
2635
|
+
preprocesses to:
|
|
2636
|
+
|
|
2637
|
+
```yaml
|
|
2638
|
+
items:
|
|
2639
|
+
- A
|
|
2640
|
+
- $empty: true
|
|
2641
|
+
- B
|
|
2642
|
+
```
|
|
2643
|
+
|
|
2644
|
+
It does not preprocess to `[A, B]`.
|
|
2645
|
+
|
|
2646
|
+
### 17.8 Expansion with limits (informative)
|
|
2647
|
+
|
|
2648
|
+
Starting from:
|
|
2649
|
+
|
|
2650
|
+
```yaml
|
|
2651
|
+
blueId: 3JTd8s... # Alice
|
|
2652
|
+
```
|
|
2653
|
+
|
|
2654
|
+
expanding `/spent` may hydrate only the `spent` subtree:
|
|
2655
|
+
|
|
2656
|
+
```yaml
|
|
2657
|
+
name: Alice
|
|
2658
|
+
type:
|
|
2659
|
+
blueId: GRwTYs...
|
|
2660
|
+
age: 25
|
|
2661
|
+
spent:
|
|
2662
|
+
amount: 27.15
|
|
2663
|
+
currency: USD
|
|
2664
|
+
```
|
|
2665
|
+
|
|
2666
|
+
Node BlueId is unchanged if the hydrated content verifies to the referenced BlueIds.
|
|
2667
|
+
|
|
2668
|
+
### 17.9 Canonicalization (informative)
|
|
2669
|
+
|
|
2670
|
+
From a Resolved View with fully materialized type subtrees, canonicalization:
|
|
2671
|
+
|
|
2672
|
+
- collapses type objects to `{ blueId: ... }` when available;
|
|
2673
|
+
- removes structure derivable from the type chain;
|
|
2674
|
+
- consumes `$pos` overlays;
|
|
2675
|
+
- normalizes list placeholders to `$empty: true`;
|
|
2676
|
+
- keeps instance contributions;
|
|
2677
|
+
- produces valid BlueId Input.
|
|
2678
|
+
|
|
2679
|
+
The Canonical Identity Input yields the Content BlueId. A Minimized Overlay, when produced, re-resolves to the same Resolved View through ordinary Source overlay semantics.
|
|
2680
|
+
|
|
2681
|
+
### 17.10 Contracts merge as content (informative)
|
|
2682
|
+
|
|
2683
|
+
```yaml
|
|
2684
|
+
# Parent type
|
|
2685
|
+
name: With Audit
|
|
2686
|
+
contracts:
|
|
2687
|
+
audit:
|
|
2688
|
+
type: Audit Contract
|
|
2689
|
+
enabled: true
|
|
2690
|
+
|
|
2691
|
+
# Child instance
|
|
2692
|
+
type: With Audit
|
|
2693
|
+
contracts:
|
|
2694
|
+
audit:
|
|
2695
|
+
retentionDays: 30
|
|
2696
|
+
```
|
|
2697
|
+
|
|
2698
|
+
Language resolution merges `contracts.audit` as content. It does not execute the contract. The resolved contract entry contains both `enabled: true` and `retentionDays: 30`, unless normal fixed-value, type, or schema rules reject the merge.
|
|
2699
|
+
|
|
2700
|
+
### 17.11 Common invalid forms (informative)
|
|
2701
|
+
|
|
2702
|
+
Mixed reference and content is invalid:
|
|
2703
|
+
|
|
2704
|
+
```yaml
|
|
2705
|
+
blueId: X
|
|
2706
|
+
name: Not allowed
|
|
2707
|
+
```
|
|
2708
|
+
|
|
2709
|
+
`blue` is root-only and preprocessing-only:
|
|
2710
|
+
|
|
2711
|
+
```yaml
|
|
2712
|
+
child:
|
|
2713
|
+
blue: something
|
|
2714
|
+
```
|
|
2715
|
+
|
|
2716
|
+
`$pos` cannot appear in Canonical Identity Input or BlueId Input:
|
|
2717
|
+
|
|
2718
|
+
```yaml
|
|
2719
|
+
items:
|
|
2720
|
+
- $pos: 0
|
|
2721
|
+
value: A
|
|
2722
|
+
```
|
|
2723
|
+
|
|
2724
|
+
Use `$replace` for non-scalar positional replacement:
|
|
2725
|
+
|
|
2726
|
+
```yaml
|
|
2727
|
+
# Invalid
|
|
2728
|
+
- $pos: 0
|
|
2729
|
+
value:
|
|
2730
|
+
items: [A, B]
|
|
2731
|
+
|
|
2732
|
+
# Valid
|
|
2733
|
+
- $pos: 0
|
|
2734
|
+
$replace:
|
|
2735
|
+
items: [A, B]
|
|
2736
|
+
```
|
|
2737
|
+
|
|
2738
|
+
---
|
|
2739
|
+
|
|
2740
|
+
## Appendix A — Core Primitive and Collection Types
|
|
2741
|
+
|
|
2742
|
+
Appendix A defines the canonical primitive and collection types referenced throughout this specification.
|
|
2743
|
+
|
|
2744
|
+
The nodes in §A.1 are canonical type definitions, not illustrative sketches. Their `description` fields are normative, identity-bearing Blue content. The exact registry files used to calculate published BlueIds MUST be byte/string equivalent after Blue parsing to the intended canonical nodes.
|
|
2745
|
+
|
|
2746
|
+
Changing a canonical node's `description` is a type-identity change. Implementations MUST NOT silently update canonical descriptions while keeping the old BlueId.
|
|
2747
|
+
|
|
2748
|
+
If a typo or editorial issue is found after publication and it does not change semantics, publish errata outside the canonical node. If the text change is intended to alter or clarify the type's meaning in an identity-bearing way, publish a new registry entry with a new BlueId.
|
|
2749
|
+
|
|
2750
|
+
### A.1 Canonical core type nodes
|
|
2751
|
+
|
|
2752
|
+
#### Text
|
|
2753
|
+
|
|
2754
|
+
```yaml
|
|
2755
|
+
name: Text
|
|
2756
|
+
description: >
|
|
2757
|
+
Core Blue Language 1.0 primitive scalar representing Unicode text. Text
|
|
2758
|
+
values are exact Unicode code-point sequences after parsing. Blue Language
|
|
2759
|
+
performs no Unicode normalization, case folding, locale-sensitive collation,
|
|
2760
|
+
whitespace normalization, or line-ending normalization by default. String
|
|
2761
|
+
schema constraints minLength and maxLength count Unicode code points. The
|
|
2762
|
+
empty string is valid unless restricted by schema. Applicable schema
|
|
2763
|
+
constraints are minLength, maxLength, and enum.
|
|
2764
|
+
```
|
|
2765
|
+
|
|
2766
|
+
#### Integer
|
|
2767
|
+
|
|
2768
|
+
```yaml
|
|
2769
|
+
name: Integer
|
|
2770
|
+
description: >
|
|
2771
|
+
Core Blue Language 1.0 primitive scalar for exact mathematical integer
|
|
2772
|
+
values. Integer values are arbitrary precision in the language model.
|
|
2773
|
+
Unquoted integer tokens are portable only in the safe JSON numeric integer
|
|
2774
|
+
range [-9007199254740991, 9007199254740991]. Integer values outside that
|
|
2775
|
+
range are represented as quoted canonical decimal text with explicit or
|
|
2776
|
+
inherited effective Integer type. The canonical decimal text form uses an
|
|
2777
|
+
optional leading minus sign followed by decimal digits, with no leading
|
|
2778
|
+
zeros except the single digit zero. Applicable schema constraints are
|
|
2779
|
+
minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, and enum.
|
|
2780
|
+
```
|
|
2781
|
+
|
|
2782
|
+
#### Double
|
|
2783
|
+
|
|
2784
|
+
```yaml
|
|
2785
|
+
name: Double
|
|
2786
|
+
description: >
|
|
2787
|
+
Core Blue Language 1.0 primitive scalar for finite IEEE 754 binary64
|
|
2788
|
+
floating-point values. NaN, positive Infinity, and negative Infinity are
|
|
2789
|
+
invalid Blue values. Double parsing uses round-to-nearest, ties-to-even
|
|
2790
|
+
binary64 semantics; numeric tokens that overflow to Infinity or parse as NaN
|
|
2791
|
+
are invalid. Source numeric tokens with a decimal point or exponent infer
|
|
2792
|
+
Double when no explicit type is provided, even when their mathematical value
|
|
2793
|
+
is integral. Negative zero and positive zero compare as the same numeric
|
|
2794
|
+
value and canonicalize as JSON number zero, while the effective Double type
|
|
2795
|
+
remains part of canonical BlueId input. Applicable schema constraints are
|
|
2796
|
+
minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, and enum.
|
|
2797
|
+
```
|
|
2798
|
+
|
|
2799
|
+
#### Boolean
|
|
2800
|
+
|
|
2801
|
+
```yaml
|
|
2802
|
+
name: Boolean
|
|
2803
|
+
description: >
|
|
2804
|
+
Core Blue Language 1.0 primitive scalar with exactly two values: true and
|
|
2805
|
+
false. Blue Language defines no truthiness conversion for Boolean values.
|
|
2806
|
+
Only the literal parsed boolean values true and false are Boolean values.
|
|
2807
|
+
Applicable schema constraint is enum.
|
|
2808
|
+
```
|
|
2809
|
+
|
|
2810
|
+
#### Dictionary
|
|
2811
|
+
|
|
2812
|
+
```yaml
|
|
2813
|
+
name: Dictionary
|
|
2814
|
+
description: >
|
|
2815
|
+
Core Blue Language 1.0 object-map collection type. A Dictionary is encoded
|
|
2816
|
+
as a Blue object node whose ordinary child fields represent direct keys
|
|
2817
|
+
when those keys do not collide with reserved language fields. Direct object
|
|
2818
|
+
encoding cannot represent data keys named name, description, type, itemType,
|
|
2819
|
+
keyType, valueType, value, items, blueId, blue, schema, mergePolicy,
|
|
2820
|
+
contracts, properties, or constraints. Direct object encoding cannot
|
|
2821
|
+
represent reserved language keys as data keys. Applications needing
|
|
2822
|
+
arbitrary keys use an application-defined escaped representation. keyType is optional; if
|
|
2823
|
+
omitted and no effective keyType is inherited, keys default to Text for
|
|
2824
|
+
direct object encoding. For direct object encoding, keyType must resolve to
|
|
2825
|
+
a scalar key type with a canonical textual form, such as Text, Integer,
|
|
2826
|
+
Double, or Boolean. valueType is optional; if omitted and no effective
|
|
2827
|
+
valueType is inherited, values may be any Blue node. Applicable schema
|
|
2828
|
+
constraints are minFields and maxFields.
|
|
2829
|
+
```
|
|
2830
|
+
|
|
2831
|
+
#### List
|
|
2832
|
+
|
|
2833
|
+
```yaml
|
|
2834
|
+
name: List
|
|
2835
|
+
description: >
|
|
2836
|
+
Core Blue Language 1.0 ordered collection type. Surface array form and
|
|
2837
|
+
wrapped items form are equivalent authoring forms. Order and multiplicity
|
|
2838
|
+
are preserved. List BlueId calculation uses a domain-separated streaming
|
|
2839
|
+
fold over element BlueIds. itemType is optional; if omitted and no effective
|
|
2840
|
+
itemType is inherited, elements are not constrained by itemType. If
|
|
2841
|
+
mergePolicy is omitted and no effective mergePolicy is inherited, resolvers
|
|
2842
|
+
assume positional. append-only forbids changes to the inherited prefix.
|
|
2843
|
+
positional allows $pos overlays within the inherited prefix. $previous,
|
|
2844
|
+
$pos, $replace, and $empty are recognized only at the top level of items
|
|
2845
|
+
when the node's effective type is List. Source list null and empty object
|
|
2846
|
+
elements normalize to $empty: true and are not deleted. Applicable schema
|
|
2847
|
+
constraints are minItems, maxItems, and uniqueItems.
|
|
2848
|
+
```
|
|
2849
|
+
|
|
2850
|
+
### A.2 Editorial and registry rules
|
|
2851
|
+
|
|
2852
|
+
The canonical registry nodes above are part of the Blue Language 1.0 type identity. Non-normative examples, tutorials, rationale, translations, and implementation notes are not part of the canonical type nodes unless intentionally included in the registry entries.
|
|
2853
|
+
|
|
2854
|
+
Additional explanatory documentation MAY follow this appendix or appear in separate registry documentation, but it MUST be clearly marked non-canonical unless it is included in the registry node itself.
|
|
2855
|
+
|
|
2856
|
+
---
|
|
2857
|
+
|
|
2858
|
+
## Appendix B — Reserved Extension Boundary
|
|
2859
|
+
|
|
2860
|
+
`contracts` is reserved for the Blue Contracts and Processor Specification. Blue Language 1.0 treats it as identity-bearing content only. See §4.4.
|
|
2861
|
+
|
|
2862
|
+
---
|
|
2863
|
+
|
|
2864
|
+
## Appendix C — Common Implementer Mistakes
|
|
2865
|
+
|
|
2866
|
+
This appendix is informative.
|
|
2867
|
+
|
|
2868
|
+
### C.1 Do not delete list positions
|
|
2869
|
+
|
|
2870
|
+
`[A, null, B]` does not mean `[A, B]`. Source list `null` and `{}` elements normalize to `$empty: true`.
|
|
2871
|
+
|
|
2872
|
+
### C.2 Do not hash `blue`
|
|
2873
|
+
|
|
2874
|
+
`blue` is a preprocessing directive. Direct BlueId input containing `blue` must be rejected.
|
|
2875
|
+
|
|
2876
|
+
### C.3 Do not treat `value` as a generic replacement field
|
|
2877
|
+
|
|
2878
|
+
`value` is the scalar payload wrapper. Positional non-scalar replacement uses `$replace`.
|
|
2879
|
+
|
|
2880
|
+
### C.4 Do not let `$pos` reach BlueId input
|
|
2881
|
+
|
|
2882
|
+
`$pos` is an overlay instruction. Canonical Identity Input and direct BlueId Input must not contain `$pos`.
|
|
2883
|
+
|
|
2884
|
+
### C.5 Do not trust provider content without verification
|
|
2885
|
+
|
|
2886
|
+
When expanding `blueId: X` through an ordinary BlueId provider, compute the returned content's Node BlueId and verify that it equals `X`.
|
|
2887
|
+
|
|
2888
|
+
### C.6 Do not treat `name` and `description` as comments
|
|
2889
|
+
|
|
2890
|
+
They affect BlueId. They are ignored by matchers, not by identity.
|
|
2891
|
+
|
|
2892
|
+
### C.7 Use only the schema keywords defined in §9
|
|
2893
|
+
|
|
2894
|
+
A `schema` object accepts only the keywords listed in §9.2.
|
|
2895
|
+
|
|
2896
|
+
### C.8 Do not use reserved language keys as ordinary object fields
|
|
2897
|
+
|
|
2898
|
+
Reserved keys such as `type`, `value`, `items`, and `schema` have language meaning.
|
|
2899
|
+
|
|
2900
|
+
---
|
|
2901
|
+
|
|
2902
|
+
## Appendix D — Error Categories
|
|
2903
|
+
|
|
2904
|
+
This appendix is normative for conformance diagnostics but does not require a particular exception class, wire format, or exact error message.
|
|
2905
|
+
|
|
2906
|
+
When an operation fails deterministically, implementations MUST be able to classify the failure into one of these categories for conformance reporting:
|
|
2907
|
+
|
|
2908
|
+
| Category | Meaning |
|
|
2909
|
+
|---|---|
|
|
2910
|
+
| `InvalidSyntax` | Serialized JSON/YAML is malformed or outside the Blue JSON data model. |
|
|
2911
|
+
| `DuplicateKey` | A serialized object contains duplicate keys. |
|
|
2912
|
+
| `InvalidReservedField` | A reserved field has an invalid type, shape, or position. |
|
|
2913
|
+
| `InvalidBlueId` | A BlueId string is malformed or invalid for its context. |
|
|
2914
|
+
| `InvalidReferenceShape` | `blueId` appears with sibling fields or invalid mixed reference shape. |
|
|
2915
|
+
| `InvalidBlueIdInput` | Direct Node BlueId received a node that is not valid BlueId Input. |
|
|
2916
|
+
| `ProviderUnavailable` | Required provider content is unavailable. |
|
|
2917
|
+
| `ProviderBlueIdMismatch` | Provider content does not verify against the requested BlueId. |
|
|
2918
|
+
| `TypeCycle` | Resolution detected a type-cycle in the active type stack. |
|
|
2919
|
+
| `FixedValueConflict` | A descendant attempted to override or contradict an inherited fixed value. |
|
|
2920
|
+
| `TypeCompatibilityViolation` | A descendant type, itemType, keyType, or valueType is incompatible with an inherited constraint. |
|
|
2921
|
+
| `SchemaVocabularyError` | A schema contains an unknown keyword or invalid schema value shape. |
|
|
2922
|
+
| `SchemaViolation` | A node violates accumulated schema constraints. |
|
|
2923
|
+
| `ListControlViolation` | `$previous`, `$pos`, `$replace`, or `$empty` has invalid shape or context. |
|
|
2924
|
+
| `CanonicalizationError` | A Canonical Identity Input cannot be produced deterministically. |
|
|
2925
|
+
| `CircularSetError` | Cyclic-set input is malformed or cannot produce deterministic member IDs. |
|
|
2926
|
+
| `UnsupportedPreprocessingTransform` | A Source Document requires a preprocessing transform that is unsupported. |
|
|
2927
|
+
|
|
2928
|
+
An invalid document may contain multiple independent errors. Blue Language 1.0 does not require a universal precedence order for all possible simultaneous failures. Conformance fixtures that assert an exact error category MUST isolate one primary error so that a conforming implementation can deterministically report that category without ambiguity. If a fixture intentionally contains multiple independent errors, it MUST assert only that the operation fails, or it MUST explicitly declare acceptable error categories.
|
|
2929
|
+
|
|
2930
|
+
---
|
|
2931
|
+
|
|
2932
|
+
*End of Blue Language Specification 1.0.*
|