From 90afbb1c2e1c863e77fec0d8aaa1ca9cbf246e1b Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Mon, 10 Aug 2026 15:48:54 +0900 Subject: [PATCH] docs: resolve WWAR protocol contradictions Make the schema-1 transcription mechanically consistent before the protocol freeze: restore compiler-protocol identity, use the typed native-contract record identity, distinguish encoding and path classes, and close the package artifact kinds. These corrections must land together because one exhaustive IDL cannot encode the prior conflicting rules. --- docs/build-system.md | 93 +++++++++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 31 deletions(-) diff --git a/docs/build-system.md b/docs/build-system.md index 42421269..7834eef4 100644 --- a/docs/build-system.md +++ b/docs/build-system.md @@ -579,9 +579,11 @@ integer overflow, and a comment marker inside an unclosed string are errors. Whitespace, comments, assignment order, record-key order, and clause order where the schema declares identity keys are non-semantic. List order is semantic. -Parsing produces a typed record and its semantic digest is the WWAR encoding of -that record, not the original text. `ww fmt` writes two-space canonical text; -generated lock/vendor files MUST already equal that rendering in frozen mode. +Parsing produces a typed record whose canonical semantic encoding is +`WWAR(record)`, not the original text. Its semantic digest is the applicable +kind/schema-bound `record_id` from section 6.6. `ww fmt` writes two-space +canonical text; generated lock/vendor files MUST already equal that rendering +in frozen mode. ## 5. Build model and graph construction @@ -847,20 +849,31 @@ Schema defaults are always encoded, so no semantic field is inferred from absence. Floats, signed integers, null, and indefinite lengths do not exist. One byte string/string is at most `2^31-1` bytes, a container has at most -`2^24-1` members, and nesting depth is at most 64. A logical path string uses `/`, -has no NUL/backslash/absolute prefix, empty/`.`/`..` segment, and passes the -schema's ASCII-identity or NFC-source-path rule. These are protocol limits, not -host `size_t` limits. Human-readable JSON is a lossless rendering, not the -hashed representation. Phase-0 golden vectors include empty/nested records, -ordered lists, sorted maps, every rejection, and their complete bytes/digests. +`2^24-1` members, and nesting depth is at most 64. A content/container-relative +logical path string uses `/`, is relative, has no NUL/backslash, empty/`.`/`..` +segment, and passes the schema's ASCII-identity or NFC-source-path rule. A field +that explicitly permits `.` as its complete root sentinel is the sole exception. +These are protocol limits, not host `size_t` limits. Human-readable JSON is a +lossless rendering, not the hashed representation. Phase-0 golden vectors +include empty/nested records, ordered lists, sorted maps, every rejection, and +their complete bytes/digests. The normative empty-record vector is `57574152000107000000000000000400000000`, SHA-256 `138c6acb7f01e91df73cb1d9c3356d18f19d7b8eb8b0a15426bef32e515d0de0`. -Path values in WWAR are normalized logical slash paths. Absolute paths, -filesystem device/inode numbers, mtimes, cache locations, and command process IDs -are invalid fields. A physical input enters only through a logical name, content -digest, type, and semantic mode. +Each schema assigns every path field a path class. Artifact, source, generated +output, install-destination, bundle-relative, sysroot-relative, and +vendor-relative paths use the relative rule above. Sandbox-execution paths are +path-independent absolute paths only in the closed virtual namespaces `/work`, +`/in`, `/out`, `/tool`, and `/data`; schema-1 action working directory is exactly +`/work`, and exact sandbox path spellings in argv are encoded. Platform-validated +target-runtime paths are a separate type and may be absolute in H's namespace. +Workspace locations and observation physical paths are separately typed and +never enter an artifact action record or key as host locations. Absolute host +paths, filesystem device/inode numbers, mtimes, cache locations, and command +process IDs are invalid in action templates and final action records. A physical +input enters only through a logical name, content digest, type, and semantic +mode. ### 6.2 Required action-record fields @@ -876,10 +889,11 @@ Every record contains, in this order: acquisition but unused targets/tools do not invalidate this action; 5. profile fields: optimization, debug, assertions, overflow, panic, sanitizers, LTO, relocation/code model, symbol stripping, and reproducibility policy; -6. logical package/product/action identity and logical working directory; +6. logical package/product/action identity and sandbox-virtual working directory + (schema 1 exactly `/work`); 7. exact argument vector and a sorted literal environment map; -8. byte-sorted named inputs, each with edge kind, logical path, file/tree type, - semantic mode, content digest, and—where applicable—origin package identity; +8. byte-sorted named inputs, each with edge kind, logical path, semantic artifact + kind, semantic mode, content digest, and—where applicable—origin package identity; 9. direct export-data inputs byte-sorted by package identity for `ww.package` actions; 10. selected source-membership list and target-selection explanation; @@ -918,7 +932,8 @@ A `ww.package` action consumes: - their ordered membership metadata; - only the `.wwe` artifacts of direct imported packages; - the compiler/backend and toolchain resources; -- B/H/T, target descriptor, profile, language/export/object/runtime protocols; +- B/H/T, target descriptor, profile, language/compiler/export/object/runtime + protocols, and manifest/lock schemas; - package-specific native-provider declarations; and - its literal built-in environment and sandbox policy. @@ -1129,13 +1144,22 @@ record. Its tags are: 1 namespace (`source`, `generated`, `package`, `toolchain` `provider-output`, or `cas`); 2 owner identity (empty only for a root source); 3 normalized logical name/path; 4 semantic artifact kind (`file`, `tree`, `object`, `archive`, `shared`, `import-library`, `script`, `crt`, `loader`, -`native-sidecar`, or `native-abi`); +`native-sidecar`, `native-abi`, `export`, or `package-link`); 5 optional expected `TypedDigestV1`; and 6 mode (`data` or `executable`). A local source may omit tag 5 because analysis hashes it. A `cas`, external prebuilt, toolchain, or sysroot reference must include it. A generated/package/provider output gets its digest only from the declared predecessor output. Absolute host paths are invalid. +`InputSlotRefV1`, `TemplateInputV1`, `ResolvedInputV1`, built-in/template/final +action-output records, and `ResultOutputV1` use that same closed semantic +artifact-kind enum; `GenerateDecl.OutputDecl` remains restricted to `file` or +`tree`. In schema 1, `file`, `object`, `archive`, `shared`, `import-library`, +`script`, `crt`, and `loader` require a blob digest. `tree` requires record kind +1, `native-sidecar` kind 15, `native-abi` kind 16, `export` kind 18, and +`package-link` kind 19, each at record schema 1. Any other digest domain, record +kind, or schema is invalid kind substitution. + `InputSlotRefV1` has tag 1 slot name and tag 2 expected semantic artifact type. A final action record contains no `ArtifactRefV1`: every artifact-bearing field is recursively lowered to an `InputSlotRefV1`. `TemplateInputV1` tags are 1 unique slot name, 2 edge @@ -1209,11 +1233,11 @@ A profile is toolchain data, not an open project map: |---|---|---| | 1 | schema | `1` | | 2 | kind/version | exact built-in kind or generate version | -| 3 | protocol record | language/export/object/runtime/manifest/lock | +| 3 | protocol record | language/compiler/export/object/runtime/manifest/lock; compiler protocol is distinct from compiler/backend byte identity | | 4 | platform roles | B, H, optional T descriptor refs | | 5 | selected tool closure | identity plus semantic closure digest/resources | | 6 | profile | complete `ProfileV1` | -| 7 | logical identity/cwd | normalized, path-independent | +| 7 | logical identity/cwd | normalized identity; cwd exactly `/work`, path-independent | | 8 | argv | ordered strings | | 9 | environment | sorted literal map, no secrets | | 10 | input slots | sorted `(name, edge kind, producer/output or source ref, type, mode)` | @@ -1284,9 +1308,10 @@ float ABI; CPU baseline; required feature set; forbidden feature set; minimum SDK; relocation; code model; PIC requirement. Empty scalar/set means no constraint. Matching is exactly section 8.4; no expression field exists. -`ToolchainV1` tags are: 1 schema; 2 ID; 3 version; 4 protocol record; 5 sorted -`Tool` records; 6 sorted platform descriptors; 7 sorted profiles; 8 sorted link -policies; 9 runtime/provider records; 10 bundle tree digest/signature provenance. +`ToolchainV1` tags are: 1 schema; 2 ID; 3 version; 4 the same complete protocol +record used by action tag 3; 5 sorted `Tool` records; 6 sorted platform +descriptors; 7 sorted profiles; 8 sorted link policies; 9 runtime/provider +records; 10 bundle tree digest/signature provenance. A `Tool` is `(name, bundle-relative path, executable blob digest, ordered dynamic tool dependencies, resource-tree digests, adapter record)` tags 1–6. A link policy is `LinkPolicyV1`: tag 1 product-platform descriptor; 2 product kind; 3 @@ -1373,9 +1398,9 @@ record. In a resolved action, those records and every artifact field above are `InputSlotRefV1` values; source/action/provider output digests live only in action tag 10. A sidecar's internal artifact digest must equal the corresponding object/archive/shared input-slot digest, and its contract digest must equal the -referenced native-ABI input record. Section/layout/provenance digests inside a -sidecar are verification facts, not locators from which the action may read -undeclared content. +kind-16 `TypedDigestV1` of the referenced native-ABI input record. +Section/layout/provenance digests inside a sidecar are verification facts, not +locators from which the action may read undeclared content. | Tag | `NativeABIContractV1` field | Rule | |---|---|---| @@ -1389,9 +1414,12 @@ undeclared content. | 8 | minimum-platform | optional `PlatformVersionV1` | | 9 | code | `NativeCodeContractV1` | -Its identity is -`SHA256("WW-NATIVE-ABI-CONTRACT-V1\0" || u64be(length) || WWAR(contract))`. -WW computes it; a supplied digest is never accepted in place of the record. +Its typed record identity is `record_id(16, 1, contract)` as defined in section +6.6. Every schema-1 digest identifying a complete `NativeABIContractV1` is the +corresponding record-domain, kind-16, schema-1 `TypedDigestV1`. WW computes it; a +supplied digest is never accepted in place of the record. Subordinate layout, +calling-convention, type-contract, and header-contract digests remain their +separately specified semantic values. | Tag | `NativeABIPlatformV1` field | Rule | |---|---|---| @@ -1565,7 +1593,9 @@ referenced init symbol against section garbage collection. `.wwe` is a cache/build protocol, not source text and not a long-term binary distribution promise. It starts with the eight-byte magic `WWEX\0\0\0\1` and a -WWAR-encoded body containing: +WWAR-encoded body. The magic is fixed framing that is reconstructed and verified +around the body; it does not create a second blob identity. The typed `.wwe` +identity is `record_id(18, 1, ExportV1)` over that body. The body contains: 1. export schema, language edition, type-system protocol, and required reader capabilities; @@ -1712,7 +1742,8 @@ An immutable toolchain bundle has a canonical `toolchain.wwt` descriptor with: ww-toolchain 1 id = "ww.org/toolchain" version = "v1.4.0" -protocols = { language = "1", export = "1", object = "1", runtime = "1" } +protocols = { language = "1", compiler = "1", export = "1", object = "1", + runtime = "1", manifest = 1, lock = 1 } tool "wwc" { path = "bin/wwc", digest = "sha256:..." } tool "cc" { path = "bin/clang", digest = "sha256:..." }