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
1 change: 1 addition & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ fresh_doc() {
fresh_artifact_path() {
case "$1" in
.github/workflows/ci.yml*) return 0 ;;
.github/workflows/falsifier.yml*) return 0 ;;
.gitignore*) return 0 ;;
ROADMAP.md*) return 0 ;;
DESIGN.md*) return 0 ;;
Expand Down
85 changes: 85 additions & 0 deletions .github/workflows/falsifier.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: affected-set-falsifier
on:
workflow_dispatch:
schedule:
- cron: 0 7 * * *
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
jobs:
falsifier:
runs-on: [self-hosted, linux, arm64]
timeout-minutes: 155
steps:
- name: Checkout
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Isolate toolchain dirs
run: |
rm -rf "$RUNNER_TEMP/rustup" "$RUNNER_TEMP/cargo"
echo "HOME=$RUNNER_TEMP" >> "$GITHUB_ENV"
echo "CARGO_HOME=$RUNNER_TEMP/cargo" >> "$GITHUB_ENV"
echo "RUSTUP_HOME=$RUNNER_TEMP/rustup" >> "$GITHUB_ENV"
echo "MAKEFLAGS=" >> "$GITHUB_ENV"
echo "CARGO_BUILD_JOBS=6" >> "$GITHUB_ENV"
if sccache --show-stats >/dev/null 2>&1; then
echo "RUSTC_WRAPPER=sccache" >> "$GITHUB_ENV"
echo "CARGO_INCREMENTAL=0" >> "$GITHUB_ENV"
fi
- name: Setup Rust
uses: actions-rust-lang/setup-rust-toolchain@v1.16.0
with:
components: rustfmt
cache: false
rustflags: ''
env:
HOME: ${{ runner.temp }}
- name: Pin rustup default (isolated RUSTUP_HOME has no default toolchain)
run: rustup default "$(rustup show active-toolchain | awk '{print $1; exit}')"
- name: Cache Cargo
uses: actions/cache@v5
with:
path: |
${{ runner.temp }}/cargo/registry/index/
${{ runner.temp }}/cargo/registry/cache/
${{ runner.temp }}/cargo/git/db/
target/
key: cargo-ci-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/Cargo.lock', 'rust-toolchain.toml') }}
restore-keys: |
cargo-ci-${{ runner.os }}-${{ runner.arch }}-
- name: Build release bins (claim_executor + gunbc)
run: |
ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
set -o pipefail
BUILD_LOG=$(mktemp)
if ! ("$CARGO_HOME/bin/cargo" build -p v1-compiler --release --features text_lookup_work_counter --bins) 2>&1 | tee "$BUILD_LOG"; then
if grep -qiE 'Resource temporarily unavailable|failed to spawn|sccache: encountered fatal error|(exit status: 254)|sccache: error: failed to execute compile' "$BUILD_LOG"; then
echo "::warning::cargo/sccache EAGAIN under fleet pressure; cold retry CARGO_BUILD_JOBS=1 (keep sccache)"
RETRY_LOG=$(mktemp)
if ! ( CARGO_BUILD_JOBS=1 "$CARGO_HOME/bin/cargo" build -p v1-compiler --release --features text_lookup_work_counter --bins ) 2>&1 | tee "$RETRY_LOG"; then
if grep -qiE 'Resource temporarily unavailable|failed to spawn|sccache: encountered fatal error|(exit status: 254)|sccache: error: failed to execute compile' "$RETRY_LOG"; then
echo "::warning::cargo/sccache still failing; retry without RUSTC_WRAPPER"
env -u RUSTC_WRAPPER CARGO_BUILD_JOBS=1 "$CARGO_HOME/bin/cargo" build -p v1-compiler --release --features text_lookup_work_counter --bins || exit 1
else
exit 1
fi
fi
rm -f "$RETRY_LOG"
else
exit 1
fi
fi
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
- name: affected-set falsifier (predict-only cold run)
run: |
ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
"$ROOT/target/release/claim_executor" --source-root dag --source-root src/v2 --plan-entry src/v2/workflow/ci_floor_plan.dag --plan-function gunbc_falsifier_batches
env:
GUNBC_CI_DIFF_BASE: HEAD~20
GUNBC_CI_DIFF_HEAD: HEAD
timeout-minutes: 120
11 changes: 8 additions & 3 deletions dag/extdeps/languages/yaml/gha_workflow.dag
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import extdeps.languages.yaml.types {
yaml_string, yaml_int, yaml_bool, yaml_mapping, yaml_sequence, kv,
empty_yaml_values
}
import extdeps.cron.schedule_model { render_cron_schedule }
import extdeps.github.actions {
Workflow, Job, Step, RunStep, UsesStep, ActionRef,
WorkflowTrigger, Push, PullRequest, WorkflowDispatch,
WorkflowTrigger, Push, PullRequest, WorkflowDispatch, Schedule,
PullRequestActivity, Opened, Synchronize, Reopened, ReadyForReview, Closed,
WorkflowPermissions, PermissionLevel, PermRead, PermWrite, PermNone,
ConcurrencySpec, ConcurrencyScalar, ConcurrencyMappingQueueMax, ConcurrencyMappingQueueNotMax,
Expand All @@ -26,6 +27,8 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority {
}
}

