Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions dsl/gunbc/auth/credentials.dag
Original file line number Diff line number Diff line change
@@ -1,21 +1,10 @@
// gunbc/auth/credentials.dag -- Concrete gunbc credential acquisition bindings.
//
// This module binds provider-neutral credential needs to concrete runtime
// mechanisms. It is intentionally not part of std/: these patterns depend on
// a specific provider and local runtime tooling.

module gunbc.auth.credentials

import extdeps.cloud.gcp.gcp
import extdeps.cloud.gcp.secret_manager
import std.resources { Network }
import std.types { FilePath, NonEmptyStr }

// Acquire a credential from GCP Secret Manager via the canonical REST interface.
//
// Local dev composes shell.GCloud.AuthPrintAccessToken (auth) with
// gcp.SecretManager.AccessVersion (REST) — not a forked shell duplicate of the endpoint.

pattern gcp_secret_credential(
project_id: NonEmptyStr,
secret_name: NonEmptyStr,
Expand All @@ -33,9 +22,6 @@ pattern gcp_secret_credential(
return { token: utf8_secret_from_access_payload(payload: result.payload) }
}

// OAuth2 access token via ADC refresh: gcloud.Auth.ReadADC (file) → oauth2.Google.Refresh (REST).
// One interface shape for the token endpoint; ReadADC is a prerequisite handler, not a fork.

pattern gcp_oauth_access_token_via_adc_refresh(
adc_path: FilePath = "~/.config/gcloud/application_default_credentials.json"
) -> { token: Secret }
Expand All @@ -50,18 +36,11 @@ pattern gcp_oauth_access_token_via_adc_refresh(
return { token: refresh.access_token }
}

// OAuth2 access token via gcloud CLI (shell.GCloud.AuthPrintAccessToken).
// Distinct realization path — gcloud's credential store, not a fork of Refresh.
// Shell transport is not yet a declared resource (same as gcp_secret_credential's auth step).

pattern gcp_oauth_access_token_via_gcloud() -> { token: Secret } {
auth = shell.GCloud.AuthPrintAccessToken()
return { token: auth.access_token }
}

// Dispatch entry: GcpOAuth2AccessTokenStrategy → the leaf materializer for that path.
// Network is declared only on the AdcRefresh leaf chain; GcloudCli is shell-only.

pattern gcp_oauth_access_token(strategy: GcpOAuth2AccessTokenStrategy) -> { token: Secret }
{
node result = match strategy {
Expand All @@ -71,10 +50,6 @@ pattern gcp_oauth_access_token(strategy: GcpOAuth2AccessTokenStrategy) -> { toke
return { token: result.token }
}

// ADC path dispatch: Present/Absent for encoded FilePath? values.
// 🟡 SCAFFOLD — feature:literal-optional-none-match — dissolve-on: literal-built
// `FilePath? = none` encodes as Absent (not raw null) so Present/Absent match is total;
// delete the third arm once the substrate routes literal none into Absent.
pattern gcp_oauth_access_token_adc_for_path(path: FilePath?) -> { token: Secret }
uses net: Network
{
Expand Down
48 changes: 2 additions & 46 deletions dsl/gunbc/auth/patterns.dag
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
// gunbc/auth/patterns.dag -- Gunbc-specific auth composition.
//
// These patterns intentionally live outside std/: they compose concrete
// runtime environments, provider services, and local tooling to materialize
// credentials and auth contexts.

module gunbc.auth.patterns

import std.resources { Filesystem, Network, AuthContext }
Expand All @@ -24,34 +18,23 @@ import extdeps.github.actions { GitHubActionsRuntime }
import extdeps.runtime.local { LocalDevRuntime }
import extdeps.shell

// 🟢 terminal coproduct: consumer-owned auth runtime choice; each payload lives in its discrete concern home.
type AuthRuntime
= GitHubActions { runtime: GitHubActionsRuntime }
| GcpMetadata { runtime: MetadataRuntime }
| LocalDev { runtime: LocalDevRuntime }

// Acquire a subject token based on runtime environment.
// Useful independently for: any workflow that needs a subject token
// without the full credential chain (e.g., direct STS exchange,
// non-GCP federated auth).

pattern acquire_subject_token(
runtime: AuthRuntime,
audience: NonEmptyStr
) -> { token: Secret } {
node token = match runtime {
GitHubActions { runtime: github_actions } => github_oidc(audience: audience, runtime: github_actions)
GcpMetadata { runtime: _ } => metadata_oidc(audience: audience)
LocalDev { runtime: _ } => metadata_oidc(audience: audience) // placeholder: local_auth() needs if/else expression support
LocalDev { runtime: _ } => metadata_oidc(audience: audience)
}
return { token: token.token }
}

// Optionally impersonate a service account.
// Passes through the original token when no SA is specified.
// Useful independently for: any workflow that needs conditional
// SA impersonation outside of the credential chain.

pattern optional_impersonation(
access_token: Secret,
service_account: ServiceAccountEmail?,
Expand All @@ -73,9 +56,6 @@ fn build_token(payload: Secret, scheme: AuthScheme, header_name: String, source_
{ token: payload, scheme: scheme, expires_at: none }
}

// OIDC -> STS -> optional impersonation -> secret access -> credential.
// Composes fundamental auth steps with GCP service calls.

pattern credential_chain(
runtime: AuthRuntime,
audience: NonEmptyStr,
Expand All @@ -89,7 +69,7 @@ pattern credential_chain(
lifetime_seconds: Int where range(min: 1, max: 3600)= 3600
) -> { token: AccessToken }
uses net: Network
// provides auth: AuthContext -- commented: parser doesn't support provides yet

{
node subject: acquire_subject_token(runtime: runtime, audience: audience)

Expand Down Expand Up @@ -121,9 +101,6 @@ pattern credential_chain(
}
}

// Real implementations replacing stubs. Each acquires a subject token
// from the runtime environment using the appropriate protocol.

func github_oidc(audience: String, runtime: GitHubActionsRuntime) -> { token: Secret }
uses net: Network
{
Expand All @@ -144,24 +121,3 @@ func metadata_oidc(audience: String) -> { token: Secret }
response = gcp.Metadata.GetIdentityToken(audience: audience)
return { token: response.subject_token as String }
}

// ADC check -> OAuth2 refresh -> conditional re-auth via gcloud -> merge.
// Commented: parser doesn't support if/else as inline expression yet.
// Materializers (when enabled): gunbc.auth.credentials.gcp_oauth_access_token(strategy).
//
// func local_auth() -> Secret
// uses fs: Filesystem
// {
// adc_path = shell.Env.Get(name: "GOOGLE_APPLICATION_CREDENTIALS")
//
// adc = gcloud.Auth.ReadADC(path: adc_path.value) [when adc_path.value != none] // parses ADC JSON -> client_id, client_secret, refresh_token
// adc_refresh = oauth2.Google.Refresh(
// client_id: adc.client_id, client_secret: adc.client_secret, refresh_token: adc.refresh_token
// ) [when adc_path.value != none]
// gcloud_auth = shell.GCloud.AuthPrintAccessToken()
//
// let adc_token = adc_refresh.access_token
// let gcloud_token = gcloud_auth.access_token
// let result = if adc_path.value != none { adc_token } else { gcloud_token }
// return result
// }
69 changes: 0 additions & 69 deletions dsl/gunbc/bootstrap.dag
Original file line number Diff line number Diff line change
@@ -1,28 +1,7 @@
// gunbc/bootstrap.dag -- Bootstrap pipeline data model.
//
// The gunbc compiler is self-hosting. The bootstrap pipeline is:
// 1. .dag source files define the compiler
// 2. stage0 .rs files are a frozen compiled version
// 3. stage0 compiles .dag -> produces new .rs -> must match stage0
//
// This file models the pipeline stages, their inputs/outputs, and the
// strategies for handling structural changes (new Node fields, new types)
// so the pipeline knows what to do automatically instead of requiring
// manual stage0 edits.
//
// These types are gunbc-specific (not std/): they model THIS compiler's
// bootstrap process, not a general-purpose build system.

module gunbc.bootstrap

import std.types { ContentHash, FilePath, NonEmptyStr }

// --- Pipeline stages ------------------------------------------------------

// The ordered stages of the compiler pipeline.
// Each stage is a pure function: input -> (output, diagnostics).
// Ordering is total: tokenize < parse < resolve < normalize < infer
// < complexity < ownership < emit.
type CompilerStage
= Tokenize
| Parse
Expand All @@ -33,8 +12,6 @@ type CompilerStage
| Ownership
| Emit

// What a stage consumes. Every stage after Tokenize consumes the
// previous stage's output.
type StageInput
= SourceText { files: List<SourceEntry> }
| TokenStream { from_stage: CompilerStage }
Expand All @@ -44,8 +21,6 @@ type StageInput
| TypedGraph { from_stage: CompilerStage }
| AnnotatedGraph { from_stage: CompilerStage }

// What a stage produces. Diagnostics thread through every stage
// boundary (DESIGN.md: "Every stage returns { value, diagnostics }").
type StageOutput {
stage: CompilerStage
artifact_kind: ArtifactKind
Expand All @@ -62,18 +37,12 @@ type ArtifactKind
| OwnershipProofs
| RenderedFiles

// --- Source entry ----------------------------------------------------------

type SourceEntry {
path: FilePath
content: String
module_name: NonEmptyStr?
}

// --- Change classification ------------------------------------------------

// What kind of structural change is being made to the compiler.
// This drives the BootstrapStrategy selection.
type ChangeKind
= AddField
| RemoveField
Expand All @@ -84,7 +53,6 @@ type ChangeKind
| ModifyVariant
| AddStage

// A classified change to the compiler's own structure.
type ChangeClassification {
kind: ChangeKind
target_type: NonEmptyStr
Expand All @@ -93,57 +61,27 @@ type ChangeClassification {
affects_stages: List<CompilerStage>
}

// --- Bootstrap strategy ---------------------------------------------------

// How to handle a change through the bootstrap pipeline.
//
// SinglePass: the change is backward-compatible (e.g. new field with
// default, new coproduct variant). The current stage0 can compile
// the new .dag source and produce correct output.
//
// TwoPhase: the change is NOT backward-compatible (e.g. new required
// field, removed field). The old compiler must first be taught to
// handle defaults, then the new compiler can take over.
//
// Additive: a special case of SinglePass where the change only adds
// new structure without modifying existing paths.
type BootstrapStrategy = SinglePass | TwoPhase | Additive

// The resolved strategy for a specific change.
type BootstrapPlan {
change: ChangeClassification
strategy: BootstrapStrategy
requires_manual_stage0_edit: Bool
reason: String
}

// --- Fixed-point verification ---------------------------------------------

// The convergence check: regen(regen(source)) == regen(source).
// If pass1 != pass2, the change is not at fixed point and the
// pipeline must iterate.
type FixedPointCheck {
pass1_hash: ContentHash
pass2_hash: ContentHash
converged: Bool
diff_files: List<FilePath>
}

// Overall result of a bootstrap cycle.
type BootstrapResult
= Converged { check: FixedPointCheck }
| Diverged { check: FixedPointCheck, iteration: Int }
| CompileError { stage: CompilerStage, message: String }

// --- Field propagation ----------------------------------------------------

// Which transforms preserve which fields across pipeline stages.
// This is the structural fact that determines whether a field
// survives a stage boundary or must be recomputed.
//
// Example: map_children preserves ident (it copies the parent node's
// metadata while transforming children). But normalize may discard
// source spans from desugared nodes.
type PropagationRule
= Preserved
| Recomputed
Expand All @@ -155,20 +93,13 @@ type FieldPropagation {
rule: PropagationRule
}

// A transform and the fields it guarantees to preserve.
type TransformContract {
transform_name: NonEmptyStr
stage: CompilerStage
preserved_fields: List<NonEmptyStr>
recomputed_fields: List<NonEmptyStr>
}

// --- Strategy selection ---------------------------------------------------

// Determine the bootstrap strategy from a change classification.
// Additive: new field with default, or new type.
// SinglePass: new coproduct variant (existing match arms still work).
// TwoPhase: everything else (requires old compiler to handle the gap).
fn classify_strategy(change: ChangeClassification) -> BootstrapStrategy {
match change.kind {
AddField => if change.has_default { Additive } else { TwoPhase }
Expand Down
6 changes: 0 additions & 6 deletions dsl/gunbc/ci_fleet.dag
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
// gunbc/ci_fleet.dag — gunbc CI runner identity (ComputeOffer → GitHub Actions runs-on labels).
//
// OUR self-hosted runner as compute_fabric data, consumed by ci_workflow / ci_yaml_emit via
// gunbc_ci_runner_spec(). The memory-aware spawn-width modeling was removed (the floor pins a
// flat width); the real per-host fleet inventory lives in gunbc.operator_fleet.

module gunbc.ci_fleet

import extdeps.cpu.ampere { altra_q6430_catalog }
Expand Down
48 changes: 0 additions & 48 deletions dsl/gunbc/ci_floor_measurement.dag
Original file line number Diff line number Diff line change
@@ -1,39 +1,3 @@
// gunbc/ci_floor_measurement.dag — the CI floor's MEASURED per-shard memory peak (§1-C).
//
// This is the committed half of the §1 measurement→plan loop (realization-measurement-loop.md
// Phase 0/1). The spawn-width derivation (src/v2/workflow/ci_floor_plan.dag) divides the LIVE
// host memory budget by the per-shard peak recorded HERE. Per DESIGN §3 (measured⇒peripheral):
// - the per-shard peak is OUR measurement → we COMMIT it, provenance-stamped (this file);
// - the cgroup budget is authored by an EXTERNAL system (the host/scheduler) → the host
// realizer READS it live (claim_executor), never committed.
// This file is the peripheral measured realization; the v2 plan stays pure topology.
//
// NOT a hand-grounded literal: the number below is claim_executor's MEASURED VmHWM emit
// ("[measurement] floor peak RSS: <bytes> (VmHWM) at spawn_width=N", added in #5431). It
// replaces — does not re-add — the ~14GB hand-grounded literal #5419 deleted as unwired.
//
// ── PROVENANCE (re-stamp on every re-measure) ────────────────────────────────
// source emit : "[measurement] floor peak RSS: 8400113664 bytes (VmHWM) at spawn_width=4"
// run : GitHub Actions run 27893441091 (#5431 PR CI, job 82540829121)
// commit : cb71163cf2 (the #5431 merge that landed the VmHWM emit)
// corpus : 616 discovery witnesses (0 skipped)
// date : 2026-06-21
// Each DiscoveryBatch shard does a WHOLE-TREE resolve, so the per-shard peak ≈ the whole-floor
// VmHWM ÷ the spawn_width it was measured at (the concurrency). It scales with TREE size, not
// witnesses-per-shard — which is why a larger tree (the old ~2900-row era) peaked far higher.
//
// 🟡 SCAFFOLD — feature:measured-peak-drift-gate —
// consumer: ci_floor_plan.gunbc_ci_floor_spawn_width (via std.realization_width).
// RESIDUE (DESIGN §6, legit unstructurable-before-execution): the committed peak is stale in
// exactly ONE dangerous direction — the tree grows un-re-stamped → committed peak too LOW →
// ⌊budget ÷ peak⌋ too HIGH → OOM. A peak is fundamentally a runtime OUTPUT (you cannot know a
// run's peak before running it), so a committed-prior-measurement + a drift-check is the legit
// §6 residue, not a construction wall. The #5431 emit each run is the drift MONITOR but nothing
// GATES on it yet (observe-by-eyeball = validation, not construction).
// dissolve-on: a cheap CI gate compares this committed peak against the live emit's VmHWM÷width
// and fails closed when committed is stale-LOW beyond a margin (re-stamp required). Out of scope
// for the §1-C width PR; this marker keeps the committed fact from being a silent staleness trap.

module gunbc.ci_floor_measurement

import std.measure { ByteSize, byte_size }
Expand All @@ -43,25 +7,13 @@ import std.realization_measurement {
concurrent_memory_peak_per_share,
}

// The measured whole-floor concurrent peak (VmHWM) bundled with the concurrency it was sampled
// at — ONE fact (a ConcurrentMemoryPeakSample), the single authority for the §1-C derivation.
// Peak and concurrency are only meaningful together (per-share = peak ÷ concurrency), so they
// live in one carrier rather than as two loose rows that could drift apart. Re-stamp the pair
// here on every re-measure (provenance above).
data gunbc_ci_floor_measured_peak: ConcurrentMemoryPeakSample = ConcurrentMemoryPeakSample {
peak: byte_size(8400113664)
concurrency: 4
}

// Per-shard peak: each DiscoveryBatch shard does a whole-tree resolve, so the per-shard peak is
// the measured concurrent peak distributed across its sample concurrency. Delegates to the std
// measure-algebra derivation (std.realization_measurement) — no inline unwrap/divide/re-ground
// here; the division is a grounded measure operation, not a one-off expression.
fn gunbc_ci_floor_per_shard_peak_rss_bytes() -> ByteSize {
concurrent_memory_peak_per_share(sample: gunbc_ci_floor_measured_peak)
}

// Fail-closed fallback width when the host cannot read a live memory budget: the last
// known-safe MEASURED width (the run above passed at width 4 = 8.40 GB concurrent on the real
// fleet). A bounded, grounded fallback — never fabricated, never an unbounded memory-blind width.
data gunbc_ci_floor_conservative_fallback_width: Int = 4
Loading