Experiment formal simulator exposure source plan 01 - kmosoti/FabricO11y GitHub Wiki

Separate simulator admission checker: source pre-flight 01

Prospective NOT RUN at clean 958f99ab1e00b4946b46457408560880a00c312e. The actual registration red was recorded before production implementation. Separate trust docs3af5d30 label the controls qualification-only; production958f99a adds129 pure Python lines, within the proposed180-line budget. Original243-line test bytes unchanged. No Rust/Cargo/config/vendor or canonical three-helper/source/oracle bytes changed. No native helper edit, compiler or native timing evidence.

Four serial default-capped source cells:16 controls (all methods, zero expected skips/failures), docs checker,55 documentation probes,10 hooks. Fresh full DATA namespace census/full1GiB reservation each/admission includingreserve below95e9/100GB ceiling/16GiBhigh20GiBmax/no swap/1800seconds. Root alone executes and holds source; unexpected failures stop, log/receipt/evidence preserved; successful launcher scratch removed and59 read after each cell. No Cargo/native/browser/VM/smoke/FULL or canonical helper substitution.

The source APIs validate caller-supplied records against independently pinned expected source/build/native bindings; they do not authenticate raw receipt/file hashes, observer truth, actual source census or publication booleans themselves. Literal two-second/two-identity records remain synthetic. Complete input-source census, actual loaded/clock/publication/source/stop joins are later native prerequisites. A bounded coverage bytearray is at most720,000 bytes (7200seconds×100identities); offers may be iterated without a full tuple set. The native1ms clock bound remains prospective/unmeasured.

Existing Bun1.4.0 and locked dependencies are reused through106 individually ignored links under a real node_modules directory; no install or dependency mutation. Hosted CI does not execute this qualification-only source module; local16-method receipt is required independently of any hosted checks.

Exact commands

python3 -B /run/media/kmosoti/data/FabricO11y/results/candidate-build-fresh-8fb6f413179b-01/run-step-simulator-source-01.py simulator-exposure-source-controls-01 1073741824 env PYTHONPATH=tools/qualification:tools python3 -B -m unittest -v test_simulator_exposure
python3 -B /run/media/kmosoti/data/FabricO11y/results/candidate-build-fresh-8fb6f413179b-01/run-step-simulator-source-01.py simulator-exposure-docs-check-01 1073741824 env PATH=/run/media/kmosoti/data/FabricO11y/tools/bun-1.4.0:/usr/local/bin:/usr/bin:/bin BUN_INSTALL_CACHE_DIR=/run/media/kmosoti/data/FabricO11y/tools/docs-bun-cache /run/media/kmosoti/data/FabricO11y/tools/bun-1.4.0/bun tools/docs/check.mjs
python3 -B /run/media/kmosoti/data/FabricO11y/results/candidate-build-fresh-8fb6f413179b-01/run-step-simulator-source-01.py simulator-exposure-docs-tests-01 1073741824 env PATH=/run/media/kmosoti/data/FabricO11y/tools/bun-1.4.0:/usr/local/bin:/usr/bin:/bin BUN_INSTALL_CACHE_DIR=/run/media/kmosoti/data/FabricO11y/tools/docs-bun-cache /run/media/kmosoti/data/FabricO11y/tools/bun-1.4.0/bun tools/docs/check.test.mjs
python3 -B /run/media/kmosoti/data/FabricO11y/results/candidate-build-fresh-8fb6f413179b-01/run-step-simulator-source-01.py simulator-exposure-docs-hooks-01 1073741824 env PATH=/run/media/kmosoti/data/FabricO11y/tools/bun-1.4.0:/usr/local/bin:/usr/bin:/bin BUN_INSTALL_CACHE_DIR=/run/media/kmosoti/data/FabricO11y/tools/docs-bun-cache python3 -B tools/docs/test_hooks.py

