From 8cc09467c1f36b97149c4ab81944dea99aff087c Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 2 Aug 2026 01:47:48 +0000 Subject: [PATCH 1/3] Repair main: repoint rest.dag's ContentHash import to std.content_hash main is red. #7480 moved ContentHash out of std.types into std.content_hash as part of the hash-family grounding, but dag/extdeps/transports/rest.dag was cut before that removal and merged after it, so its std.types import still names a symbol that no longer exists: dag/extdeps/transports/rest.dag:3:140: error: name 'ContentHash' not found in module 'std.types' (imported by 'extdeps.transports.rest') That refuses resolve for every entry whose closure reaches rest.dag, which is why the heal_generated_artifacts job fails at main_wet on unrelated PRs. The repair is mechanical, not a modeling choice: the union ContentHash still exists and std.content_hash is where every other consumer already imports it from (extdeps.docker, extdeps.container.oci.types, and others on main). rest.dag uses it at RestAuthenticated.digest and RestReplayKey.input_digest, neither of which is in #7480's list of carriers that must narrow to a specific family, so the union remains correct here. Verified by execution on clean origin/main plus this line: main_wet resolves the whole corpus and completes ExitSuccess, with zero generated-artifact drift. Co-Authored-By: Claude Opus 5 (1M context) --- dag/extdeps/transports/rest.dag | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dag/extdeps/transports/rest.dag b/dag/extdeps/transports/rest.dag index f76ee334b3d..6ef3904b861 100644 --- a/dag/extdeps/transports/rest.dag +++ b/dag/extdeps/transports/rest.dag @@ -1,6 +1,7 @@ module extdeps.transports.rest -import std.types { HttpMethod, GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, FermiDepth, NonEmptyStr, HttpStatus, Bool, String, Int, List, ContentHash } +import std.types { HttpMethod, GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, FermiDepth, NonEmptyStr, HttpStatus, Bool, String, Int, List } +import std.content_hash { ContentHash } import std.serialization { WireFormat } import std.fidelity { TransportFidelity } import std.effect_grant { Envelope, HandlerBinding, Read, Write, CoveredBy, NoCoveringGrant, covering_grant, NamespacePosition, ServiceOpTree } From c2ccca1eb8aa1dd2158d77d78f1519173ebcc58b Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 2 Aug 2026 02:11:03 +0000 Subject: [PATCH 2/3] Repair main: enroll oci/digest.dag in the extdeps scope frontier Second half of the same post-cutover race. The ci job fails at extdeps_scope_placement_gate_passes -> Bool(false), and the refused path is dag/extdeps/container/oci/digest.dag: #7480 added it after legacy_manifest_freeze_sha and enrolled it in neither scope_carrier_paths nor scope_machinery_exempt_paths. The gate diffs freeze..HEAD, so this reds every PR, not just the one that introduced it. Computed rather than guessed: of the 7 .dag files added under dag/extdeps since the freeze SHA, digest.dag is the only one absent from the frontier rosters. It is a real external-model carrier, not machinery, so it takes the carrier route the gate's own message prescribes: declare extdeps_model_scope and join scope_carrier_paths. It already carries its extdeps_external_authority_anchor (OCI image-spec descriptor.md), so only the scope declaration was missing. The subject names OciContentDigest, which its own authority note identifies as what the module models. The frozen legacy manifest is deliberately NOT touched: it is remove-only, and a post-freeze file cannot be smuggled into it. external_model_scope_witness_test 22/22 green. Co-Authored-By: Claude Opus 5 (1M context) --- dag/extdeps/container/oci/digest.dag | 15 ++++++++++++++- dag/gunbc/extdeps_scope_frontier.dag | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/dag/extdeps/container/oci/digest.dag b/dag/extdeps/container/oci/digest.dag index 1a9fe3b59ff..d2cbabb01d0 100644 --- a/dag/extdeps/container/oci/digest.dag +++ b/dag/extdeps/container/oci/digest.dag @@ -6,7 +6,8 @@ import std.content_hash { sha256_hex_digest, content_hash_validate_lower_hex_length, } -import extdeps.external_authority { ExternalAuthority } +import extdeps.external_authority { ExternalAuthority, ExternalModelScope, ExternalSubjectRef } +import std.decl_ref { DeclarationRef, WholeDeclaration } import extdeps.uri { Uri, Https } data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { @@ -16,6 +17,18 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } +data extdeps_model_scope: ExternalModelScope = ExternalModelScope { + subject: ExternalSubjectRef { + declaration: DeclarationRef { + module_path: "extdeps.container.oci.digest", + decl_name: "OciContentDigest", + field: WholeDeclaration + } + }, + first_citation: extdeps.container.oci.digest.extdeps_external_authority_anchor, + further_citations: [] +} + data oci_content_digest_note: String = "OCI digest authority (image-spec descriptor.md; distribution-spec digest): algorithm-qualified content address with wire form algorithm:encoded. Modelled as OciContentDigest coproduct (review 45466) — OciSha256Digest(Sha256Digest) | OciSha512Digest(OciSha512DigestBody) | OciOtherDigest(OciOtherDigestBody) — so algorithm tag and payload cannot be forged independently. sha256 arm carries std.content_hash.Sha256Digest directly; sha512 body uses OciSha512DigestHex (String where lower_hex_128); other body uses OciOtherDigestAlgorithm (String where oci_other_digest_algorithm — construction-walls reserved sha256/sha512 wire tokens and cites image-spec algorithm grammar algorithm-component ([a-z0-9]+) separated by [+._-], review 45505) plus OciOtherDigestEncoded (String where oci_other_digest_encoded — [a-zA-Z0-9=_-]+ per descriptor.md, review 45479/45731). Equality is substrate structural == on the coproduct (no parallel oci_content_digest_eq predicate). dissolve-on: cite digest-length law per algorithm when a second validated sha512 consumer needs more than length-128 wire check." fn oci_encoded_digest_char_allowed(cp: Int) -> Bool { diff --git a/dag/gunbc/extdeps_scope_frontier.dag b/dag/gunbc/extdeps_scope_frontier.dag index b540baeeccd..40cef1f962b 100644 --- a/dag/gunbc/extdeps_scope_frontier.dag +++ b/dag/gunbc/extdeps_scope_frontier.dag @@ -126,6 +126,7 @@ fn scope_placement_refused_paths(added: List, carriers: List, ma data scope_carrier_paths: List = [ "dag/extdeps/automation/playwright.dag", "dag/extdeps/browser/chromium.dag", + "dag/extdeps/container/oci/digest.dag", "dag/extdeps/github/actions_environment.dag", "dag/extdeps/os/debian.dag", "dag/extdeps/session_dashboard.dag", From 9bc08e6fbe4c3416299ee10677c49b143e792c07 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 2 Aug 2026 02:37:00 +0000 Subject: [PATCH 3/3] Regenerate stage0 for the scope declaration; record a qualified-reference emit defect regen_verify_gate_passes went red because the scope declaration added to oci/digest.dag is inside the regen input closure, so the committed generated Rust was stale. Regenerated rather than hand-picked: exactly one generated file changed, matching the one declaration added. Regenerating surfaced a real emitter defect. The fully qualified self-reference extdeps.container.oci.digest.extdeps_external_authority_anchor -- the exact form the actions_environment precedent uses -- emits crate::extdeps_cargo::extdeps_external_authority_anchor.clone(): the wrong module, and a fn item rather than a call, so stage0 fails E0308. The precedent never exercised it because actions_environment.dag is not in the regen closure. The bare same-module reference emits correctly and is the natural spelling for a sibling declaration, so it is not a respelling chosen to dodge an obstacle. What would have been the workaround is picking it silently, so the defect is recorded in the carrier with a dissolution trigger rather than left for the next author to rediscover. The emitter defect is NOT fixed here. Co-Authored-By: Claude Opus 5 (1M context) --- dag/extdeps/container/oci/digest.dag | 4 ++- .../src/extdeps_container_oci_digest.rs | 34 ++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/dag/extdeps/container/oci/digest.dag b/dag/extdeps/container/oci/digest.dag index d2cbabb01d0..23f51c69238 100644 --- a/dag/extdeps/container/oci/digest.dag +++ b/dag/extdeps/container/oci/digest.dag @@ -25,10 +25,12 @@ data extdeps_model_scope: ExternalModelScope = ExternalModelScope { field: WholeDeclaration } }, - first_citation: extdeps.container.oci.digest.extdeps_external_authority_anchor, + first_citation: extdeps_external_authority_anchor, further_citations: [] } +data qualified_self_reference_emit_defect_note: String = "WHY first_citation IS A BARE REFERENCE HERE WHILE THE actions_environment PRECEDENT WRITES A DOTTED PATH, recorded because it is a live emitter defect rather than a style preference. Writing first_citation: extdeps.container.oci.digest.extdeps_external_authority_anchor -- the fully qualified self-reference, exactly the form dag/extdeps/github/actions_environment.dag uses -- emits crate::extdeps_cargo::extdeps_external_authority_anchor.clone(): the WRONG MODULE (extdeps_cargo is unrelated to this one) and a fn item rather than a call, so the generated stage0 fails to compile with E0308. The bare same-module reference emits extdeps_external_authority_anchor() correctly.\n\nTHE PRECEDENT NEVER EXERCISED THIS. dag/extdeps/github/actions_environment.dag is not in the regen input closure, so no generated Rust is produced from it and its dotted spelling has never reached the emitter. This module IS in that closure, which is why the defect surfaced here first and why copying the precedent verbatim is not safe.\n\nTHIS IS NOT A DODGE, AND THE DISTINCTION MATTERS (DESIGN.md 5, unmarked workaround): a bare reference to a sibling declaration in the SAME module is the natural spelling, not a respelling chosen to avoid an obstacle. What would have been a workaround is silently picking it and saying nothing, which is why this row exists. The defect is real, is not fixed here, and is not this PR to fix: qualified declaration references in a data initializer resolve to the wrong module and lose their call. DISSOLVE-ON: the emitter resolving a qualified declaration reference to its declaring module and emitting a call, at which point either spelling works and this note deletes." + data oci_content_digest_note: String = "OCI digest authority (image-spec descriptor.md; distribution-spec digest): algorithm-qualified content address with wire form algorithm:encoded. Modelled as OciContentDigest coproduct (review 45466) — OciSha256Digest(Sha256Digest) | OciSha512Digest(OciSha512DigestBody) | OciOtherDigest(OciOtherDigestBody) — so algorithm tag and payload cannot be forged independently. sha256 arm carries std.content_hash.Sha256Digest directly; sha512 body uses OciSha512DigestHex (String where lower_hex_128); other body uses OciOtherDigestAlgorithm (String where oci_other_digest_algorithm — construction-walls reserved sha256/sha512 wire tokens and cites image-spec algorithm grammar algorithm-component ([a-z0-9]+) separated by [+._-], review 45505) plus OciOtherDigestEncoded (String where oci_other_digest_encoded — [a-zA-Z0-9=_-]+ per descriptor.md, review 45479/45731). Equality is substrate structural == on the coproduct (no parallel oci_content_digest_eq predicate). dissolve-on: cite digest-length law per algorithm when a second validated sha512 consumer needs more than length-128 wire check." fn oci_encoded_digest_char_allowed(cp: Int) -> Bool { diff --git a/src/v1/stage0/src/extdeps_container_oci_digest.rs b/src/v1/stage0/src/extdeps_container_oci_digest.rs index 9a3a7ed5093..ed9bf59c043 100644 --- a/src/v1/stage0/src/extdeps_container_oci_digest.rs +++ b/src/v1/stage0/src/extdeps_container_oci_digest.rs @@ -2,11 +2,15 @@ // Source module: extdeps.container.oci.digest use self::OciContentDigest::*; -pub use crate::extdeps_external_authority::ExternalAuthority; +pub use crate::extdeps_external_authority::{ + ExternalAuthority, ExternalModelScope, ExternalSubjectRef, +}; use crate::extdeps_uri::UriScheme::Https; pub use crate::extdeps_uri::{Uri, UriScheme}; pub use crate::std_content_hash::Sha256Digest; pub use crate::std_content_hash::{content_hash_validate_lower_hex_length, sha256_hex_digest}; +use crate::std_decl_ref::DeclField::WholeDeclaration; +pub use crate::std_decl_ref::{DeclField, DeclarationRef}; pub use crate::std_types::NonEmptyStr; use crate::v1_rt; use crate::v1_rt::{VecCompat, VecJoin}; @@ -29,6 +33,34 @@ pub fn extdeps_external_authority_anchor() -> Rc { CACHED.with(|c: &Rc| c.clone()) } +pub fn extdeps_model_scope() -> Rc { + thread_local! { + static CACHED: Rc = { + Rc::new(ExternalModelScope { + subject: Rc::new(ExternalSubjectRef { + declaration: Rc::new(DeclarationRef { + module_path: "extdeps.container.oci.digest".to_string(), + decl_name: "OciContentDigest".to_string(), + field: Rc::new(DeclField::WholeDeclaration), + }), + }), + first_citation: extdeps_external_authority_anchor(), + further_citations: Rc::new(vec![]), + }) + }; + } + CACHED.with(|c: &Rc| c.clone()) +} + +pub fn qualified_self_reference_emit_defect_note() -> String { + thread_local! { + static CACHED: String = { + "WHY first_citation IS A BARE REFERENCE HERE WHILE THE actions_environment PRECEDENT WRITES A DOTTED PATH, recorded because it is a live emitter defect rather than a style preference. Writing first_citation: extdeps.container.oci.digest.extdeps_external_authority_anchor -- the fully qualified self-reference, exactly the form dag/extdeps/github/actions_environment.dag uses -- emits crate::extdeps_cargo::extdeps_external_authority_anchor.clone(): the WRONG MODULE (extdeps_cargo is unrelated to this one) and a fn item rather than a call, so the generated stage0 fails to compile with E0308. The bare same-module reference emits extdeps_external_authority_anchor() correctly.\n\nTHE PRECEDENT NEVER EXERCISED THIS. dag/extdeps/github/actions_environment.dag is not in the regen input closure, so no generated Rust is produced from it and its dotted spelling has never reached the emitter. This module IS in that closure, which is why the defect surfaced here first and why copying the precedent verbatim is not safe.\n\nTHIS IS NOT A DODGE, AND THE DISTINCTION MATTERS (DESIGN.md 5, unmarked workaround): a bare reference to a sibling declaration in the SAME module is the natural spelling, not a respelling chosen to avoid an obstacle. What would have been a workaround is silently picking it and saying nothing, which is why this row exists. The defect is real, is not fixed here, and is not this PR to fix: qualified declaration references in a data initializer resolve to the wrong module and lose their call. DISSOLVE-ON: the emitter resolving a qualified declaration reference to its declaring module and emitting a call, at which point either spelling works and this note deletes.".to_string() + }; + } + CACHED.with(|c: &String| c.clone()) +} + pub fn oci_content_digest_note() -> String { thread_local! { static CACHED: String = {