diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6fcf0c61dba..caaf8ef6172 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ env: jobs: ci: runs-on: [self-hosted, linux, arm64] - timeout-minutes: 130 + timeout-minutes: 145 steps: - name: Checkout uses: actions/checkout@v5 @@ -82,7 +82,7 @@ jobs: rm -f "$BUILD_LOG" "$ROOT/target/release/claim_executor" --verify-build-artifacts "$ROOT/target/release/claim_executor" "$ROOT/target/release/gunbc" sccache --show-stats 2>/dev/null || true - timeout-minutes: 30 + timeout-minutes: 45 - name: gunbc ci (.dag witnesses + gates) run: | ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) @@ -126,7 +126,7 @@ jobs: timeout-minutes: 5 rust_tests: runs-on: [self-hosted, linux, arm64] - timeout-minutes: 30 + timeout-minutes: 105 steps: - name: Checkout uses: actions/checkout@v5 @@ -174,7 +174,7 @@ jobs: curl -LsSf --retry 3 "https://get.nexte.st/0.9.138/$A" | tar zxf - -C "$CARGO_HOME/bin" fi timeout-minutes: 5 - - name: v1 rust gate (fmt + clippy + nextest) + - name: Build release bins (claim_executor + gunbc) run: | ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) set -o pipefail @@ -199,6 +199,9 @@ jobs: rm -f "$BUILD_LOG" "$ROOT/target/release/claim_executor" --verify-build-artifacts "$ROOT/target/release/claim_executor" "$ROOT/target/release/gunbc" sccache --show-stats 2>/dev/null || true + timeout-minutes: 45 + - name: v1 rust gate (fmt + clippy + nextest) + run: | ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) git fetch --no-tags origin main 2>/dev/null || true set -o pipefail @@ -221,7 +224,7 @@ jobs: fi fi rm -f "$BUILD_LOG" - timeout-minutes: 15 + timeout-minutes: 45 - name: rust_tests cgroup peak (placement divisor) run: | BIN="$(git rev-parse --show-toplevel 2>/dev/null || pwd)/target/release/claim_executor" @@ -297,3 +300,4 @@ jobs: "$ROOT/target/release/claim_executor" --verify-build-artifacts "$ROOT/target/release/claim_executor" "$ROOT/target/release/gunbc" sccache --show-stats 2>/dev/null || true "$ROOT/target/release/gunbc" run --source-root dag --source-root src/v2 --entry dag/gunbc/live_deploy/apply.dag --function live_deploy_apply_srv1_wet + diff --git a/dag/gunbc/ci_layer_roots.dag b/dag/gunbc/ci_layer_roots.dag index 5a7b823e122..6bba55ae92a 100644 --- a/dag/gunbc/ci_layer_roots.dag +++ b/dag/gunbc/ci_layer_roots.dag @@ -2,6 +2,12 @@ module gunbc.ci_layer_roots data witness_layer_roots: List = ["dag", "src/v2"] +data compile_clean_source_roots_note: String = "Compile-clean pool extends witness_layer_roots with src/v1 for cross-tree import resolution only (e.g. dag/test/claim/ownership_movable_test imports v1.compiler.ownership). src/v1 stays excluded from floor witness_layer_roots per gunbc.plans.seed_debt_bundle_item_2 §1 (parse-cursor fork deferred — no floor witness discovery over src/v1)." + +fn compile_clean_source_roots() -> List { + concat(witness_layer_roots, ["src/v1"]) +} + data witness_discovery_scan_dirs: List = ["dag/test/claim", "src/v2/test/claim/manual"] data witness_exclusion_substrings: List = [ diff --git a/dag/gunbc/ci_spec.dag b/dag/gunbc/ci_spec.dag index 588cc5caa33..b6aab7581dc 100644 --- a/dag/gunbc/ci_spec.dag +++ b/dag/gunbc/ci_spec.dag @@ -355,6 +355,10 @@ fn gunbc_ci_workflow_run(spec: CiSpec) -> String { gunbc_ci_floor_only_script(spec: spec) } +fn gunbc_ci_floor_run(spec: CiSpec) -> String { + gunbc_ci_floor_only_script(spec: spec) +} + fn gunbc_ci_rust_gate_invoke() -> String { ci_cargo_eagain_retry_script( command: concat( diff --git a/dag/gunbc/ci_workflow.dag b/dag/gunbc/ci_workflow.dag index bcc21a80800..e15b2f029be 100644 --- a/dag/gunbc/ci_workflow.dag +++ b/dag/gunbc/ci_workflow.dag @@ -5,7 +5,7 @@ import gunbc.ci_workflow_expressions { ci_concurrency_group, ci_setup_rust_home, ci_cache_path, ci_cache_key, ci_cache_restore_keys } import gunbc.ci_spec { - CiSpec, gunbc_ci_spec, gunbc_ci_workflow_run, gunbc_ci_rust_job_run, + CiSpec, gunbc_ci_spec, gunbc_ci_floor_run, gunbc_ci_deploy_stages, DeployStage, gunbc_ci_deploy_run_script, ci_release_build_script, gunbc_ci_rust_gate_only_script, @@ -182,13 +182,13 @@ fn ci_floor_step() -> Step { RunStep { name: Present { value: "gunbc ci (.dag witnesses + gates)" }, id: none, - run: gunbc_ci_workflow_run(spec: ci_floor_spec_from_roster()), + run: gunbc_ci_floor_run(spec: ci_floor_spec_from_roster()), shell: none, env: none, working_directory: none, if_condition: none, continue_on_error: none, - timeout_minutes: Present { value: gunbc_ci_job_timeout_policy_minutes } + timeout_minutes: Present { value: gunbc_ci_floor_gate_step_timeout_minutes } } } @@ -250,7 +250,7 @@ fn ci_rust_gate_step() -> Step { RunStep { name: Present { value: "v1 rust gate (fmt + clippy + nextest)" }, id: none, - run: gunbc_ci_rust_job_run(), + run: gunbc_ci_rust_gate_only_script(), shell: none, env: none, working_directory: none, @@ -296,14 +296,26 @@ fn ci_deploy_step(stage: DeployStage) -> Step { data gunbc_ci_job_timeout_policy_minutes: Int = 90 -data gunbc_ci_rust_gate_step_timeout_minutes: Int = 15 +data gunbc_ci_rust_gate_step_timeout_minutes: Int = 45 -data gunbc_ci_release_build_step_timeout_minutes: Int = 30 +data gunbc_ci_rust_gate_step_budget_note: String = "Interim rust-gate-only step budget (fmt/clippy/nextest after release build): 45 = prior 30m + margin after post-main-merge cold clippy exceeded gates-only step (job 85246635625, run 28749725167 on f2aa0ab). Prior: job 85237415376 bundled build+gates at 60m (10c53165bd split); job 85235032960 bundled at 30m. Re-derive DOWNWARD when fleet cache/build path stabilizes." + +data ci_rust_build_gate_step_split_note: String = "Build and rust gate are separate workflow steps (same discipline as ci_build_floor_step_split_note): bundling cargo build + rust_gates_ci under one step timeout produced step-FAILURE during v1-compiler compile with zero gate verdict (receipt: rust_tests job 85237415376, run 28746200534 on dfbff0f). Build step carries gunbc_ci_release_build_step_timeout_minutes; rust gate step carries gunbc_ci_rust_gate_step_timeout_minutes." data gunbc_ci_aux_step_timeout_minutes: Int = 5 data gunbc_ci_prelude_allowance_minutes: Int = 5 +data ci_build_floor_step_split_note: String = "Build and floor are separate workflow steps so gate budgets apply to claim_executor only, not cargo build: bundling both under one step timeout produced step-FAILURE during v1-compiler compile with zero gate verdict (receipt: PR #6259 ci job 85192573905, 2026-07-05). Build step carries gunbc_ci_release_build_step_timeout_minutes; floor step carries gunbc_ci_floor_gate_step_timeout_minutes." + +data gunbc_ci_release_build_step_timeout_minutes: Int = 45 + +data gunbc_ci_release_build_step_budget_note: String = "Interim release-build step budget until cold v1-compiler fits 15m: 45 = prior 30m + margin after main merge (CARGO_BUILD_JOBS=6, text_lookup_work_counter). Receipt: job 85235032962 timed out at 30m still Compiling v1-compiler (~25m dep prelude + compile in progress; run 28745277854 on 1ba1895). Prior: job 85194701830 at 15m. Re-derive DOWNWARD when fleet cache/build path stabilizes." + +data gunbc_ci_floor_gate_step_timeout_minutes: Int = 90 + +data gunbc_ci_floor_gate_step_budget_note: String = "Interim floor-gate step budget until dag_compile_clean_gate fits gunbc_ci_job_timeout_policy_minutes (10): 90 = prior 60m budget + margin; compile_clean_source_roots src/v1 pool measured ~58m shell at 60m kill (still in batch-1), ~78m full compile locally. Receipt: job 85223768433 timed out at 60m mid batch-1 compile-clean (~58m in shell, zero verdict; run 28741045613 on abd03b9). Prior: job 85219793614 at 45m (dc05863), job 85217499061 at 30m (5c1131). Re-derive DOWNWARD when S2a node store / compile-clean scoping lands." + data gunbc_ci_deploy_job_backstop_timeout_minutes: Int = 10 data gunbc_ci_job_timeout_policy_disposition: Disposition = Terminal { @@ -311,11 +323,11 @@ data gunbc_ci_job_timeout_policy_disposition: Disposition = Terminal { } fn gunbc_ci_job_backstop_timeout_minutes() -> Int { - gunbc_ci_release_build_step_timeout_minutes + gunbc_ci_job_timeout_policy_minutes + gunbc_ci_aux_step_timeout_minutes + gunbc_ci_prelude_allowance_minutes + gunbc_ci_release_build_step_timeout_minutes + gunbc_ci_floor_gate_step_timeout_minutes + gunbc_ci_aux_step_timeout_minutes + gunbc_ci_prelude_allowance_minutes } fn gunbc_ci_rust_job_backstop_timeout_minutes() -> Int { - gunbc_ci_rust_gate_step_timeout_minutes + gunbc_ci_aux_step_timeout_minutes + gunbc_ci_aux_step_timeout_minutes + gunbc_ci_prelude_allowance_minutes + gunbc_ci_release_build_step_timeout_minutes + gunbc_ci_rust_gate_step_timeout_minutes + gunbc_ci_aux_step_timeout_minutes + gunbc_ci_aux_step_timeout_minutes + gunbc_ci_prelude_allowance_minutes } fn ci_deploy_job(stage: DeployStage) -> Job { @@ -361,7 +373,7 @@ fn rust_tests_job() -> Job { id: "rust_tests", name: none, runner: gunbc_ci_runner_spec(), - steps: concat(ci_prelude_steps(), [ci_nextest_install_step(), ci_rust_gate_step(), ci_rust_cgroup_measurement_step()]), + steps: concat(ci_prelude_steps(), [ci_nextest_install_step(), ci_release_build_step(), ci_rust_gate_step(), ci_rust_cgroup_measurement_step()]), needs: [], env: none, outputs: none, diff --git a/dag/test/claim/dag_compile_clean_shard_a_witness_test.dag b/dag/test/claim/dag_compile_clean_shard_a_witness_test.dag index bae81ce788f..28f4b4d4e65 100644 --- a/dag/test/claim/dag_compile_clean_shard_a_witness_test.dag +++ b/dag/test/claim/dag_compile_clean_shard_a_witness_test.dag @@ -2,7 +2,7 @@ module test.claim.dag_compile_clean_shard_a_witness import tools.dag_compile_clean_partition { witness_partition_entry_root_is_first_witness_layer_root, - witness_partition_pool_roots_are_witness_layer_roots, + witness_partition_pool_roots_are_compile_clean_source_roots, witness_compose_all_clean_is_clean, witness_compose_any_failure_fails_closed, witness_compose_associativity, @@ -21,9 +21,9 @@ data witness_compose_red_on_injected_failure: Bool = compose_compile_clean_shard verdicts: [ShardClean, ShardFailed { entry_path: shard_a_exemplar_entry_path }] ) != ShardClean -test fn compile_clean_partition_boundary_matches_witness_layer_roots() -> Bool { +test fn compile_clean_partition_boundary_matches_compile_clean_source_roots() -> Bool { witness_partition_entry_root_is_first_witness_layer_root() - && witness_partition_pool_roots_are_witness_layer_roots() + && witness_partition_pool_roots_are_compile_clean_source_roots() } test fn compile_clean_shard_verdict_compose_laws_hold() -> Bool { diff --git a/dag/test/claim/inert_lens_hygiene_witness_test.dag b/dag/test/claim/inert_lens_hygiene_witness_test.dag index 85e79566a38..5bc0ca0dd21 100644 --- a/dag/test/claim/inert_lens_hygiene_witness_test.dag +++ b/dag/test/claim/inert_lens_hygiene_witness_test.dag @@ -1,9 +1,14 @@ module test.claim.inert_lens_hygiene_witness +import v2.lens.inert_lens { + inert_lens_hygiene_has_no_unreached_modules_holds, + inert_lens_hygiene_universe_is_nonempty_holds +} + test fn inert_lens_hygiene_has_no_unreached_modules() -> Bool { - return inert_lens_unreached_module_count() == 0 + return inert_lens_hygiene_has_no_unreached_modules_holds() } test fn inert_lens_hygiene_universe_is_nonempty() -> Bool { - return inert_lens_top_level_module_count() > 0 + return inert_lens_hygiene_universe_is_nonempty_holds() } diff --git a/dag/tools/dag_compile_clean_partition.dag b/dag/tools/dag_compile_clean_partition.dag index fe04935d4db..1651ed28151 100644 --- a/dag/tools/dag_compile_clean_partition.dag +++ b/dag/tools/dag_compile_clean_partition.dag @@ -1,6 +1,6 @@ module tools.dag_compile_clean_partition -import gunbc.ci_layer_roots { witness_layer_roots } +import gunbc.ci_layer_roots { witness_layer_roots, compile_clean_source_roots } import std.list { List } import std.types { String, Bool } import std.reducible { @@ -24,7 +24,7 @@ type CompileCleanShardVerdict fn compile_clean_partition_boundary() -> CompileCleanPartitionBoundary { CompileCleanPartitionBoundary { entry_root: witness_layer_roots.first(), - pool_roots: witness_layer_roots + pool_roots: compile_clean_source_roots() } } @@ -77,8 +77,8 @@ fn witness_partition_entry_root_is_first_witness_layer_root() -> Bool { compile_clean_partition_boundary().entry_root == witness_layer_roots.first() } -fn witness_partition_pool_roots_are_witness_layer_roots() -> Bool { - compile_clean_partition_boundary().pool_roots == witness_layer_roots +fn witness_partition_pool_roots_are_compile_clean_source_roots() -> Bool { + compile_clean_partition_boundary().pool_roots == compile_clean_source_roots() } fn witness_compose_all_clean_is_clean() -> Bool { diff --git a/dag/tools/dag_compile_clean_transport.dag b/dag/tools/dag_compile_clean_transport.dag index 6654e3a46cf..f6dd0a38753 100644 --- a/dag/tools/dag_compile_clean_transport.dag +++ b/dag/tools/dag_compile_clean_transport.dag @@ -1,7 +1,7 @@ module tools.dag_compile_clean_transport import extdeps.shell -import gunbc.ci_layer_roots { witness_layer_roots } +import gunbc.ci_layer_roots { compile_clean_source_roots } import std.disposition { Disposition, Scaffold, RealizationDispatch } import std.decl_ref { DeclarationRef, WholeDeclaration } import extdeps.languages.bash.program { @@ -14,7 +14,7 @@ import extdeps.languages.bash.program { import tools.host_prelude { ensure_gunbc_built } fn dcc_source_root_flags() -> List { - fold(witness_layer_roots, init: [], f: (acc, r) => concat(acc, [lit(text: "--source-root"), lit(text: r)])) + fold(compile_clean_source_roots(), init: [], f: (acc, r) => concat(acc, [lit(text: "--source-root"), lit(text: r)])) } fn dcc_pool_index_flags() -> List { @@ -220,6 +220,7 @@ data dcc_target_dag_marker: String = "'--target' 'dag'" data dcc_source_root_marker: String = "'--source-root'" data dcc_witness_root_dag_marker: String = "'dag'" data dcc_witness_root_v2_marker: String = "'src/v2'" +data dcc_witness_root_v1_marker: String = "'src/v1'" data dcc_pool_index_marker: String = "'--dependency-pool-index' 'primary-precedence'" data clean_tree_compile_invocation_marker: String = "'compile' '--source-root' 'dag'" @@ -237,6 +238,7 @@ fn shell_serializes_dcc_common_compile_invocation(script: String) -> Bool { && string_contains(s: script, pattern: dcc_source_root_marker) && string_contains(s: script, pattern: dcc_witness_root_dag_marker) && string_contains(s: script, pattern: dcc_witness_root_v2_marker) + && string_contains(s: script, pattern: dcc_witness_root_v1_marker) && string_contains(s: script, pattern: dcc_pool_index_marker) } diff --git a/src/v1/04_method.dag b/src/v1/04_method.dag index eb1f0d9fd63..c98fb56a79b 100644 --- a/src/v1/04_method.dag +++ b/src/v1/04_method.dag @@ -93,6 +93,8 @@ fn builtin_function_registry() -> Map { let m = map_insert(m, "hash_combine", hash_type) let m = map_insert(m, "atom_identity_hash", hash_type) let m = map_insert(m, "string_contains", bool_type) + let m = map_insert(m, "length", int_type) + let m = map_insert(m, "starts_with", bool_type) let m = map_insert(m, "replace", string_type) let m = map_insert(m, "filesystem_read", type_variable_node(id: "filesystem_read_result")) let m = map_insert(m, "contiguous_loop_elementwise_kernel", list_of_type_variable(id: "collection_element")) diff --git a/src/v1/stage0/src/v1_compiler_infer_method.rs b/src/v1/stage0/src/v1_compiler_infer_method.rs index 5f804819aaa..2a5ad79761a 100644 --- a/src/v1/stage0/src/v1_compiler_infer_method.rs +++ b/src/v1/stage0/src/v1_compiler_infer_method.rs @@ -186,6 +186,8 @@ pub fn builtin_function_registry() -> Rc>> { let m = v1_rt::rc_map_insert(m.clone(), "hash_combine".to_string(), hash_type()); let m = v1_rt::rc_map_insert(m.clone(), "atom_identity_hash".to_string(), hash_type()); let m = v1_rt::rc_map_insert(m.clone(), "string_contains".to_string(), bool_type()); + let m = v1_rt::rc_map_insert(m.clone(), "length".to_string(), int_type()); + let m = v1_rt::rc_map_insert(m.clone(), "starts_with".to_string(), bool_type()); let m = v1_rt::rc_map_insert(m.clone(), "replace".to_string(), string_type()); let m = v1_rt::rc_map_insert( m.clone(), diff --git a/src/v1/stage0/src/v1_interpreter.rs b/src/v1/stage0/src/v1_interpreter.rs index 9342dd7220a..a44011efba1 100644 --- a/src/v1/stage0/src/v1_interpreter.rs +++ b/src/v1/stage0/src/v1_interpreter.rs @@ -2264,6 +2264,11 @@ pub(crate) const STD_FN_INDEX_BRIDGE_FNS: &[&str] = &["fn_arrow_decl_facts_live" pub(crate) const STD_DATA_INDEX_BRIDGE_FNS: &[&str] = &["data_init_decl_facts_live"]; +pub(crate) const INERT_LENS_BRIDGE_FNS: &[&str] = &[ + "inert_lens_unreached_module_count", + "inert_lens_top_level_module_count", +]; + pub fn std_node_bridge_fn_names() -> &'static [&'static str] { STD_NODE_BRIDGE_FNS } @@ -2351,6 +2356,15 @@ fn is_v4_std_qualified_name_bridge_call(ctx: &InterpContext, func_name: &str) -> .is_some_and(|info| info.module_name == "v2.std.qualified_name") } +fn is_v4_inert_lens_bridge_call(ctx: &InterpContext, func_name: &str) -> bool { + if !INERT_LENS_BRIDGE_FNS.contains(&func_name) { + return false; + } + ctx.item_registry + .get(func_name) + .is_some_and(|info| info.module_name == "v2.lens.inert_lens") +} + fn eval_call(node: &Rc, env: &Rc, ctx: &InterpContext) -> InterpResult { let func_name = { let key = Rc::as_ptr(node) as usize; @@ -2437,6 +2451,18 @@ fn eval_call(node: &Rc, env: &Rc, ctx: &InterpContext) -> InterpResul }; } + if is_v4_inert_lens_bridge_call(ctx, &func_name) { + return match func_name.as_str() { + "inert_lens_unreached_module_count" => Ok(Value::Int( + crate::cli_run::inert_lens_unreached_module_count(), + )), + "inert_lens_top_level_module_count" => Ok(Value::Int( + crate::cli_run::inert_lens_top_level_module_count(), + )), + _ => unreachable!("inert_lens bridge fn set mismatch"), + }; + } + match func_name.as_str() { "fold_list" => return eval_fold_list_native(&args, env, ctx), "fold_list_right" => return eval_fold_list_right_native(&args, env, ctx), @@ -5309,6 +5335,21 @@ fn eval_builtin( Ok(Some(Value::Bool(s.contains(&sub)))) } + "starts_with" => { + let s = expect_str(positional.first().copied(), "starts_with")?; + let prefix = expect_str(positional.get(1).copied(), "starts_with prefix")?; + Ok(Some(Value::Bool(s.starts_with(&prefix)))) + } + + "length" => match positional.first() { + Some(Value::Str(s)) => Ok(Some(Value::Int(s.chars().count() as i64))), + Some(v) => match free_monoid_to_vec(v) { + Some(items) => Ok(Some(Value::Int(items.len() as i64))), + None => Ok(None), + }, + None => Ok(None), + }, + "contains" => match positional.as_slice() { [Value::Str(s), Value::Str(sub), ..] => Ok(Some(Value::Bool(s.contains(sub)))), [xs, target, ..] => match free_monoid_to_vec(xs) { diff --git a/src/v2/lens/inert_lens.dag b/src/v2/lens/inert_lens.dag new file mode 100644 index 00000000000..b31f2a8a1ba --- /dev/null +++ b/src/v2/lens/inert_lens.dag @@ -0,0 +1,35 @@ +module v2.lens.inert_lens + +import v2.lens.common.construction_justification { ConstructionJustification, WallAfterGrounding } +import std.disposition { RealizationDispatch } +import v2.std.logic { Bool } + +fn inert_lens_unreached_clean_for_count(unreached_count: Int) -> Bool { + unreached_count == 0 +} + +fn inert_lens_universe_nonempty_for_count(module_count: Int) -> Bool { + module_count > 0 +} + +data inert_lens_substrate_bridge_stub_note: String = "Self-recursive bodies below are compile-time substrate stubs, not evaluable semantics: v1_interpreter is_v4_inert_lens_bridge_call dispatches v2.lens.inert_lens module-qualified calls before body evaluation (same shape as v2.std.concept_index / fn_index). DISSOLVE-ON: construction_justification.class." + +fn inert_lens_unreached_module_count() -> Int { + inert_lens_unreached_module_count() +} + +fn inert_lens_top_level_module_count() -> Int { + inert_lens_top_level_module_count() +} + +fn inert_lens_hygiene_has_no_unreached_modules_holds() -> Bool { + inert_lens_unreached_clean_for_count(unreached_count: inert_lens_unreached_module_count()) +} + +fn inert_lens_hygiene_universe_is_nonempty_holds() -> Bool { + inert_lens_universe_nonempty_for_count(module_count: inert_lens_top_level_module_count()) +} + +data construction_justification: ConstructionJustification = ConstructionJustification { + class: WallAfterGrounding { dissolves_to: RealizationDispatch } +}