Repository navigation
CI witness enrollment opt-in inversion (2026-07-04) - #6232
Merged
Merged
Conversation
… declared roster row Operator decision 2026-07-04: the tree-wide glob roster (543 files / ~1,551 test fns, growing quadratically - a witness is definable between any two pipeline segments) pushed both CI jobs to the 90-min timeout: maximum cost, zero delivered signal, every merge effectively fail-open. Existence no longer enrolls a witness in CI. - CiSpec.witness_entries: the opt-in roster, projected from CommitWitnessClaim rows on the GithubActionsCiJob surface of commit_gate_roster (the existing enrollment authority - no new mechanism). Empty today. - ci_floor_plan: an empty roster puts NO witness-corpus node in the plan (structural omission, not an empty glob - the executor's empty-corpus fail-closed diagnostic stays meaningful); a non-empty roster becomes explicit-entries discovery batches (scan_dirs/discovery_scope_dirs empty, so the glob path is unreachable from CI), partitioned corpus vs execution by path prefix, still compile-gated and heavy-serialized. The dedicated grounding whole-tree node dissolved into the roster. - claim_executor: when a plan carries no DiscoveryBatch, run the naming- hygiene tree walk (test fn outside *_test.dag, __ basenames) once, fail-closed - a witness must stay nameable even when not enrolled. - Witness tests inverted: live plan asserts discovery tracks the roster (zero today); the enrollment machinery is proven on synthetic rosters (presence, partition, gating after compile, heavy serialization, exclusion edges) with red discrimination. - Rust lane, same inversion: the two whole-tree tests (func_env whole-tree ptr-count, whole-corpus semantic oracle) are now #[ignore] with written reasons per the #5427 discipline; run via -- --ignored. - Found and fixed two files the v1 interpreter grammar could not parse (top-level // comments): affected_set_floor_runner.dag - which made resolve_floor_runner_context fail and silently disabled the affected-set skip, falling back to full corpus on every floor run - and phase_profile_proof_plan.dag. Comments converted to data-string markers. - Local tree-wide discovery unchanged (claim_batch --roster-from-discovery). - Dissolve-on: affected-set selection + floor memoization make per-PR selection-by-affectedness affordable; enrollment returns to discovery shrunk by the affected set. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DcouXUHJmm4NPqwDyvnDKf
…le pure-fn canary) Per operator intent: exactly one witness in CI for now, to observe the floor's behavior around a known-tiny payload. The canary is dag/test/claim/variant_owner_expected_type_test.dag :: expected_type_picks_variant_owner_not_alpha_order - a single test fn over self-contained pure functions (no host intrinsics, one std.logic import; measured locally: 3ms resolve / 2-module closure, ~0ms eval), so whatever time the CI witness lane now costs is the floor's fixed overhead, not the witness. Also: run the witness naming-hygiene walk unconditionally in claim_executor's plan path, BEFORE plan evaluation - explicit-entries discovery batches skip the glob scan that used to carry the placement checks, and pre-plan ordering makes a naming violation the cheapest possible failure. Verified by execution: red probe (planted test fn in a non-_test.dag file) fails closed with the placement diagnostic in seconds; green probe on the live tree passes the walk and proceeds to plan eval; the enrolled canary runs green via claim_batch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DcouXUHJmm4NPqwDyvnDKf
…et (pre-existing on main; surfaces on any .rs-touching PR) The ratchet constant deliberately sits at its minimum (0); scoped allow with justification keeps raising the ceiling a one-constant edit instead of hardcoding == 0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DcouXUHJmm4NPqwDyvnDKf
…y fails immediately Operator decision: 'fail closed' here means DON'T PROCEED, never 'silently run more'. skip_unaffected_node_frontier: true is a declared capability, so every input it needs is required - a failure is a loud typed error: - git diff observation failed -> error (was: run full corpus). The FloorGitDiffOutcome degradation enum is deleted; an absent diff is no longer a representable input state to selection. To run without selection, declare skip_unaffected_node_frontier: false - an explicit bit, not a silent state. - diff->declaration attribution failed -> error (was: run full corpus) - affected-set runner unresolvable -> error naming the declared entry (was: run full corpus - the arm that hid the broken runner for weeks) - same per shard -> error through the shard join (was: run all rows in shard) - precompute_would_skip / per-witness would_skip / frontier-touch fns erroring -> error naming the witness (was: run anyway) - roster row file unreadable -> error (was: silently reclassify as host-scaffold) Rationale: the 'safe' superset fallback conflated broken artifacts with missing observations, hid the defect permanently (no consumer of the eprintln), and at corpus scale 'run more' inverted into fail-open-by-timeout. The runner provisioning, fetch step, and observers are all declared by this repo's own spec, so there is no 'environment' excuse category: a missing input is a bug in a declared step and stops the floor. cargo build green, clippy -D warnings green, fmt clean; floor-scoped lib unit tests and a live red/green probe through a discovery batch are running and any regression they surface lands as a follow-up. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DcouXUHJmm4NPqwDyvnDKf
…ll-clock marks The 'gunbc ci' step went silent for 35+ minutes after the release build on the self-hosted runner - all of it pre-witness prelude: naming walk, output-policy install, plan-entry resolve, interpreted scheduler eval (gunbc_ci_floor_batches), then a SECOND resolve of the same plan entry for spawn-width, then another interpreted eval. Nothing printed until all of it finished, so a 30-minute prelude was indistinguishable from a hang. - resolve_entry_graph(plan_entry) now runs once; the hermetic plan eval and the wet spawn-width eval share the resolved graph (the double-paid-compute trap from the floor memoization thread, paid at minutes per resolve). - claim_executor stamps [t+Xs] phase marks: hygiene walk, policy install, plan resolved, plan evaluated, width evaluated / walk starting. The floor log now itemizes its own prelude. eval_plan stays as a resolve+eval wrapper for the --perturb-check path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DcouXUHJmm4NPqwDyvnDKf
…atchet) The prior ratchet went 30 -> 50 -> 90, each raise buying headroom for the unfixed resolve cost; at 90 the queue backed up and runs still died at the cap having delivered zero signal. The budget is now a forcing function: the floor must fit it, and the [t+Xs] phase marks itemize exactly which phase does not. Jobs stay red-by-timeout until resolve memoization lands - an honest red, unlike a 90-minute lane that never completed. ci.yml hand-synced with the ci_workflow.dag authority (3 job sites); the generated-artifact drift gate byte-verifies the pairing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DcouXUHJmm4NPqwDyvnDKf
…rator session 2026-07-04) Names the target architecture for the resolve problem measured during the CI dig-out: request-major private universes -> cheap edge graph + reverse-reachable minimal set + forward once-per-node evaluation (construction, not cache lookup), windowed-frontier memory (interface vs body artifacts), isolation-as-purity, and the full v1/v2 change surface. Staged S1 (union resolve, in-process, ships in the current PR line) / S2a (module nodes + Merkle keys) / S2b (persistence, gated on determinism #5941) / S3 (shared store) so it is not a 10-PR arc. Cross-linked from the M1/M2 memoization doc it supersedes (that doc's own M1 dissolution trigger anticipated exactly this design). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DcouXUHJmm4NPqwDyvnDKf
…llet, ci-selection-vs-scheduling section 7) The interpreted main_wet regeneration was killed twice by container restarts (~2 CPU-hours each attempt, itself a receipt for the resolver-graph-major design). The generated outputs are hand-applied to byte-match what the emitters produce from the already-committed authorities (dag/gunbc/design_document.dag, dag/gunbc/plans/ci_selection_vs_scheduling.dag); the GeneratedArtifactDriftGate adjudicates exactness once the floor fits its 10-minute budget. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DcouXUHJmm4NPqwDyvnDKf
…xecutor) Without it, claim_batch diagnostics cannot attribute time to resolve/typecheck/eval phases - a 20-minute silent resolve is uninterpretable, and the resolver investigation needs per-phase receipts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DcouXUHJmm4NPqwDyvnDKf
…o-special-cases section; per-module typecheck attribution Instrumented, isolated measurement: the 11-module closure finishes parse+resolve+normalize in ~1.1s then sits in typecheck 13+ minutes - inference is ~99.9% of cold resolve cost. Reprioritizes the plan: pathology lane first (per-module [typecheck-attribution] lines now name any module over 2s), unification (module obligations under the existing executor) second, union-of-global-passes demoted to a ~1s-class cut. Adds the operator's formulation as design section 1b: resolution is the system's one special case - the Bazel-shaped executor schedules eleven coarse gates while the dominant work hides in one opaque recursive host call; module resolution IS dependency execution over the same substrate. Maps the external witness-frontier-cursor vocabulary onto existing authorities (Runnable/RunnableCompile, Realization content-hash key + EffectShape, executor batches, receipts) per the section-3 anti-nickname discipline, and adopts the four-terminal-state invariant. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DcouXUHJmm4NPqwDyvnDKf
…e per process First implementation increment of the resolver graph-major design (and of the stratification rule: resolution is declared shared work, not ambient per-consumer control flow). A thread-local store keyed by (source_roots, entry) now serves the floor runner context, the diff observer, the output policy, the group syntax, the wet-hermetic roster prefix, and the executor's plan entry - each was previously a private resolve, re-paid per consumer and per discovery batch within one process. Failure semantics unchanged: a miss resolves exactly as before, including the typed error path; the store never converts an error into a fallback. Receipt: process_resolve_store_dedupes_repeat_resolve - Rc identity on the second resolve proves zero recompute (0.00s, fixture tree under target/). Thread-local by design: resolved graphs are Rc-based (not Send); shard threads keep their own store rather than smuggling Rc across threads. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DcouXUHJmm4NPqwDyvnDKf
…gical module Verdict from the instrumented run: all std modules in the closure - including std.algebra and std.realization_schedule themselves - typecheck in under 2s each; the call that runs 17+ minutes is typecheck_module on the 80-line CONSUMER module (test.claim.realization_schedule_witness). The inference pathology is at generic use sites, not definition sites. Next lane: the existing type-env lookup profiler (text_lookup_work_counter feature, reset_type_env_lookup_profile) pointed at that one module. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DcouXUHJmm4NPqwDyvnDKf
Heartbeats now carry env_flatten/env_builds/env_merges/env_rewires from the existing v1_compiler_infer_env atomics. First live capture on the pathological entry: env_flatten grows ~80k/sec unbounded (9.7M by t=120s) while builds=11, merges=37, rewires=0 stay flat. Root site: record_lit_variant_fields_from_visible_env (v1_compiler_infer.rs, generated from v1.compiler.infer) - every VARIANT LITERAL flattens the entire visible environment (recursive parent fold; the counter) and then scans every visible binding with expand_type_for_field_access per candidate to find the variant's owner. Cost = variant literals x |visible env| x expansion - definitions cheap, consumers explode. 04_env.dag:35 carries an invariant expecting flatten_visible_parent_recurses==0 on import chains; live count says 9.7M in 2 minutes. Fix shape (next block, dag source + regen): a variant-name -> owner index built once per env, and expected-type short-circuit before any global scan. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DcouXUHJmm4NPqwDyvnDKf
… resolution follows the binding edge The ambiguity support (bare constructor names legal across coproducts, expected-type tie-break, whole-env owner scan as fallback) is itself the bug - accidental semantics, never intended. The DAG already provides the namespace: imports bind arm names to arm nodes; the parent edge names the owner; resolution is following the edge already held. Rules: bound-name resolution via parent edge; unbound constructor literal = typed error (today a silent undeclared-dependency fail-open via the scan); double binding = collision error at env build; patterns resolve via scrutinee type; expected-type owner-picking deleted. The pathological scan is removed, not memoized. Census: 5,526 arm names, 221 global collisions (uniqueness must be scoped to co-visibility); <=4,572 unbound arm-name uses upper bound, dominated by legal pattern positions. Control run killed at 60+ min still inside one typecheck_module call on the 80-line module. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DcouXUHJmm4NPqwDyvnDKf
… with explicit contract; flat name visibility refinement Union resolve leads the resolve lane with a recorded contract: minimum upper bound (resolve cost <= 1x union closure, receipt-enforced), successor must be maximally parallel (topo-antichain module typecheck, budget-tree width) and frontier-window efficient; it dissolves into S2a and must not grow features that delay that. Namespacing ruling refined per operator: visibility is FLAT - locals + direct imports only, never transitive - making collision detection per-file with zero graph traversal; types propagate by graph identity underneath. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DcouXUHJmm4NPqwDyvnDKf
Conflicts: src/v1/stage0/src/cli_run.rs import_closure_equivalence_tests - both hunks resolved to the rewritten main's side (our branch never touched that test module; the conflict was old-main vs force-pushed-main content). Post-merge: rustfmt over the incoming fmt-dirty generated files, release bins rebuild clean, process_resolve_store receipt green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DcouXUHJmm4NPqwDyvnDKf
This was referenced Jul 4, 2026
briansrls
added a commit
that referenced
this pull request
Jul 5, 2026
…(E0 / PR-0c) - verdict 5-green/1-red Executes lens_contract_cost_mode_repromotion_trigger's own named actions, exactly (the row is deleted - fired): - dag/gunbc/commit_workflow.dag: CommitWitnessClaim row enrolls budget_roster_completeness_test.dag::complexity_budget_roster_family_gate_holds on the GithubActionsCiJob surface (the #6232 opt-in authority; zero ci.yml change - the floor plan reads spec.witness_entries at eval time). - contract.dag: lens_contract_cost.mode AuditOnly -> Blocking. The claim is now TRUE by derivation: the enforcement gate reads the roster and derives consumer_observed = FloorGate; enforcement_consistency_gate_holds (Blocking requires a live consumer) is green BY EXECUTION - the same gate that proved the old Blocking claim false now proves this one true. - enforcement_live_witness_test.dag: pinned verdict updated in the same PR (roadmap-as-executable): claimed GREEN, scope RED (fn-body reflection residue - the E1 lane), subjects GREEN, consumer GREEN, red_control GREEN, self_application GREEN. 5 green / 1 red. What is now enforced that was not before: the cost lens family has a real merge-surface consumer - the fixture-band budget gate (4-exemplar roster, family-complete check) runs on the CI floor witness corpus, and any lens contract claiming Blocking without such a consumer reds the floor. Receipts (by execution, 2026-07-05): bound witness green; enforcement_consistency_gate_holds green at Blocking; new 5/1 pin green. The old 3-red/3-green pin fails against this tree by construction - the expectation update rides the same PR, per the drift-witness design. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
briansrls
added a commit
that referenced
this pull request
Jul 5, 2026
…(E0 PR-0c) - verdict 5-green/1-red (#6276) * WIP: complexity lens enforcement * Cost contract re-promoted to Blocking: budget witness enrolled on CI (E0 / PR-0c) - verdict 5-green/1-red Executes lens_contract_cost_mode_repromotion_trigger's own named actions, exactly (the row is deleted - fired): - dag/gunbc/commit_workflow.dag: CommitWitnessClaim row enrolls budget_roster_completeness_test.dag::complexity_budget_roster_family_gate_holds on the GithubActionsCiJob surface (the #6232 opt-in authority; zero ci.yml change - the floor plan reads spec.witness_entries at eval time). - contract.dag: lens_contract_cost.mode AuditOnly -> Blocking. The claim is now TRUE by derivation: the enforcement gate reads the roster and derives consumer_observed = FloorGate; enforcement_consistency_gate_holds (Blocking requires a live consumer) is green BY EXECUTION - the same gate that proved the old Blocking claim false now proves this one true. - enforcement_live_witness_test.dag: pinned verdict updated in the same PR (roadmap-as-executable): claimed GREEN, scope RED (fn-body reflection residue - the E1 lane), subjects GREEN, consumer GREEN, red_control GREEN, self_application GREEN. 5 green / 1 red. What is now enforced that was not before: the cost lens family has a real merge-surface consumer - the fixture-band budget gate (4-exemplar roster, family-complete check) runs on the CI floor witness corpus, and any lens contract claiming Blocking without such a consumer reds the floor. Receipts (by execution, 2026-07-05): bound witness green; enforcement_consistency_gate_holds green at Blocking; new 5/1 pin green. The old 3-red/3-green pin fails against this tree by construction - the expectation update rides the same PR, per the drift-witness design. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansrls@gunb.ai> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Inverts CI witness enrollment from always-on (tree-wide discovery) to opt-in (explicit roster). Witnesses now run in CI only when declared in
commit_gate_rosterasCommitWitnessClaimrows on theGithubActionsCiJobsurface. This eliminates quadratic roster growth that caused floor timeouts while preserving local tree-wide discovery for development.Key Changes
Floor plan architecture:
scan_dirs,discovery_scope_dirs) with explicitwitness_entriesroster inCiSpecfloor_grounding_whole_tree_node; grounding witness must be re-enrolled as aCommitWitnessClaimrowcorpus_plan_nodes()now conditionally includes corpus nodes only when roster is non-empty (fail-closed: empty roster → no corpus node)floor_schedule_for(spec, serialize_heavy)replaces hardcodedgunbc_ci_specreferencesWitness entry routing:
corpus_witness_entries()andexecution_witness_entries()filters to partition roster by scope prefix (src/v2/test/claim/execution/)corpus_runnable_for()andexecution_corpus_runnable_for()now acceptCiSpecand use explicit entries instead of discoverywitness_discovery_scan_dirsimport; discovery is now local-only (claim_batch--roster-from-discovery)Enrollment authority:
gunbc.commit_workflowprojectsCommitWitnessClaimrows intoScheduleWitnessEntrylist viaproject_ci_floor_witness_entries()CiSpec.witness_entriesis the single source of truth for CI enrollmentci_spec_with_witness_entries()helper to construct specs with custom rosters (for testing)Test coverage:
ci_floor_plan_witnesses()covers live plan behavior; newci_floor_optin_roster_witnesses()validates opt-in mechanicswitness_live_floor_discovery_tracks_optin_roster(),witness_optin_roster_drives_corpus_presence(),witness_optin_plan_gates_corpus_after_compile(), etc.discovery_carries_exactly()to verify roster rows are carried as explicit entries, not discoveredoptin_spec(full roster),corpus_only_spec,zero_roster_spec(empty)Fail-closed safety:
claim_executorruns naming hygiene walk (check_floor_filename_hygiene,discover_floor_corpus_rows) when plan has noDiscoveryBatch, ensuring witnesses remain nameable even when unenrolledRust formatting:
Implementation Details
ScheduleWitnessEntry(fromstd.realization_schedule) carries{entry: String, function: String}pairsfloor_corpus_exclusion_resource_edges) now fold over actual corpus nodes in plan, not hardcoded listfloor_heavy_resolve_chain_resource_edges) no longer includes grounding nodecorpus_plan_nodes()instead of hardcoded three-node listgunbc_ci_spec(single authority preserved)https://claude.ai/code/session_01DcouXUHJmm4NPqwDyvnDKf