data gha_schedule_trigger_note: String = "schedule renders as the GHA-required list-of-mappings - a schedule key holding a sequence of cron mappings, each cron value a 5-field POSIX string (authority above). Formerly a payload-dropping stub (bare schedule: key — invalid GHA syntax); first live constructor is the affected-set falsifier workflow. GHA quirks vs plain crontab, per the cited syntax authority: cron strings are evaluated in UTC only, and the shortest supported interval is 5 minutes."

fn permission_level_yaml(level: PermissionLevel) -> YamlValue {
match level {
PermRead => yaml_string(s: "read")
Expand Down Expand Up @@ -98,8 +101,10 @@ fn workflow_trigger_entry(trigger: WorkflowTrigger) -> YamlKeyValue {
kv(key: "branches", value: string_list_flow(items: bs)),
kv(key: "types", value: pr_activities_flow(types: ts))
]))
Schedule { cron: _ } =>
kv(key: "schedule", value: YamlNull)
Schedule { cron: c } =>
kv(key: "schedule", value: yaml_sequence(elements: [
yaml_mapping(entries: [kv(key: "cron", value: yaml_string(s: render_cron_schedule(s: c)))])
]))
WorkflowCall { inputs: _ } =>
kv(key: "workflow_call", value: YamlNull)
}
Expand Down
2 changes: 1 addition & 1 deletion dag/gunbc/accelerator_demo_plan.dag
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ fn demo_plan_fused_op_count(plan: RealizationPlan<Nano>) -> Int {
Present { value: runnable } => match runnable {
RunnableKernelWorkload { fused_op_count: count } => count
RunnableSingleClaim { entry: _, function: _, profile: _ } => 0
RunnableDiscoveryBatch { source_roots: _, scan_dirs: _, explicit_entries: _, skip_unaffected_node_frontier: _, exclude_substrings: _, discovery_scope_dirs: _, spawn_width_cap: _, profile: _ } => 0
RunnableDiscoveryBatch { source_roots: _, scan_dirs: _, explicit_entries: _, node_frontier_selection: _, exclude_substrings: _, discovery_scope_dirs: _, spawn_width_cap: _, profile: _ } => 0
}
}
}
Expand Down
112 changes: 112 additions & 0 deletions dag/gunbc/falsifier_workflow.dag
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
module gunbc.falsifier_workflow

import extdeps.languages.yaml.types { yaml_string, kv }
import extdeps.cron.schedule_model { CronSchedule, Wildcard, Exact }
import extdeps.github.actions {
Workflow, Job, Step, RunStep,
WorkflowTrigger, Schedule, WorkflowDispatch,
WorkflowPermissions, PermRead
}
import gunbc.ci_workflow {
ci_prelude_steps, ci_release_build_step,
gunbc_ci_release_build_step_timeout_minutes, gunbc_ci_prelude_allowance_minutes
}
import gunbc.runner_spec_from_offer { gunbc_ci_runner_spec }
import gunbc.ci_spec {
claim_executor_bin_shell, ci_repo_root_shell
}
import gunbc.ci_layer_roots { witness_layer_roots, witness_layer_source_flags }
import extdeps.languages.yaml.emit { serialize_yaml }
import extdeps.languages.yaml.gha_workflow { project_workflow_to_yaml }

