Repository navigation
Provider spine: native request families, persistent local materialization store, typed file-failure channel - #11059
Conversation
…d file-failure channel Extend std.materialization_provider with NativeCompilerArtifactRequest, UniverseArtifactRequest and NativeModuleVerdictBundleRequest (+ artifact variants, manifests, RealizationReceipt carrying provider identity outside the key). Add std.materialization_object (realization-agnostic store object, observations, lookup/commit decisions), std.materialization_store_grant (durable host-volume root vs ephemeral witness scratch), and extdeps.realization.materialization_store_local (first real realization: put-if-absent via WriteCreateNew, exact read-back, no listing, no shadow store). GCS interface rows in extdeps.cloud.gcp.storage (no handler). Prerequisite: Filesystem.Read / WriteCreateNew gain a typed error_kind channel (interpreter + 05_emit/05_emit_rust, mirrors regenerated to fixed point) so a miss is never inferred from error text. Controls: 17 hermetic + 8 wet (enrolled on the local-repo wet lane). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016AYera4CKxLqZJn5YW5Mzw
extdeps.cloud.gcp.storage gains gcs_interface_consumer_frontier: a std.roster_frontier FrontierRow naming the consumer (extdeps.realization.materialization_store_gcs gcs_store_read_observation) as a bound dissolution, per the operator's 2026-09-11 provider ruling (interface rows day one; handler at ruled dispatch step 5). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016AYera4CKxLqZJn5YW5Mzw
|
Re review 63841. Finding 1 (GCS rows have no consumer): kept, and the frontier is now typed. This is not discretionary debt. The operator's 2026-09-11 provider ruling puts the GCS interface rows in extdeps on day one, with the handler later. The ruled dispatch order is: 1 recut #10940, 2 ancestry, 3 provider spine (this PR), 4 route integration, 5 NFS/GCS realization, 6 incubation. So under §3c this is the middle state: a named consumer that lands in a named later change. The module now says that as data, not prose.
That consumer is the GCS handler. It sits beside Your true half stands, and the module says so too. GCS-readiness today comes from the path-free observation types in Finding 2 (misindented line in v1_interpreter.rs): real, fixed. Note that Both are in 837cf78. CI on the previous head 50cf46c was fully green: build, floor, and the aggregate. — sent from sharp-koi-253 |
The required declarations phase refused CITED-MODULE-ABSENT on 837cf78: a bound dissolution cited extdeps.realization.materialization_store_gcs, which does not exist yet. The not-yet-landed consumer is carried in an unbound_dissolution description naming the declaration and ruled step 5; the handler's change rebinds it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016AYera4CKxLqZJn5YW5Mzw
gcs_storage_frontier_rows joins census_closure_frontier_row_groups beside the sibling extdeps frontier groups, so gunbc.dissolution_census folds it (well-formedness and expiry) instead of the row being untracked. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016AYera4CKxLqZJn5YW5Mzw
|
Re review 63874: agreed, and fixed in 68e755b. The frontier row is now a group, Checked by execution against this tree: the 29 test fns in the three census-consuming witness files all pass ( The dissolution stays unbound until the handler exists. The previous head, ba3a82a, is fully green in CI. On 837cf78 the declarations phase refused a bound dissolution that cited the not-yet-existing — sent from sharp-koi-253 |
…-decl GCS frontier, no endpoint re-mint - payload_part sizes are UTF-8 byte counts (std.bytes), not code points; new control a_part_size_counts_utf8_bytes_not_code_points. - store_object_line_fold is the one match over StoreObjectLine; the predicates and projections derive from it. - gcs_storage_frontier_rows carries one row per unconsumed declaration. - gcs_objects_get names extdeps.cloud.gcp.gcp's GcpStorage endpoint instead of restating its base URL; the media-upload endpoint lives once, cited. - v1_interpreter write_create_new comment matches the error_kind channel. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016AYera4CKxLqZJn5YW5Mzw
|
Re review 63888: all five findings were real, and all five are fixed in 27eed91.
Checked by execution against this tree:
The floor red on 68e755b was an infrastructure refusal on runner srv4-15, not a claim failure: — sent from sharp-koi-253 |
materialization_store_durable_root is absolute_path_position of materialization_store_durable_root_path instead of a hand-written segment list, so the grant root and the admission target are one datum. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016AYera4CKxLqZJn5YW5Mzw
|
Re review 63898. Finding (durable root expressed twice): real, fixed in bed50e8. I checked this by execution:
Advisory (v1 seed-growth receipt): added to the PR body under "v1 seed growth receipt". It is measured from the merge base, 199aee7. Its contents:
The previous head, 27eed91, is fully green in CI. — sent from sharp-koi-253 |
|
srv2 closure receipt for the provider spine at head 27eed91 (overlay on main c560821; instrument Regressed files vs the main baseline (
Carry-over to the current head bed50e8: the delta from 27eed91 is one file, Receipt-neutral by execution; nothing blocks landing on the closure side. |
A second payload line for one output id now refuses as StoreLookupPayloadRepeated instead of serving the first copy, matching the repeated-part refusal on the manifest side. The three payload checks share store_payload_refusal; new control a_repeated_payload_line_is_refused_not_resolved. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016AYera4CKxLqZJn5YW5Mzw
|
Re review 63921: real finding, fixed in a2c0b08. The defect. A second The fix. It now refuses as New control. Checked by execution:
The previous head, bed50e8, is fully green in CI. — sent from sharp-koi-253 |
…view 63940) filesystem_fault now names the host's failure kind in StoreFault.detail, giving filesystem_failure_kind_name its consumer; new control an_unreadable_object_fault_names_the_host_kind. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016AYera4CKxLqZJn5YW5Mzw
|
Re review 63940: real finding, fixed in 9d4c04c.
New control: Checked by execution: all 20 hermetic and 8 wet store controls pass, and nothing is left in — sent from sharp-koi-253 |
store_lookup_decide binds the manifest decode once; store_commit_prepare binds the decode, the offered digest and the request binding once; store_commit_verify binds the committed digest once. No arm recomputes the value its match already holds. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016AYera4CKxLqZJn5YW5Mzw
|
Re review 63959: real finding, fixed in 2c6f702. Each value is now computed once and shared by every arm:
After the change, — sent from sharp-koi-253 |
Conflicts: - dag/gunbc/census_closure_frontier.dag: both sides appended a frontier group (gcs_storage_frontier_rows, ebay_browse_frontier_rows); kept both. - src/v1/stage0/src/v1_compiler_emit_rust.rs (generated mirror): main's #10990 image plus this branch's error_kind delta; claim_executor --required-regen reproduces it byte-for-byte (first_generation_equal=true) and --required-regen-fixed-point holds (fixed_point_equal=true). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016AYera4CKxLqZJn5YW5Mzw
Conflicts, both roster appends beside main's fabric_event_log_append enrollment (#11009 wave): - src/v2/workflow/floor_route_gap.dag: main took chunk_08; this branch's eight materialization_store_local_wet_witness expectations move to chunk_09, both enrolled in floor_route_gap_expectation_chunks. - src/v2/workflow/local_repo_wet_terminal.dag: main's three fabric rows and this branch's eight store rows both kept. Stage0 mirrors regenerated on the merged tree: required-regen first_generation_equal=true, fixed_point_equal=true. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016AYera4CKxLqZJn5YW5Mzw
Conflict: src/v2/workflow/local_repo_wet_terminal.dag, both sides appended wet-lane schedule rows. Kept main's (devboot_text_blob_real_execution, fabric_event_log_append_real_execution) and this branch's eight materialization_store_local_wet_witness rows. No mirror is involved, so no stage0 regeneration. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016AYera4CKxLqZJn5YW5Mzw
|
srv2 closure receipt at d5bf048 (this head overlaid on main bdf9823, producer built from the overlay, native fold over the 167-module closure of
So the composed emitter change (#10990's walls plus this PR's error_kind delta on Instrument: — sent from eager-raven-113 |
std.materialization_provider keyed NativeCompilerArtifactRequest on
{emitted closure, toolchain, target platform}, a second spelling of an
identity v2.compiler.self_host.generation already owns: a changed producer
compiler or build configuration left the key fixed, so two generations read
as one computation and a differing artifact read as a same-key content
conflict rather than a changed input.
generation now exposes PreMaterializationIdentity (the five CAUSAL axes) and
pre_materialization_digest, derived on demand, no composite stored. The
request carries that projection and derives its key from it. The sixth axis,
materialized_artifact, stays out of a pre-build lookup: it is earned from
verified bytes and joined back afterwards.
Controls: every_generation_causal_axis_is_load_bearing_on_the_compiler_key
perturbs each axis independently, and
a_compiler_request_key_ignores_which_store_serves_it holds the provider out
of the key. Reproducing the old three-field shape reds the first.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016AYera4CKxLqZJn5YW5Mzw
|
srv2 closure receipt for #11059 @ 128185c (overlay on main 6cdebf5, instrument Caveat stated rather than hidden: #11105 landed on main (bb31b63) after this overlay was taken, touching — sent from eager-raven-113 |
What this changes
This is the provider spine the replacement native CI job runs on (operator rulings 2026-09-11, as corrected by design review C2/C3). The interface is
std.materialization_provider.std.artifact_storeis not touched: retention, capacity and eviction stay under the provider and are not built here.1. Model: three request families, with manifests (
std.materialization_provider)ArtifactRequestgetsNativeCompilerArtifactRequest,UniverseArtifactRequestandNativeModuleVerdictBundleRequest(NativeModuleVerdictBundleSubject { route_binary_identity, module_identity, canonical_module_import_closure_identity, ordered_test_identity_population, eval_interpretation_identity }).MaterializedArtifactgets the matching variants, each with required per-kind parts: executable + build diagnostics, test population + import closures, and verdicts + preparation diagnostics.std.cache_identity.ArtifactManifestis a projection (artifact_manifest).artifact_from_manifestis its inverse and is the only place a stored claim becomes an artifact again. A manifest with an unknown kind, an undeclared part or a repeated part refuses. A missing part decodes to the incompleteness variant, so the contract's own completeness check refuses it.RealizationReceipt { request_key, kind, content_digest, provider: CacheInterfaceId, store_instance, disposition }. Provider identity lives in the receipt, never in the key. A hermetic control shows two providers give the same key and the same content digest with different receipts.2. Division of authority (
std.materialization_object)The native route emits typed requests. The provider contract owns request↔artifact correctness. This new module is the realization-agnostic half of the store:
StoreObjectRead= present | absent | unavailable,StoreObjectPublish= published | occupied | refused)StoreLookupMissis reachable only fromStoreObjectAbsent. Unavailable, malformed/torn, uninterpretable manifests, and contract refusals (wrong kind, wrong artifact, wrong content, incomplete) all refuse and are never reclassified as a miss. A commit settles only on a verified read-back:CommittedConvergedOnPriorCommitConflictReadBackRefused3. First real realization: local persistent filesystem (
extdeps.realization.materialization_store_local)Filesystem.Read/Filesystem.WriteCreateNew, and maps the results onto the observations. It never consults a directory listing.LocalStoreNotInitialized): a missing volume is never read as an empty store, and nothing is written anywhere else, so there is no shadow store.std.materialization_store_grant).DurableHostVolumeRoothas no path field. Its root is the declared/var/lib/gunbc/materialization-store, and a caller cannot hand in/tmpunder that name.WitnessScratchRootadmits only/tmp/gunbc_*, and its durability is derived asEphemeralToFrame.CacheInterfaceCatalogFactsrow is added toextdeps.cachecache_catalog. The cache witnesses (104 fns across cache_layer_planner, cache_key_completeness, host_build_cache_provision_design and both provider/store witness files) all pass locally.4. Prerequisite: a typed failure channel on the file transport (seed maintenance, v2-serving)
Without this, a miss could not be told apart from an unavailable object except by reading error text.
Filesystem.ReadandFilesystem.WriteCreateNewnow declareerror_kind(not_found | already_exists | permission_denied | other, projected fromstd::io::ErrorKind).filesystem_exact_read/filesystem_create_new. They carry typed absent/occupied arms, and an unrecognized kind is refused rather than folded intoother.v1_interpreterdispatch_file/io_error_kind_name05_emitFileChanErrorKind, and05_emit_rustfile_io_error_kind_fnbound once per file callclaim_executor --required-regennow reportsfirst_generation_equal=true, and--required-regen-fixed-pointreportsfixed_point_equal=true. Onlyv1_compiler_emit.rsandv1_compiler_emit_rust.rschanged.concurrent_same_target_creates_produce_one_winner_and_no_residue) now also checks that every loser maps toalready_exists.5. GCS interface-ready; NFS later
extdeps.cloud.gcp.storagehas interface rows only: objects.get (404 = absent), objects.insert withifGenerationMatch=0(412 = occupied), and the status meanings. There is no handler. Declared frontier; trigger: the operator names the GCS realization lane.BuildBuddy is not a provider, and there are no CI workflow edits.
v1 seed growth receipt (PURPOSE admission,
gunbc.v1_maintenance_standingv1_seed_standing)Measured from the merge base, never the moving tip:
git diff 199aee77ab..HEAD -- 'src/v1/stage0/src/*.rs'.v1_interpreterio_error_kind_nameprojectsstd::io::ErrorKindonto the closederror_kindroster.FileResultstruct gains anerror_kindfield;dispatch_file's arms populate the field;map_file_outputsanswers the"error_kind"key;the_emitted_listing_producer_refuses_toobinds the five-tuple, andconcurrent_same_target_creates_produce_one_winner_and_no_residuegains one assertion.v1_compiler_emit.rsandv1_compiler_emit_rust.rsdeltas are mirrors ofsrc/v1/05_emit.dagandsrc/v1/05_emit_rust.dag.claim_executor --required-regenreportsfirst_generation_equal=true, and--required-regen-fixed-pointreportsfixed_point_equal=true.extdeps.realization.materialization_store_localgoes throughextdeps.filesystem.filesystem_iofilesystem_exact_read/filesystem_create_new, which is how a store miss is told apart from an unavailable store without reading error text. The emitter carries the same channel, so the emitted native route can compile that module.io_error_kind_nameis private tov1_interpreter.Controls, executed
Hermetic controls live in
test.claim.materialization_store_witness(17 fns, floor-discovered). Wet controls live intest.claim.materialization_store_local_wet_witness(8 fns, real filesystem in a throwaway/tmp/gunbc_matstore.*). The wet file is enrolled on the required floor's local-repo wet lane with the full triple: thelocal_repo_wet_schedulerows,floor_route_gap_expectation_chunk_08, and theci_layer_rootsLocalRepoWetLanerow. All 25 were executed withgunbc runagainst this tree and hold. Nothing was left behind in/tmp.a_committed_object_reads_back_as_a_hit_with_its_payloads,commit_settles_only_on_a_verified_read_backcommit_then_read_back_by_real_executioncommit_settles_only_on_a_verified_read_backredsa_corrupted_payload_is_an_integrity_refusal,a_tampered_part_size_is_an_integrity_refusal,a_truncated_object_is_malformed_not_incompletecorruption_is_an_integrity_refusal_by_real_execution(also asserts not-a-miss)an_object_of_another_kind_refuses_as_kind_mismatch(+ wrong artifact)wrong_kind_refuses_by_real_executionan_object_missing_a_required_part_refuses_as_incomplete,the_write_door_refuses_before_publishingincomplete_refuses_by_real_executioncommit_settles_only_on_a_verified_read_backa_second_writer_converges_on_the_committed_artifact_by_real_execution,a_divergent_second_writer_conflicts_and_changes_nothing_by_real_executionconcurrent_same_target_creates_produce_one_winner_and_no_residue)an_unavailable_object_refuses_and_is_not_a_miss,a_store_opens_only_on_its_own_markeran_unavailable_store_refuses_and_leaves_no_shadow_by_real_execution(uninitialized, ungranted, batch; no marker or object written)a_batch_answers_each_request_by_real_executionevery_verdict_bundle_identity_is_load_bearing_on_the_key(each of the 5 fields),native_families_key_apart_over_identical_digests,provider_identity_is_in_the_receipt_and_not_in_the_keyConcurrency, stated precisely. The wet second writer runs sequentially. That exercises exactly the loser's arm (create-new answers
already_exists, then a read-back), because publication is a singlelink(2). The real 8-thread race is executed at the primitive by the Rust test named above.Declared frontiers (DESIGN §3c)
gunbc.witness.v2_native_route's operator-invoked instrument), in a later lane. Trigger: the emitted route builds these requests from its receipt identities and serves or commits throughlocal_store_lookup_batch/local_store_commitinstead of re-preparing every module per run. Emission already supports the new file channel, so that route can compile this module.CapacityUnobserveduntilstd.artifact_storeaccounting binds to the store.Known limits
string_length, which counts characters for non-ASCII text. That is consistent on both doors, but it is a character count, not a byte count.🤖 Generated with Claude Code
https://claude.ai/code/session_016AYera4CKxLqZJn5YW5Mzw