diff --git a/dag/extdeps/deepseek/deepseek_v4_1_flash.dag b/dag/extdeps/deepseek/deepseek_v4_1_flash.dag index 6a32daa4345..1283b26170d 100644 --- a/dag/extdeps/deepseek/deepseek_v4_1_flash.dag +++ b/dag/extdeps/deepseek/deepseek_v4_1_flash.dag @@ -2,6 +2,8 @@ module extdeps.deepseek.deepseek_v4_1_flash import std.types { NonEmptyStr, String, Bool, List } import std.nat { Nat, nat_range_inclusive } +import std.list { list_cover, list_member, duplicated_by_key, distinct_by_key } +import std.decimal { zero_pad_left } import std.measure { TokenCount, token_count, token_count_value, ParameterCount, parameter_count, @@ -642,6 +644,364 @@ data deepseek_v4_1_flash_engram_shards: List = [ deepseek_v4_1_flash_engram_shard_14, ] +// THE WEIGHT MANIFEST: every safetensors shard at this revision with the publisher's sha256 (the +// LFS object id) and whole-file size, read from `hub_repo_tree_api_url` at dba1be0a on 2026-09-21 +// (48 files; deepseek_v4_1_flash_admit_weight_manifest establishes the exact population -- every +// generated shard path once, the index's shard set, the count, the sizes summed against +// deepseek_v4_1_flash_safetensors_tree_file_bytes -- and the two Engram shard rows are DERIVED from +// deepseek_v4_1_flash_engram_shard_1 / _14, the rows that own them, rather than declared twice). +// These are the publisher's DECLARED digests, cited to the tree API at the revision; a fleet-side +// reading over bytes present on a Spark is the same declared frontier as the Engram rows +// (DSV41-10). The ADMITTED manifest is what the V4.1 candidate's weights axis is keyed by: +// gunbc.spark.v41_runtime_candidate digests its canonical text and never the raw rows. +// A PUBLISHED FILE AT THIS REVISION: its path, whole-file size and the publisher's sha256. One +// record for every file the candidate is keyed by -- the weight shards and the tokenizer files -- +// and one canonical serialization (deepseek_v4_1_flash_published_manifest_text) for both lists. +type DeepseekV41PublishedFile sole_constructor { + path: NonEmptyStr + file_bytes: ByteSize + sha256: Sha256Digest +} + +// A row from its three facts -- the one constructor a claim may supply a population through +// (the record is sole_constructor: production rows are declared here, with their provenance). +fn deepseek_v4_1_flash_published_file_row(path: NonEmptyStr, file_bytes: ByteSize, sha256_hex: Sha256DigestHex) -> DeepseekV41PublishedFile { + DeepseekV41PublishedFile { path: path, file_bytes: file_bytes, sha256: Sha256Digest { hex: sha256_hex } } +} + +// The two Engram shards are the rows deepseek_v4_1_flash_engram_shard_1 / _14 already own (path, +// size, digest, plus the header bytes only they carry); the manifest takes them from there. +fn deepseek_v4_1_flash_published_file_of_engram(shard: DeepseekV41EngramShard) -> DeepseekV41PublishedFile { + DeepseekV41PublishedFile { path: shard.file.path, file_bytes: shard.file.file_bytes, sha256: shard.sha256 } +} + +data deepseek_v4_1_flash_weight_manifest_backbone_rows: List = [ + DeepseekV41PublishedFile { path: "model-00001-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 970533624), sha256: Sha256Digest { hex: "886aebdafa08cc27bbae2165ed35bdfe0de9370bf88c1411283c155c6ae4ff89" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00002-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 1323858272), sha256: Sha256Digest { hex: "4320066fc6958e5bc01d8c3feba79b7454b59f0f4b7299ab7145ed44bbf4ecec" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00003-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389759032), sha256: Sha256Digest { hex: "e1281f85d0ce4a3dfb63d41926fc4a47fa71f36ba20992e3597e702ead49d4c9" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00004-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389759032), sha256: Sha256Digest { hex: "79456c9db0cda3b8115fe1c726fe3db1a34b434584a3991917088a0ab56a39de" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00005-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7405953784), sha256: Sha256Digest { hex: "4a42dc78698bee6b1a821aa01c9650749ef1f716143751f1cdb815c6400280a9" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00006-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389759032), sha256: Sha256Digest { hex: "020a6df51a2853452561d91268a65481f7a7d7954ed47f8e6c9ce69a4a134f77" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00007-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389759032), sha256: Sha256Digest { hex: "40f8b52f763f6380d41257e1af04eee3aad300af6a418c38e49ff99e3604163a" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00008-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389759032), sha256: Sha256Digest { hex: "d62cca4e698f030d4b96ec624c08bed7ad604cec13077da6d6b06669281c4650" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00009-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389759032), sha256: Sha256Digest { hex: "1ca62e4c294df31aee69a782974cb14269264fdc08465ab4835760258f05d6ef" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00010-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389759032), sha256: Sha256Digest { hex: "dd33c9750a40cbfcdfb19cd8335d955f533e3a18b790c0ee43d1e5d77911595c" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00011-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7405953784), sha256: Sha256Digest { hex: "a9b309f90e0d1e2252a224ed6b057b9c82c27d3a49cff64bfbfef12efd067f7c" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00012-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389759032), sha256: Sha256Digest { hex: "b359227eceb3f839c80de19dddf946648ca89425d9b719ff44702cf5e8cfbe0e" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00013-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "41d87a4c81fec1550f9cb975db05598a18ee0161c2664e8e1a0c7b60742755a6" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00014-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "e7ca4a12688a5819829ead3a03282aedb380e438bc41a00e969f70952c6d0eb9" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00015-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "fa9d49314bbb25118b3d52c573ed66a4d0acfb01dcb26d8367f43c66a52f46c4" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00016-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "07d08bce9d73d416eaca0f42843440a8c45c5f939eff1a3690fb460d8dd7f623" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00017-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7405956128), sha256: Sha256Digest { hex: "3d35e330a6c28cd59a06a1caab8b0048f7e12cc037d728736f74431c4c0a1a4c" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00018-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "48bd0c28b7f441f131f562cb664366d7726447a3698da3dd56ebbfeb1b916c75" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00019-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "b7a25cb64a959ca5e5a99e239bb1ba2092b9bcf022bec4ba71f7441334107bd1" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00020-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "8aea8c4026ba4b93e82b4ed1b6b4620d02b6aaac88d211aaf577acea443aff84" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00021-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "4cb6558dedfdc75a6be472e27bc3e830d8443a3371854e61dc54454a1b5b18f7" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00022-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "81031b68c967539a7c51d1b12d37d18de926ca3045ec554ccdd49a83b4dc0084" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00023-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7400713088), sha256: Sha256Digest { hex: "096723fc8afa9886b976fb63aabef159406dc483e6f2a41e3fe386435b0436cc" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00024-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "c9438ff607bd902fdeb38267d36239ccf60d38595988364562b862791841da75" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00025-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "4227ef9fe34d10de584d67250845fab905cbd8462fd84d9da24d772f223db6b4" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00026-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "0af8c8f1b96b502eda652a0549cf55cd8a4d472a34d27ef9bf1c1d7c4567ca3f" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00027-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7395337384), sha256: Sha256Digest { hex: "3066bd03043726d2400302cb9af759ec4e3957a935d56e241b83b52870322e28" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00028-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "9bc915075568b75e2aec9c645cc0fece6287f115c32031a52ab4f9ba9d12fde6" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00029-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "d153dd9cde7c4aa7ea9896cf7aa25b49447af573f90ad14cfaaa532fbbd19434" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00030-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "3c9ccd96e908e00f02a70930b0821a6c53e5301376a261284a092e1aea7bb5da" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00031-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7395337384), sha256: Sha256Digest { hex: "0de7b6d7142df18ad45a215e9c0ef004f78cdbfefd59cc16345b2bc004047343" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00032-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "6a5aaa73c6f97294bd079914ba44209ecf3d0491c8b95ef9995655511e35aee6" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00033-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "386e3e91f7f02f7e2c25f398b3a63379051c2077839b3081f7556e18c29a69c9" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00034-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "9deab3c4f27c956f91cd989d9a1f6cf4bbb91858ce3f7164caa5ae61125c943f" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00035-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7395337384), sha256: Sha256Digest { hex: "226573bc07f35091b0ec27b0056ab3059f9bc1c0afd0bc104c93c86dd029cad2" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00036-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "90d6a85c1eb0cae68c6c7bffa11b60654ea00353d27a0ae17701b72e239894cd" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00037-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "207aef18f995fdfe7506175aabd700aa62dcf6f488c7cc375e9de06f56891b83" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00038-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "cbbaa0b0807311807a696efec09f9b5a5d63bdf68b82378e1fc7402a2533c627" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00039-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7395337384), sha256: Sha256Digest { hex: "f4cf191547b50efbc35c4ed1f36cfb26043d94f987c49d54b15ef2d632a14a77" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00040-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "e991bfc416055c45ddb89f1447eae1e67dba2816e7580044ffff3db7e2af27a3" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00041-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "48a1c08afadf4e73223c587f9c6ad6f32aef57c01342ae75e96b07a001711d42" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00042-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 7389761368), sha256: Sha256Digest { hex: "e1a4d5d30ae51bafda75078d49b05a585c924b0af9b3481c075b04341507c2ef" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00043-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 1323837624), sha256: Sha256Digest { hex: "d762b688f138e00a24eac96f27b842715bb4b534ecc9ca39076bed2b8c33201e" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00044-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 2652728736), sha256: Sha256Digest { hex: "9a6b39fb88a2510487a8efaef77aa7864e8061f6b62c95a0f010e9dd538f3b05" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00045-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 2573998176), sha256: Sha256Digest { hex: "0cc9d5f6ca3a2158ccc63ce2c70c76aeda8177d54913340481af566680329eb5" as Sha256DigestHex } }, + DeepseekV41PublishedFile { path: "model-00046-of-00048.safetensors" as NonEmptyStr, file_bytes: byte_size(count: 2706402896), sha256: Sha256Digest { hex: "e625902027b9d23d416f8818c665fab4704e0b96dc1bc778321601b700475a9d" as Sha256DigestHex } }, +] + +data deepseek_v4_1_flash_weight_manifest: List = concat( + deepseek_v4_1_flash_weight_manifest_backbone_rows, + map(deepseek_v4_1_flash_engram_shards, s => deepseek_v4_1_flash_published_file_of_engram(shard: s)), +) + +// THE CANONICAL TEXT OF A FILE POPULATION: one line per file -- path, digest, size -- with the +// rows SORTED BY PATH. A population is set-like (the identity rule for shard and wheel +// populations: reordering the same files leaves the identity unchanged), so list order may not +// reach the digest; the path is injective over an admitted population (duplicates refuse before +// this text is written), the digest is fixed-width and the size is decimal, so the encoding is +// injective too: a path, a digest or a size that changes changes the text. +fn deepseek_v4_1_flash_published_manifest_text(rows: List) -> String { + join(map(sort_by(rows, fn(r) { r.path as String }), r => join([r.path as String, " ", r.sha256.hex as String, " ", to_string(byte_size_count(b: r.file_bytes))], "")), "\n") +} + +fn deepseek_v4_1_flash_published_rows_bytes(rows: List) -> ByteSize { + byte_size(count: fold(rows, init: 0, f: (acc, r) => acc + byte_size_count(b: r.file_bytes))) +} + +// THE GENERATED SHARD PATHS: `model--of-.safetensors` for i in 1..n, the only paths a +// safetensors shard population of n may carry. The admission below is an identity join against +// them in both directions. +fn deepseek_v4_1_flash_shard_path(index: Nat, count: Nat) -> NonEmptyStr { + join(["model-", zero_pad_left(digits: to_string(index), width: 5), "-of-", zero_pad_left(digits: to_string(count), width: 5), ".safetensors"], "") as NonEmptyStr +} + +fn deepseek_v4_1_flash_shard_paths() -> List { + map(nat_range_inclusive(1, deepseek_v4_1_flash_safetensors_shard_count), i => deepseek_v4_1_flash_shard_path(index: i, count: deepseek_v4_1_flash_safetensors_shard_count)) +} + +// THE SAFETENSORS INDEX AT THIS REVISION, as a published file (resolved bytes, sha256 taken over +// them on 2026-09-21) and as READ: its weight_map names, as shard files, exactly the generated +// paths above -- every one of the 48 appears and no other path does (the tensor count it also +// carries is deepseek_v4_1_flash_index_tensor_count, a fact about the population fold, not about +// this admission, so the reading does not carry it). That reading is what the manifest admission +// reconciles the file population against: a shard file the index never names, or an index shard +// no file carries, is a refusal. +data deepseek_v4_1_flash_safetensors_index_file: DeepseekV41PublishedFile = DeepseekV41PublishedFile { + path: deepseek_v4_1_flash_safetensors_index_path, + file_bytes: byte_size(count: 7470294), + sha256: Sha256Digest { hex: "74b0686a3d2891980d5e303251b075a3bccae2c2ff650747db2620a649b98fa8" as Sha256DigestHex }, +} + +type DeepseekV41IndexReading sole_constructor { + file: DeepseekV41PublishedFile + shard_paths: List +} + +// A reading from its two facts, the constructor a claim supplies a divergent index through. +fn deepseek_v4_1_flash_index_reading_of(file: DeepseekV41PublishedFile, shard_paths: List) -> DeepseekV41IndexReading { + DeepseekV41IndexReading { file: file, shard_paths: shard_paths } +} + +// THE WEIGHT_MAP'S SHARD POPULATION AS READ -- the distinct values of the index's weight_map, +// transcribed from the file whose digest is cited above (read 2026-09-21), NOT derived from the +// generator the admission joins them against: a reading that was the generator would make the +// index join green by construction. It happens to equal the generated set at this revision, which +// is the fact the admission establishes rather than assumes; an index naming one shard fewer, or +// one more, is a refusal the witness drives with a supplied reading. +data deepseek_v4_1_flash_index_weight_map_shards: List = [ + "model-00001-of-00048.safetensors" as NonEmptyStr, + "model-00002-of-00048.safetensors" as NonEmptyStr, + "model-00003-of-00048.safetensors" as NonEmptyStr, + "model-00004-of-00048.safetensors" as NonEmptyStr, + "model-00005-of-00048.safetensors" as NonEmptyStr, + "model-00006-of-00048.safetensors" as NonEmptyStr, + "model-00007-of-00048.safetensors" as NonEmptyStr, + "model-00008-of-00048.safetensors" as NonEmptyStr, + "model-00009-of-00048.safetensors" as NonEmptyStr, + "model-00010-of-00048.safetensors" as NonEmptyStr, + "model-00011-of-00048.safetensors" as NonEmptyStr, + "model-00012-of-00048.safetensors" as NonEmptyStr, + "model-00013-of-00048.safetensors" as NonEmptyStr, + "model-00014-of-00048.safetensors" as NonEmptyStr, + "model-00015-of-00048.safetensors" as NonEmptyStr, + "model-00016-of-00048.safetensors" as NonEmptyStr, + "model-00017-of-00048.safetensors" as NonEmptyStr, + "model-00018-of-00048.safetensors" as NonEmptyStr, + "model-00019-of-00048.safetensors" as NonEmptyStr, + "model-00020-of-00048.safetensors" as NonEmptyStr, + "model-00021-of-00048.safetensors" as NonEmptyStr, + "model-00022-of-00048.safetensors" as NonEmptyStr, + "model-00023-of-00048.safetensors" as NonEmptyStr, + "model-00024-of-00048.safetensors" as NonEmptyStr, + "model-00025-of-00048.safetensors" as NonEmptyStr, + "model-00026-of-00048.safetensors" as NonEmptyStr, + "model-00027-of-00048.safetensors" as NonEmptyStr, + "model-00028-of-00048.safetensors" as NonEmptyStr, + "model-00029-of-00048.safetensors" as NonEmptyStr, + "model-00030-of-00048.safetensors" as NonEmptyStr, + "model-00031-of-00048.safetensors" as NonEmptyStr, + "model-00032-of-00048.safetensors" as NonEmptyStr, + "model-00033-of-00048.safetensors" as NonEmptyStr, + "model-00034-of-00048.safetensors" as NonEmptyStr, + "model-00035-of-00048.safetensors" as NonEmptyStr, + "model-00036-of-00048.safetensors" as NonEmptyStr, + "model-00037-of-00048.safetensors" as NonEmptyStr, + "model-00038-of-00048.safetensors" as NonEmptyStr, + "model-00039-of-00048.safetensors" as NonEmptyStr, + "model-00040-of-00048.safetensors" as NonEmptyStr, + "model-00041-of-00048.safetensors" as NonEmptyStr, + "model-00042-of-00048.safetensors" as NonEmptyStr, + "model-00043-of-00048.safetensors" as NonEmptyStr, + "model-00044-of-00048.safetensors" as NonEmptyStr, + "model-00045-of-00048.safetensors" as NonEmptyStr, + "model-00046-of-00048.safetensors" as NonEmptyStr, + "model-00047-of-00048.safetensors" as NonEmptyStr, + "model-00048-of-00048.safetensors" as NonEmptyStr +] + +data deepseek_v4_1_flash_index_reading: DeepseekV41IndexReading = DeepseekV41IndexReading { + file: deepseek_v4_1_flash_safetensors_index_file, + shard_paths: deepseek_v4_1_flash_index_weight_map_shards, +} + +// THE WEIGHT MANIFEST IS ADMITTED, NOT COUNTED. A count and a byte total let a duplicated row of +// one size stand in for an omitted row of the same size; admission establishes the exact +// population: no duplicate path, no path outside the generated shard set, every generated path +// present (an identity join both ways), the declared count and total, and the index's shard +// population equal to the files'. Only an admitted manifest has a canonical text, and that text +// carries the INDEX FILE as a row beside the shards -- the index is the weight map, so an index +// that changes is a different model source even over the same shard bytes; the candidate +// (gunbc.spark.v41_runtime_candidate) consumes this standing, never the raw row list, so a +// defective population is an unestablished model source rather than a differently keyed one. +type DeepseekV41WeightManifestStanding + = WeightManifestAdmitted { files: List, index: DeepseekV41PublishedFile, canonical_text: String } + | WeightManifestRefused { defects: List } + +fn path_eq(a: NonEmptyStr, b: NonEmptyStr) -> Bool { + (a as String) == (b as String) +} + +fn deepseek_v4_1_flash_admit_weight_manifest(rows: List, index: DeepseekV41IndexReading, shard_count: Nat, tree_bytes: ByteSize) -> DeepseekV41WeightManifestStanding { + let generated = map(nat_range_inclusive(1, shard_count), i => deepseek_v4_1_flash_shard_path(index: i, count: shard_count)) + let paths = map(rows, r => r.path) + let duplicate = map(duplicated_by_key(rows, fn(r) { r.path as String }), d => join(["path declared more than once: ", d.path as String], "") as NonEmptyStr) + let foreign = map(filter(paths, p => !list_member(xs: generated, x: p, eq: path_eq)), p => join(["path outside the generated shard set: ", p as String], "") as NonEmptyStr) + let missing = map(filter(generated, g => !list_member(xs: paths, x: g, eq: path_eq)), g => join(["generated shard path absent: ", g as String], "") as NonEmptyStr) + let count = if length(rows) == shard_count { [] as List } else { [join(["row count ", to_string(length(rows)), " is not the shard count ", to_string(shard_count)], "") as NonEmptyStr] } + let total = if byte_size_count(b: deepseek_v4_1_flash_published_rows_bytes(rows: rows)) == byte_size_count(b: tree_bytes) { [] as List } else { ["the rows' sizes do not sum to the tree's safetensors bytes" as NonEmptyStr] } + let index_join = if list_cover(held: paths, expected: index.shard_paths, eq: path_eq) && length(index.shard_paths) == length(paths) { [] as List } else { ["the index's weight_map shard population is not the file population" as NonEmptyStr] } + let defects = concat(duplicate, concat(foreign, concat(missing, concat(count, concat(total, index_join))))) + if length(defects) == 0 { + WeightManifestAdmitted { files: sort_by(rows, fn(r) { r.path as String }), index: index.file, canonical_text: deepseek_v4_1_flash_published_manifest_text(rows: concat(rows, [index.file])) } + } else { + WeightManifestRefused { defects: defects } + } +} + +fn deepseek_v4_1_flash_weight_manifest_standing() -> DeepseekV41WeightManifestStanding { + deepseek_v4_1_flash_admit_weight_manifest(rows: deepseek_v4_1_flash_weight_manifest, index: deepseek_v4_1_flash_index_reading, shard_count: deepseek_v4_1_flash_safetensors_shard_count, tree_bytes: deepseek_v4_1_flash_safetensors_tree_file_bytes) +} + +// A PUBLISHED FILE BY PATH, from the manifest: the one read the Engram shard rows derive from. +fn deepseek_v4_1_flash_published_file(path: NonEmptyStr) -> DeepseekV41PublishedFile? { + first(filter(deepseek_v4_1_flash_weight_manifest, r => (r.path as String) == (path as String))) +} + +// THE TOKENIZER POPULATION, BY ROLE. Every role a serving runtime needs of the tokenizer side is +// named and each says how the publisher carries it at this revision: an exact published file, a +// file another role's file embeds it in, no separate file at all (established by reading the tree +// at the revision), or not consumed by this runtime. The files at this revision (tree API at +// dba1be0a, 2026-09-21): tokenizer.json, tokenizer_config.json and encoding/encoding.py; there is +// no special_tokens_map.json, no generation_config.json and no Jinja chat template +// (deepseek_v4_1_flash_encoder_has_no_jinja_chat_template) -- the prompt encoding IS the encoder +// module. The digests were taken over the resolved bytes (the tokenizer files are not LFS objects, +// so the tree API carries only their git blob id). +type DeepseekV41TokenizerRole + = TokenizerVocabulary + | TokenizerConfiguration + | TokenizerSpecialTokens + | TokenizerPromptEncoding + | TokenizerGenerationDefaults + +fn deepseek_v4_1_flash_tokenizer_role_wire(r: DeepseekV41TokenizerRole) -> NonEmptyStr { + match r { + TokenizerVocabulary => "vocabulary" as NonEmptyStr + TokenizerConfiguration => "configuration" as NonEmptyStr + TokenizerSpecialTokens => "special-tokens" as NonEmptyStr + TokenizerPromptEncoding => "prompt-encoding" as NonEmptyStr + TokenizerGenerationDefaults => "generation-defaults" as NonEmptyStr + } +} + +type DeepseekV41RoleCarrier + = RolePublishedFile { file: DeepseekV41PublishedFile } + | RoleEmbeddedIn { file: DeepseekV41PublishedFile } + | RoleNoSeparateFile { established_at: NonEmptyStr } + | RoleNotConsumedByRuntime + +type DeepseekV41TokenizerRoleRow sole_constructor { + role: DeepseekV41TokenizerRole + carrier: DeepseekV41RoleCarrier +} + +fn deepseek_v4_1_flash_tokenizer_role_row(role: DeepseekV41TokenizerRole, carrier: DeepseekV41RoleCarrier) -> DeepseekV41TokenizerRoleRow { + DeepseekV41TokenizerRoleRow { role: role, carrier: carrier } +} + +data deepseek_v4_1_flash_tokenizer_json_file: DeepseekV41PublishedFile = DeepseekV41PublishedFile { path: "tokenizer.json" as NonEmptyStr, file_bytes: byte_size(count: 6367257), sha256: Sha256Digest { hex: "c90dfa01249db1be4245780a052ede752e1361c612ac6d08e2bdada7d599476b" as Sha256DigestHex } } +data deepseek_v4_1_flash_tokenizer_config_file: DeepseekV41PublishedFile = DeepseekV41PublishedFile { path: "tokenizer_config.json" as NonEmptyStr, file_bytes: byte_size(count: 801), sha256: Sha256Digest { hex: "6ac8c8dc065ed118161d02dd532749ae3f52c243deac27872134fae2f50d8547" as Sha256DigestHex } } +data deepseek_v4_1_flash_encoder_file: DeepseekV41PublishedFile = DeepseekV41PublishedFile { path: deepseek_v4_1_flash_encoder_path, file_bytes: byte_size(count: 37316), sha256: Sha256Digest { hex: "502bdaec8a3fd88ebc24c4721a7038fbe42f2063c664638127056107920035c1" as Sha256DigestHex } } + +// Special tokens: tokenizer.json carries the added-token table (1283 entries) and +// tokenizer_config.json names bos/eos/pad among them; there is no special_tokens_map.json. +// Generation defaults: no generation_config.json at the revision; sampling defaults are the +// runtime's, not the publisher's. +data deepseek_v4_1_flash_tokenizer_roles: List = [ + DeepseekV41TokenizerRoleRow { role: TokenizerVocabulary, carrier: RolePublishedFile { file: deepseek_v4_1_flash_tokenizer_json_file } }, + DeepseekV41TokenizerRoleRow { role: TokenizerConfiguration, carrier: RolePublishedFile { file: deepseek_v4_1_flash_tokenizer_config_file } }, + DeepseekV41TokenizerRoleRow { role: TokenizerSpecialTokens, carrier: RoleEmbeddedIn { file: deepseek_v4_1_flash_tokenizer_json_file } }, + DeepseekV41TokenizerRoleRow { role: TokenizerPromptEncoding, carrier: RolePublishedFile { file: deepseek_v4_1_flash_encoder_file } }, + DeepseekV41TokenizerRoleRow { role: TokenizerGenerationDefaults, carrier: RoleNoSeparateFile { established_at: deepseek_v4_1_flash_revision } }, +] + +data deepseek_v4_1_flash_tokenizer_required_roles: List = [TokenizerVocabulary, TokenizerConfiguration, TokenizerSpecialTokens, TokenizerPromptEncoding, TokenizerGenerationDefaults] + +// THE TOKENIZER POPULATION IS ADMITTED BY ROLE COVER AND KEYED BY THE ROLE MANIFEST: every +// required role has exactly one row; an embedding role names a file some published-file row +// carries with the SAME identity (path, size, digest); two published-file rows naming one path +// with different identities refuse rather than coalesce. The canonical text is the sorted ROLE +// rows -- role, carrier arm, and the exact file identity, the establishing revision or the +// not-consumed disposition -- so a role that moves from embedded to not consumed, or a +// no-separate-file fact re-established at another revision, changes the key while the file set +// stays the same; the file population is a projection beside it, not the identity. A role with no +// row is an obligation, not an empty line. +type DeepseekV41TokenizerStanding + = TokenizerPopulationAdmitted { files: List, canonical_text: String } + | TokenizerPopulationRefused { defects: List } + +fn published_file_identity_line(f: DeepseekV41PublishedFile) -> String { + join([f.path as String, " ", f.sha256.hex as String, " ", to_string(byte_size_count(b: f.file_bytes))], "") +} + +fn published_file_identity_eq(a: DeepseekV41PublishedFile, b: DeepseekV41PublishedFile) -> Bool { + published_file_identity_line(f: a) == published_file_identity_line(f: b) +} + +fn tokenizer_role_line(r: DeepseekV41TokenizerRoleRow) -> String { + join([deepseek_v4_1_flash_tokenizer_role_wire(r: r.role) as String, " ", match r.carrier { + RolePublishedFile { file: f } => join(["published-file ", published_file_identity_line(f: f)], "") + RoleEmbeddedIn { file: f } => join(["embedded-in ", published_file_identity_line(f: f)], "") + RoleNoSeparateFile { established_at: rev } => join(["no-separate-file ", rev as String], "") + RoleNotConsumedByRuntime => "not-consumed-by-runtime" + }], "") +} + +fn deepseek_v4_1_flash_tokenizer_manifest_text(rows: List) -> String { + join(map(sort_by(rows, fn(r) { deepseek_v4_1_flash_tokenizer_role_wire(r: r.role) as String }), r => tokenizer_role_line(r: r)), "\n") +} + +fn role_eq(a: DeepseekV41TokenizerRole, b: DeepseekV41TokenizerRole) -> Bool { + (deepseek_v4_1_flash_tokenizer_role_wire(r: a) as String) == (deepseek_v4_1_flash_tokenizer_role_wire(r: b) as String) +} + +fn deepseek_v4_1_flash_admit_tokenizer_population(rows: List, required: List) -> DeepseekV41TokenizerStanding { + let roles = map(rows, r => r.role) + let duplicate = map(duplicated_by_key(rows, fn(r) { deepseek_v4_1_flash_tokenizer_role_wire(r: r.role) as String }), d => join(["tokenizer role carried twice: ", deepseek_v4_1_flash_tokenizer_role_wire(r: d.role) as String], "") as NonEmptyStr) + let missing = map(filter(required, q => !list_member(xs: roles, x: q, eq: role_eq)), q => join(["tokenizer role without a carrier: ", deepseek_v4_1_flash_tokenizer_role_wire(r: q) as String], "") as NonEmptyStr) + let published_all = fold(rows, init: [] as List, f: (acc, r) => match r.carrier { RolePublishedFile { file: f } => concat(acc, [f]) _ => acc }) + let published = distinct_by_key(published_all, fn(f) { f.path as String }) + let conflicting = map(filter(duplicated_by_key(published_all, fn(f) { f.path as String }), d => any(filter(published_all, q => path_eq(a: q.path, b: d.path)), q => !published_file_identity_eq(a: q, b: d))), d => join(["published path carried with two identities: ", d.path as String], "") as NonEmptyStr) + let embedded_unbacked = fold(rows, init: [] as List, f: (acc, r) => match r.carrier { + RoleEmbeddedIn { file: f } => if list_member(xs: published, x: f, eq: published_file_identity_eq) { acc } else { concat(acc, [join(["tokenizer role ", deepseek_v4_1_flash_tokenizer_role_wire(r: r.role) as String, " is embedded in a file no role publishes with that identity: ", f.path as String], "") as NonEmptyStr]) } + _ => acc + }) + let defects = concat(duplicate, concat(missing, concat(conflicting, embedded_unbacked))) + if length(defects) == 0 { + TokenizerPopulationAdmitted { files: sort_by(published, fn(f) { f.path as String }), canonical_text: deepseek_v4_1_flash_tokenizer_manifest_text(rows: rows) } + } else { + TokenizerPopulationRefused { defects: defects } + } +} + +fn deepseek_v4_1_flash_tokenizer_standing() -> DeepseekV41TokenizerStanding { + deepseek_v4_1_flash_admit_tokenizer_population(rows: deepseek_v4_1_flash_tokenizer_roles, required: deepseek_v4_1_flash_tokenizer_required_roles) +} + // THE SHARD FILES REACH THE POPULATION FOLD, so the tensor extents are bounded by the payload each // shard's own header declares rather than only by each other. data deepseek_v4_1_flash_engram_shard_files: List = map(deepseek_v4_1_flash_engram_shards, s => s.file) diff --git a/dag/gunbc/auth/approval_gate.dag b/dag/gunbc/auth/approval_gate.dag new file mode 100644 index 00000000000..e4a7016a082 --- /dev/null +++ b/dag/gunbc/auth/approval_gate.dag @@ -0,0 +1,286 @@ +module gunbc.auth.approval_gate + +import std.types { String, Bool, Int, NonEmptyStr, List, Timestamp } +import std.measure { Second, second_count } +import v2.std.optional { Present, Absent } +import std.resources { Network } +import std.algebra { trim } +import std.scoped_authorization { + AuthorizationRequest, ScopedAuthorization, authorize, AuthorizationPermitted, AuthorizationRefused, authorization_refusal_reason, +} +import extdeps.clock { Clock } +import extdeps.filesystem.filesystem_io { Filesystem } +import extdeps.http.client +import extdeps.tools.sleep { sleep_delay_seconds_second_carrier_projection } +import extdeps.github.actions_environment { github_runner_temp_variable_name } +import gunbc.clock_read { clock_now_probed_at } +import gunbc.actions_run_binding { actions_variable_trimmed } +import gunbc.auth.approval_capability { utc_instant_is_canonical } +import gunbc.auth.approval_decision_store { grant_from_approved_decision, GrantDerived, GrantForAnotherIntent, request_revision_of, StoredApprovalRequest } +import gunbc.auth.approval_keyring_pins { approval_submission_mac_key_path_env } +import gunbc.auth.approval_request_client { + sign_stored_request, approval_submit_url, approval_status_url, approval_poll_standing, + SubmissionMacReady, SubmissionMacKeyNotHex, + ApprovalPollStanding, PollApproved, PollDenied, PollExpired, PollStillPending, PollNotFiled, PollUnreadable, +} +import gunbc.auth.approval_request_submission { submission_envelope_json } +import gunbc.auth.approval_status_wire { parse_filed_approval_status, FiledApprovalStatus, StatusUnreadable, submission_body_admits_poll } + +// THE OPERATOR'S DECISION AS A GATE, ONCE, FOR EVERY SUBJECT. A run that needs the operator's +// consent files a signed request with the approval broker, polls its standing, and turns an +// approval over the exact request revision into the ScopedAuthorization it acts under. +// Every ingredient of that route is already generic over the subject (std.scoped_authorization, +// gunbc.auth.approval_decision_store), so the gate is too: the Mt. Collins boot and the pair-serving +// D0 transaction each rebind it to their subject rather than carrying a copy (DESIGN 2: net concepts +// must not grow by re-invention -- the second adopter is when the shared fold becomes payable). +// +// A gate is a reading of the broker's standing joined to one request. It names, distinctly, every +// way the run does not proceed: the decision is still pending, was never filed, expired undecided, +// was denied, was taken over another intent, could not be read, or is a grant std.scoped_authorization +// refuses for this request. Only GateAdmitted carries an authorization. + +// THE REFUSALS HAVE THEIR OWN CARRIER, one that cannot hold an authorization: every non-admitted +// standing is a cause, and a value that is not GateAdmitted is by construction one nothing may +// act under. The recorded-decision fold below shares the same cause carrier for its negative arm +// for the same reason -- "not recorded" cannot smuggle an admission. +type ApprovalGateRefusal + = ApprovalPending { escalation_id: NonEmptyStr } + | ApprovalNotFiled { escalation_id: NonEmptyStr } + | ApprovalDenied { reason: NonEmptyStr } + | ApprovalExpired + | ApprovalIntentMismatch { requested_revision: NonEmptyStr, decided_revision: NonEmptyStr } + | ApprovalStoreUnreadable { detail: NonEmptyStr } + | ApprovalAuthorizeRefused { detail: NonEmptyStr } + +type ApprovalGate + = GateAdmitted { authorization: ScopedAuthorization } + | GateRefused { cause: ApprovalGateRefusal } + +// The standing read once for both folds: every non-approved standing is its cause, and an +// approval is its four decision facts. Neither fold has an arm the other's reading cannot reach. +type ApprovalReading + = ApprovalUndecided { cause: ApprovalGateRefusal } + | ApprovalDecidedApproved { revision: NonEmptyStr, decided_by: NonEmptyStr, decided_at: Timestamp, execute_by: Timestamp } + +fn approval_reading(poll: ApprovalPollStanding, request: AuthorizationRequest) -> ApprovalReading { + match poll { + PollStillPending => ApprovalUndecided { cause: ApprovalPending { escalation_id: request.escalation_id } } + PollNotFiled => ApprovalUndecided { cause: ApprovalNotFiled { escalation_id: request.escalation_id } } + PollExpired => ApprovalUndecided { cause: ApprovalExpired } + PollUnreadable { detail: d } => ApprovalUndecided { cause: ApprovalStoreUnreadable { detail: d } } + PollDenied { revision: r, decided_by: _, decided_at: _, reason: why } => + if r != request_revision_of(request: request) { ApprovalUndecided { cause: ApprovalIntentMismatch { requested_revision: request_revision_of(request: request), decided_revision: r } } } + else { ApprovalUndecided { cause: ApprovalDenied { reason: why } } } + PollApproved { revision: r, decided_by: by, decided_at: at, execute_by: until } => ApprovalDecidedApproved { revision: r, decided_by: by, decided_at: at, execute_by: until } + } +} + +// An approval over this request's revision derives to its authorization, or names why not. +type ApprovalDerivation + = ApprovalDerived { authorization: ScopedAuthorization } + | ApprovalNotDerived { cause: ApprovalGateRefusal } + +fn approval_derive(reading: ApprovalReading, request: AuthorizationRequest) -> ApprovalDerivation { + match reading { + ApprovalUndecided { cause: c } => ApprovalNotDerived { cause: c } + ApprovalDecidedApproved { revision: r, decided_by: by, decided_at: at, execute_by: until } => + match grant_from_approved_decision(request: request, revision: r, decided_by: by, decided_at: at, execute_by: until) { + GrantForAnotherIntent { requested_revision: a, decided_revision: b } => ApprovalNotDerived { cause: ApprovalIntentMismatch { requested_revision: a, decided_revision: b } } + GrantDerived { authorization: auth } => ApprovalDerived { authorization: auth } + _ => ApprovalNotDerived { cause: ApprovalStoreUnreadable { detail: "the approved decision did not yield a grant" as NonEmptyStr } } + } + } +} + +// THE LIVE GATE: the derived authorization is admitted only if std.scoped_authorization permits +// it at the observed instant, so a grant whose window has not opened or has closed refuses. This +// is the only fold that mints GateAdmitted. +fn approval_gate_from_poll(poll: ApprovalPollStanding, request: AuthorizationRequest, observed_at: Timestamp) -> ApprovalGate { + match approval_derive(reading: approval_reading(poll: poll, request: request), request: request) { + ApprovalNotDerived { cause: c } => GateRefused { cause: c } + ApprovalDerived { authorization: auth } => + match authorize(authorization: auth, request: request, observed_at: observed_at) { + AuthorizationPermitted { grant: _ } => GateAdmitted { authorization: auth } + AuthorizationRefused { cause: c } => GateRefused { cause: ApprovalAuthorizeRefused { detail: join(["scoped authorization refused the approved grant for this request: ", authorization_refusal_reason(cause: c)], "") as NonEmptyStr } } + } + } +} + +// THE DECISION AS RECORDED is a different fact from an admission to begin, and it has its own +// constructor so the two cannot inhabit one arm. An approval over exactly this request's revision +// is handed back as the authorization it derives to -- expired or not -- and NOTHING here says the +// caller may act under it: the right to finish what an approval began belongs to the lifecycle +// that durably claimed it, and only a consumer holding that proof (gunbc.spark.pair_serving_d0_authorization +// d0_resumable_authorization joins it to the D0 claim slot) may turn a recorded approval into a +// resume. Every other standing is the live gate's arm, so a caller cannot mistake "not approved" +// for "recorded". +type RecordedApproval + = ApprovalRecorded { authorization: ScopedAuthorization } + | ApprovalNotRecorded { cause: ApprovalGateRefusal } + +fn approval_recorded_from_poll(poll: ApprovalPollStanding, request: AuthorizationRequest) -> RecordedApproval { + match approval_derive(reading: approval_reading(poll: poll, request: request), request: request) { + ApprovalNotDerived { cause: c } => ApprovalNotRecorded { cause: c } + ApprovalDerived { authorization: auth } => ApprovalRecorded { authorization: auth } + } +} + +fn approval_refusal_text(cause: ApprovalGateRefusal) -> String { + match cause { + ApprovalPending { escalation_id: e } => join(["escalation ", e as String, " is still pending the operator's decision"], "") + ApprovalNotFiled { escalation_id: e } => join(["escalation ", e as String, " is not filed with the approval broker"], "") + ApprovalDenied { reason: r } => join(["the operator denied the request: ", r as String], "") + ApprovalExpired => "the approval window expired before a decision" + ApprovalIntentMismatch { requested_revision: a, decided_revision: b } => join(["the decision is over another intent (requested ", a as String, ", decided ", b as String, ")"], "") + ApprovalStoreUnreadable { detail: d } => join(["the approval store could not be read: ", d as String], "") + ApprovalAuthorizeRefused { detail: d } => d as String + } +} + +fn approval_gate_text(g: ApprovalGate) -> String { + match g { + GateAdmitted { authorization: _ } => "admitted" + GateRefused { cause: c } => approval_refusal_text(cause: c) + } +} + +// ── THE INSTANT ────────────────────────────────────────────────────────────────────────────── +// A clock probe is admitted as an instant only when it is canonical UTC; the probe's own +// "clock-unreadable" rendering and any other non-instant refuse, so no String reaches a +// permission decision or a claim as a timestamp. +fn approval_instant_from_probe(reading: NonEmptyStr?) -> Timestamp? { + match reading { + Absent => none + Present { value: ts } => if utc_instant_is_canonical(t: ts as Timestamp) { Present { value: ts as Timestamp } } else { none } + } +} + +fn approval_instant_now() -> Timestamp? { + approval_instant_from_probe(reading: clock_now_probed_at()) +} + +fn approval_expires_at(issued: Timestamp, window: Second) -> Timestamp { + Clock.TimestampAdd(timestamp: issued, offset: second_count(s: window)).result +} + +// ── THE STANDING READ ──────────────────────────────────────────────────────────────────────── +fn approval_status_from_get(success: Bool, body: String) -> FiledApprovalStatus { + if success { parse_filed_approval_status(body: body) } + else { StatusUnreadable { detail: "status GET did not succeed; the decision's standing is unknown, not pending" as NonEmptyStr } } +} + +// THE EFFECTFUL READS ARE NOT GENERIC -- the language realizes no declaration carrying both type +// parameters and a `uses` row -- and they need not be: what the broker is asked about is the +// escalation id, and what comes back is a standing at an instant. The subject enters only in the +// pure gate fold above, which the caller applies to the standing the read returns. +// +// A SPENT WAITING BUDGET IS NOT AN EXPIRED WINDOW. Only the timestamp fold (approval_poll_standing, +// against the filed expires_at) may say the operator can no longer decide; a run that stops +// waiting while the filing is still live says so as PollBudgetExhausted, whose remedy is to rerun +// or keep polling the SAME filing, where expiry's remedy is a deliberate new request. +type ApprovalStandingRead + = StandingReadAt { standing: ApprovalPollStanding, observed_at: Timestamp } + | StandingClockUnreadable + +type ApprovalPollOutcome + = PollObservedAt { standing: ApprovalPollStanding, observed_at: Timestamp } + | PollBudgetExhausted { escalation_id: NonEmptyStr, observed_at: Timestamp } + | PollClockUnreadable + +// One read of the broker's standing for this escalation, judged at a fresh canonical instant. +fn approval_standing_read(escalation_id: NonEmptyStr, expires_at: Timestamp) -> ApprovalStandingRead + uses net: Network +{ + match approval_instant_now() { + Absent => StandingClockUnreadable + Present { value: observed } => { + let got = http.Client.GetLocalhostBounded(url: approval_status_url(escalation_id: escalation_id)) + StandingReadAt { standing: approval_poll_standing(status: approval_status_from_get(success: got.success, body: got.body), observed_at: observed, expires_at: expires_at), observed_at: observed } + } + } +} + +// THE DECISION AFTER ONE READ, pure, so the ordering the bounded poll depends on is a witnessed +// fact rather than a property of the wet recursion: a decided standing returns as read; a pending +// one continues while ticks remain and is the exhausted budget when none do -- never an expiry. +type ApprovalPollStep + = PollReturn { outcome: ApprovalPollOutcome } + | PollSleepAndContinue { next_remaining: Int } + +fn approval_poll_step(escalation_id: NonEmptyStr, standing: ApprovalPollStanding, observed_at: Timestamp, remaining: Int) -> ApprovalPollStep { + match standing { + PollStillPending => + if remaining <= 0 { PollReturn { outcome: PollBudgetExhausted { escalation_id: escalation_id, observed_at: observed_at } } } + else { PollSleepAndContinue { next_remaining: remaining - 1 } } + _ => PollReturn { outcome: PollObservedAt { standing: standing, observed_at: observed_at } } + } +} + +// THE BOUNDED POLL: N waits and a terminal read at the declared boundary, each read at a fresh +// instant, each step decided by approval_poll_step. +fn approval_poll_ticks(remaining: Int, cadence: Second, escalation_id: NonEmptyStr, expires_at: Timestamp) -> ApprovalPollOutcome + uses net: Network +{ + match approval_standing_read(escalation_id: escalation_id, expires_at: expires_at) { + StandingClockUnreadable => PollClockUnreadable + StandingReadAt { standing: standing, observed_at: observed } => + match approval_poll_step(escalation_id: escalation_id, standing: standing, observed_at: observed, remaining: remaining) { + PollReturn { outcome: o } => o + PollSleepAndContinue { next_remaining: n } => { + let _paced = sleep_delay_seconds_second_carrier_projection(duration: cadence) + approval_poll_ticks(remaining: n, cadence: cadence, escalation_id: escalation_id, expires_at: expires_at) + } + } + } +} + +// The gate over a poll outcome, admitted live at the outcome's own instant. +fn approval_gate_from_outcome(outcome: ApprovalPollOutcome, request: AuthorizationRequest) -> ApprovalGate { + match outcome { + PollClockUnreadable => GateRefused { cause: ApprovalStoreUnreadable { detail: "clock unreadable; refusing to judge expiry against a fabricated instant" as NonEmptyStr } } + PollBudgetExhausted { escalation_id: e, observed_at: _ } => GateRefused { cause: ApprovalPending { escalation_id: e } } + PollObservedAt { standing: standing, observed_at: observed } => approval_gate_from_poll(poll: standing, request: request, observed_at: observed) + } +} + +// ── THE FILING ─────────────────────────────────────────────────────────────────────────────── +// The signed submission: the MAC key the keyring pinned, the stored request over this window, +// the envelope written owner-only under RUNNER_TEMP, one POST, the body wiped. Every refusal +// names what was missing and happens before the broker is reached. +type ApprovalFiling + = ApprovalFiled + | ApprovalFilingRefused { reason: String } + +fn approval_file_stored_request(stored: StoredApprovalRequest, body_file_name: String, submit_timeout: Second) -> ApprovalFiling + uses net: Network +{ + let sub_path = actions_variable_trimmed(name: approval_submission_mac_key_path_env) + if sub_path == "" { + ApprovalFilingRefused { reason: join([approval_submission_mac_key_path_env as String, " is unset; the request cannot be filed"], "") } + } else { + let key_read = Filesystem.Read(path: sub_path) + if !key_read.success { + ApprovalFilingRefused { reason: join(["submission MAC key unreadable: ", key_read.error], "") } + } else { + match sign_stored_request(key_material: trim(s: key_read.content), request: stored) { + SubmissionMacKeyNotHex { key_id: k } => ApprovalFilingRefused { reason: join(["submission MAC key is not hex: ", k as String], "") } + SubmissionMacReady { tag_hex: tag } => { + let tmp = actions_variable_trimmed(name: github_runner_temp_variable_name as NonEmptyStr) + if tmp == "" { + ApprovalFilingRefused { reason: "RUNNER_TEMP is unset; cannot write the submit body" } + } else { + let body_path = join([tmp, "/", body_file_name], "") + let written = Filesystem.WriteOwnerOnly(path: body_path, content: submission_envelope_json(request: stored, tag_hex: tag)) + if !written.success { + ApprovalFilingRefused { reason: join(["could not write the submit body: ", written.error], "") } + } else { + let posted = http.Client.PostJsonFromFile(url: approval_submit_url(), request_body_file: body_path as NonEmptyStr, max_seconds: to_string(second_count(s: submit_timeout)) as NonEmptyStr) + let _wiped = Filesystem.Delete(path: body_path) + if submission_body_admits_poll(body: posted.body) { ApprovalFiled } else { ApprovalFilingRefused { reason: join(["POST /approvals refused: ", posted.body], "") } } + } + } + } + } + } + } +} diff --git a/dag/gunbc/auth/approval_request_client.dag b/dag/gunbc/auth/approval_request_client.dag index cafb82c65a7..f7aceb0336d 100644 --- a/dag/gunbc/auth/approval_request_client.dag +++ b/dag/gunbc/auth/approval_request_client.dag @@ -8,6 +8,7 @@ import extdeps.crypto.mac { import gunbc.auth.approval_status_wire { FiledApprovalStatus, StatusNotFiled, StatusPending, StatusApproved, StatusDenied, StatusUnreadable, } +import gunbc.auth.approval_capability { utc_instant_before } import gunbc.auth.approval_decision_store { StoredApprovalRequest, request_revision_of, approval_mac_key_id, } @@ -90,29 +91,27 @@ type ApprovalPollStanding | PollNotFiled | PollUnreadable { detail: NonEmptyStr } +// THE BOUNDARY IS THE CAPABILITY'S: expires_at is the instant a request STOPS being decidable +// (gunbc.auth.approval_capability admits only observed_at < expires_at), so equality is expired +// here too -- a client that still called the operator's request pending at the very second the +// broker can no longer redeem the capability would wait for a decision that cannot land. +// THE FILED REQUEST'S OWN WINDOW GOVERNS A PENDING STANDING. A pending status carries the +// expires_at the broker filed (the one the operator was shown); the caller's expires_at is the +// window it would file under and governs only a request that is NOT filed. A rerun that computes +// a fresh window may therefore not extend a pending filing past what was filed, and a decision is +// a decision whenever it is read. fn approval_poll_standing( status: FiledApprovalStatus, observed_at: Timestamp, expires_at: Timestamp, ) -> ApprovalPollStanding { - if observed_at > expires_at { - match status { - StatusApproved { revision: r, decided_by: by, decided_at: at, execute_by: until } => - PollApproved { revision: r, decided_by: by, decided_at: at, execute_by: until } - StatusDenied { revision: r, decided_by: by, decided_at: at, reason: why } => - PollDenied { revision: r, decided_by: by, decided_at: at, reason: why } - StatusUnreadable { detail: d } => PollUnreadable { detail: d } - _ => PollExpired - } - } else { - match status { - StatusNotFiled => PollNotFiled - StatusPending { expires_at: _ } => PollStillPending - StatusApproved { revision: r, decided_by: by, decided_at: at, execute_by: until } => - PollApproved { revision: r, decided_by: by, decided_at: at, execute_by: until } - StatusDenied { revision: r, decided_by: by, decided_at: at, reason: why } => - PollDenied { revision: r, decided_by: by, decided_at: at, reason: why } - StatusUnreadable { detail: d } => PollUnreadable { detail: d } - } + match status { + StatusApproved { revision: r, decided_by: by, decided_at: at, execute_by: until } => + PollApproved { revision: r, decided_by: by, decided_at: at, execute_by: until } + StatusDenied { revision: r, decided_by: by, decided_at: at, reason: why } => + PollDenied { revision: r, decided_by: by, decided_at: at, reason: why } + StatusUnreadable { detail: d } => PollUnreadable { detail: d } + StatusPending { expires_at: filed } => if utc_instant_before(a: observed_at, b: filed) { PollStillPending } else { PollExpired } + StatusNotFiled => if utc_instant_before(a: observed_at, b: expires_at) { PollNotFiled } else { PollExpired } } } diff --git a/dag/gunbc/machine_intake/mtcollins1_boot_authorization.dag b/dag/gunbc/machine_intake/mtcollins1_boot_authorization.dag index e5ff58719d7..ad50041a875 100644 --- a/dag/gunbc/machine_intake/mtcollins1_boot_authorization.dag +++ b/dag/gunbc/machine_intake/mtcollins1_boot_authorization.dag @@ -1,6 +1,6 @@ module gunbc.machine_intake_mtcollins1_boot_authorization -import std.types { Bool, List, NonEmptyStr, String, Timestamp } +import std.types { Bool, List, NonEmptyStr, String } import std.content_hash { ContentHash, content_hash_of_value } import std.effect_grant { NamespacePosition, ServiceOpTree, Write } import std.scoped_authorization { @@ -8,20 +8,6 @@ import std.scoped_authorization { AttemptIdentity, AuthorizationScope, AuthorizationRequest, - ScopedAuthorization, - AuthorizationGranted, - AuthorizationDenied, - authorize, - AuthorizationPermitted, - AuthorizationRefused, -} -import gunbc.auth.approval_decision_store { - grant_from_approved_decision, GrantDerived, GrantForAnotherIntent, - request_revision_of, -} -import gunbc.auth.approval_request_client { - ApprovalPollStanding, PollApproved, PollDenied, PollExpired, PollStillPending, - PollNotFiled, PollUnreadable, } import gunbc.machine_intake_mtcollins1_boot_artifact { mtcollins1_diskless_image_name, mtcollins1_boot_export_dir } import gunbc.machine_intake_mtcollins1_boot_image_fetch { mtcollins1_boot_image_sha256 } @@ -199,54 +185,9 @@ fn mtcollins1_boot_authorization_request( } } -type MtCollins1BootGate - = BootGateAdmitted { authorization: ScopedAuthorization } - | BootGatePending { escalation_id: NonEmptyStr } - | BootGateDenied { reason: NonEmptyStr } - | BootGateExpired - | BootGateNotFiled { escalation_id: NonEmptyStr } - | BootGateIntentMismatch { requested_revision: NonEmptyStr, decided_revision: NonEmptyStr } - | BootGateStoreUnreadable { detail: NonEmptyStr } - | BootGateAuthorizeRefused { detail: NonEmptyStr } - -fn mtcollins1_boot_gate_from_poll( - poll: ApprovalPollStanding, - request: AuthorizationRequest, - observed_at: Timestamp, -) -> MtCollins1BootGate { - match poll { - PollStillPending => BootGatePending { escalation_id: request.escalation_id } - PollNotFiled => BootGateNotFiled { escalation_id: request.escalation_id } - PollExpired => BootGateExpired - PollUnreadable { detail: d } => BootGateStoreUnreadable { detail: d } - PollDenied { revision: r, decided_by: _, decided_at: _, reason: why } => - if r != request_revision_of(request: request) { - BootGateIntentMismatch { - requested_revision: request_revision_of(request: request), - decided_revision: r, - } - } else { - BootGateDenied { reason: why } - } - PollApproved { revision: r, decided_by: by, decided_at: at, execute_by: until } => - match grant_from_approved_decision( - request: request, - revision: r, - decided_by: by, - decided_at: at, - execute_by: until, - ) { - GrantForAnotherIntent { requested_revision: a, decided_revision: b } => - BootGateIntentMismatch { requested_revision: a, decided_revision: b } - GrantDerived { authorization: auth } => - match authorize(authorization: auth, request: request, observed_at: observed_at) { - AuthorizationPermitted { grant: _ } => BootGateAdmitted { authorization: auth } - AuthorizationRefused { cause: _ } => - BootGateAuthorizeRefused { detail: "scoped authorization refused the HTTP grant for this request" as NonEmptyStr } - } - _ => - BootGateStoreUnreadable { detail: "approved GET standing did not yield a grant" as NonEmptyStr } - } - } -} +// THE GATE IS THE SHARED ONE. The operator's decision over this subject is read through +// gunbc.auth.approval_gate, generic over the subject: ApprovalGate and +// approval_gate_from_poll, admitted live at the observed instant. Nothing about the gate is a fact +// about Mt. Collins, so nothing about it is declared here. + diff --git a/dag/gunbc/machine_intake/mtcollins1_boot_run.dag b/dag/gunbc/machine_intake/mtcollins1_boot_run.dag index f768605b970..57dac858e04 100644 --- a/dag/gunbc/machine_intake/mtcollins1_boot_run.dag +++ b/dag/gunbc/machine_intake/mtcollins1_boot_run.dag @@ -23,26 +23,17 @@ import gunbc.machine_intake_mtcollins1_census_medium_readback { mtcollins1_census_medium_readback, mtcollins1_census_readback_refusal_before_filing, mtcollins1_census_readback_refusal_before_attach, } import gunbc.machine_intake_mtcollins1_boot_authorization { - MtCollins1BootGate, MtCollins1BootMedium, MtCollins1CensusMedium, MtCollins1StockInstallerMedium, mtcollins1_boot_medium, mtcollins1_boot_medium_image_name, mtcollins1_boot_medium_image_sha256, mtcollins1_boot_medium_label, MtCollins1BootSubject, mtcollins1_boot_authorization_request, - mtcollins1_boot_gate_from_poll, - BootGateAdmitted, BootGatePending, BootGateDenied, BootGateExpired, BootGateNotFiled, - BootGateIntentMismatch, BootGateStoreUnreadable, BootGateAuthorizeRefused, } -import gunbc.auth.approval_request_client { - stored_request_from_authorization, sign_stored_request, - approval_submit_url, approval_status_url, - approval_poll_standing, - SubmissionMacReady, SubmissionMacKeyNotHex, - PollStillPending, +import gunbc.auth.approval_gate { + ApprovalGate, GateAdmitted, GateRefused, ApprovalPending, ApprovalDenied, ApprovalExpired, ApprovalNotFiled, ApprovalIntentMismatch, ApprovalStoreUnreadable, ApprovalAuthorizeRefused, + approval_instant_now, approval_expires_at, approval_poll_ticks, approval_gate_from_outcome, + approval_file_stored_request, ApprovalFiled, ApprovalFilingRefused, } -import gunbc.auth.approval_status_wire { - parse_filed_approval_status, FiledApprovalStatus, StatusUnreadable, submission_body_admits_poll, -} -import gunbc.auth.approval_request_submission { submission_envelope_json } +import gunbc.auth.approval_request_client { stored_request_from_authorization } import gunbc.auth.approval_keyring_pins { approval_submission_mac_key_path_env } import gunbc.machine_intake_mtcollins1_media_attach { mtcollins1_attach_diskless_image } import gunbc.machine_intake_mtcollins1_actuate { mtcollins1_bmc_username, mtcollins1_drive_handoff } @@ -54,19 +45,15 @@ import gunbc.machine_intake_host_capture_envelope { } import gunbc.machine_intake_mtcollins1_access_observation { mtcollins1_endpoint, mtcollins1_capability_row } import gunbc.host_reset_return_run { host_reset_bmc_credential_path_env } -import gunbc.clock_read { clock_now_probed_at } -import gunbc.auth.approval_capability { utc_instant_is_canonical } -import extdeps.clock { Clock } import v2.std.optional { Present } import gunbc.actions_run_binding { actions_variable_read, ActionsVariablePresent, ActionsVariableAbsent, actions_variable_trimmed, fleet_converge_expected_host_env_name } import gunbc.fleet_intent_network { operator_host_srv1 } -import extdeps.github.actions_environment { github_run_id_variable_name, github_sha_variable_name, github_runner_temp_variable_name } +import extdeps.github.actions_environment { github_run_id_variable_name, github_sha_variable_name } import extdeps.bmc.ipmi import gunbc.machine_intake_sol_hold { mtcollins1_sol_hold_shell_emit_dissolution_trigger } import std.dissolution { dissolution_description } import extdeps.tools.sleep { sleep_delay_seconds_second_carrier_projection } import extdeps.filesystem.filesystem_io { Filesystem } -import extdeps.http.client import std.durable_compare_and_set { CasGeneration } data mtcollins1_boot_label: String = "mtcollins1 boot" @@ -95,6 +82,8 @@ data mtcollins1_boot_cleanup_allowance: Second = second(count: 180) data mtcollins1_boot_submit_timeout: Second = second(count: 30) +data mtcollins1_boot_submit_body_file_name: String = "mtcollins1-approval-submit.json" + fn mtcollins1_boot_approval_window() -> Second { second(count: mtcollins1_boot_poll_tick_budget * (second_count(s: mtcollins1_boot_poll_cadence) as Int)) } @@ -108,50 +97,25 @@ fn mtcollins1_boot_step_timeout_minutes() -> Minute { minute(count: (secs + 59) / 60) } -fn mtcollins1_status_from_get(success: Bool, body: String) -> FiledApprovalStatus { - if success { - parse_filed_approval_status(body: body) - } else { - StatusUnreadable { detail: "status GET did not succeed; the roadmap standing is unknown, not pending" as NonEmptyStr } - } -} - -fn mtcollins1_approval_expires_at(issued: Timestamp) -> Timestamp? { - if !utc_instant_is_canonical(t: issued) { - none - } else { - Present { value: Clock.TimestampAdd(timestamp: issued, offset: second_count(s: mtcollins1_boot_approval_window())).result } - } -} - -fn mtcollins1_boot_refusal(gate: MtCollins1BootGate) -> ProcessExit { +fn mtcollins1_boot_refusal(gate: ApprovalGate) -> ProcessExit { match gate { - BootGateAdmitted { authorization: _ } => ExitSuccess - BootGatePending { escalation_id: e } => - exit_failure(reason: concat("mtcollins1 boot: still pending operator decision for ", e as String)) - BootGateDenied { reason: r } => - exit_failure(reason: concat("mtcollins1 boot: operator denied; controller untouched: ", r as String)) - BootGateExpired => - exit_failure(reason: "mtcollins1 boot: approval window expired; controller untouched") - BootGateNotFiled { escalation_id: e } => - exit_failure(reason: concat("mtcollins1 boot: no request filed for ", e as String)) - BootGateIntentMismatch { requested_revision: a, decided_revision: b } => - exit_failure(reason: concat("mtcollins1 boot: stored decision is for another intent (", concat(a as String, concat(" vs ", b as String)), ")")) - BootGateStoreUnreadable { detail: d } => - exit_failure(reason: concat("mtcollins1 boot: approval store unreadable: ", d as String)) - BootGateAuthorizeRefused { detail: d } => - exit_failure(reason: concat("mtcollins1 boot: grant present but authorize refused: ", d as String)) - } -} - -fn mtcollins1_boot_instant_from_probe(reading: NonEmptyStr?) -> Timestamp? { - match reading { - Absent => none - Present { value: ts } => - if utc_instant_is_canonical(t: ts as Timestamp) { - Present { value: ts as Timestamp } - } else { - none + GateAdmitted { authorization: _ } => ExitSuccess + GateRefused { cause: c } => + match c { + ApprovalPending { escalation_id: e } => + exit_failure(reason: concat("mtcollins1 boot: still pending operator decision for ", e as String)) + ApprovalDenied { reason: r } => + exit_failure(reason: concat("mtcollins1 boot: operator denied; controller untouched: ", r as String)) + ApprovalExpired => + exit_failure(reason: "mtcollins1 boot: approval window expired; controller untouched") + ApprovalNotFiled { escalation_id: e } => + exit_failure(reason: concat("mtcollins1 boot: no request filed for ", e as String)) + ApprovalIntentMismatch { requested_revision: a, decided_revision: b } => + exit_failure(reason: concat("mtcollins1 boot: stored decision is for another intent (", concat(a as String, concat(" vs ", b as String)), ")")) + ApprovalStoreUnreadable { detail: d } => + exit_failure(reason: concat("mtcollins1 boot: approval store unreadable: ", d as String)) + ApprovalAuthorizeRefused { detail: d } => + exit_failure(reason: concat("mtcollins1 boot: grant present but authorize refused: ", d as String)) } } } @@ -440,7 +404,7 @@ fn mtcollins1_boot_settle_from_fresh_clock( ) -> ProcessExit uses fs: std.resources.Filesystem { - match mtcollins1_boot_instant_from_probe(reading: clock_now_probed_at()) { + match approval_instant_now() { Absent => unterminated_claim_exit( label: mtcollins1_boot_label, @@ -460,7 +424,7 @@ fn mtcollins1_boot_settle_from_fresh_clock( } fn mtcollins1_boot_after_gate( - gate: MtCollins1BootGate, + gate: ApprovalGate, request: AuthorizationRequest, password_file: String, attempt: String, @@ -470,8 +434,8 @@ fn mtcollins1_boot_after_gate( uses net: std.resources.Network { match gate { - BootGateAdmitted { authorization: auth } => - match mtcollins1_boot_instant_from_probe(reading: clock_now_probed_at()) { + GateAdmitted { authorization: auth } => + match approval_instant_now() { Absent => exit_failure(reason: "mtcollins1 boot: clock unreadable; cannot decide whether the operator grant has expired before a controller write") Present { value: at } => @@ -544,36 +508,6 @@ fn mtcollins1_boot_after_gate( } } -fn mtcollins1_boot_poll_ticks( - remaining: Int, - request: AuthorizationRequest, - expires_at: Timestamp, -) -> MtCollins1BootGate - uses net: std.resources.Network -{ - match mtcollins1_boot_instant_from_probe(reading: clock_now_probed_at()) { - Absent => - BootGateStoreUnreadable { - detail: "clock unreadable; refusing to judge expiry against a fabricated instant" as NonEmptyStr, - } - Present { value: observed } => - if remaining <= 0 { - BootGateExpired - } else { - let got = http.Client.GetLocalhostBounded(url: approval_status_url(escalation_id: request.escalation_id)) - let status = mtcollins1_status_from_get(success: got.success, body: got.body) - let standing = approval_poll_standing(status: status, observed_at: observed, expires_at: expires_at) - match standing { - PollStillPending => { - let _paced = sleep_delay_seconds_second_carrier_projection(duration: mtcollins1_boot_poll_cadence) - mtcollins1_boot_poll_ticks(remaining: remaining - 1, request: request, expires_at: expires_at) - } - _ => mtcollins1_boot_gate_from_poll(poll: standing, request: request, observed_at: observed) - } - } - } -} - fn mtcollins1_boot_host_must_be_srv1(host: String) -> Bool { host == operator_host_srv1 as String } @@ -641,49 +575,23 @@ fn mtcollins1_boot_wet_on_srv1() -> ProcessExit attempt: concat("mtcollins1-boot-", run_id) as AttemptIdentity, execution_revision: sha as NonEmptyStr, ) - match mtcollins1_boot_instant_from_probe(reading: clock_now_probed_at()) { + match approval_instant_now() { Absent => exit_failure(reason: "mtcollins1 boot: clock unreadable; cannot mint issued_at or an approval window; controller untouched") Present { value: issued } => { - let expires = match mtcollins1_approval_expires_at(issued: issued) { - Absent => "" - Present { value: e } => e - } - if expires == "" { - return exit_failure(reason: "mtcollins1 boot: issued_at is not a canonical UTC instant; cannot mint an approval window; controller untouched") - } - let stored = stored_request_from_authorization(request: request, issued_at: issued, expires_at: expires) - let key_read = Filesystem.Read(path: sub_path) - if !key_read.success { - return exit_failure(reason: concat("mtcollins1 boot: submission MAC key unreadable: ", key_read.error)) - } - match sign_stored_request(key_material: trim(s: key_read.content), request: stored) { - SubmissionMacKeyNotHex { key_id: k } => - exit_failure(reason: concat("mtcollins1 boot: submission MAC key is not hex: ", k as String)) - SubmissionMacReady { tag_hex: tag } => { - let tmp = actions_variable_trimmed(name: github_runner_temp_variable_name as NonEmptyStr) - if tmp == "" { - return exit_failure(reason: "mtcollins1 boot: RUNNER_TEMP is unset; cannot write the submit body") - } - let body_path = concat(tmp, "/mtcollins1-approval-submit.json") - let body = submission_envelope_json(request: stored, tag_hex: tag) - let written = Filesystem.WriteOwnerOnly(path: body_path, content: body) - if !written.success { - return exit_failure(reason: concat("mtcollins1 boot: could not write submit body: ", written.error)) - } - let posted = http.Client.PostJsonFromFile( - url: approval_submit_url(), - request_body_file: body_path as NonEmptyStr, - max_seconds: to_string(second_count(s: mtcollins1_boot_submit_timeout)) as NonEmptyStr, - ) - let _wiped = Filesystem.Delete(path: body_path) - if !submission_body_admits_poll(body: posted.body) { - return exit_failure(reason: concat("mtcollins1 boot: POST /approvals refused; controller untouched; ", posted.body)) - } - let gate = mtcollins1_boot_poll_ticks( - remaining: mtcollins1_boot_poll_tick_budget, + let expires = approval_expires_at(issued: issued, window: mtcollins1_boot_approval_window()) + match approval_file_stored_request(stored: stored_request_from_authorization(request: request, issued_at: issued, expires_at: expires), body_file_name: mtcollins1_boot_submit_body_file_name, submit_timeout: mtcollins1_boot_submit_timeout) { + ApprovalFilingRefused { reason: r } => + exit_failure(reason: concat("mtcollins1 boot: ", concat(r, "; controller untouched"))) + ApprovalFiled => { + let gate = approval_gate_from_outcome( + outcome: approval_poll_ticks( + remaining: mtcollins1_boot_poll_tick_budget, + cadence: mtcollins1_boot_poll_cadence, + escalation_id: escalation, + expires_at: expires, + ), request: request, - expires_at: expires, ) let pw_read = Filesystem.Read(path: cred) if !pw_read.success { diff --git a/dag/gunbc/roadmap/roadmap_authority.dag b/dag/gunbc/roadmap/roadmap_authority.dag index be673ac5621..8fbf393fbf8 100644 --- a/dag/gunbc/roadmap/roadmap_authority.dag +++ b/dag/gunbc/roadmap/roadmap_authority.dag @@ -2836,7 +2836,7 @@ fn declared_roadmap_nodes() -> List { headline: "Cut D D0: suspend Group A under an exact operator consent, read the fleet inside it, settle to one typed terminal, and never free a host early", boundary: "gunbc.spark.pair_serving_d0 over gunbc.spark.pair_serving_authority_log on the fabric DB: one durable genesis per group partition, the host-placement partition as the linearization point, prepare -> append-claim -> authority -> finalize as one saga bound by a typed AuthorityWriteIntent, consumed/cancelled exclusivity, claim-bound quiescence evidence, total crash recovery by lifecycle identity, the operator consent slot as a fabric-DB head (gunbc.durable_cas_fabric_storage, generation-bearing objects), and a wet door that refuses while the store's write walls are missing. STATE (2026-09-20, wound down under operator direction to re-prioritize v1 performance and v2 migration): the whole stack is one branch, plan/dsv41-cut-d-2b, re-rooted onto the rewritten main and source-approved through twenty-one review rounds; the operator ruled it may land under the widened fabric-DB principal drop. Its stacked follow-up branch, plan/dsv41-cut-d-2b-admission-cleanup, deletes the twenty transition-admission rows the stack consumed and carries the detached-process wet-lane admission row.", displaced_cost: "Without D0 the V4.1 cut over Group A has no transaction: no consent that is spent exactly once across executors, no state in which the group is neither serving nor being mutated by two writers, and no receipt of the fleet as it was read before the authority moved -- the prior state, in which membership and placement were roster words and a crashed lane left no recoverable trace.", - first_slice: "LANDED ON THE BRANCH: the authority log and its folds, the saga and both joined reads, D0 recovery, the fabric-DB CAS, the quiescence observer, the front-door and head-host absence readings, 32 hermetic + 9 wet authority-log claims, 21 hermetic + 13 wet + 6 front-door D0 claims, 2 CAS wet claims, host-commitment and seat gates over the current authority. REMAINING, IN ORDER: (1) land plan/dsv41-cut-d-2b, then its admission-cleanup follow-up (operator merge). (2) The fabric-DB write walls: retire gunbc.rung_drop fabric_storage_append_principal_unrefused by its trigger (observed writer-principal roster in fabric_storage_serve) AND restore gunbc.spark.pair_serving_d0 d0_store_operation_wall (per-operation D0 authorization verified at the store) -- the wet door consumes both and refuses until both stand. (3) Cut 0 keys the V4.1 candidate and the escalation -> ScopedAuthorization producer lands, so resolve_d0_authorization can admit; only then is a fleet run of D0 possible. (4) D1 converger: freeze the host population on PairServingActive (retires the one lane-roster dependence stated on authority_fold) and consume released_baseline_retains_reservation. (5) Retire the detached-process wet-lane row (gunbc.ci_layer_roots excl_local_repo_wet_detached_process_reason): a modeled process/listener fixture and mock_response seams for python.Interpreter.RunFile, the pgrep leg, http.Client.StatusWithin and /proc/net/tcp. (6) A v1 resolver defect found and reproduced on the way (a braced import of extdeps.http.client, or v2.std.algebra { filter }, makes the builtins split/last unresolvable inside a match-arm block; minimal fixture recorded on the branch's pull request, round 18) -- owned by the seed lane, avoided here by homing the curl exit codes with extdeps.tools.curl.", + first_slice: "LANDED ON THE BRANCH: the authority log and its folds, the saga and both joined reads, D0 recovery, the fabric-DB CAS, the quiescence observer, the front-door and head-host absence readings, 32 hermetic + 9 wet authority-log claims, 21 hermetic + 13 wet + 6 front-door D0 claims, 2 CAS wet claims, host-commitment and seat gates over the current authority. REMAINING, IN ORDER: (1) land plan/dsv41-cut-d-2b, then its admission-cleanup follow-up (operator merge). (2) The fabric-DB write walls: retire gunbc.rung_drop fabric_storage_append_principal_unrefused by its trigger (observed writer-principal roster in fabric_storage_serve) AND restore gunbc.spark.pair_serving_d0 d0_store_operation_wall (per-operation D0 authorization verified at the store) -- the wet door consumes both and refuses until both stand. (3) Cut 0 keys the V4.1 candidate: the weight manifest is admitted as an exact population reconciled against the index's read shard set, the index file and the tokenizer role manifest are keyed and the escalation -> ScopedAuthorization producer (gunbc.spark.pair_serving_d0_authorization, through gunbc.auth.approval_gate) and the wet door (gunbc.spark.pair_serving_d0_door) are landed by the Cut 0 pull request; the row-store content digest (a fleet read) is the one axis still unestablished, and only once it is keyed is a fleet run of D0 possible. (4) D1 converger: freeze the host population on PairServingActive (retires the one lane-roster dependence stated on authority_fold) and consume released_baseline_retains_reservation. (5) Retire the detached-process wet-lane row (gunbc.ci_layer_roots excl_local_repo_wet_detached_process_reason): a modeled process/listener fixture and mock_response seams for python.Interpreter.RunFile, the pgrep leg, http.Client.StatusWithin and /proc/net/tcp. (6) A v1 resolver defect found and reproduced on the way (a braced import of extdeps.http.client, or v2.std.algebra { filter }, makes the builtins split/last unresolvable inside a match-arm block; minimal fixture recorded on the branch's pull request, round 18) -- owned by the seed lane, avoided here by homing the curl exit codes with extdeps.tools.curl.", red_control: "A stranger's abort of a prepared or claimed preparation refuses with nothing written; a cancelled preparation cannot be consumed and a consumed one cannot be cancelled; an authority event that is not the exact write its append claim named is unread on every join; a cycled CAS value does not let a stale writer advance at fabric_storage_advance; the wet door refuses while either store wall is missing; a 401/500 front door is an answer and a failed connect is absence only when the head host is quiet.", out_of_scope: "Cut 0 candidate keying and the authorization producer; the fabric-DB principal and per-operation walls (fabric-DB lane); D1 convergence; P1 Cut 3 held-seat invalidation; any fleet mutation before the walls stand.", handback: "Group A suspended under an exact consent with the fleet reading recorded on the log, settled to Suspended / restored Active / FencedRefusal, the consent spent once, every host fence released only by observed quiescence, and the placement finalized -- by execution against the fleet, which no branch has yet done.", diff --git a/dag/gunbc/spark/pair_serving_d0.dag b/dag/gunbc/spark/pair_serving_d0.dag index d1b67cb0343..6dcadf92d6c 100644 --- a/dag/gunbc/spark/pair_serving_d0.dag +++ b/dag/gunbc/spark/pair_serving_d0.dag @@ -1,6 +1,6 @@ module gunbc.spark.pair_serving_d0 -import std.types { String, Bool, Int, NonEmptyStr, List, EpochSecs, Port } +import std.types { String, Bool, Int, NonEmptyStr, List, EpochSecs, Port, Timestamp } import std.nat { Nat } import std.measure { Second, second, second_count } import v2.std.optional { Present, Absent } @@ -21,6 +21,7 @@ import std.durable_compare_and_set { } import gunbc.durable_cas_file_store { CasAttemptAdmitted, CasAttemptDigestMismatch, CasAttemptDigestIncomparable, CasAttemptKeyNotSlotAddressable, admit_cas_attempt, + admit_cas_attempt_for_derived_payload, DerivedPayloadAdmitted, DerivedPayloadKeyNotSlotAddressable, } import gunbc.durable_cas_fabric_storage { fabric_storage_compare_and_set, fabric_storage_observe_cas_slot } import extdeps.tools.sha256sum { Sha256FileDigest, Sha256FileDigestUnavailable, sha256sum_stdin_digest_via_shell } @@ -33,6 +34,7 @@ import extdeps.filesystem.filesystem_io { Filesystem } import gunbc.clock_read { clock_now_probed_at, probed_at_word } import gunbc.fabric_event_log_host { HostStoreResolved, HostStoreRefused, event_log_store_for_host, now_epoch_seconds } import gunbc.fabric_storage_client { FabricStorageBinding } +import std.fabric_storage { FabricStoreRefused, fabric_storage_fault_wire } import gunbc.host_effect { FleetSsh } import gunbc.fleet_known_hosts_anchor { FleetSshExecutionContext } import gunbc.rung_drop { Standing, Retired, TypedDeclaration } @@ -60,7 +62,7 @@ import gunbc.spark.pair_incumbent_identity { DeclaredPairRealization, DeclaredRankUnit, DeclaredPairRealizationStanding, DeclaredPairRealizationKeyed, DeclaredPairRealizationUnavailable, declared_pair_realization, observe_pair_realization, PairRealizationAgreement, PairRealizationEstablished, pair_realization_agreement, pair_realization_agreement_lines, } -import gunbc.spark.released_baseline { ReleasedBaselineSpec, QuiescentReservedBaseline, released_baseline_wire } +import gunbc.spark.released_baseline { ReleasedBaselineSpec, QuiescentReservedBaseline, released_baseline_wire, parse_released_baseline } import gunbc.spark.pair_serving_authority { PairServingGroupAuthority, PairServingActive, SuspensionPendingReconciliation, SuspendedForAuthorizedSuccessor, FencedRefusal, PairRealizationKeyed, @@ -137,9 +139,12 @@ import gunbc.spark.pair_serving_authority_log { // THE ENTRY IS NON-ADMITTING UNTIL THE AUTHORIZATION EXISTS, BY CONSTRUCTION. The dispatch // requires an exact, time-bounded operator authorization over the candidate key, this group's // EXACT HOST POPULATION, the cleanup baseline and the lease term (std.scoped_authorization -// OperatorGrant over D0Subject), and a successor that is KEYED (Cut 0). No producer joins an -// escalation to such a grant today and no candidate is keyed, so resolve_d0_authorization answers -// D0AuthorizationUnestablished and the entry refuses before its first write. The transaction +// OperatorGrant over D0Subject), and a successor that is KEYED (Cut 0). The producer that joins an +// escalation to such a grant is gunbc.spark.pair_serving_d0_authorization (the request over the +// keyed successor, the frozen filing re-derived on a rerun, the recorded approval joined to this +// transaction's held claim) consumed through gunbc.auth.approval_gate by the wet door +// gunbc.spark.pair_serving_d0_door, which files, waits and dispatches; while the candidate is +// unkeyed the request has no subject and the door refuses before its first write. The transaction // itself takes the grant as a value, which is how its real-execution witness drives the whole // two-write route with a fixture grant. // @@ -262,6 +267,170 @@ fn d0_request(escalation_id: NonEmptyStr, subject: D0Subject, transaction: NonEm } } +// ── THE FILING: THE REQUEST AS IT WAS ASKED, FROZEN BEFORE IT IS ASKED ───────────────────────── +// +// The operator decides over ONE request revision, and the transaction that revision authorizes may +// outlive the run that filed it: a rerun after a crash must finish the lifecycle under the request +// the operator saw, not under a request rebuilt from today's source (a candidate re-keyed, a host +// population edited, a term changed) -- that rebuild would either be refused as another intent or, +// worse, be admitted over facts nobody consented to. The approval broker keeps the decision, not +// the domain subject. So the request's canonical intent text -- the exact bytes the intent hash is +// taken over, which carry the scope, the group, the attempt and the whole subject -- is frozen on +// the fabric event log under the escalation before the request is filed, at generation 1 with +// ExpectSlotAbsent. A rerun reads it back, re-derives the identical request (same text, same +// hash, same revision) and never files again; a first run that finds the slot already held is a +// rerun that did not know it. +data d0_filing_key_scope: String = "pair-serving-d0-filing-" + +fn d0_filing_key(escalation_id: NonEmptyStr) -> NonEmptyStr { + join([d0_filing_key_scope, escalation_id as String], "") as NonEmptyStr +} + +type D0IntentParsed { + group: FabricGroup + transaction: NonEmptyStr + subject: D0Subject +} + +fn intent_field(line: String, key: String) -> String? { + let prefix = join([key, "="], "") + if starts_with(s: line, prefix: prefix) { Present { value: substring(s: line, start: length(prefix), end: length(line)) } } else { none } +} + +fn subject_field(words: List, key: String) -> String? { + match first(filter(words, w => starts_with(s: w, prefix: join([key, "="], "")))) { + Present { value: w } => intent_field(line: w, key: key) + Absent => none + } +} + +fn parse_d0_hosts(wire: String) -> List { + if wire == "" { [] as List } else { map(split(wire, separator: ","), h => h as HostIdentity) } +} + +fn parse_d0_term(wire: String) -> Second? { + if ends_with(s: wire, suffix: "s") { + match parse_int(s: substring(s: wire, start: 0, end: length(wire) - 1)) { + Present { value: n } => if n >= 0 { Present { value: second(count: n) } } else { none } + Absent => none + } + } else { none } +} + +// The inverse of d0_intent_text, refusing anything that is not one intent under this schema with +// this scope. It is a parse, not a validation: a text that round-trips is by construction the text +// the hash was taken over, so the request it yields carries the filed revision. +fn intent_lines(text: String) -> List { + split(text, separator: "\n") +} + +fn intent_words(line: String) -> List { + split(line, separator: " ") +} + +fn line_at(lines: List, i: Int) -> String { + match first(lines |> skip(n: i)) { Present { value: l } => l Absent => "" } +} + +fn parse_d0_intent_text(text: String) -> D0IntentParsed? { + let lines = intent_lines(text: text) + if line_at(lines: lines, i: 0) != d0_intent_schema { none } + else if line_at(lines: lines, i: 1) != join(["scope=", authorization_scope_render(scope: d0_required_scope())], "") { none } + else { + match intent_field(line: line_at(lines: lines, i: 2), key: "target") { + Absent => none + Present { value: target } => + match parse_fabric_group(wire: target) { + Absent => none + Present { value: group } => + match intent_field(line: line_at(lines: lines, i: 3), key: "attempt") { + Absent => none + Present { value: attempt } => + if attempt == "" { none } else { + let words = intent_words(line: line_at(lines: lines, i: 4)) + match subject_field(words: words, key: "group") { + Absent => none + Present { value: sg } => + match parse_fabric_group(wire: sg) { + Absent => none + Present { value: subject_group } => + match subject_field(words: words, key: "successor") { + Absent => none + Present { value: succ } => + match parse_content_hash(wire: succ) { + Absent => none + Present { value: successor } => + match subject_field(words: words, key: "cleanup") { + Absent => none + Present { value: cl } => + match parse_released_baseline(wire: cl) { + Absent => none + Present { value: cleanup } => + match subject_field(words: words, key: "term") { + Absent => none + Present { value: tw } => + match parse_d0_term(wire: tw) { + Absent => none + Present { value: term } => + match subject_field(words: words, key: "hosts") { + Absent => none + Present { value: hw } => { + let subject = D0Subject { group: subject_group, hosts: parse_d0_hosts(wire: hw), successor: successor, cleanup: cleanup, term: term } + if d0_intent_text(subject: subject, group: group, transaction: attempt as NonEmptyStr) == text { + Present { value: D0IntentParsed { group: group, transaction: attempt as NonEmptyStr, subject: subject } } + } else { none } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } +} + +type D0FilingFreeze + = D0FilingFrozen + | D0FilingAlreadyHeld { text: String } + | D0FilingFreezeRefused { reason: NonEmptyStr } + +fn d0_freeze_filing(store: FabricStorageBinding, escalation_id: NonEmptyStr, intent_text: String) -> D0FilingFreeze { + match admit_cas_attempt_for_derived_payload(key: d0_filing_key(escalation_id: escalation_id), expected: ExpectSlotAbsent, proposed: intent_text as NonEmptyStr) { + DerivedPayloadKeyNotSlotAddressable { key: k } => D0FilingFreezeRefused { reason: join(["filing key is not slot-addressable: ", k as String], "") as NonEmptyStr } + DerivedPayloadAdmitted { verified: v } => + match fabric_storage_compare_and_set(store: store, verified: v) { + CasCommitted { committed: _ } => D0FilingFrozen + CasPreconditionFailed { expected: _, observed: _ } => + match d0_read_filing(store: store, escalation_id: escalation_id) { + D0FilingAt { text: t } => D0FilingAlreadyHeld { text: t } + D0FilingAbsent => D0FilingFreezeRefused { reason: "the filing slot moved and then read absent" as NonEmptyStr } + D0FilingUnreadable { reason: r } => D0FilingFreezeRefused { reason: r } + } + CasStoreRefused { cause: c } => D0FilingFreezeRefused { reason: join(["the filing could not be frozen: ", fabric_storage_fault_wire(fault: FabricStoreRefused { cause: c })], "") as NonEmptyStr } + } + } +} + +type D0FilingReading + = D0FilingAbsent + | D0FilingAt { text: String } + | D0FilingUnreadable { reason: NonEmptyStr } + +fn d0_read_filing(store: FabricStorageBinding, escalation_id: NonEmptyStr) -> D0FilingReading { + match fabric_storage_observe_cas_slot(store: store, key: d0_filing_key(escalation_id: escalation_id)) { + CasObservedUnreadable { cause: c } => D0FilingUnreadable { reason: join(["filing slot unreadable: ", cas_unreadable_slot_detail(cause: c)], "") as NonEmptyStr } + CasObservedReadable { readable: CasReadableAbsent } => D0FilingAbsent + CasObservedReadable { readable: CasReadablePresent { version: v } } => D0FilingAt { text: v.value as String } + } +} + // ── THE CLAIM: CONSENT IS CONSUMED ONCE, FLEET-WIDE, BEFORE THE FIRST WRITE ──────────────────── // // std.scoped_authorization decides whether a grant PERMITS an operation; it models single use as @@ -284,7 +453,7 @@ type D0ClaimStanding | D0ClaimLost { holder: NonEmptyStr } | D0ClaimUndecided { reason: NonEmptyStr } -fn d0_claim_grant(store: FabricStorageBinding, escalation_id: NonEmptyStr, transaction: NonEmptyStr, now: String) -> D0ClaimStanding { +fn d0_claim_grant(store: FabricStorageBinding, escalation_id: NonEmptyStr, transaction: NonEmptyStr, now: Timestamp) -> D0ClaimStanding { let proposed = claim_transition_claimed(attempt: (transaction as String) as AttemptIdentity, at: now) match admit_cas_attempt(attempt: claim_authorization(escalation_id: escalation_id, expected: ExpectSlotAbsent, proposed: proposed)) { CasAttemptAdmitted { verified: v } => @@ -346,7 +515,7 @@ type D0ClaimTerminal | D0ClaimNotAttempted { still_held_by: NonEmptyStr } | D0ClaimUnterminated { detail: String } -fn d0_terminate_claim(store: FabricStorageBinding, escalation_id: NonEmptyStr, transaction: NonEmptyStr, held: CasGeneration, completed: Bool, cause: String, now: String) -> D0ClaimTerminal { +fn d0_terminate_claim(store: FabricStorageBinding, escalation_id: NonEmptyStr, transaction: NonEmptyStr, held: CasGeneration, completed: Bool, cause: String, now: Timestamp) -> D0ClaimTerminal { let attempt = (transaction as String) as AttemptIdentity let terminal = if completed { claim_transition_completed(attempt: attempt, at: now) } else { claim_transition_aborted(attempt: attempt, at: now, cause: cause as NonEmptyStr) } match admit_cas_attempt(attempt: claim_authorization(escalation_id: escalation_id, expected: ExpectSlotGeneration { generation: held }, proposed: terminal)) { @@ -447,7 +616,7 @@ fn d0_subject_standing(authorization: ScopedAuthorization, group: Fab // START: the subject checks, the intent, the permission decision, then the claim; a binding that // cannot be digested AFTER the claim landed aborts the claim rather than stranding it. -fn admit_d0_grant(store: FabricStorageBinding, authorization: ScopedAuthorization, escalation_id: NonEmptyStr, group: FabricGroup, current_hosts: List, transaction: NonEmptyStr, executor: NonEmptyStr, at: EpochSecs, now: String) -> D0GrantAdmission { +fn admit_d0_grant(store: FabricStorageBinding, authorization: ScopedAuthorization, escalation_id: NonEmptyStr, group: FabricGroup, current_hosts: List, transaction: NonEmptyStr, executor: NonEmptyStr, at: EpochSecs, now: Timestamp) -> D0GrantAdmission { match d0_subject_standing(authorization: authorization, group: group, check_population: PopulationAgainst { current: current_hosts }) { D0SubjectNotGranted => D0GrantRefused { cause: d0_not_granted_cause(authorization: authorization, escalation_id: escalation_id, group: group) } D0SubjectDisagrees { admission: a } => a @@ -503,29 +672,9 @@ fn resume_d0_grant(store: FabricStorageBinding, authorization: ScopedAuthorizati } } -type D0AuthorizationStanding - = D0AuthorizationResolved { authorization: ScopedAuthorization } - | D0AuthorizationUnestablished { obligation: NonEmptyStr } - -// THE PRODUCTION RESOLVER, AND WHY IT REFUSES. An authorization id is a reference to an operator -// decision; the ScopedAuthorization it names has to be produced by joining the escalation to a -// decision over THIS subject, and the subject needs a keyed candidate. Neither producer exists at -// this head, so the resolver refuses with what would ground it, and the entry refuses before its -// first write. TRIGGER: Cut 0 keys the V4.1 candidate (produced runtime image, closed weight and -// tokenizer manifests, four rank-store identities) and an escalation-to-ScopedAuthorization -// producer lands whose grant carries the write scope over the pair-serving authority, the -// transaction as attempt, the exact host population and the SHA-256 intent over the exact -// operation. SUFFICIENT FOR: this fn answers D0AuthorizationResolved for a real escalation id, -// admit_d0_grant decides it under std.scoped_authorization, and the wet entry admits exactly the -// operation that grant names. -fn resolve_d0_authorization(group: FabricGroup, authorization: String) -> D0AuthorizationStanding { - D0AuthorizationUnestablished { - obligation: join([ - "authorization `", authorization, "` over ", fabric_group_wire(g: group) as String, - " cannot be resolved: no producer joins an escalation id to a ScopedAuthorization over D0Subject, and the V4.1 candidate is not keyed (Cut 0), so the successor has no exact identity to authorize", - ], "") as NonEmptyStr, - } -} +// THE AUTHORIZATION IS PRODUCED AT THE DOOR: gunbc.spark.pair_serving_d0_authorization builds the +// request over the keyed successor and turns the operator's approval decision into the +// ScopedAuthorization that gunbc.spark.pair_serving_d0_door hands to d0_dispatch. // The lease as the authority carries it. The epoch names the transaction, the group as the // resource and the executor as the owner; the generation is the authority-log generation the @@ -1039,7 +1188,7 @@ fn transition_text(t: AuthorityTransition) -> String { // and the log refuses a grant carried into a state with none -- so those two terminals write the // transition without one, and only the suspension carries the term minted from the admitting // write. An earlier shape carried it on every arm and could reach neither. -fn d0_settle(store: FabricStorageBinding, pending: PairServingGroupAuthority, head: HeadExpectation, active: PairServingGroupAuthority, lease: HeldLease, admitted: AdmittedD0Grant, admitting: EventId, pending_generation: Nat, transaction: NonEmptyStr, executor: NonEmptyStr, at: EpochSecs, now: String, declared: DeclaredPairRealizationStanding, observation: D0Observation) -> D0Outcome { +fn d0_settle(store: FabricStorageBinding, pending: PairServingGroupAuthority, head: HeadExpectation, active: PairServingGroupAuthority, lease: HeldLease, admitted: AdmittedD0Grant, admitting: EventId, pending_generation: Nat, transaction: NonEmptyStr, executor: NonEmptyStr, at: EpochSecs, now: Timestamp, declared: DeclaredPairRealizationStanding, observation: D0Observation) -> D0Outcome { let group = observation.group let decision = d0_decide(declared: declared, observation: observation, active: active, lease: lease, grant: admitted.grant) let receipt = EntryStateReceipt { group: group, transaction: transaction, at: now, observation: observation, decision: decision } @@ -1090,7 +1239,7 @@ fn d0_settle(store: FabricStorageBinding, pending: PairServingGroupAuthority, he // that left and came back is the same value at another generation, and a value-only compare-and-set // would land a pending state whose lease epoch is not the generation that landed -- a grant fence // the genealogy then refuses, stranding the group. Head-exact, the landed generation is gen + 1. -fn d0_transaction(store: FabricStorageBinding, group: FabricGroup, current_hosts: List, admitted: AdmittedD0Grant, transaction: NonEmptyStr, executor: NonEmptyStr, at: EpochSecs, now: String, observe: fn(FabricGroup) -> D0Observation) -> D0Outcome { +fn d0_transaction(store: FabricStorageBinding, group: FabricGroup, current_hosts: List, admitted: AdmittedD0Grant, transaction: NonEmptyStr, executor: NonEmptyStr, at: EpochSecs, now: Timestamp, observe: fn(FabricGroup) -> D0Observation) -> D0Outcome { match current_pair_serving_authority(store: store, group: group, at: at) { CurrentAuthorityUnread { group: _, step: st, reason: why } => D0Refused { cause: join(["authority unread at ", st, ": ", why], "") } CurrentAuthorityRead { authority: cur, head: head, generation: gen, grant: _, entry_state: _, previous: previous, admitted_by: admitted_by, transitions: _ } => @@ -1248,11 +1397,9 @@ fn d0_recovery_text(r: D0Recovery) -> String { } } -// THE ENTRY. Arguments: the group's wire word, the transaction id, the authorization id. -// gunbc run --source-root dag --source-root src/v2 --entry dag/gunbc/spark/pair_serving_d0.dag \ -// --function pair_serving_d0_wet --arg group=group-a --arg transaction= --arg authorization= -// Refuses before any write unless the authorization resolves to an admitted grant -- which no -// producer yields today (resolve_d0_authorization). Exit 0 only on D0Eligible settled. +// THE ENTRY IS THE DOOR, gunbc.spark.pair_serving_d0_door pair_serving_d0_wet: it files the +// consent over the keyed successor, waits for the operator's decision, and dispatches here under +// the admitted grant. Exit 0 only on D0Eligible settled. // THE RUN AS ONE AUTHORIZATION LIFECYCLE, dispatched by d0_recovery over the claim and the // authority as read: a start decides permission, claims and writes; a recovery under a held claim // resumes (claim found held, no re-decision) and writes what is still owed; the claim is completed @@ -1283,7 +1430,7 @@ fn d0_drift_observation(group: FabricGroup, granted: List, current } } -fn d0_run_admitted(store: FabricStorageBinding, g: FabricGroup, current_hosts: List, admitted: AdmittedD0Grant, transaction: NonEmptyStr, executor: NonEmptyStr, escalation_id: NonEmptyStr, at: EpochSecs, now: String, claimed_here: Bool) -> ProcessExit { +fn d0_run_admitted(store: FabricStorageBinding, g: FabricGroup, current_hosts: List, admitted: AdmittedD0Grant, transaction: NonEmptyStr, executor: NonEmptyStr, escalation_id: NonEmptyStr, at: EpochSecs, now: Timestamp, claimed_here: Bool) -> ProcessExit { match d0_population(subject: admitted.grant.subject, current: current_hosts) { D0PopulationDiffers { granted: gr, current: cu } => d0_settle_admitted(store: store, g: g, current_hosts: current_hosts, admitted: admitted, transaction: transaction, executor: executor, escalation_id: escalation_id, at: at, now: now, observe: fn(og) { d0_drift_observation(group: og, granted: gr, current: cu) }) @@ -1299,7 +1446,7 @@ fn d0_run_admitted(store: FabricStorageBinding, g: FabricGroup, current_hosts: L } } -fn d0_settle_admitted(store: FabricStorageBinding, g: FabricGroup, current_hosts: List, admitted: AdmittedD0Grant, transaction: NonEmptyStr, executor: NonEmptyStr, escalation_id: NonEmptyStr, at: EpochSecs, now: String, observe: fn(FabricGroup) -> D0Observation) -> ProcessExit { +fn d0_settle_admitted(store: FabricStorageBinding, g: FabricGroup, current_hosts: List, admitted: AdmittedD0Grant, transaction: NonEmptyStr, executor: NonEmptyStr, escalation_id: NonEmptyStr, at: EpochSecs, now: Timestamp, observe: fn(FabricGroup) -> D0Observation) -> ProcessExit { match placement_repair_pending(store: store, group: g, actor: executor, at: at) { Present { value: PlacementAbortedAt { preparation: pr, id: _ } } => exit_failure(reason: join(["the group's pending placement preparation ", pr as String, " was aborted by the repair, which no run of this transaction does: an operator's disposition, so this run does not proceed on it"], "")) Present { value: PlacementCleanupStillFencing { preparation: pr, cause: c } } => exit_failure(reason: join(["the group's pending placement preparation ", pr as String, " cannot be repaired by this run: ", c, "\n the authorization claim stays held"], "")) @@ -1313,7 +1460,7 @@ fn d0_settle_admitted(store: FabricStorageBinding, g: FabricGroup, current_hosts // transaction that died after its group append left a consumed, unfinalized preparation, which // the join finalizes here; one no authority event consumed is the operator's, and the run refuses // rather than sitting on it. -fn d0_settle_admitted_over(store: FabricStorageBinding, g: FabricGroup, current_hosts: List, admitted: AdmittedD0Grant, transaction: NonEmptyStr, executor: NonEmptyStr, escalation_id: NonEmptyStr, at: EpochSecs, now: String, observe: fn(FabricGroup) -> D0Observation) -> ProcessExit { +fn d0_settle_admitted_over(store: FabricStorageBinding, g: FabricGroup, current_hosts: List, admitted: AdmittedD0Grant, transaction: NonEmptyStr, executor: NonEmptyStr, escalation_id: NonEmptyStr, at: EpochSecs, now: Timestamp, observe: fn(FabricGroup) -> D0Observation) -> ProcessExit { let outcome = d0_transaction(store: store, group: g, current_hosts: current_hosts, admitted: admitted, transaction: transaction, executor: executor, at: at, now: now, observe: observe) match outcome { D0Settled { decision: _, generation: _, receipt_path: _, entry_state: _ } => { @@ -1354,7 +1501,7 @@ fn claim_terminal_text(t: D0ClaimTerminal) -> String { // carried into the readings and fences rather than stranding the group // Complete → the claim's terminal only; the authority is not touched // Abort → the claim's terminal only -fn d0_dispatch(store: FabricStorageBinding, g: FabricGroup, group: String, current_hosts: List, scoped: ScopedAuthorization, tx: NonEmptyStr, esc: NonEmptyStr, executor: NonEmptyStr, at: EpochSecs, now: String, current: CurrentAuthority) -> ProcessExit { +fn d0_dispatch(store: FabricStorageBinding, g: FabricGroup, group: String, current_hosts: List, scoped: ScopedAuthorization, tx: NonEmptyStr, esc: NonEmptyStr, executor: NonEmptyStr, at: EpochSecs, now: Timestamp, current: CurrentAuthority) -> ProcessExit { match current { CurrentAuthorityUnread { group: _, step: st, reason: why } => refuse(reason: join(["authority unread at ", st, ": ", why], "")) CurrentAuthorityRead { authority: cur, head: _, generation: _, grant: _, entry_state: _, previous: _, admitted_by: _, transitions: recs } => { @@ -1469,39 +1616,3 @@ fn fabric_storage_append_principal_unrefused_trigger() -> String { } } -fn pair_serving_d0_wet(group: String, transaction: String, authorization: String) -> ProcessExit - uses net: Network -{ - let now = probed_at_word(reading: clock_now_probed_at()) as String - match parse_fabric_group(wire: group) { - Absent => refuse(reason: join(["`", group, "` names no fabric group"], "")) - Present { value: g } => - if transaction == "" { - refuse(reason: "a transaction must be named") - } else if authorization == "" { - refuse(reason: "an authorization must be named") - } else { - match d0_store_write_wall_standing() { - Present { value: wall } => refuse(reason: wall) - Absent => - match resolve_d0_authorization(group: g, authorization: authorization) { - D0AuthorizationUnestablished { obligation: o } => refuse(reason: o as String) - D0AuthorizationResolved { authorization: scoped } => - match observe_executor_reach() { - ExecutorReachUnknown { cause: c } => refuse(reason: c) - ExecutorReachKnown { short_hostname: executor, path: _ } => - match event_log_store_for_host(short_hostname: executor) { - HostStoreRefused { detail: d } => refuse(reason: d) - HostStoreResolved { store: store, executor: _ } => - match now_epoch_seconds() { - Absent => refuse(reason: "the clock could not be read as epoch seconds") - Present { value: at } => - d0_dispatch(store: store, g: g, group: group, current_hosts: fabric_group_hosts(g: g), scoped: scoped, tx: transaction as NonEmptyStr, esc: authorization as NonEmptyStr, executor: executor as NonEmptyStr, at: at, now: now, current: current_pair_serving_authority(store: store, group: g, at: at)) - } - } - } - } - } - } - } -} diff --git a/dag/gunbc/spark/pair_serving_d0_authorization.dag b/dag/gunbc/spark/pair_serving_d0_authorization.dag new file mode 100644 index 00000000000..57d1fa9b004 --- /dev/null +++ b/dag/gunbc/spark/pair_serving_d0_authorization.dag @@ -0,0 +1,130 @@ +module gunbc.spark.pair_serving_d0_authorization + +import std.types { String, Bool, Int, NonEmptyStr, List, Timestamp } +import std.measure { Second, second, second_count } +import v2.std.optional { Present, Absent } +import std.content_hash { ContentHash } +import std.scoped_authorization { AuthorizationRequest, ScopedAuthorization, ClaimedBy } +import gunbc.auth.approval_gate { ApprovalGateRefusal, ApprovalRecorded, ApprovalNotRecorded, approval_recorded_from_poll } +import gunbc.auth.approval_request_client { ApprovalPollStanding } +import gunbc.spark.fabric_switch_observed { FabricGroup, fabric_group_wire, fabric_group_hosts } +import gunbc.spark.released_baseline { ReleasedBaselineSpec, QuiescentReservedBaseline } +import gunbc.spark.v41_runtime_candidate { v41_candidate, V41CandidateStanding, V41CandidateKeyed, V41CandidateUnestablished, V41CandidateRefused } +import gunbc.spark.pair_serving_d0 { D0Subject, d0_request, d0_intent_hash, d0_intent_text, parse_d0_intent_text, D0ClaimReading, D0ClaimAt, D0ClaimAbsent, D0ClaimUnreadable } + +// ── THE ESCALATION → AUTHORIZATION PRODUCER FOR D0 (Cut D, the gate Cut 0 opens) ───────────── +// +// An operator's consent to D0 is an approval decision over ONE exact request: the group, its +// current host population, the KEYED successor candidate, the cleanup baseline, the lease term +// and the transaction word, digested into the intent the decision's revision names. This module +// produces that request from the live authorities -- and, for a rerun, re-derives the SAME request +// from the intent text the door froze when it filed (gunbc.spark.pair_serving_d0 d0_freeze_filing), +// so a lifecycle finishes under the request the operator saw rather than one rebuilt from moved +// source. Turning the broker's poll into a ScopedAuthorization is not D0's to own: that +// is gunbc.auth.approval_gate, generic over the subject, which the door binds to this request +// exactly as the Mt. Collins boot binds it to its own. This module is pure over supplied readings. + +// THE SUCCESSOR IS THE KEYED CANDIDATE, OR THERE IS NO SUBJECT. Identity is not permission, but +// a consent over an unkeyed successor would authorize whatever bytes turned up: the subject +// refuses to exist until gunbc.spark.v41_runtime_candidate keys the candidate (Cut 0). +// A DEFECT IS NOT AN OBLIGATION here either: a candidate the source authority refuses (a malformed +// published population) is a correction owed to the source, and no reading discharges it; an +// unestablished one names what is still to be read. The door renders them apart. +type D0SubjectStanding + = D0SubjectFor { subject: D0Subject } + | D0SubjectUnestablished { obligations: List } + | D0SubjectRefused { defects: List } + +// The lease term the consent is asked for: the bounded window in which D0 reads the fleet and +// settles. Declared here as the one term every D0 consent names. +data d0_consent_term: Second = second(count: 3600) + +fn d0_subject_of_candidate(group: FabricGroup, standing: V41CandidateStanding) -> D0SubjectStanding { + match standing { + V41CandidateKeyed { runtime_artifact: _, model_source: _, engram_realization: _, execution_profile: _, candidate: c, authorization_obligation: _ } => + D0SubjectFor { subject: D0Subject { group: group, hosts: fabric_group_hosts(g: group), successor: c, cleanup: QuiescentReservedBaseline, term: d0_consent_term } } + V41CandidateUnestablished { obligations: o } => D0SubjectUnestablished { obligations: o } + V41CandidateRefused { defects: d } => D0SubjectRefused { defects: d } + } +} + +fn d0_live_subject(group: FabricGroup) -> D0SubjectStanding { + d0_subject_of_candidate(group: group, standing: v41_candidate().standing) +} + +// THE REQUEST, with the intent over the exact operation (sha256 through the realization; an +// unavailable digest is no request, never a structural substitute). +type D0RequestStanding + = D0RequestFor { request: AuthorizationRequest } + | D0RequestUnestablished { obligations: List } + | D0RequestRefused { defects: List } + +fn d0_authorization_request(group: FabricGroup, escalation_id: NonEmptyStr, transaction: NonEmptyStr) -> D0RequestStanding { + match d0_live_subject(group: group) { + D0SubjectUnestablished { obligations: o } => D0RequestUnestablished { obligations: o } + D0SubjectRefused { defects: d } => D0RequestRefused { defects: d } + D0SubjectFor { subject: s } => + match d0_intent_hash(subject: s, group: group, transaction: transaction) { + Absent => D0RequestUnestablished { obligations: ["the intent over the exact operation could not be digested (sha256sum unavailable)" as NonEmptyStr] } + Present { value: i } => D0RequestFor { request: d0_request(escalation_id: escalation_id, subject: s, transaction: transaction, intent: i) } + } + } +} + +// THE REQUEST AS IT WAS FILED, from the frozen intent text. The text is parsed, not trusted: it +// must round-trip through d0_intent_text, name the group and transaction this run was dispatched +// for, and digest -- so the request it yields carries the filed revision by construction, and a +// slot holding another transaction's filing under this escalation is a refusal, not a resume. +type D0FiledRequestStanding + = D0FiledRequestFor { request: AuthorizationRequest, intent_text: String } + | D0FiledRequestRefused { reason: NonEmptyStr } + +fn d0_filed_request(text: String, group: FabricGroup, escalation_id: NonEmptyStr, transaction: NonEmptyStr) -> D0FiledRequestStanding { + match parse_d0_intent_text(text: text) { + Absent => D0FiledRequestRefused { reason: "the frozen filing under this escalation is not one D0 intent" as NonEmptyStr } + Present { value: parsed } => + if (fabric_group_wire(g: parsed.group) as String) != (fabric_group_wire(g: group) as String) { + D0FiledRequestRefused { reason: join(["the frozen filing under this escalation is over group ", fabric_group_wire(g: parsed.group) as String, ", not ", fabric_group_wire(g: group) as String], "") as NonEmptyStr } + } else if (parsed.transaction as String) != (transaction as String) { + D0FiledRequestRefused { reason: join(["the frozen filing under this escalation is transaction ", parsed.transaction as String, ", not ", transaction as String], "") as NonEmptyStr } + } else { + match d0_intent_hash(subject: parsed.subject, group: group, transaction: transaction) { + Absent => D0FiledRequestRefused { reason: "the frozen intent could not be digested (sha256sum unavailable)" as NonEmptyStr } + Present { value: i } => D0FiledRequestFor { request: d0_request(escalation_id: escalation_id, subject: parsed.subject, transaction: transaction, intent: i), intent_text: text } + } + } + } +} + +// The intent text a live request is frozen as: the same bytes its intent hash was taken over. +fn d0_request_intent_text(request: AuthorizationRequest, group: FabricGroup, transaction: NonEmptyStr) -> String { + d0_intent_text(subject: request.subject, group: group, transaction: transaction) +} + +// A RECORDED APPROVAL BECOMES A RESUMABLE AUTHORIZATION ONLY AGAINST THE DURABLE CLAIM. The right +// to finish what an approval began belongs to the lifecycle that claimed it: the claim slot must +// read ClaimedBy THIS transaction. Any other reading -- absent (nothing began; a start is a live +// admission and must pass the live gate), held by another attempt, completed, aborted, or +// unreadable -- refuses here, so "historically approved" never reaches d0_dispatch as an +// authorization without the proof that distinguishes a resume from a start. +type D0ResumableAuthorization + = D0Resumable { authorization: ScopedAuthorization } + | D0NotRecorded { cause: ApprovalGateRefusal } + | D0NotClaimedHere { reason: NonEmptyStr } + +fn d0_resumable_authorization(claim: D0ClaimReading, transaction: NonEmptyStr, poll: ApprovalPollStanding, request: AuthorizationRequest) -> D0ResumableAuthorization { + match claim { + D0ClaimAt { state: ClaimedBy { attempt: who, claimed_at: _ }, generation: _ } => + if (who as String) == (transaction as String) { + match approval_recorded_from_poll(poll: poll, request: request) { + ApprovalRecorded { authorization: a } => D0Resumable { authorization: a } + ApprovalNotRecorded { cause: c } => D0NotRecorded { cause: c } + } + } else { + D0NotClaimedHere { reason: join(["the consent is claimed by attempt ", who as String, ", not ", transaction as String], "") as NonEmptyStr } + } + D0ClaimAt { state: _, generation: _ } => D0NotClaimedHere { reason: "the consent's claim is not held: unclaimed, completed or aborted" as NonEmptyStr } + D0ClaimAbsent => D0NotClaimedHere { reason: "no claim of the consent exists; this run is a start" as NonEmptyStr } + D0ClaimUnreadable { reason: r } => D0NotClaimedHere { reason: r } + } +} diff --git a/dag/gunbc/spark/pair_serving_d0_door.dag b/dag/gunbc/spark/pair_serving_d0_door.dag new file mode 100644 index 00000000000..a2ca36fb490 --- /dev/null +++ b/dag/gunbc/spark/pair_serving_d0_door.dag @@ -0,0 +1,242 @@ +module gunbc.spark.pair_serving_d0_door + +import std.types { String, Bool, Int, NonEmptyStr, List, Timestamp, EpochSecs } +import std.measure { Second, second, second_count } +import v2.std.optional { Present, Absent } +import std.process { ProcessExit, exit_failure } +import std.resources { Network } +import std.scoped_authorization { AuthorizationRequest, ScopedAuthorization } +import gunbc.auth.approval_gate { + ApprovalGate, GateAdmitted, GateRefused, ApprovalStoreUnreadable, approval_gate_from_poll, approval_gate_from_outcome, approval_refusal_text, + approval_instant_now, approval_expires_at, approval_standing_read, approval_poll_ticks, ApprovalStandingRead, StandingReadAt, StandingClockUnreadable, + approval_file_stored_request, ApprovalFiled, ApprovalFilingRefused, +} +import gunbc.auth.approval_request_client { PollStillPending, PollNotFiled, stored_request_from_authorization } +import gunbc.fabric_storage_client { FabricStorageBinding } +import gunbc.fabric_event_log_host { HostStoreResolved, HostStoreRefused, event_log_store_for_host, now_epoch_seconds } +import gunbc.spark.fabric_reach { ExecutorReachKnown, ExecutorReachUnknown, observe_executor_reach } +import gunbc.spark.fabric_switch_observed { FabricGroup, parse_fabric_group, fabric_group_hosts } +import gunbc.spark.pair_serving_authority_log { current_pair_serving_authority } +import gunbc.spark.pair_serving_d0 { + D0Subject, d0_dispatch, d0_store_write_wall_standing, + d0_read_filing, D0FilingAbsent, D0FilingAt, D0FilingUnreadable, + d0_freeze_filing, D0FilingFrozen, D0FilingAlreadyHeld, D0FilingFreezeRefused, + d0_read_claim, D0ClaimAbsent, D0ClaimAt, D0ClaimUnreadable, +} +import gunbc.spark.pair_serving_d0_authorization { + D0RequestFor, D0RequestUnestablished, D0RequestRefused, d0_authorization_request, d0_request_intent_text, + D0FiledRequestFor, D0FiledRequestRefused, d0_filed_request, + d0_resumable_authorization, D0Resumable, D0NotRecorded, D0NotClaimedHere, +} + +// ── THE WET DOOR OF D0: file the consent, wait for the operator, then run the transaction ───── +// +// gunbc run --source-root dag --source-root src/v2 --entry dag/gunbc/spark/pair_serving_d0_door.dag +// --function pair_serving_d0_wet --arg group=group-a --arg transaction= --arg authorization= +// +// THE ORDER IS THE SAFETY. Nothing on the fleet moves before, in this order: the store's two write +// walls stand (gunbc.spark.pair_serving_d0 d0_store_write_wall_standing); the store this executor +// reaches is resolved; the FILING under the named escalation is read from it, which decides +// whether this run is the first or a rerun; the request over the exact operation is either +// re-derived from the frozen filing (rerun) or built from the live authorities -- the V4.1 +// candidate keyed (Cut 0), the group's hosts read -- frozen, and FILED with the approval broker, +// signed with the submission key (gunbc.auth.approval_keyring_pins); the operator's decision is +// polled for a bounded window; and only then is the transaction dispatched +// (gunbc.spark.pair_serving_d0 d0_dispatch), which reads the durable claim and the authority +// history and decides start, resume, complete or abort. Every other poll outcome is a typed +// refusal naming what the operator or the run must do. The broker route is gunbc.auth.approval_gate, +// the same one gunbc.machine_intake_mtcollins1_boot_run binds to the Mt. Collins boot. +// +// A RERUN IS DECIDED BY THE STORE, NOT BY THE CLOCK OR THE SOURCE. The lifecycle #11555 made +// recoverable can outlive the grant's window, the candidate's key and the group's host roster: +// once the claim is held and the pending state is written, the transaction must reach a terminal +// under the request the operator consented to. So a rerun never rebuilds the subject from live +// source and never re-files -- it reads the frozen intent, re-derives the identical request, reads +// the broker's decision AS RECORDED (an approval past its execute_by is still the approval that +// started this lifecycle), and hands the grant to the dispatcher, which alone decides whether a +// fresh start is still permitted (it re-authorizes at a fresh instant before claiming) or the +// held lifecycle simply continues (no permission re-decided). A first run that finds the filing +// already frozen is a rerun that did not know it, and proceeds as one. +// +// THE CLAIM IS TIMESTAMPED WHERE IT IS MADE. The instant that authorizes and stamps the claim is +// probed after the poll returns, immediately before dispatch: a grant that expired between the +// admitting poll and the claim refuses, a claim never predates the operator's decision, and an +// unreadable clock there refuses rather than handing a rendering to the authorization boundary. +// +// WHERE IT RUNS. The broker is reached on its loopback origin (approval_loopback_origin), so the +// door runs on the broker's host, from a fleet-converge workflow mode that supplies the +// submission key path and a scratch directory -- the same environment the boot run consumes. A +// door run without them refuses before filing anything. + +data d0_poll_cadence: Second = second(count: 15) +data d0_poll_tick_budget: Int = 120 +data d0_submit_timeout: Second = second(count: 30) +data d0_submit_body_file_name: String = "pair-serving-d0-approval-submit.json" + +fn d0_approval_window() -> Second { + second(count: d0_poll_tick_budget * (second_count(s: d0_poll_cadence) as Int)) +} + +fn refuse(reason: String) -> ProcessExit { + exit_failure(reason: join(["pair_serving_d0: ", reason], "")) +} + +// WHICH RUN THIS IS, from the filing slot: the frozen intent (rerun) or none yet (first run). +type D0RunKind + = D0FirstRun { request: AuthorizationRequest } + | D0Rerun { request: AuthorizationRequest } + | D0RunRefused { reason: String } + +fn d0_run_kind(store: FabricStorageBinding, g: FabricGroup, escalation_id: NonEmptyStr, transaction: NonEmptyStr) -> D0RunKind { + match d0_read_filing(store: store, escalation_id: escalation_id) { + D0FilingUnreadable { reason: r } => D0RunRefused { reason: join(["the filing under this escalation could not be read: ", r as String], "") } + D0FilingAt { text: t } => + match d0_filed_request(text: t, group: g, escalation_id: escalation_id, transaction: transaction) { + D0FiledRequestRefused { reason: r } => D0RunRefused { reason: r as String } + D0FiledRequestFor { request: request, intent_text: _ } => D0Rerun { request: request } + } + D0FilingAbsent => + match d0_authorization_request(group: g, escalation_id: escalation_id, transaction: transaction) { + D0RequestUnestablished { obligations: o } => D0RunRefused { reason: join(["the consent has no subject to be asked over yet; still to be established: ", join(map(o, x => x as String), "; ")], "") } + D0RequestRefused { defects: d } => D0RunRefused { reason: join(["the consent has no subject to be asked over: the candidate's source is refused and must be corrected, not read further: ", join(map(d, x => x as String), "; ")], "") } + D0RequestFor { request: request } => + match d0_freeze_filing(store: store, escalation_id: escalation_id, intent_text: d0_request_intent_text(request: request, group: g, transaction: transaction)) { + D0FilingFreezeRefused { reason: r } => D0RunRefused { reason: r as String } + D0FilingFrozen => D0FirstRun { request: request } + D0FilingAlreadyHeld { text: t } => + match d0_filed_request(text: t, group: g, escalation_id: escalation_id, transaction: transaction) { + D0FiledRequestRefused { reason: r } => D0RunRefused { reason: r as String } + D0FiledRequestFor { request: filed, intent_text: _ } => D0Rerun { request: filed } + } + } + } + } +} + +// THE GATE FOR THIS RUN. A first run files and polls live. A rerun reads the durable claim: held +// by this transaction, the decision is read AS RECORDED and joined to that proof +// (d0_resumable_authorization) -- the lifecycle finishes under the consent that began it, expired +// or not; absent, nothing began, so the standing is polled and admitted LIVE exactly as a first +// run's (still pending: wait; not filed: the intent was frozen but the broker never reached, so the +// frozen request is filed now); any other holder or state refuses. +type D0DoorGate + = D0DoorAdmitted { authorization: ScopedAuthorization } + | D0DoorRefused { reason: String } + +fn d0_door_gate_of(gate: ApprovalGate) -> D0DoorGate { + match gate { + GateAdmitted { authorization: scoped } => D0DoorAdmitted { authorization: scoped } + GateRefused { cause: c } => D0DoorRefused { reason: join(["the consent was not admitted: ", approval_refusal_text(cause: c)], "") } + } +} + +// THE STEP FOR A FROZEN FILING WITH NO CLAIM, pure over the read: nothing began, so the standing +// is a first run's -- not filed: file the frozen request; pending: enter the bounded poll; decided: +// the live gate at the instant of the read; unreadable clock: refuse before anything is dispatched. +type D0AbsentClaimStep + = D0AbsentClaimClockUnreadable + | D0AbsentClaimFileFrozen + | D0AbsentClaimEnterPoll + | D0AbsentClaimDecided { gate: ApprovalGate } + +fn d0_absent_claim_step(read: ApprovalStandingRead, request: AuthorizationRequest) -> D0AbsentClaimStep { + match read { + StandingClockUnreadable => D0AbsentClaimClockUnreadable + StandingReadAt { standing: standing, observed_at: observed } => + match standing { + PollNotFiled => D0AbsentClaimFileFrozen + PollStillPending => D0AbsentClaimEnterPoll + decided => D0AbsentClaimDecided { gate: approval_gate_from_poll(poll: decided, request: request, observed_at: observed) } + } + } +} + +fn d0_gate(store: FabricStorageBinding, kind: D0RunKind, transaction: NonEmptyStr, expires: Timestamp, issued: Timestamp) -> D0DoorGate + uses net: Network +{ + match kind { + D0RunRefused { reason: r } => D0DoorRefused { reason: r } + D0FirstRun { request: request } => d0_file_and_poll(request: request, issued: issued, expires: expires) + D0Rerun { request: request } => { + let claim = d0_read_claim(store: store, escalation_id: request.escalation_id) + match claim { + D0ClaimAbsent => + match d0_absent_claim_step(read: approval_standing_read(escalation_id: request.escalation_id, expires_at: expires), request: request) { + D0AbsentClaimClockUnreadable => D0DoorRefused { reason: "clock unreadable; refusing to judge expiry against a fabricated instant" } + D0AbsentClaimFileFrozen => d0_file_and_poll(request: request, issued: issued, expires: expires) + D0AbsentClaimEnterPoll => d0_poll(request: request, expires: expires) + D0AbsentClaimDecided { gate: g } => d0_door_gate_of(gate: g) + } + _ => + match approval_standing_read(escalation_id: request.escalation_id, expires_at: expires) { + StandingClockUnreadable => D0DoorRefused { reason: "clock unreadable; refusing to judge expiry against a fabricated instant" } + StandingReadAt { standing: standing, observed_at: _ } => + match d0_resumable_authorization(claim: claim, transaction: transaction, poll: standing, request: request) { + D0Resumable { authorization: a } => D0DoorAdmitted { authorization: a } + D0NotRecorded { cause: c } => D0DoorRefused { reason: join(["the consent's recorded decision does not resume this run: ", approval_refusal_text(cause: c)], "") } + D0NotClaimedHere { reason: r } => D0DoorRefused { reason: join(["the consent cannot be resumed by this run: ", r as String], "") } + } + } + } + } + } +} + +fn d0_poll(request: AuthorizationRequest, expires: Timestamp) -> D0DoorGate + uses net: Network +{ + d0_door_gate_of(gate: approval_gate_from_outcome(outcome: approval_poll_ticks(remaining: d0_poll_tick_budget, cadence: d0_poll_cadence, escalation_id: request.escalation_id, expires_at: expires), request: request)) +} + +fn d0_file_and_poll(request: AuthorizationRequest, issued: Timestamp, expires: Timestamp) -> D0DoorGate + uses net: Network +{ + match approval_file_stored_request(stored: stored_request_from_authorization(request: request, issued_at: issued, expires_at: expires), body_file_name: d0_submit_body_file_name, submit_timeout: d0_submit_timeout) { + ApprovalFilingRefused { reason: r } => D0DoorRefused { reason: r } + ApprovalFiled => d0_poll(request: request, expires: expires) + } +} + +fn pair_serving_d0_wet(group: String, transaction: String, authorization: String) -> ProcessExit + uses net: Network +{ + match parse_fabric_group(wire: group) { + Absent => refuse(reason: join(["`", group, "` names no fabric group"], "")) + Present { value: g } => + if transaction == "" { + refuse(reason: "a transaction must be named") + } else if authorization == "" { + refuse(reason: "an authorization (escalation id) must be named") + } else { + match d0_store_write_wall_standing() { + Present { value: wall } => refuse(reason: wall) + Absent => + match observe_executor_reach() { + ExecutorReachUnknown { cause: c } => refuse(reason: c) + ExecutorReachKnown { short_hostname: executor, path: _ } => + match event_log_store_for_host(short_hostname: executor) { + HostStoreRefused { detail: d } => refuse(reason: d) + HostStoreResolved { store: store, executor: _ } => + match approval_instant_now() { + Absent => refuse(reason: "clock unreadable; cannot mint an approval window") + Present { value: issued } => + match d0_gate(store: store, kind: d0_run_kind(store: store, g: g, escalation_id: authorization as NonEmptyStr, transaction: transaction as NonEmptyStr), transaction: transaction as NonEmptyStr, expires: approval_expires_at(issued: issued, window: d0_approval_window()), issued: issued) { + D0DoorRefused { reason: r } => refuse(reason: r) + D0DoorAdmitted { authorization: scoped } => + match approval_instant_now() { + Absent => refuse(reason: "clock unreadable at the claim; the consent is admitted but no instant can authorize or stamp the claim") + Present { value: now } => + match now_epoch_seconds() { + Absent => refuse(reason: "the clock could not be read as epoch seconds") + Present { value: at } => + d0_dispatch(store: store, g: g, group: group, current_hosts: fabric_group_hosts(g: g), scoped: scoped, tx: transaction as NonEmptyStr, esc: authorization as NonEmptyStr, executor: executor as NonEmptyStr, at: at, now: now, current: current_pair_serving_authority(store: store, group: g, at: at)) + } + } + } + } + } + } + } + } + } +} diff --git a/dag/gunbc/spark/v41_runtime_candidate.dag b/dag/gunbc/spark/v41_runtime_candidate.dag index 6cfb2ebb17d..0b303af5c30 100644 --- a/dag/gunbc/spark/v41_runtime_candidate.dag +++ b/dag/gunbc/spark/v41_runtime_candidate.dag @@ -27,6 +27,8 @@ import extdeps.safetensors.format { import extdeps.deepseek.deepseek_v4_1_flash { deepseek_v4_1_flash_revision, deepseek_v4_1_flash_engram_population, DeepseekV41EngramTables, deepseek_v4_1_flash_engram, + deepseek_v4_1_flash_weight_manifest_standing, WeightManifestAdmitted, WeightManifestRefused, + deepseek_v4_1_flash_tokenizer_standing, TokenizerPopulationAdmitted, TokenizerPopulationRefused, } import gunbc.spark.vllm_runtime_image_build { v41_gb10_torch_cuda_arch_list, v41_build_max_jobs, v41_build_nvcc_threads, @@ -37,7 +39,7 @@ import gunbc.spark.vllm_image_identity { import gunbc.spark.serving_runtime_capability_probe { gb10_observed_compute_capability } import gunbc.spark.serving_deployment_selection { TopologyShape, topology_shape } import gunbc.fabric.engram_materialization { engram_route_b_identity, engram_route_d_identity } -import extdeps.tools.sha256sum { Sha256FileDigest, Sha256FileDigestUnavailable, sha256sum_file_digest_via_shell } +import extdeps.tools.sha256sum { Sha256FileDigest, Sha256FileDigestUnavailable, sha256sum_file_digest_via_shell, sha256sum_stdin_digest_via_shell } // ── ONE EXACT DeepSeek V4.1 RUNTIME CANDIDATE, AS IDENTITY ONLY ────────────────────────────────── // @@ -418,9 +420,14 @@ fn v41_partition_inputs(p: V41EngramResidencyPartition) -> List } type V41ModelSourceInputs { checkpoint_revision: NonEmptyStr @@ -432,6 +439,24 @@ fn v41_manifest_obligations(m: V41ManifestStanding) -> List { match m { V41ManifestObserved { digest: _ } => [] as List V41ManifestUnestablished { obligation: o } => [o] + V41ManifestRefused { first: _, rest: _ } => [] as List + } +} + +// A refusal carries at least one defect BY CONSTRUCTION (first, rest), so an empty refusal that +// would fall through to keying is not writable. +fn v41_manifest_defects(m: V41ManifestStanding) -> List { + match m { + V41ManifestObserved { digest: _ } => [] as List + V41ManifestUnestablished { obligation: _ } => [] as List + V41ManifestRefused { first: f, rest: r } => concat([f], r) + } +} + +fn v41_manifest_refused(defects: List, subject: String) -> V41ManifestStanding { + match first(defects) { + Present { value: f } => V41ManifestRefused { first: f, rest: defects |> skip(n: 1) } + Absent => V41ManifestRefused { first: join([subject, ": refused with no defect named -- the admission's refusal carried an empty population"], "") as NonEmptyStr, rest: [] as List } } } @@ -439,12 +464,16 @@ fn v41_manifest_value(m: V41ManifestStanding) -> String { match m { V41ManifestObserved { digest: d } => d.hex as String V41ManifestUnestablished { obligation: _ } => "" + V41ManifestRefused { first: _, rest: _ } => "" } } fn v41_model_source_key(s: V41ModelSourceInputs) -> V41IdentityStanding { + let defects = concat(v41_manifest_defects(m: s.weights), v41_manifest_defects(m: s.tokenizer)) let obligations = concat(v41_manifest_obligations(m: s.weights), v41_manifest_obligations(m: s.tokenizer)) - if length(obligations) != 0 { + if length(defects) != 0 { + V41IdentityRefused { defects: defects } + } else if length(obligations) != 0 { V41IdentityUnestablished { obligations: obligations } } else { V41IdentityKeyed { key: artifact_realization_digest(inputs: [ @@ -490,10 +519,7 @@ fn v41_decl_field_wire(f: DeclField) -> String { // one missing axis where there were two -- a partial answer that looks complete, which is worse than the // silence it replaced because it would be read as the full list. fn v41_row_store_obligations(m: V41ManifestStanding) -> List { - match m { - V41ManifestUnestablished { obligation: o } => [o] - V41ManifestObserved { digest: _ } => [] as List - } + v41_manifest_obligations(m: m) } // AN UNRECONCILED MEMBERSHIP IS AN UNESTABLISHED AXIS, NOT A KEYABLE ONE. This module's own law is that @@ -507,7 +533,10 @@ fn v41_row_store_obligations(m: V41ManifestStanding) -> List { // discharged by reading the index rather than by writing something. fn v41_engram_realization_key(e: V41EngramRealizationInputs) -> V41IdentityStanding { let membership = safetensors_population_closure_obligations(s: e.population) - if length(membership) != 0 { + let row_store_defects = v41_manifest_defects(m: e.row_store_encoding) + if length(row_store_defects) != 0 { + V41IdentityRefused { defects: row_store_defects } + } else if length(membership) != 0 { V41IdentityUnestablished { obligations: concat(membership, v41_row_store_obligations(m: e.row_store_encoding)) } } else { match v41_admit_partition(p: e.partition, standing: e.population) { @@ -518,6 +547,7 @@ fn v41_engram_realization_key(e: V41EngramRealizationInputs) -> V41IdentityStand } else { match e.row_store_encoding { V41ManifestUnestablished { obligation: o } => V41IdentityUnestablished { obligations: [o] } + V41ManifestRefused { first: f, rest: r } => V41IdentityRefused { defects: concat([f], r) } V41ManifestObserved { digest: d } => V41IdentityKeyed { key: artifact_realization_digest(inputs: concat(v41_partition_inputs(p: p), [ v41_input(identity: "row_store_encoding", value: d.hex as String), @@ -696,8 +726,8 @@ data v41_candidate_inputs: V41CandidateInputs = V41CandidateInputs { }, model_source: V41ModelSourceInputs { checkpoint_revision: deepseek_v4_1_flash_revision, - weights: V41ManifestUnestablished { obligation: "the weight manifest at dba1be0a is not read: extdeps.deepseek.deepseek_v4_1_flash carries sha256 for the two Engram shards only, not the other 46" as NonEmptyStr }, - tokenizer: V41ManifestUnestablished { obligation: "the tokenizer file population and digests at dba1be0a are not read" as NonEmptyStr }, + weights: v41_weight_manifest_standing(), + tokenizer: v41_tokenizer_standing(), }, engram: V41EngramRealizationInputs { partition: v41_candidate_partition, @@ -709,6 +739,40 @@ data v41_candidate_inputs: V41CandidateInputs = V41CandidateInputs { device: gb10_observed_compute_capability, } +// A MANIFEST AXIS IS KEYED BY THE DIGEST OF AN ADMITTED POPULATION'S CANONICAL TEXT. The rows are +// the publisher's declared digests at the pinned revision (extdeps.deepseek.deepseek_v4_1_flash +// carries them with their provenance); the candidate never digests the raw row list -- it consumes +// the module's admission (exact shard cover, index reconciliation, role cover), so a defective +// population is a REFUSED model source naming its defects -- not an obligation and never a +// differently keyed one. +// The canonical text is order-free (sorted by path), so a shard digest, a file size or a path +// that changes changes the key and a reordering does not. The digest is taken through the +// sha256sum realization; unavailable is a typed obligation, never a structural fallback. +fn v41_weight_manifest_standing() -> V41ManifestStanding { + match deepseek_v4_1_flash_weight_manifest_standing() { + WeightManifestRefused { defects: d } => v41_manifest_refused(defects: map(d, x => join(["weight manifest: ", x as String], "") as NonEmptyStr), subject: "the weight manifest") + WeightManifestAdmitted { files: _, index: _, canonical_text: t } => v41_manifest_digest(text: t, subject: "the admitted weight manifest (48 shards at dba1be0a)") + } +} + +fn v41_tokenizer_standing() -> V41ManifestStanding { + match deepseek_v4_1_flash_tokenizer_standing() { + TokenizerPopulationRefused { defects: d } => v41_manifest_refused(defects: map(d, x => join(["tokenizer population: ", x as String], "") as NonEmptyStr), subject: "the tokenizer population") + TokenizerPopulationAdmitted { files: _, canonical_text: t } => v41_manifest_digest(text: t, subject: "the admitted tokenizer population at dba1be0a") + } +} + +fn v41_manifest_digest(text: String, subject: String) -> V41ManifestStanding { + match sha256sum_stdin_digest_via_shell(content: text) { + Sha256FileDigestUnavailable { path: _, reason: r } => V41ManifestUnestablished { obligation: join([subject, " could not be digested: ", r], "") as NonEmptyStr } + Sha256FileDigest { digest: d } => + match sha256_hex_digest(hex: d.hex as String) { + Absent => V41ManifestUnestablished { obligation: join([subject, ": sha256sum did not answer a sha256 digest"], "") as NonEmptyStr } + Present { value: h } => V41ManifestObserved { digest: h } + } + } +} + fn v41_candidate() -> V41CandidateVerdict { v41_candidate_standing(c: v41_candidate_inputs) } diff --git a/dag/gunbc/workflow_escalation.dag b/dag/gunbc/workflow_escalation.dag index 216531cebe4..2e05a39e28c 100644 --- a/dag/gunbc/workflow_escalation.dag +++ b/dag/gunbc/workflow_escalation.dag @@ -9,7 +9,7 @@ import std.scoped_authorization { AuthorizationRefused, AuthorizationRefusalCause, AuthorizationNotGranted, - AuthorizationExpired, + AuthorizationExpired, AuthorizationObservedBeforeGrant, AuthorizationAlreadyCompleted, AuthorizationClaimedByOtherAttempt, AuthorizationAborted, @@ -87,6 +87,8 @@ fn workflow_step_disposition_for_decision( StepBlocked { reason: authorization_refusal_reason(cause: cause) } AuthorizationExpired { expires_at: _, observed_at: _ } => StepBlocked { reason: authorization_refusal_reason(cause: cause) } + AuthorizationObservedBeforeGrant { granted_at: _, observed_at: _ } => + StepBlocked { reason: authorization_refusal_reason(cause: cause) } AuthorizationAlreadyCompleted { completed_by: _, completed_at: _ } => StepBlocked { reason: authorization_refusal_reason(cause: cause) } AuthorizationClaimedByOtherAttempt { requested: _, holder: _ } => diff --git a/dag/std/scoped_authorization.dag b/dag/std/scoped_authorization.dag index 93cebefc32e..e8bc110bd50 100644 --- a/dag/std/scoped_authorization.dag +++ b/dag/std/scoped_authorization.dag @@ -178,6 +178,7 @@ type AuthorizationClaimState type AuthorizationRefusalCause = AuthorizationNotGranted { escalation_id: NonEmptyStr } | AuthorizationExpired { expires_at: Timestamp, observed_at: Timestamp } + | AuthorizationObservedBeforeGrant { granted_at: Timestamp, observed_at: Timestamp } | AuthorizationAlreadyCompleted { completed_by: AttemptIdentity, completed_at: Timestamp } | AuthorizationClaimedByOtherAttempt { requested: AttemptIdentity, holder: AttemptIdentity } | AuthorizationAborted { aborted_by: AttemptIdentity, cause: NonEmptyStr } @@ -244,6 +245,15 @@ fn grant_not_expired_at(observed_at: Timestamp, expires_at: Timestamp) -> Bool { observed_at <= expires_at } +// THE WINDOW HAS A LOWER BOUND TOO. An instant before the operator's decision cannot be one at +// which the grant permits anything: a claim stamped with it would predate the consent it consumes, +// which is the shape a stale or fabricated clock produces (an instant read before the request was +// even filed, carried past the poll). The refusal names both instants so the remedy -- a fresh +// canonical read -- is the only one that fits. +fn grant_reached_at(observed_at: Timestamp, granted_at: Timestamp) -> Bool { + granted_at <= observed_at +} + // The single decision procedure. Ordered so the cause reported is the FIRST thing wrong rather // than the last check to run: identity, then reach, then time. // @@ -321,8 +331,14 @@ fn authorize_reached_time( grant: OperatorGrant, observed_at: Timestamp, ) -> AuthorizationDecision { - if !grant_not_expired_at(observed_at: observed_at, expires_at: grant.expires_at) { - + if !grant_reached_at(observed_at: observed_at, granted_at: grant.granted_at) { + AuthorizationRefused { + cause: AuthorizationObservedBeforeGrant { + granted_at: grant.granted_at, + observed_at: observed_at, + }, + } + } else if !grant_not_expired_at(observed_at: observed_at, expires_at: grant.expires_at) { AuthorizationRefused { cause: AuthorizationExpired { expires_at: grant.expires_at, @@ -603,6 +619,8 @@ fn authorization_refusal_reason(cause: AuthorizationRefusalCause) -> String { concat("operator authorization absent for escalation ", id as String) AuthorizationExpired { expires_at: exp, observed_at: at } => concat("operator authorization expired at ", concat(exp, concat(", observed at ", at))) + AuthorizationObservedBeforeGrant { granted_at: g, observed_at: at } => + concat("operator authorization granted at ", concat(g, concat(" is observed at the earlier instant ", concat(at, "; the clock is behind the decision or the instant is stale")))) AuthorizationAlreadyCompleted { completed_by: who, completed_at: when } => concat("operator authorization already completed by attempt ", concat(who as String, concat(" at ", when))) AuthorizationClaimedByOtherAttempt { requested: req, holder: holder } => diff --git a/dag/test/claim/approval_request_client_witness_test.dag b/dag/test/claim/approval_request_client_witness_test.dag index 8a936ab260f..721a546e382 100644 --- a/dag/test/claim/approval_request_client_witness_test.dag +++ b/dag/test/claim/approval_request_client_witness_test.dag @@ -109,6 +109,52 @@ test fn poll_expires_after_expires_at_unless_already_decided() -> Bool { } } +// THE FILED WINDOW GOVERNS A PENDING REQUEST, NOT THE CALLER'S: a rerun that computed a fresh, +// later window cannot keep a filing pending past the expires_at the broker filed; and a filing +// still inside its own window stays pending even when the caller's window has passed. The caller's +// window governs only a request that is not filed. +test fn a_pending_filing_expires_by_its_filed_window_not_the_callers() -> Bool { + match approval_poll_standing(status: StatusPending { expires_at: "2026-09-16T21:00:00Z" }, observed_at: "2026-09-16T21:30:00Z", expires_at: "2026-09-16T23:00:00Z") { + PollExpired => true + _ => false + } + && match approval_poll_standing(status: StatusPending { expires_at: "2026-09-16T23:00:00Z" }, observed_at: "2026-09-16T21:30:00Z", expires_at: "2026-09-16T21:00:00Z") { + PollStillPending => true + _ => false + } + && match approval_poll_standing(status: StatusNotFiled, observed_at: "2026-09-16T21:30:00Z", expires_at: "2026-09-16T21:00:00Z") { + PollExpired => true + _ => false + } + && match approval_poll_standing(status: StatusNotFiled, observed_at: "2026-09-16T20:30:00Z", expires_at: "2026-09-16T21:00:00Z") { + PollNotFiled => true + _ => false + } +} + +// THE BOUNDARY IS THE CAPABILITY'S: at the exact expires_at the request is expired (the broker +// can no longer redeem the capability), one second before it is still pending / still fileable. +test fn the_exact_expiry_instant_is_expired_and_one_second_before_is_live() -> Bool { + match approval_poll_standing(status: StatusPending { expires_at: "2026-09-16T21:00:00Z" }, observed_at: "2026-09-16T21:00:00Z", expires_at: "2026-09-16T23:00:00Z") { + PollExpired => true + _ => false + } + && match approval_poll_standing(status: StatusNotFiled, observed_at: "2026-09-16T21:00:00Z", expires_at: "2026-09-16T21:00:00Z") { + PollExpired => true + _ => false + } + && match approval_poll_standing(status: StatusPending { expires_at: "2026-09-16T21:00:00Z" }, observed_at: "2026-09-16T20:59:59Z", expires_at: "2026-09-16T21:00:00Z") { + PollStillPending => true + _ => false + } + && match approval_poll_standing(status: StatusNotFiled, observed_at: "2026-09-16T20:59:59Z", expires_at: "2026-09-16T21:00:00Z") { + PollNotFiled => true + _ => false + } +} + + + test fn post_filed_token_admits_poll_including_notify_failure() -> Bool { submission_body_admits_poll(body: submission_filed_text(filed: true, reason: "approval submission: filed esc-1 and notified (ntfy message m)")) && submission_body_admits_poll(body: submission_filed_text(filed: true, reason: "approval submission: escalation esc-1 is already filed")) diff --git a/dag/test/claim/auth/approval_gate_witness_test.dag b/dag/test/claim/auth/approval_gate_witness_test.dag new file mode 100644 index 00000000000..1e6692b3249 --- /dev/null +++ b/dag/test/claim/auth/approval_gate_witness_test.dag @@ -0,0 +1,25 @@ +module test.claim.auth.approval_gate_witness + +import std.types { Bool, NonEmptyStr, Timestamp } +import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } +import gunbc.auth.approval_request_client { PollStillPending, PollExpired, PollApproved, PollNotFiled } +import gunbc.auth.approval_gate { + approval_poll_step, PollReturn, PollSleepAndContinue, PollObservedAt, PollBudgetExhausted, +} + +data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly + +// THE STEP AFTER A READ, in the order the bounded poll depends on: a decided standing returns as +// read whatever the budget (a decision read on the last tick is that decision, review 69509); a +// pending one continues while ticks remain, and with none left is the SPENT BUDGET -- never an +// expiry, which only the timestamp fold may mint; an expiry the timestamp fold did mint returns +// as read. +test fn the_poll_step_returns_a_decision_on_the_last_tick_and_never_relabels_a_spent_budget_as_expiry() -> Bool { + let at = "2026-09-21T10:00:00Z" as Timestamp + let approved = PollApproved { revision: "r" as NonEmptyStr, decided_by: "op" as NonEmptyStr, decided_at: at, execute_by: "2026-09-21T11:00:00Z" as Timestamp } + (match approval_poll_step(escalation_id: "e" as NonEmptyStr, standing: approved, observed_at: at, remaining: 0) { PollReturn { outcome: PollObservedAt { standing: PollApproved { revision: _, decided_by: _, decided_at: _, execute_by: _ }, observed_at: _ } } => true _ => false }) + && (match approval_poll_step(escalation_id: "e" as NonEmptyStr, standing: PollStillPending, observed_at: at, remaining: 0) { PollReturn { outcome: PollBudgetExhausted { escalation_id: e, observed_at: o } } => (e as String) == "e" && o == at _ => false }) + && (match approval_poll_step(escalation_id: "e" as NonEmptyStr, standing: PollStillPending, observed_at: at, remaining: 3) { PollSleepAndContinue { next_remaining: n } => n == 2 _ => false }) + && (match approval_poll_step(escalation_id: "e" as NonEmptyStr, standing: PollExpired, observed_at: at, remaining: 5) { PollReturn { outcome: PollObservedAt { standing: PollExpired, observed_at: _ } } => true _ => false }) + && (match approval_poll_step(escalation_id: "e" as NonEmptyStr, standing: PollNotFiled, observed_at: at, remaining: 0) { PollReturn { outcome: PollObservedAt { standing: PollNotFiled, observed_at: _ } } => true _ => false }) +} diff --git a/dag/test/claim/deepseek/deepseek_v4_1_flash_authority_witness_test.dag b/dag/test/claim/deepseek/deepseek_v4_1_flash_authority_witness_test.dag index 72d7c430c1e..1525b9673e1 100644 --- a/dag/test/claim/deepseek/deepseek_v4_1_flash_authority_witness_test.dag +++ b/dag/test/claim/deepseek/deepseek_v4_1_flash_authority_witness_test.dag @@ -1,7 +1,7 @@ module test.claim.deepseek.deepseek_v4_1_flash_authority_witness import std.types { Bool, String, List, NonEmptyStr } -import std.measure { token_count, token_count_value, token_count_remaining_in_window, byte_size_count } +import std.measure { token_count, token_count_value, token_count_remaining_in_window, byte_size_count, byte_size } import std.roster_frontier { FrontierRow, frontier_rows_well_formed, frontier_rows_keyed_roster_build, frontier_path_subjects, @@ -12,6 +12,14 @@ import std.decl_ref { DeclarationRef, WholeDeclaration, declaration_ref_display_ import extdeps.huggingface.hub { hub_blob_url, hub_repo_tree_api_url, hub_repo_https_uri } import extdeps.uri { uri_wire } import extdeps.deepseek.deepseek_v4_1_flash { + deepseek_v4_1_flash_weight_manifest, deepseek_v4_1_flash_published_file, + deepseek_v4_1_flash_engram_shard_1, deepseek_v4_1_flash_engram_shard_14, + deepseek_v4_1_flash_published_manifest_text, deepseek_v4_1_flash_published_file_row, deepseek_v4_1_flash_tokenizer_role_row, + deepseek_v4_1_flash_admit_weight_manifest, deepseek_v4_1_flash_weight_manifest_standing, WeightManifestAdmitted, WeightManifestRefused, + deepseek_v4_1_flash_index_reading, deepseek_v4_1_flash_index_reading_of, deepseek_v4_1_flash_safetensors_index_file, deepseek_v4_1_flash_safetensors_shard_count, deepseek_v4_1_flash_shard_path, + deepseek_v4_1_flash_admit_tokenizer_population, deepseek_v4_1_flash_tokenizer_standing, deepseek_v4_1_flash_tokenizer_roles, deepseek_v4_1_flash_tokenizer_required_roles, + TokenizerPopulationAdmitted, TokenizerPopulationRefused, TokenizerVocabulary, TokenizerPromptEncoding, TokenizerSpecialTokens, TokenizerGenerationDefaults, RoleNotConsumedByRuntime, RoleNoSeparateFile, RolePublishedFile, + deepseek_v4_1_flash_tokenizer_json_file, deepseek_v4_1_flash_hub_repo, deepseek_v4_1_flash_revision, deepseek_v4_1_flash_encoder_path, deepseek_v4_1_flash_config_path, deepseek_v4_1_flash_license_path, deepseek_v4_1_flash_license_spdx, @@ -206,3 +214,88 @@ test fn dsml_block_name_is_the_encoder_leading_space_not_v4_tool_calls() -> Bool && !(deepseek_v4_1_flash_dsml_tool_calls_block_name as String).contains("tool_calls") && string_contains(s: deepseek_v4_1_flash_dsml_tool_calls_open(), pattern: deepseek_v4_1_flash_dsml_token as String) } + +// THE WEIGHT MANIFEST IS ADMITTED AS AN EXACT POPULATION, NOT COUNTED: the declared 48 rows admit +// (every generated path once, the index's shard set equal to the files', the tree total); the two +// Engram shards in it are the rows their owners declare (one source for path, size and digest). +// The REDs are the mutations a count-and-total fold lets through: one shard replaced by a +// duplicate of another shard OF THE SAME SIZE keeps the count and the total and must refuse +// (duplicate AND absent, named); a foreign path refuses; and the admitted canonical text is +// order-free -- the same rows reversed key identically -- while a path, a size or a digest that +// changes changes it. +test fn the_weight_manifest_admits_exactly_the_48_shards_and_refuses_a_same_size_duplicate() -> Bool { + let rows = deepseek_v4_1_flash_weight_manifest + let admitted = match deepseek_v4_1_flash_weight_manifest_standing() { + WeightManifestAdmitted { files: fs, index: ix, canonical_text: t } => + length(fs) == 48 + && (match first(fs) { Present { value: f } => (f.path as String) == "model-00001-of-00048.safetensors" Absent => false }) + && (ix.path as String) == "model.safetensors.index.json" + && t == deepseek_v4_1_flash_published_manifest_text(rows: concat([ix], reverse(rows))) + && t != deepseek_v4_1_flash_published_manifest_text(rows: rows) + WeightManifestRefused { defects: _ } => false + } + let owners = (match deepseek_v4_1_flash_published_file(path: deepseek_v4_1_flash_engram_shard_1.file.path) { Present { value: f } => (f.sha256.hex as String) == (deepseek_v4_1_flash_engram_shard_1.sha256.hex as String) Absent => false }) + && (match deepseek_v4_1_flash_published_file(path: deepseek_v4_1_flash_engram_shard_14.file.path) { Present { value: f } => (f.sha256.hex as String) == (deepseek_v4_1_flash_engram_shard_14.sha256.hex as String) Absent => false }) + // rows 3 and 4 have the same size: drop row 4 and repeat row 3 -- count 48, total unchanged. + let row3 = rows |> skip(n: 2) |> take(n: 1) + let swapped = concat(rows |> take(n: 3), concat(row3, rows |> skip(n: 4))) + let same_size_duplicate = match deepseek_v4_1_flash_admit_weight_manifest(rows: swapped, index: deepseek_v4_1_flash_index_reading, shard_count: deepseek_v4_1_flash_safetensors_shard_count, tree_bytes: deepseek_v4_1_flash_safetensors_tree_file_bytes) { + WeightManifestRefused { defects: d } => any(d, x => (x as String).contains("more than once: model-00003")) && any(d, x => (x as String).contains("absent: model-00004")) + WeightManifestAdmitted { files: _, index: _, canonical_text: _ } => false + } + let foreign = match deepseek_v4_1_flash_admit_weight_manifest(rows: concat(rows |> take(n: 47), [deepseek_v4_1_flash_published_file_row(path: "model-00049-of-00048.safetensors" as NonEmptyStr, file_bytes: deepseek_v4_1_flash_engram_shard_14.file.file_bytes, sha256_hex: deepseek_v4_1_flash_engram_shard_14.sha256.hex)]), index: deepseek_v4_1_flash_index_reading, shard_count: deepseek_v4_1_flash_safetensors_shard_count, tree_bytes: deepseek_v4_1_flash_safetensors_tree_file_bytes) { + WeightManifestRefused { defects: d } => any(d, x => (x as String).contains("outside the generated shard set: model-00049")) + WeightManifestAdmitted { files: _, index: _, canonical_text: _ } => false + } + // THE INDEX JOIN HAS ITS OWN RED: the same 48 files against an index whose weight_map names one + // shard fewer, and against one naming a 49th, refuse on the index arm alone. + let index_short = deepseek_v4_1_flash_index_reading_of(file: deepseek_v4_1_flash_safetensors_index_file, shard_paths: deepseek_v4_1_flash_index_reading.shard_paths |> take(n: 47)) + let index_wide = deepseek_v4_1_flash_index_reading_of(file: deepseek_v4_1_flash_safetensors_index_file, shard_paths: concat(deepseek_v4_1_flash_index_reading.shard_paths, ["model-00049-of-00048.safetensors" as NonEmptyStr])) + let index_refuses = (match deepseek_v4_1_flash_admit_weight_manifest(rows: rows, index: index_short, shard_count: deepseek_v4_1_flash_safetensors_shard_count, tree_bytes: deepseek_v4_1_flash_safetensors_tree_file_bytes) { WeightManifestRefused { defects: d } => length(d) == 1 && any(d, x => (x as String).contains("weight_map shard population")) _ => false }) + && (match deepseek_v4_1_flash_admit_weight_manifest(rows: rows, index: index_wide, shard_count: deepseek_v4_1_flash_safetensors_shard_count, tree_bytes: deepseek_v4_1_flash_safetensors_tree_file_bytes) { WeightManifestRefused { defects: d } => length(d) == 1 && any(d, x => (x as String).contains("weight_map shard population")) _ => false }) + let text = deepseek_v4_1_flash_published_manifest_text(rows: rows) + let resized = map(rows, r => if (r.path as String) == "model-00002-of-00048.safetensors" { deepseek_v4_1_flash_published_file_row(path: r.path, file_bytes: byte_size(count: byte_size_count(b: r.file_bytes) + 1), sha256_hex: r.sha256.hex) } else { r }) + admitted && owners && same_size_duplicate && foreign && index_refuses + && text != deepseek_v4_1_flash_published_manifest_text(rows: resized) + && (deepseek_v4_1_flash_shard_path(index: 7, count: 48) as String) == "model-00007-of-00048.safetensors" +} + +// THE TOKENIZER POPULATION IS ADMITTED BY ROLE COVER AND KEYED BY THE ROLE MANIFEST: every +// required role carried once, the published files (tokenizer.json, tokenizer_config.json, the +// encoder module) sorted into the projection; a role without a carrier is a named refusal (and +// dropping the vocabulary row also strands the special-tokens role embedded in its file: two +// defects). The REDs the file projection alone would let through: special tokens moved from +// embedded to not-consumed, or generation defaults re-established at another revision, keep the +// file set and change the key; the same rows reordered key identically; one published path with +// two identities refuses. +test fn the_tokenizer_role_manifest_is_the_identity_and_a_missing_role_refuses() -> Bool { + let rows = deepseek_v4_1_flash_tokenizer_roles + let admitted = match deepseek_v4_1_flash_tokenizer_standing() { + TokenizerPopulationAdmitted { files: fs, canonical_text: t } => + length(fs) == 3 + && (match first(fs) { Present { value: f } => (f.path as String) == "encoding/encoding.py" Absent => false }) + && t.contains("configuration published-file tokenizer_config.json 6ac8c8dc") + && t.contains("special-tokens embedded-in tokenizer.json ") + && t.contains("generation-defaults no-separate-file dba1be0a") + TokenizerPopulationRefused { defects: _ } => false + } + let text = match deepseek_v4_1_flash_admit_tokenizer_population(rows: rows, required: deepseek_v4_1_flash_tokenizer_required_roles) { TokenizerPopulationAdmitted { files: _, canonical_text: t } => t TokenizerPopulationRefused { defects: _ } => "" } + let reordered = match deepseek_v4_1_flash_admit_tokenizer_population(rows: reverse(rows), required: deepseek_v4_1_flash_tokenizer_required_roles) { TokenizerPopulationAdmitted { files: _, canonical_text: t } => t == text TokenizerPopulationRefused { defects: _ } => false } + let special_unconsumed = concat(filter(rows, r => match r.role { TokenizerSpecialTokens => false _ => true }), [deepseek_v4_1_flash_tokenizer_role_row(role: TokenizerSpecialTokens, carrier: RoleNotConsumedByRuntime)]) + let moved = match deepseek_v4_1_flash_admit_tokenizer_population(rows: special_unconsumed, required: deepseek_v4_1_flash_tokenizer_required_roles) { TokenizerPopulationAdmitted { files: fs, canonical_text: t } => length(fs) == 3 && t != text TokenizerPopulationRefused { defects: _ } => false } + let other_revision = concat(filter(rows, r => match r.role { TokenizerGenerationDefaults => false _ => true }), [deepseek_v4_1_flash_tokenizer_role_row(role: TokenizerGenerationDefaults, carrier: RoleNoSeparateFile { established_at: "0000000000000000000000000000000000000000" as NonEmptyStr })]) + let re_established = match deepseek_v4_1_flash_admit_tokenizer_population(rows: other_revision, required: deepseek_v4_1_flash_tokenizer_required_roles) { TokenizerPopulationAdmitted { files: fs, canonical_text: t } => length(fs) == 3 && t != text TokenizerPopulationRefused { defects: _ } => false } + let without_vocabulary = filter(rows, r => match r.role { TokenizerVocabulary => false _ => true }) + let missing = match deepseek_v4_1_flash_admit_tokenizer_population(rows: without_vocabulary, required: deepseek_v4_1_flash_tokenizer_required_roles) { + TokenizerPopulationRefused { defects: d } => length(d) == 2 && any(d, x => (x as String).contains("without a carrier: vocabulary")) && any(d, x => (x as String).contains("embedded in a file no role publishes with that identity: tokenizer.json")) + TokenizerPopulationAdmitted { files: _, canonical_text: _ } => false + } + let tj = deepseek_v4_1_flash_tokenizer_json_file + let forged_file = deepseek_v4_1_flash_published_file_row(path: tj.path, file_bytes: byte_size(count: 1), sha256_hex: tj.sha256.hex) + let forged = concat(filter(rows, r => match r.role { TokenizerPromptEncoding => false _ => true }), [deepseek_v4_1_flash_tokenizer_role_row(role: TokenizerPromptEncoding, carrier: RolePublishedFile { file: forged_file })]) + let conflicting = match deepseek_v4_1_flash_admit_tokenizer_population(rows: forged, required: deepseek_v4_1_flash_tokenizer_required_roles) { + TokenizerPopulationRefused { defects: d } => any(d, x => (x as String).contains("two identities: tokenizer.json")) + TokenizerPopulationAdmitted { files: _, canonical_text: _ } => false + } + admitted && reordered && moved && re_established && missing && conflicting +} diff --git a/dag/test/claim/machine_intake/mtcollins1_boot_authorization_witness_test.dag b/dag/test/claim/machine_intake/mtcollins1_boot_authorization_witness_test.dag index cd2110713fd..a5d0aee7037 100644 --- a/dag/test/claim/machine_intake/mtcollins1_boot_authorization_witness_test.dag +++ b/dag/test/claim/machine_intake/mtcollins1_boot_authorization_witness_test.dag @@ -7,18 +7,14 @@ import gunbc.machine_intake_mtcollins1_boot_authorization { mtcollins1_boot_authorization_request, mtcollins1_boot_subject, mtcollins1_boot_required_scopes, - mtcollins1_boot_gate_from_poll, - BootGatePending, - BootGateAdmitted, - BootGateIntentMismatch, - BootGateDenied, - BootGateExpired, - BootGateNotFiled, - BootGateStoreUnreadable, mtcollins1_boot_medium, mtcollins1_boot_medium_image_name, mtcollins1_boot_medium_image_sha256, } +import gunbc.auth.approval_gate { + approval_gate_from_poll, + GateAdmitted, GateRefused, ApprovalPending, ApprovalIntentMismatch, ApprovalDenied, ApprovalExpired, ApprovalNotFiled, ApprovalStoreUnreadable, +} import gunbc.auth.approval_request_client { PollStillPending, PollExpired, PollDenied, PollNotFiled, PollUnreadable, PollApproved } import gunbc.auth.approval_decision_store { request_revision_of } import extdeps.toolchain.types { Aarch64 } @@ -60,24 +56,24 @@ test fn pending_denied_expired_and_unfiled_do_not_write_the_controller() -> Bool decided_at: at, reason: "no" as NonEmptyStr, } - match mtcollins1_boot_gate_from_poll(poll: PollStillPending, request: r, observed_at: at) { - BootGatePending { escalation_id: _ } => true + match approval_gate_from_poll(poll: PollStillPending, request: r, observed_at: at) { + GateRefused { cause: ApprovalPending { escalation_id: _ } } => true _ => false } - && match mtcollins1_boot_gate_from_poll(poll: denied, request: r, observed_at: at) { - BootGateDenied { reason: _ } => true + && match approval_gate_from_poll(poll: denied, request: r, observed_at: at) { + GateRefused { cause: ApprovalDenied { reason: _ } } => true _ => false } - && match mtcollins1_boot_gate_from_poll(poll: PollExpired, request: r, observed_at: at) { - BootGateExpired => true + && match approval_gate_from_poll(poll: PollExpired, request: r, observed_at: at) { + GateRefused { cause: ApprovalExpired } => true _ => false } - && match mtcollins1_boot_gate_from_poll(poll: PollNotFiled, request: r, observed_at: at) { - BootGateNotFiled { escalation_id: _ } => true + && match approval_gate_from_poll(poll: PollNotFiled, request: r, observed_at: at) { + GateRefused { cause: ApprovalNotFiled { escalation_id: _ } } => true _ => false } - && match mtcollins1_boot_gate_from_poll(poll: PollUnreadable { detail: "get failed" as NonEmptyStr }, request: r, observed_at: at) { - BootGateStoreUnreadable { detail: _ } => true + && match approval_gate_from_poll(poll: PollUnreadable { detail: "get failed" as NonEmptyStr }, request: r, observed_at: at) { + GateRefused { cause: ApprovalStoreUnreadable { detail: _ } } => true _ => false } } @@ -88,8 +84,8 @@ test fn poll_pending_is_the_pending_gate() -> Bool { attempt: "mtc1-1" as AttemptIdentity, execution_revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", ) - match mtcollins1_boot_gate_from_poll(poll: PollStillPending, request: r, observed_at: "2026-09-16T20:30:00Z") { - BootGatePending { escalation_id: e } => e as String == "esc-mtc1-1" + match approval_gate_from_poll(poll: PollStillPending, request: r, observed_at: "2026-09-16T20:30:00Z") { + GateRefused { cause: ApprovalPending { escalation_id: e } } => e as String == "esc-mtc1-1" _ => false } } @@ -114,12 +110,12 @@ test fn poll_approved_http_fields_admit_and_a_foreign_revision_does_not() -> Boo decided_at: at, execute_by: until, } - match mtcollins1_boot_gate_from_poll(poll: matching, request: r, observed_at: at) { - BootGateAdmitted { authorization: _ } => true + match approval_gate_from_poll(poll: matching, request: r, observed_at: at) { + GateAdmitted { authorization: _ } => true _ => false } - && match mtcollins1_boot_gate_from_poll(poll: foreign, request: r, observed_at: at) { - BootGateIntentMismatch { requested_revision: _, decided_revision: d } => d as String == "other-intent" + && match approval_gate_from_poll(poll: foreign, request: r, observed_at: at) { + GateRefused { cause: ApprovalIntentMismatch { requested_revision: _, decided_revision: d } } => d as String == "other-intent" _ => false } } @@ -138,8 +134,8 @@ test fn an_execute_by_that_lapses_after_poll_is_expired_on_the_actuation_clock() decided_at: poll_at, execute_by: until, } - match mtcollins1_boot_gate_from_poll(poll: matching, request: r, observed_at: poll_at) { - BootGateAdmitted { authorization: auth } => + match approval_gate_from_poll(poll: matching, request: r, observed_at: poll_at) { + GateAdmitted { authorization: auth } => match authorize(authorization: auth, request: r, observed_at: "2026-09-16T20:45:01Z") { AuthorizationRefused { cause: AuthorizationExpired { expires_at: _, observed_at: _ } } => true _ => false diff --git a/dag/test/claim/machine_intake/mtcollins1_boot_run_witness_test.dag b/dag/test/claim/machine_intake/mtcollins1_boot_run_witness_test.dag index b81ecca2c5a..06d4fced1c8 100644 --- a/dag/test/claim/machine_intake/mtcollins1_boot_run_witness_test.dag +++ b/dag/test/claim/machine_intake/mtcollins1_boot_run_witness_test.dag @@ -9,13 +9,14 @@ import gunbc.machine_intake_mtcollins1_boot_run { mtcollins1_boot_step_timeout_minutes, mtcollins1_boot_prelude_allowance, mtcollins1_boot_actuation_allowance, mtcollins1_boot_issue_allowance, mtcollins1_boot_cleanup_allowance, mtcollins1_boot_submit_timeout, - mtcollins1_status_from_get, mtcollins1_boot_instant_from_probe, mtcollins1_boot_sol_is_held, + mtcollins1_boot_sol_is_held, mtcollins1_boot_sol_held_from_observations, mtcollins1_sol_observed_from_collector, mtcollins1_boot_terminal_observed, mtcollins1_boot_medium_refusal, mtcollins1_boot_host_must_be_srv1, mtcollins1_boot_refuses_off_srv1, } +import gunbc.auth.approval_gate { approval_status_from_get, approval_instant_from_probe } import gunbc.fleet_intent_network { operator_host_srv1, operator_host_srv2 } import gunbc.fleet_converge_workflow { fleet_converge_fleet_ssh_key_step_if } import std.process { ExitSuccess } @@ -68,12 +69,12 @@ test fn a_zero_window_expires_on_the_next_observation() -> Bool { } test fn a_failed_status_get_is_unreadable_not_pending() -> Bool { - match mtcollins1_status_from_get(success: false, body: "") { + match approval_status_from_get(success: false, body: "") { StatusUnreadable { detail: _ } => true _ => false } && match approval_poll_standing( - status: mtcollins1_status_from_get(success: false, body: ""), + status: approval_status_from_get(success: false, body: ""), observed_at: "2026-09-16T20:00:00Z", expires_at: "2026-09-16T20:22:30Z", ) { @@ -87,9 +88,9 @@ test fn a_failed_status_get_is_unreadable_not_pending() -> Bool { } test fn clock_unreadable_is_not_an_observation_instant() -> Bool { - match mtcollins1_boot_instant_from_probe(reading: none) { Absent => true _ => false } - && match mtcollins1_boot_instant_from_probe(reading: Present { value: "clock-unreadable" as NonEmptyStr }) { Absent => true _ => false } - && match mtcollins1_boot_instant_from_probe(reading: Present { value: "2026-09-16T20:00:00Z" as NonEmptyStr }) { + match approval_instant_from_probe(reading: none) { Absent => true _ => false } + && match approval_instant_from_probe(reading: Present { value: "clock-unreadable" as NonEmptyStr }) { Absent => true _ => false } + && match approval_instant_from_probe(reading: Present { value: "2026-09-16T20:00:00Z" as NonEmptyStr }) { Present { value: t } => t as String == "2026-09-16T20:00:00Z" _ => false } diff --git a/dag/test/claim/spark/pair_serving_d0_authorization_witness_test.dag b/dag/test/claim/spark/pair_serving_d0_authorization_witness_test.dag new file mode 100644 index 00000000000..d5a47a78746 --- /dev/null +++ b/dag/test/claim/spark/pair_serving_d0_authorization_witness_test.dag @@ -0,0 +1,126 @@ +module test.claim.spark.pair_serving_d0_authorization_witness + +import std.logic { Bool } +import std.types { String, NonEmptyStr, List, Timestamp } +import v2.std.optional { Present, Absent } +import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } +import std.content_hash { ContentHash, Sha256Hash, sha256_hex_digest, serialize_content_hash } +import std.scoped_authorization { AuthorizationRequest, AuthorizationGranted } +import gunbc.auth.approval_decision_store { request_revision_of } +import gunbc.auth.approval_request_client { PollApproved, PollNotFiled, PollStillPending, PollDenied } +import gunbc.auth.approval_gate { StandingReadAt, StandingClockUnreadable, ApprovalDenied } +import gunbc.spark.pair_serving_d0_door { d0_absent_claim_step, D0AbsentClaimClockUnreadable, D0AbsentClaimFileFrozen, D0AbsentClaimEnterPoll, D0AbsentClaimDecided } +import gunbc.spark.fabric_switch_observed { FabricGroupA } +import std.measure { second } +import gunbc.spark.fabric_switch_observed { fabric_group_hosts } +import gunbc.spark.released_baseline { QuiescentReservedBaseline } +import gunbc.spark.pair_serving_d0 { D0Subject, d0_request, d0_intent_text, d0_intent_hash } +import gunbc.spark.v41_runtime_candidate { V41CandidateRefused, V41CandidateUnestablished } +import gunbc.spark.pair_serving_d0_authorization { + D0SubjectFor, D0SubjectUnestablished, D0SubjectRefused, d0_live_subject, d0_subject_of_candidate, + D0FiledRequestFor, D0FiledRequestRefused, d0_filed_request, + d0_resumable_authorization, D0Resumable, D0NotRecorded, D0NotClaimedHere, +} +import gunbc.spark.pair_serving_d0 { D0ClaimAbsent, D0ClaimAt } +import std.scoped_authorization { ClaimedBy, CompletedBy, AttemptIdentity } +import gunbc.auth.approval_gate { approval_gate_from_poll, approval_recorded_from_poll, ApprovalRecorded, ApprovalNotRecorded, GateAdmitted, GateRefused, ApprovalAuthorizeRefused, ApprovalIntentMismatch } + +data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly + +fn w_sha(hex: String) -> ContentHash? { + match sha256_hex_digest(hex: hex) { Absent => none Present { value: d } => Present { value: Sha256Hash(d) } } +} + +fn w_request(intent: ContentHash) -> AuthorizationRequest { + d0_request(escalation_id: "d0-esc-1" as NonEmptyStr, subject: D0Subject { group: FabricGroupA, hosts: fabric_group_hosts(g: FabricGroupA), successor: intent, cleanup: QuiescentReservedBaseline, term: second(count: 1000) }, transaction: "tx-1" as NonEmptyStr, intent: intent) +} + +// THE LIVE SUBJECT FOLLOWS THE CANDIDATE: while gunbc.spark.v41_runtime_candidate leaves an axis +// unestablished there is no subject and the obligations are the candidate's own (the row-store +// digest, at this writing); a keyed candidate is the successor. The claim is exhaustive over +// both so it flips, rather than rots, when Cut 0 completes. +test fn the_live_subject_exists_exactly_when_the_candidate_is_keyed() -> Bool { + let live = match d0_live_subject(group: FabricGroupA) { + D0SubjectUnestablished { obligations: o } => length(o) >= 1 && any(o, x => (x as String).contains("row-store")) + D0SubjectFor { subject: s } => length(s.hosts) == 4 + D0SubjectRefused { defects: _ } => false + } + let refused = match d0_subject_of_candidate(group: FabricGroupA, standing: V41CandidateRefused { defects: ["weight manifest: path declared more than once" as NonEmptyStr] }) { D0SubjectRefused { defects: d } => length(d) == 1 _ => false } + let pending = match d0_subject_of_candidate(group: FabricGroupA, standing: V41CandidateUnestablished { obligations: ["row-store digest" as NonEmptyStr] }) { D0SubjectUnestablished { obligations: o } => length(o) == 1 _ => false } + live && refused && pending +} + +// THE FILED REQUEST IS THE FROZEN TEXT, EXACTLY. The intent text a live request is frozen as +// parses back to the same subject and digests to the same revision, so a rerun re-derives the +// request the operator decided over; the same text under another group or transaction is refused +// as another filing, not resumed; and a hosts order in the text is not identity (the wire sorts). +test fn a_frozen_intent_re_derives_the_filed_request_and_refuses_another_transaction() -> Bool { + match w_sha(hex: "1111111111111111111111111111111111111111111111111111111111111111") { + Absent => false + Present { value: successor } => { + let subject = D0Subject { group: FabricGroupA, hosts: fabric_group_hosts(g: FabricGroupA), successor: successor, cleanup: QuiescentReservedBaseline, term: second(count: 1000) } + let text = d0_intent_text(subject: subject, group: FabricGroupA, transaction: "tx-1" as NonEmptyStr) + let same = match d0_filed_request(text: text, group: FabricGroupA, escalation_id: "d0-esc-1" as NonEmptyStr, transaction: "tx-1" as NonEmptyStr) { + D0FiledRequestFor { request: r, intent_text: t } => + t == text + && (match d0_intent_hash(subject: subject, group: FabricGroupA, transaction: "tx-1" as NonEmptyStr) { Present { value: h } => (request_revision_of(request: r) as String) == (serialize_content_hash(hash: h) as String) Absent => false }) + && length(r.subject.hosts) == 4 + && (r.escalation_id as String) == "d0-esc-1" + D0FiledRequestRefused { reason: _ } => false + } + let other_tx = match d0_filed_request(text: text, group: FabricGroupA, escalation_id: "d0-esc-1" as NonEmptyStr, transaction: "tx-2" as NonEmptyStr) { D0FiledRequestRefused { reason: r } => (r as String).contains("tx-1") _ => false } + let garbage = match d0_filed_request(text: "not an intent", group: FabricGroupA, escalation_id: "d0-esc-1" as NonEmptyStr, transaction: "tx-1" as NonEmptyStr) { D0FiledRequestRefused { reason: _ } => true _ => false } + let edited = match d0_filed_request(text: join([text, "x"], ""), group: FabricGroupA, escalation_id: "d0-esc-1" as NonEmptyStr, transaction: "tx-1" as NonEmptyStr) { D0FiledRequestRefused { reason: _ } => true _ => false } + same && other_tx && garbage && edited + } + } +} + +// A RECORDED APPROVAL IS NOT AN ADMISSION: the same approved decision that the live gate refuses +// after execute_by is handed back as recorded by its own constructor, and D0 turns it into a +// resumable authorization ONLY against a claim held by this transaction -- an absent claim (a +// start), another attempt's claim and a completed claim each refuse without consulting the +// decision's window. An approval over another revision is a mismatch under either fold. +test fn a_recorded_approval_resumes_only_under_this_transactions_held_claim() -> Bool { + match w_sha(hex: "1111111111111111111111111111111111111111111111111111111111111111") { + Absent => false + Present { value: intent } => { + let req = w_request(intent: intent) + let rev = request_revision_of(request: req) + let at = "2026-09-21T02:00:00Z" as Timestamp + let until = "2026-09-21T03:00:00Z" as Timestamp + let approved = PollApproved { revision: rev, decided_by: "operator" as NonEmptyStr, decided_at: at, execute_by: until } + let held = D0ClaimAt { state: ClaimedBy { attempt: "tx-1" as AttemptIdentity, claimed_at: at }, generation: 1 } + let other = D0ClaimAt { state: ClaimedBy { attempt: "tx-9" as AttemptIdentity, claimed_at: at }, generation: 1 } + let done = D0ClaimAt { state: CompletedBy { attempt: "tx-1" as AttemptIdentity, completed_at: at }, generation: 2 } + (match approval_gate_from_poll(poll: approved, request: req, observed_at: "2026-09-21T04:00:00Z" as Timestamp) { GateRefused { cause: ApprovalAuthorizeRefused { detail: _ } } => true _ => false }) + && (match approval_recorded_from_poll(poll: approved, request: req) { ApprovalRecorded { authorization: AuthorizationGranted { grant: g, claim: _ } } => (g.escalation_id as String) == "d0-esc-1" _ => false }) + && (match d0_resumable_authorization(claim: held, transaction: "tx-1" as NonEmptyStr, poll: approved, request: req) { D0Resumable { authorization: _ } => true _ => false }) + && (match d0_resumable_authorization(claim: D0ClaimAbsent, transaction: "tx-1" as NonEmptyStr, poll: approved, request: req) { D0NotClaimedHere { reason: _ } => true _ => false }) + && (match d0_resumable_authorization(claim: other, transaction: "tx-1" as NonEmptyStr, poll: approved, request: req) { D0NotClaimedHere { reason: r } => (r as String).contains("tx-9") _ => false }) + && (match d0_resumable_authorization(claim: done, transaction: "tx-1" as NonEmptyStr, poll: approved, request: req) { D0NotClaimedHere { reason: _ } => true _ => false }) + && (match d0_resumable_authorization(claim: held, transaction: "tx-1" as NonEmptyStr, poll: PollApproved { revision: "sha256:0000" as NonEmptyStr, decided_by: "operator" as NonEmptyStr, decided_at: at, execute_by: until }, request: req) { D0NotRecorded { cause: ApprovalIntentMismatch { requested_revision: _, decided_revision: _ } } => true _ => false }) + } + } +} + +// THE DOOR'S STEP FOR A FROZEN FILING WITH NO CLAIM: not filed files the frozen request, pending +// enters the poll, a decision goes through the live gate at the instant of the read (an approval +// inside its window admits; a denial refuses), and an unreadable clock refuses before any of it. +test fn a_frozen_filing_with_no_claim_files_polls_or_decides_live_by_the_read() -> Bool { + match w_sha(hex: "1111111111111111111111111111111111111111111111111111111111111111") { + Absent => false + Present { value: intent } => { + let req = w_request(intent: intent) + let rev = request_revision_of(request: req) + let at = "2026-09-21T02:00:00Z" as Timestamp + let until = "2026-09-21T03:00:00Z" as Timestamp + (match d0_absent_claim_step(read: StandingReadAt { standing: PollNotFiled, observed_at: at }, request: req) { D0AbsentClaimFileFrozen => true _ => false }) + && (match d0_absent_claim_step(read: StandingReadAt { standing: PollStillPending, observed_at: at }, request: req) { D0AbsentClaimEnterPoll => true _ => false }) + && (match d0_absent_claim_step(read: StandingReadAt { standing: PollApproved { revision: rev, decided_by: "operator" as NonEmptyStr, decided_at: at, execute_by: until }, observed_at: "2026-09-21T02:30:00Z" as Timestamp }, request: req) { D0AbsentClaimDecided { gate: GateAdmitted { authorization: _ } } => true _ => false }) + && (match d0_absent_claim_step(read: StandingReadAt { standing: PollApproved { revision: rev, decided_by: "operator" as NonEmptyStr, decided_at: at, execute_by: until }, observed_at: "2026-09-21T04:00:00Z" as Timestamp }, request: req) { D0AbsentClaimDecided { gate: GateRefused { cause: ApprovalAuthorizeRefused { detail: _ } } } => true _ => false }) + && (match d0_absent_claim_step(read: StandingReadAt { standing: PollDenied { revision: rev, decided_by: "operator" as NonEmptyStr, decided_at: at, reason: "no" as NonEmptyStr }, observed_at: at }, request: req) { D0AbsentClaimDecided { gate: GateRefused { cause: ApprovalDenied { reason: _ } } } => true _ => false }) + && (match d0_absent_claim_step(read: StandingClockUnreadable, request: req) { D0AbsentClaimClockUnreadable => true _ => false }) + } + } +} diff --git a/dag/test/claim/spark/pair_serving_d0_real_execution_witness_test.dag b/dag/test/claim/spark/pair_serving_d0_real_execution_witness_test.dag index 2dd30b7abaf..d8b4c0c4ebf 100644 --- a/dag/test/claim/spark/pair_serving_d0_real_execution_witness_test.dag +++ b/dag/test/claim/spark/pair_serving_d0_real_execution_witness_test.dag @@ -51,7 +51,12 @@ import gunbc.spark.pair_serving_d0 { AdmittedD0Grant, D0GrantAdmitted, D0GrantClaimLost, D0GrantForAnotherPopulation, admit_d0_grant, resume_d0_grant, d0_intent_hash, d0_authorized_action, D0ClaimReading, D0ClaimAbsent, D0ClaimAt, D0ClaimUnreadable, d0_read_claim, d0_terminate_claim, D0ClaimTerminated, D0Recovery, D0RecoverStart, D0RecoverFirstWrite, D0RecoverResume, D0RecoverComplete, D0RecoverAbort, D0RecoveryRefused, d0_recovery, + d0_intent_text, d0_freeze_filing, D0FilingFrozen, D0FilingAlreadyHeld, D0FilingFreezeRefused, d0_read_filing, D0FilingAt, D0FilingAbsent, D0FilingUnreadable, + D0GrantRefused, } +import gunbc.spark.pair_serving_d0_authorization { d0_filed_request, D0FiledRequestFor, D0FiledRequestRefused } +import gunbc.spark.pair_serving_d0_door { d0_run_kind, D0FirstRun, D0Rerun, D0RunRefused } +import gunbc.auth.approval_decision_store { request_revision_of } import std.scoped_authorization { ClaimedBy, CompletedBy, AbortedBy } import product.placement_supply { HostIdentity } import gunbc.fleet_intent_network { operator_host_srv1 } @@ -895,3 +900,92 @@ fn d0r_committed_to_group_a(standings: List, host: HostIdenti any(spark_authority_held_causes_of(c: c), o => match o { MemberOfClaimedServingGroup { group: FabricGroupA } => true _ => false }) } } + +// THE FILING IS FROZEN ONCE AND READ BACK AS THE SAME REQUEST, on the real store: the first +// freeze lands at generation 1; a second freeze of the same escalation is refused as already +// held and hands back the frozen text; the text re-derives the request the operator decided over +// (same revision) with NO live subject consulted -- a rerun after the candidate re-keys or the +// hosts move still finds the request it filed; and a rerun naming another transaction under the +// same escalation is refused rather than resumed. +test fn a_filing_frozen_once_is_read_back_as_the_same_request_without_a_live_subject_by_real_execution() -> Bool { + d0r_with_hash(scenario: fn(h) { + d0r_with_remote(scenario: fn(dir, store) { + let subject = D0Subject { group: FabricGroupA, hosts: fabric_group_hosts(g: FabricGroupA), successor: h, cleanup: QuiescentReservedBaseline, term: second(count: 1000) } + let text = d0_intent_text(subject: subject, group: FabricGroupA, transaction: "tx-d0" as NonEmptyStr) + let esc = "esc-d0-filing" as NonEmptyStr + let absent_before = match d0_read_filing(store: store, escalation_id: esc) { D0FilingAbsent => true _ => false } + let frozen = match d0_freeze_filing(store: store, escalation_id: esc, intent_text: text) { D0FilingFrozen => true _ => false } + let held = match d0_freeze_filing(store: store, escalation_id: esc, intent_text: join([text, "tampered"], "")) { D0FilingAlreadyHeld { text: t } => t == text _ => false } + let read = match d0_read_filing(store: store, escalation_id: esc) { D0FilingAt { text: t } => t == text _ => false } + let same_request = match d0r_w_authorization(successor: h, tx: "tx-d0" as NonEmptyStr, escalation: esc) { + Absent => false + Present { value: AuthorizationGranted { grant: g, claim: _ } } => + match d0_filed_request(text: text, group: FabricGroupA, escalation_id: esc, transaction: "tx-d0" as NonEmptyStr) { + D0FiledRequestFor { request: r, intent_text: _ } => (request_revision_of(request: r) as String) == (serialize_content_hash(hash: g.intent_hash) as String) && content_hash_equal(left: r.subject.successor, right: h) + D0FiledRequestRefused { reason: _ } => false + } + Present { value: _ } => false + } + let other_tx = match d0_filed_request(text: text, group: FabricGroupA, escalation_id: esc, transaction: "tx-else" as NonEmptyStr) { D0FiledRequestRefused { reason: _ } => true _ => false } + absent_before && frozen && held && read && same_request && other_tx + }) + }) +} + +// THE CLAIM IS AUTHORIZED AT THE INSTANT IT IS MADE, and the window has both bounds: an approval +// whose execute_by has passed by the time the claim would land is refused at admission, and so is +// an instant BEFORE the grant (a stale or fabricated clock) -- no claim is taken on the store and +// no authority write follows either way -- while the same grant admitted at an instant inside its +// window claims. +test fn a_grant_whose_window_passed_before_the_claim_takes_no_claim_by_real_execution() -> Bool { + d0r_with_hash(scenario: fn(h) { + d0r_with_remote(scenario: fn(dir, store) { + match d0r_w_authorization(successor: h, tx: "tx-d0" as NonEmptyStr, escalation: "esc-d0-late" as NonEmptyStr) { + Absent => false + Present { value: auth } => { + let late = match admit_d0_grant(store: store, authorization: auth, escalation_id: "esc-d0-late" as NonEmptyStr, group: FabricGroupA, current_hosts: fabric_group_hosts(g: FabricGroupA), transaction: "tx-d0" as NonEmptyStr, executor: "witness" as NonEmptyStr, at: 1000, now: "2026-09-19T00:00:01Z") { + D0GrantRefused { cause: _ } => true + _ => false + } + let early = match admit_d0_grant(store: store, authorization: auth, escalation_id: "esc-d0-late" as NonEmptyStr, group: FabricGroupA, current_hosts: fabric_group_hosts(g: FabricGroupA), transaction: "tx-d0" as NonEmptyStr, executor: "witness" as NonEmptyStr, at: 1000, now: "2026-09-17T23:59:59Z") { + D0GrantRefused { cause: _ } => true + _ => false + } + let unclaimed = match d0_read_claim(store: store, escalation_id: "esc-d0-late" as NonEmptyStr) { D0ClaimAbsent => true _ => false } + let in_window = match admit_d0_grant(store: store, authorization: auth, escalation_id: "esc-d0-late" as NonEmptyStr, group: FabricGroupA, current_hosts: fabric_group_hosts(g: FabricGroupA), transaction: "tx-d0" as NonEmptyStr, executor: "witness" as NonEmptyStr, at: 1000, now: "2026-09-18T23:59:59Z") { + D0GrantAdmitted { admitted: _ } => true + _ => false + } + late && early && unclaimed && in_window && d0r_claim_is(store: store, escalation: "esc-d0-late" as NonEmptyStr, by: "tx-d0", completed: false) + } + } + }) + }) +} + +// THE DOOR DECIDES WHICH RUN THIS IS FROM THE STORE, BY REAL EXECUTION: with nothing frozen and the +// live candidate unkeyed (the row-store digest is still owed) a first run refuses before filing -- +// and freezes nothing; once a filing is frozen under the escalation, the same call is a rerun +// carrying the frozen request, with no live subject consulted; and the frozen filing under another +// transaction's name refuses. +test fn the_door_reads_the_frozen_filing_to_decide_a_rerun_without_a_live_subject_by_real_execution() -> Bool { + d0r_with_hash(scenario: fn(h) { + d0r_with_remote(scenario: fn(dir, store) { + let esc = "esc-d0-door" as NonEmptyStr + let first = match d0_run_kind(store: store, g: FabricGroupA, escalation_id: esc, transaction: "tx-d0" as NonEmptyStr) { + D0RunRefused { reason: r } => r.contains("row-store") || r.contains("refused") + D0FirstRun { request: _ } => false + D0Rerun { request: _ } => false + } + let nothing_frozen = match d0_read_filing(store: store, escalation_id: esc) { D0FilingAbsent => true _ => false } + let subject = D0Subject { group: FabricGroupA, hosts: fabric_group_hosts(g: FabricGroupA), successor: h, cleanup: QuiescentReservedBaseline, term: second(count: 1000) } + let frozen = match d0_freeze_filing(store: store, escalation_id: esc, intent_text: d0_intent_text(subject: subject, group: FabricGroupA, transaction: "tx-d0" as NonEmptyStr)) { D0FilingFrozen => true _ => false } + let rerun = match d0_run_kind(store: store, g: FabricGroupA, escalation_id: esc, transaction: "tx-d0" as NonEmptyStr) { + D0Rerun { request: r } => content_hash_equal(left: r.subject.successor, right: h) && (r.escalation_id as String) == "esc-d0-door" + _ => false + } + let other = match d0_run_kind(store: store, g: FabricGroupA, escalation_id: esc, transaction: "tx-else" as NonEmptyStr) { D0RunRefused { reason: r } => r.contains("tx-d0") _ => false } + first && nothing_frozen && frozen && rerun && other + }) + }) +} diff --git a/dag/test/claim/spark/pair_serving_d0_witness_test.dag b/dag/test/claim/spark/pair_serving_d0_witness_test.dag index 519b90c085c..9137ec67015 100644 --- a/dag/test/claim/spark/pair_serving_d0_witness_test.dag +++ b/dag/test/claim/spark/pair_serving_d0_witness_test.dag @@ -40,7 +40,6 @@ import gunbc.spark.pair_serving_d0 { D0Decision, D0DecidedSuspend, D0DecidedRestore, D0DecidedFence, D0Cause, D0IncumbentLive, D0IncumbentUnidentified, D0OccupancyUnread, D0DeclarationUnavailable, d0_decide, d0_decision_is_eligible, d0_authorized_action, d0_intent_text, D0Population, D0PopulationAgrees, D0PopulationDiffers, d0_population, - D0AuthorizationStanding, D0AuthorizationResolved, D0AuthorizationUnestablished, resolve_d0_authorization, D0ClaimReading, D0ClaimAbsent, D0ClaimAt, D0ClaimUnreadable, D0Recovery, D0RecoverStart, D0RecoverFirstWrite, D0RecoverResume, D0RecoverComplete, D0RecoverAbort, D0RecoveryRefused, d0_recovery, } @@ -330,15 +329,11 @@ test fn an_answering_but_unidentified_incumbent_fences() -> Bool { }) } -// THE ENTRY IS NON-ADMITTING TODAY BY CONSTRUCTION: no authorization id resolves to a scoped -// authorization, so the wet entry refuses before its first write. This is the wall's executed -// red; the positive route is driven by the real-execution witness with a fixture grant. -test fn no_authorization_resolves_today_so_the_entry_cannot_admit() -> Bool { - match resolve_d0_authorization(group: FabricGroupA, authorization: "esc-anything") { - D0AuthorizationUnestablished { obligation: _ } => true - D0AuthorizationResolved { authorization: _ } => false - } -} +// THE ENTRY ADMITS ONLY THROUGH THE PRODUCER: the request over the exact operation exists only +// when the successor is keyed, and the door (gunbc.spark.pair_serving_d0_door) files it and admits +// only an approval over that request's revision -- test.claim.spark.pair_serving_d0_authorization_witness +// drives both. What this module's wall still executes: the door refuses before any write while +// either store wall stands (the claim below), so no authorization opens it today. fn d0w_port(n: Int) -> Port { n diff --git a/dag/test/claim/spark/v41_runtime_candidate_witness_test.dag b/dag/test/claim/spark/v41_runtime_candidate_witness_test.dag index d4af06116ee..10683e2f694 100644 --- a/dag/test/claim/spark/v41_runtime_candidate_witness_test.dag +++ b/dag/test/claim/spark/v41_runtime_candidate_witness_test.dag @@ -18,7 +18,7 @@ import gunbc.spark.v41_runtime_candidate { V41EnginePatch, v41_engine_patch, V41PatchPopulation, V41PatchesObserved, V41PatchesAbsentByObservation, V41PatchesUnestablished, V41EngramPartitionAuthority, PartitionFixedByPatch, PartitionByLaunchConfiguration, V41RuntimeArtifactInputs, V41ModelSourceInputs, V41EngramRealizationInputs, V41CandidateInputs, - V41ManifestObserved, V41ManifestUnestablished, + V41ManifestObserved, V41ManifestUnestablished, V41ManifestRefused, V41ModelSourceInputs, v41_model_source_key, V41IdentityRefused, V41IdentityUnestablished, V41IdentityKeyed, V41EngramResidencyPartition, V41PartitionAdmitted, V41PartitionRefused, v41_admit_partition, V41CandidateStanding, V41CandidateVerdict, V41CandidateKeyed, V41CandidateUnestablished, V41CandidateRefused, v41_candidate_standing, v41_candidate, v41_candidate_inputs, v41_candidate_partition, v41_candidate_recipe, @@ -133,20 +133,43 @@ fn w_refused_with(s: V41CandidateVerdict, fragment: String) -> Bool { } } -// THE LIVE CANDIDATE HAS NO KEY, AND SAYS WHAT IS MISSING. Patch bytes are not in this change; -// DigestFile + upsert_decision apply is the next PR. Weight/tokenizer manifests and row-store +// THE LIVE CANDIDATE'S REMAINING OBLIGATION IS THE ROW STORE ALONE (Cut 0, 2026-09-21): the weight +// manifest (48 shard digests at dba1be0a) and the tokenizer files are keyed from the publisher's +// declared digests in extdeps.deepseek.deepseek_v4_1_flash, so neither names an obligation any +// more; the published-shard row-store content digest is a fleet-side reading and still does. // content digest are also open. test fn the_live_candidate_is_unestablished_and_names_every_missing_axis() -> Bool { match v41_candidate().standing { V41CandidateUnestablished { obligations: o } => - any(o, x => (x as String).contains("weight manifest")) - && any(o, x => (x as String).contains("tokenizer")) + !any(o, x => (x as String).contains("weight manifest")) + && !any(o, x => (x as String).contains("tokenizer")) && any(o, x => (x as String).contains("published-shard row-store")) V41CandidateKeyed { runtime_artifact: _, model_source: _, engram_realization: _, execution_profile: _, candidate: _, authorization_obligation: _ } => false V41CandidateRefused { defects: _ } => false } } +// A DEFECT IS NOT AN OBLIGATION: a refused weight population refuses the model source naming the +// defects (and the candidate with it), while an undigested tokenizer is an obligation; both present, +// the defect is answered, never hidden behind pending work -- including on the Engram axis, where a +// refused row store under a membership residual refuses rather than joining the residual's obligations. +test fn a_refused_manifest_refuses_the_model_source_and_is_not_an_obligation() -> Bool { + let refused = V41ModelSourceInputs { checkpoint_revision: "dba1be0a40aa45a94ad051997016db3960a90277" as NonEmptyStr, weights: V41ManifestRefused { first: "weight manifest: path declared more than once: model-00003-of-00048.safetensors" as NonEmptyStr, rest: [] as List }, tokenizer: V41ManifestUnestablished { obligation: "the tokenizer text could not be digested" as NonEmptyStr } } + let pending = V41ModelSourceInputs { checkpoint_revision: "dba1be0a40aa45a94ad051997016db3960a90277" as NonEmptyStr, weights: V41ManifestObserved { digest: w_sha(c: "a") }, tokenizer: V41ManifestUnestablished { obligation: "the tokenizer text could not be digested" as NonEmptyStr } } + let residual_and_refused = v41_candidate_standing(c: V41CandidateInputs { + runtime: w_default(patches: w_two_patches()).runtime, + model_source: w_default(patches: w_two_patches()).model_source, + engram: V41EngramRealizationInputs { partition: v41_candidate_partition, population: deepseek_v4_1_flash_engram_population, row_store_encoding: V41ManifestRefused { first: "row store: a row of another table" as NonEmptyStr, rest: [] as List }, route: engram_route_b_identity }, + topology: topology_shape(tensor_parallel_degree: 4, replica_count: 1), + device: gb10_observed_compute_capability, + }) + (match v41_model_source_key(s: refused) { V41IdentityRefused { defects: d } => length(d) == 1 && any(d, x => (x as String).contains("more than once")) _ => false }) + && (match v41_model_source_key(s: pending) { V41IdentityUnestablished { obligations: o } => length(o) == 1 _ => false }) + && (match residual_and_refused.standing { V41CandidateRefused { defects: d } => any(d, x => (x as String).contains("another table")) _ => false }) + && (match v41_candidate_standing(c: V41CandidateInputs { runtime: w_default(patches: w_two_patches()).runtime, model_source: refused, engram: w_default(patches: w_two_patches()).engram, topology: topology_shape(tensor_parallel_degree: 4, replica_count: 1), device: gb10_observed_compute_capability }).standing { V41CandidateRefused { defects: d } => any(d, x => (x as String).contains("more than once")) _ => false }) + && (match v41_candidate_standing(c: V41CandidateInputs { runtime: w_default(patches: w_two_patches()).runtime, model_source: pending, engram: w_default(patches: w_two_patches()).engram, topology: topology_shape(tensor_parallel_degree: 4, replica_count: 1), device: gb10_observed_compute_capability }).standing { V41CandidateUnestablished { obligations: o } => length(o) == 1 && any(o, x => (x as String).contains("tokenizer")) _ => false }) +} + // THE POSITIVE CONTROL: the same inputs with every axis established key, and the keyed candidate still // carries the authorization obligation -- identity is not permission. test fn an_established_fixture_is_keyed_and_still_owes_authorization() -> Bool {