data falsifier_workflow_note: String = "Affected-set differential falsifier cadence (signed design: docs/plans/affected-set-differential-falsifier.md; signs 2026-07-05: N=8 windows, counted re-arm, roster authority = the existing host-scaffold/live-tree disposition facts). Nightly cold run of the discovery corpus with SelectionPredictOnly: would-skip predictions are recorded per row, every row runs, and a predicted-unaffected row that runs red is a counted DIVERGENCE attributing a missing selection edge (the red also fails the batch through the normal failure channel). An observation refusal aborts typed and is NOT a divergence. Dissolution: 8 consecutive zero-divergence windows retire this workflow (delete it; the receipt is the Actions run history); a later divergence re-arms another 8-window cycle, itself counted. Cost is bounded per window - one cold run nightly, never multiplied into PRs."

data falsifier_window_base_note: String = "GUNBC_CI_DIFF_BASE=HEAD~20 gives the nightly run a declared window so predictions have non-trivial structure (main-vs-main is empty and would predict skip-everything, which only falsifies rot in assumed-green subjects). 20 is a declared window breadth, not a smuggled threshold: the diff is exact for whatever the window contains, and a shorter history degenerates to the empty-diff posture honestly. The ci checkout is fetch-depth 0, so the window is available."

data gunbc_falsifier_step_timeout_minutes: Int = 120

data falsifier_plan_function: String = "gunbc_falsifier_batches"

fn falsifier_invoke() -> String {
concat(
concat("ROOT=", concat(ci_repo_root_shell(), "\n")),
concat(
concat(claim_executor_bin_shell(), witness_layer_source_flags(roots: witness_layer_roots)),
concat(" --plan-entry src/v2/workflow/ci_floor_plan.dag --plan-function ", falsifier_plan_function)
)
)
}

fn falsifier_step() -> Step {
RunStep {
name: Present { value: "affected-set falsifier (predict-only cold run)" },
id: none,
run: falsifier_invoke(),
shell: none,
env: Present {
value: [
kv(key: "GUNBC_CI_DIFF_BASE", value: yaml_string(s: "HEAD~20")),
kv(key: "GUNBC_CI_DIFF_HEAD", value: yaml_string(s: "HEAD"))
]
},
working_directory: none,
if_condition: none,
continue_on_error: none,
timeout_minutes: Present { value: gunbc_falsifier_step_timeout_minutes }
}
}

fn gunbc_falsifier_job_backstop_timeout_minutes() -> Int {
gunbc_ci_release_build_step_timeout_minutes + gunbc_falsifier_step_timeout_minutes + gunbc_ci_prelude_allowance_minutes
}

fn falsifier_job() -> Job {
Job {
id: "falsifier",
name: none,
runner: gunbc_ci_runner_spec(),
steps: concat(ci_prelude_steps(), [ci_release_build_step(), falsifier_step()]),
needs: [],
env: none,
outputs: none,
if_condition: none,
strategy: none,
timeout_minutes: Present { value: gunbc_falsifier_job_backstop_timeout_minutes() },
continue_on_error: none,
concurrency: none
}
}

data falsifier_nightly_cron: CronSchedule = CronSchedule {
minute: Exact { value: 0 },
hour: Exact { value: 7 },
day_of_month: Wildcard,
month: Wildcard,
day_of_week: Wildcard
}

data falsifier_workflow: Workflow = {
name: "affected-set-falsifier",
on: [
WorkflowDispatch { inputs: [] },
Schedule { cron: falsifier_nightly_cron }
],
concurrency: none,
env: Present {
value: [kv(key: "CARGO_TERM_COLOR", value: yaml_string(s: "always"))]
},
permissions: Present {
value: WorkflowPermissions {
contents: Present { value: PermRead },
pull_requests: none,
issues: none,
actions: none,
id_token: none
}
},
jobs: [falsifier_job()]
}