Pins

  • /run/media/kmosoti/data/FabricO11y/results/candidate-build-fresh-8fb6f413179b-01/run-step-simulator-source-01.py SHA-256 01d3a5069184fdd86fa1fb6b307fa235ce8b1d73e41847a0667a6c846e9ab580, 7041 bytes.
  • /run/media/kmosoti/data/FabricO11y/scratch/simulator-exposure-witness/tools/qualification/simulator_exposure.py SHA-256 31184b04f839e83f1e759ed6dd918d0087e2dc264ea3623d31671493c7ff985d, 7267 bytes.
  • /run/media/kmosoti/data/FabricO11y/scratch/simulator-exposure-witness/tools/qualification/test_simulator_exposure.py SHA-256 1bb53d2bb730c5cb70c456d4c76bdcb95498d8ce1a86075d5b3516916cff1a87, 14295 bytes.
  • /run/media/kmosoti/data/FabricO11y/scratch/simulator-exposure-witness/docs/experiments/benchmarks/simulator-exposure-witness-protocol.md SHA-256 1d97905772440f8811d7fb0895024dd5d3aa13cd56d22faccc0d0f0e707e5206, 12080 bytes.
  • /run/media/kmosoti/data/FabricO11y/scratch/simulator-exposure-witness/tools/resource_group.py SHA-256 454acd27fdd5a87a35c697d6a89d2fc807c5c2757a98676dba2745efece7667e, 10723 bytes.
  • /run/media/kmosoti/data/FabricO11y/scratch/simulator-exposure-witness/examples/spindle_sim.rs SHA-256 2b2828fed73cfe654fadc6739e31c51b9004a42a5174f51be2cb08b161385264, 22837 bytes.
  • /run/media/kmosoti/data/FabricO11y/scratch/simulator-exposure-witness/tools/qualification/cross_family/inputs.py SHA-256 3dfd336bd132fa7d904aea783c81db94f6832bea304474d86250cb2329dbec44, 3568 bytes.
  • /run/media/kmosoti/data/FabricO11y/scratch/simulator-exposure-witness/tools/docs/bun.lock SHA-256 94d175ed52993a4ff6eef5f9ebd93cce27aa53f31c25bd0cd71679313ddce272, 30744 bytes.
  • /run/media/kmosoti/data/FabricO11y/scratch/simulator-exposure-witness/tools/docs/package.json SHA-256 133c4ba06cd53868ab9d644c249a48c599010c8a4cc53f44cf364003239898bc, 326 bytes.
  • /run/media/kmosoti/data/FabricO11y/tools/bun-1.4.0/bun SHA-256 33d56b070be6a9e3da0ab013038b43d1645d0534ca811ecdba4472599117eb4b, 80761952 bytes.

Source status `` (empty means clean); locked dependency directory device/inode 64513/14555423; `106` individually linked entries.

Complete changes after the preserved red

diff --git a/docs/experiments/benchmarks/simulator-exposure-witness-protocol.md b/docs/experiments/benchmarks/simulator-exposure-witness-protocol.md
index 5b4d8c2..50f5495 100644
--- a/docs/experiments/benchmarks/simulator-exposure-witness-protocol.md
+++ b/docs/experiments/benchmarks/simulator-exposure-witness-protocol.md
@@ -118,6 +118,13 @@ native-source census. They exercise two prospective pure Python interfaces:
 and authenticate no owner. The test-only reference encodes the registration;
 it is not a fallback implementation or an oracle derived from Rust.
 