fn expected_falsifier_yml() -> String {
serialize_yaml(v: project_workflow_to_yaml(workflow: falsifier_workflow))
}
6 changes: 5 additions & 1 deletion dag/gunbc/generated_artifact.dag
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import gunbc.plan_registry { all_plans }

type GeneratedArtifact
= CiYamlArtifact
| FalsifierYamlArtifact
| GitignoreArtifact
| RoadmapArtifact
| DesignArtifact
Expand All @@ -20,7 +21,7 @@ type GeneratedArtifact
data generated_artifact_registry: List<GeneratedArtifact> = concat(
concat(
concat(
[CiYamlArtifact, GitignoreArtifact, RoadmapArtifact, DesignArtifact, GithooksPrePushArtifact, RunnerDeployArtifact, FleetConvergeArtifact],
[CiYamlArtifact, FalsifierYamlArtifact, GitignoreArtifact, RoadmapArtifact, DesignArtifact, GithooksPrePushArtifact, RunnerDeployArtifact, FleetConvergeArtifact],
map(fleet_autoinstall_specs, s => AutoinstallUserDataArtifact { spec: s })
),
map(fleet_install_server_specs, s => ProxyDhcpDnsmasqArtifact { spec: s })
Expand All @@ -41,6 +42,7 @@ type CommitPolicy
fn artifact_path(a: GeneratedArtifact) -> String {
match a {
CiYamlArtifact => ".github/workflows/ci.yml"
FalsifierYamlArtifact => ".github/workflows/falsifier.yml"
GitignoreArtifact => ".gitignore"
RoadmapArtifact => "ROADMAP.md"
DesignArtifact => "DESIGN.md"
Expand All @@ -58,6 +60,7 @@ fn artifact_commit_policy(a: GeneratedArtifact) -> CommitPolicy {
GitignoreArtifact => CommitRequired { consumer: GitProtocol }
GithooksPrePushArtifact => CommitRequired { consumer: GitProtocol }
CiYamlArtifact => CommitRequired { consumer: GithubActionsWorkflow }
FalsifierYamlArtifact => CommitRequired { consumer: GithubActionsWorkflow }
RoadmapArtifact => CommitRequired { consumer: ProjectDocumentation }
DesignArtifact => CommitRequired { consumer: ProjectDocumentation }
PlanArtifact { plan: _ } => CommitRequired { consumer: ProjectDocumentation }
Expand All @@ -82,6 +85,7 @@ fn committed_generated_artifacts() -> List<GeneratedArtifact> {
fn artifact_eq(a: GeneratedArtifact, b: GeneratedArtifact) -> Bool {
match a {
CiYamlArtifact => match b { CiYamlArtifact => true _ => false }
FalsifierYamlArtifact => match b { FalsifierYamlArtifact => true _ => false }
GitignoreArtifact => match b { GitignoreArtifact => true _ => false }
RoadmapArtifact => match b { RoadmapArtifact => true _ => false }
DesignArtifact => match b { DesignArtifact => true _ => false }
Expand Down
5 changes: 4 additions & 1 deletion dag/gunbc/generated_artifact_emit.dag
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ module gunbc.generated_artifact_emit

import gunbc.generated_artifact {
GeneratedArtifact,
CiYamlArtifact, GitignoreArtifact, RoadmapArtifact, DesignArtifact,
CiYamlArtifact, FalsifierYamlArtifact, GitignoreArtifact, RoadmapArtifact, DesignArtifact,
RunnerDeployArtifact, FleetConvergeArtifact, GithooksPrePushArtifact,
AutoinstallUserDataArtifact, ProxyDhcpDnsmasqArtifact, PlanArtifact,
artifact_path
}
import gunbc.ci_yaml_emit { expected_ci_yml }
import gunbc.falsifier_workflow { expected_falsifier_yml }
import gunbc.ci_yaml_validate { ci_yml_parses }
import gunbc.gitignore_emit { expected_gitignore }
import gunbc.roadmap_authority { expected_roadmap_md }
Expand All @@ -23,6 +24,7 @@ import gunbc.plan { expected_plan_md }
fn artifact_generate(a: GeneratedArtifact) -> String {
match a {
CiYamlArtifact => expected_ci_yml()
FalsifierYamlArtifact => expected_falsifier_yml()
GitignoreArtifact => expected_gitignore()
RoadmapArtifact => expected_roadmap_md()
DesignArtifact => expected_design_md()
Expand All @@ -38,6 +40,7 @@ fn artifact_generate(a: GeneratedArtifact) -> String {
fn artifact_extra_valid(a: GeneratedArtifact) -> Bool {
match a {
CiYamlArtifact => ci_yml_parses(path: artifact_path(a: a))
FalsifierYamlArtifact => ci_yml_parses(path: artifact_path(a: a))
GitignoreArtifact => true
RoadmapArtifact => true
DesignArtifact => true
Expand Down
4 changes: 2 additions & 2 deletions dag/gunbc/gitignore_authority.dag
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import gunbc.gitignore_model {
OpenClawControlDir, OpenClawAgentsFile, OpenClawHeartbeatFile, OpenClawIdentityFile,
OpenClawSoulFile, OpenClawToolsFile, OpenClawUserFile, OpenClawWorkboardFile,
OpenClawScriptsDir, V2InspectFile, V2InspectErrorsFile, GithubCLICacheDir,
PythonLocalDevScriptFile, PythonBytecodeCacheDir, PythonCompiledBytecode,
PythonLocalDevScriptFile, PythonAuditScriptAllowlisted, PythonBytecodeCacheDir, PythonCompiledBytecode,
ClaimMapDir, ScratchProbeFile,
GunbcPlanningDir, ScriptsFixturesDir
}
Expand Down Expand Up @@ -122,7 +122,7 @@ data gitignore_authority: List<IgnoreGroup> = [
},
IgnoreGroup {
producer: Derivable { kind: PythonLocalDevScript },
artifacts: [PythonLocalDevScriptFile]
artifacts: [PythonLocalDevScriptFile, PythonAuditScriptAllowlisted]
},
IgnoreGroup {
producer: Cited { kind: CPythonInterpreter, upstream: "python.org/peps/pep-3147" },
Expand Down
3 changes: 2 additions & 1 deletion dag/gunbc/gitignore_emit.dag
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import gunbc.gitignore_model {
OpenClawControlDir, OpenClawAgentsFile, OpenClawHeartbeatFile, OpenClawIdentityFile,
OpenClawSoulFile, OpenClawToolsFile, OpenClawUserFile, OpenClawWorkboardFile,
OpenClawScriptsDir, V2InspectFile, V2InspectErrorsFile, GithubCLICacheDir,
PythonLocalDevScriptFile, PythonBytecodeCacheDir, PythonCompiledBytecode,
PythonLocalDevScriptFile, PythonAuditScriptAllowlisted, PythonBytecodeCacheDir, PythonCompiledBytecode,
ClaimMapDir, ScratchProbeFile,
GunbcPlanningDir, ScriptsFixturesDir
}
Expand Down Expand Up @@ -84,6 +84,7 @@ fn artifact_pattern(a: IgnoreArtifact) -> String {
V2InspectErrorsFile => ".v2-inspect-errors.txt"
GithubCLICacheDir => ".gh-cache/"
PythonLocalDevScriptFile => "*.py"
PythonAuditScriptAllowlisted => "!docs/plans/witness-subject-execution-audit.py"
PythonBytecodeCacheDir => "__pycache__/"
PythonCompiledBytecode => "*.pyc"
ClaimMapDir => ".claim-map/"
Expand Down
1 change: 1 addition & 0 deletions dag/gunbc/gitignore_model.dag
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ type IgnoreArtifact
| V2InspectErrorsFile
| GithubCLICacheDir
| PythonLocalDevScriptFile
| PythonAuditScriptAllowlisted
| PythonBytecodeCacheDir
| PythonCompiledBytecode
| ClaimMapDir
Expand Down
Loading
Loading