+These are **qualification-only controls**, explicitly selected following
+[C-089](https://github.com/kmosoti/FabricO11y/issues/59#issuecomment-6138944614).
+They are not registered in `xtask/checks.json`; hosted CI is not represented as
+running them. Root's separately admitted source cell must run all 16 methods
+with zero failures and zero skips after the mechanism is implemented. Native
+and complete-source-census prerequisites below remain separate.
+
 `source/build/canonical` consume caller-read manifests and actual build file
 hashes; `expected` is separately pinned. `begin` wraps caller-read witness bytes
 as `{'sha256': actual_hash, 'value': parsed}`. `summary` is the original parsed
diff --git a/tools/qualification/simulator_exposure.py b/tools/qualification/simulator_exposure.py
new file mode 100644
index 0000000..95009a4
--- /dev/null
+++ b/tools/qualification/simulator_exposure.py
@@ -0,0 +1,129 @@
+"""Pure qualification joins; callers authenticate files, observers and receipts."""
+import re
+
+BASE = '8fb6f413179b094288316e25845c137440ba23fa'
+HELPER = 'examples/spindle_sim.rs'
+NS = 1_000_000_000
+U64 = 2**64 - 1
+
+
+def require(condition, message):
+    if not condition:
+        raise ValueError(message)
+
+
+def integer(value, lower=0, upper=U64):
+    return type(value) is int and lower <= value <= upper
+
+
+def digest(value, width=64):
+    return type(value) is str and re.fullmatch('[0-9a-f]{' + str(width) + '}', value) is not None
+
+
+def same(actual, expected):
+    if type(actual) is not type(expected):
+        return False
+    if type(actual) is dict:
+        return actual.keys() == expected.keys() and all(same(actual[k], expected[k]) for k in actual)
+    if type(actual) is list:
+        return len(actual) == len(expected) and all(same(a, b) for a, b in zip(actual, expected))
+    return actual == expected
+
+
+def validate_source_build(source, build, canonical, expected):
+    try:
+        message = 'canonical helper authority'
+        require(same(canonical, expected['canonical']) and canonical['candidate'] == BASE, message)
+        require(digest(canonical['source_commit'], 40) and all(digest(canonical[k]) for k in
+                ('source_manifest_sha256', 'source_bundle_sha256', 'helper_manifest_sha256')), message)
+        helpers = canonical['helpers']
+        require(type(helpers) is dict and set(helpers) == {'spool_dump', 'server_dump', 'spindle_sim'}
+                and all(digest(value) for value in helpers.values()), message)
+        message = 'compilation inputs'
+        actual, original = source['compilation_inputs'], expected['canonical_inputs']
+        require(type(actual) is dict and type(original) is dict and HELPER in original
+                and actual.keys() == original.keys(), message)
+        require(all(type(path) is str and path and not path.startswith('/')
+                and '\x00' not in path and all(part not in ('', '.', '..') for part in path.split('/'))
+                and digest(actual[path]) and digest(original[path]) for path in original), message)
+        require(actual[HELPER] != original[HELPER] and all(actual[path] == original[path]
+                for path in original if path != HELPER), message)
+        message = 'separate simulator source/build'
+        require(same(source, expected['source']) and source['base_commit'] == BASE
+                and all(digest(source[k], 40) for k in ('commit', 'tree'))
+                and all(digest(source[k]) for k in ('manifest_sha256', 'bundle_sha256')), message)
+        require(same(build, expected['build']) and digest(build['sha256']), message)
+        value = build['value']
+        require(same(value['source'], source) and value['state'] == 'built'
+                and integer(value['exit'], 0, 0) and value['stop_confirmed'] is True
+                and digest(value['binary_sha256']), message)
+        config, command = value['configuration'], value['command']
+        require(type(command) is list and command
+                and all(type(item) is str and item for item in command), message)
+        require(all(type(config[k]) is str and config[k] for k in ('rustc', 'target', 'profile'))
+                and all(type(config[k]) is list and all(type(item) is str for item in config[k])
+                        for k in ('features', 'rustflags')), message)
+        return True
+    except (KeyError, TypeError, AttributeError) as error:
+        raise ValueError(message) from error
+
+
+def validate_native(begin, summary, offers, loaded, expected):
+    message = 'begin witness'
+    try:
+        publication = loaded['publication']
+        require(type(begin) is dict and digest(begin.get('sha256'))
+                and begin['sha256'] == expected['begin_sha256']
+                and publication.get('unchanged_sha256') == begin['sha256']
+                and all(publication.get(k) is True for k in
+                        ('atomic', 'exclusive', 'before_first_offer', 'regular'))
+                and integer(publication.get('nlink'), 1, 1)
+                and integer(publication.get('mode'), 0o400, 0o400), message)
+        b, identity, parameters = begin['value'], expected['identity'], expected['parameters']
+        message = 'clock brackets'
+        lo, hi, wall, width = (b['mono_before_ns'], b['mono_after_ns'], b['began_unix_ns'],
+                               expected['max_clock_bracket_ns'])
+        require(integer(lo) and integer(hi) and integer(wall) and integer(width, 0, 1_000_000)
+                and lo <= hi <= lo + width, message)
+        message = 'summary/identity binding'
+        require(type(parameters) is dict and set(parameters) == {'seconds', 'identities', 'workers', 'seed'}
+                and integer(parameters['seconds'], 1, 7200)
+                and integer(parameters['identities'], 1, 100)
+                and integer(parameters['workers'], 1, 100) and integer(parameters['seed']), message)
+        process = identity['process']
+        require(type(process) is dict and set(process) ==
+                {'pid', 'start_ticks', 'boot_id', 'exe_device', 'exe_inode'}
+                and integer(process['pid'], 1, 2**31 - 1) and integer(process['start_ticks'])
+                and integer(process['exe_device']) and integer(process['exe_inode'], 1)
+                and type(process['boot_id']) is str and process['boot_id'], message)
+        require(digest(identity['binary_sha256']) and digest(identity['source_commit'], 40)
+                and digest(identity['build_receipt_sha256'])
+                and all(same(loaded.get(k), value) for k, value in identity.items())
+                and same(b['process'], process) and b['binary_sha256'] == identity['binary_sha256']
+                and same(b['parameters'], parameters) and same(summary['process'], process)
+                and all(same(summary.get(k), value) for k, value in parameters.items())
+                and same(summary['began_unix_ns'], wall)
+                and summary['begin_witness_sha256'] == begin['sha256'], message)
+        message = 'native lifetime'
+        seconds, identities = parameters['seconds'], parameters['identities']
+        duration = seconds * NS
+        require(integer(summary['elapsed_ns'], duration)
+                and integer(summary['ended_monotonic_ns'], hi + duration)
+                and integer(loaded['exit'], 0, 0) and loaded['stop_confirmed'] is True
+                and integer(summary['undelivered'], 0, 0), message)
+        message = 'worker offers'
+        seen, count = bytearray(identities * seconds), 0
+        for item in offers:
+            require(type(item) is dict, message)
+            if item.get('e') != 'created':
+                continue
+            index, sequence = item['id'], item['seq']
+            require(integer(index, 0, identities - 1) and integer(sequence, 1, seconds)
+                    and integer(item['t'], wall) and integer(item['generated_ns'], item['t']), message)
+            slot = index * seconds + sequence - 1
+            require(not seen[slot], message)
+            seen[slot], count = 1, count + 1
+        require(count == len(seen), message)
+        return True
+    except (KeyError, TypeError, AttributeError) as error:
+        raise ValueError(message) from error