Espalier std lib - #1
Conversation
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: Codex <codex@openai.com>
The repository is private and GitHub Actions is gone, so ci.yml either executes on this machine or it does not execute at all. This reads the workflow rather than restating it -- jobs, `needs` order, `if` conditions, matrices and steps all come from the YAML, so a job added to CI is a job this runs. Each is pinned to two CPUs, which is what a hosted runner has, and they run in parallel up to `--jobs`. What it does not reproduce is the runner image. Steps that provision one are skipped, because the toolchains are already installed and `sudo` here would want a password. Steps that talk to GitHub -- SARIF upload, Codecov, Bencher -- are no-ops because there is nothing to talk to. Caches report a hit when the path they name is already populated, which is what the install-unless-cached steps actually ask. Artifacts are real, so a job that consumes another's binaries gets them. tools/ci_local.rb --list tools/ci_local.rb --job sorbet tools/ci_local.rb --jobs 8 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uf8MndFjJ9y6eUZzSySSwa
A hosted runner gets a fresh disk per job; here every job shares one. Each cargo-llvm-cov job builds its own multi-gigabyte target tree, and six of them in parallel filled 154GB -- which surfaces as ""rustc-LLVM ERROR: IO failure on output stream"" and a linker bus error, neither of which reads as "out of disk". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uf8MndFjJ9y6eUZzSySSwa
`srb tc` segfaults on this repository as soon as a developer has fetched stdlib sources: `.cache/` holds 7,837 Ruby files -- 776MB of CRuby 3.2.3 and Kotlin stdlib source -- and `--dir .` walked all of it. Sorbet dies on the standard library's own source, with `Segmentation fault` and nothing else to go on. CI never saw it because a fresh checkout has no `.cache/`, which makes this exactly the kind of failure that only ever happens to a person. `.cache/` was not gitignored either, so it was one `git add -A` away from being committed. Nor were `.ci-local/`, `kcov-bin/`, or the `nil-kill-golden*` and `nil-kill-missing-evidence*` directories that crashed spec runs leave in the repository root -- 34 of them had accumulated. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uf8MndFjJ9y6eUZzSySSwa
A hosted runner checks out fresh, so SimpleCov starts with nothing to merge. Here every job shares one working tree, and SimpleCov merges whatever an earlier job left in coverage/ -- which is how the Test Miser step that tracks one directory came to report 49% line coverage over 75,000 lines of the whole repository and fail its 95% gate. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uf8MndFjJ9y6eUZzSySSwa
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
| when /\ACollections\/DictionaryEntry#/ | ||
| "System.Runtime" |
| unless File.file?(scip_java) && Digest::SHA256.file(scip_java).hexdigest == SCIP_JAVA_SHA256 | ||
| temporary = "#{scip_java}.download-#{Process.pid}" | ||
| url = "https://github.com/scip-code/scip-java/releases/download/v#{SCIP_JAVA_VERSION}/scip-java-v#{SCIP_JAVA_VERSION}" | ||
| URI.open(url) { |input| File.open(temporary, "wb") { |file| IO.copy_stream(input, file) } } |
| end | ||
|
|
||
| temporary = "#{destination}.download-#{Process.pid}" | ||
| URI.open(url) { |input| File.open(temporary, "wb") { |output| IO.copy_stream(input, output) } } |
Diff Coverage BucketsDiff base:
Src Ruby Visibility BreakdownScope: Files: 213 Counts are nonblank, non-comment Ruby source lines. Protected methods are grouped into
Zig Special Coverage AlertsNo added production Zig lines require missing Loom/VOPR/wait-loop coverage alerts. |
`FactMine Rust coverage` failed on `ruby_safe_navigation_nil_kill.rb: oracle mismatch`, and the diff was one field: `domain_id` held `/home/yahn/easy-vm/...` where the runner produced `/home/runner/work/clear/clear/...`. The oracle had been regenerated on a machine and carried that machine's home directory into the repository. `normalize_paths` allow-listed `path`, `file`, `id` and `key`, so `domain_id` and `symbol_owner` went through untouched, as did bare strings inside `requirements` and `blockers` arrays -- including a prose blocker, "unknown return expression ARGS at <path>:13", where the root sits mid-sentence rather than at the start. It now normalizes every string carrying the checkout root, whatever holds it and wherever it appears. A string with the root in it is machine-specific; which key it hangs off is not the question worth asking. The oracle guard in the test follows the same rule, so a regenerated oracle cannot smuggle one back in. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uf8MndFjJ9y6eUZzSySSwa
…tory `nil-kill gem specs` failed on the golden shard everywhere but the machine that recorded it: the fixture is a real collect, so every path in it is absolute, and the spec asked FactMine to shape it against `NilKill::ROOT` -- this checkout's root, not the one the shard was recorded under. On a runner nothing matched, and the shaping produced zero anchor executions where 3,782 were expected. The fixture is re-rooted to `/golden/easy-vm`, which the spec passes explicitly. No home directory is committed, and the shard shapes the same way in every checkout. Two things stayed machine-specific after that and should not have been pinned at all: the package name follows the root's basename, so the synthetic root keeps it; and the environment claim digesting the checkout's own Gemfile.lock says nothing about the shaping and would have failed the golden shard on any dependency bump. The buildable-corpus job also needs the collector extension it traces with -- the same step the nil-kill specs already grew. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uf8MndFjJ9y6eUZzSySSwa
Three Espalier tests named `target/debug/fact-mine-rust` outright. CI builds `--release`, so all three errored with `Errno::ENOENT` rather than running -- four errors in `Ruby gems coverage`. They now resolve it the way every other caller does, through `Espalier::StaticEvidence::FACT_MINE_RUST_BINARY`, which honours `FACT_MINE_RUST_BINARY` and otherwise prefers release over debug. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uf8MndFjJ9y6eUZzSySSwa
All five benchmark-leak shards failed with `invalid value '' for '--token <TOKEN>'`. Re-creating the repository dropped its secrets, so `BENCHER_API_TOKEN` is empty. The benchmark still runs and still fails the job on a leak; this step only publishes the numbers afterwards. Without a token there is nowhere to publish them, and failing the gate on an absent credential says nothing about the code. It skips with a message instead. Setting the secret restores the upload with no further change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uf8MndFjJ9y6eUZzSySSwa
There was a problem hiding this comment.
Boobytrap found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.
Decomplex, Espalier and Nil-Kill SARIF all exited 124 -- `timeout` -- after scoping to 335 changed source files. The analyzers are not stuck; the branch is 403 commits ahead of master, and a 15-minute budget was set for a PR of ordinary size. Raised to 40 minutes, with the job ceilings above it so the step reports the timeout rather than the job being killed around it. Worth revisiting if it recurs on a small PR: >2.7s per file is the number to look at, not the budget. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uf8MndFjJ9y6eUZzSySSwa
Reverts the skip-when-absent guard. The secret was missing because the repository had just been re-created; it is configured now, so the gate should fail loudly if the upload cannot happen rather than pass quietly without publishing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uf8MndFjJ9y6eUZzSySSwa
|
| Project | CLEAR |
| Branch | Espalier-STDLib |
| Testbed | ubuntu-latest |
⚠️ WARNING: No Threshold found!Without a Threshold, no Alerts will ever be generated.
Click here to create a new Threshold
For more information, see the Threshold documentation.
To only post results if a Threshold exists, set the--ci-only-thresholdsflag.
Click to view all benchmark results
| Benchmark | leak-build-ms | Measure (units) x 1e3 | leak-count | Measure (units) | leak-run-ms | Measure (units) |
|---|---|---|---|---|---|---|
| benchmarks/concurrent/01_socket_throughput/bench | 📈 view plot | 6.13 units x 1e3 | 📈 view plot | 0.00 units | 📈 view plot | 7.52 units |
| benchmarks/concurrent/06_dynamic_spawn/bench | 📈 view plot | 6.02 units x 1e3 | 📈 view plot | 0.00 units | 📈 view plot | 35.85 units |
| benchmarks/concurrent/11_parallel_aggregation/bench | 📈 view plot | 6.20 units x 1e3 | 📈 view plot | 0.00 units | 📈 view plot | 19.30 units |
| benchmarks/concurrent/18_atomic_counter/bench | 📈 view plot | 6.09 units x 1e3 | 📈 view plot | 0.00 units | 📈 view plot | 5.81 units |
| benchmarks/inter-clear/04_concurrent_mvcc_fat_struct/bench | 📈 view plot | 6.43 units x 1e3 | 📈 view plot | 0.00 units | 📈 view plot | 167.73 units |
| benchmarks/sequential/03_alloc_throughput/bench | 📈 view plot | 5.83 units x 1e3 | 📈 view plot | 0.00 units | 📈 view plot | 7.70 units |
| benchmarks/sequential/08_sort/bench | 📈 view plot | 5.97 units x 1e3 | 📈 view plot | 0.00 units | 📈 view plot | 5.19 units |
| benchmarks/sequential/13_soa_layout/bench | 📈 view plot | 5.98 units x 1e3 | 📈 view plot | 0.00 units | 📈 view plot | 744.11 units |
| benchmarks/server/03_pathological/server | 📈 view plot | 6.16 units x 1e3 | 📈 view plot | 0.00 units | 📈 view plot | 1,002.71 units |
Three jobs compiled overlapping sets of the same crates on three fresh runners: `sarif-rust-binaries` built fact-mine, decomplex and sql-cov; `ruby-gems-coverage` built fact-mine, nil-kill, decomplex and gigasail; `fact-mine-rust-coverage` built the same four again beside its instrumented build. `sarif-rust-binaries` now builds all five and publishes them, and the two coverage jobs download that artifact instead. Six `cargo build --release` invocations of already-built crates go. What does not move is FactMine's `cargo llvm-cov` build. Coverage comes from that instrumented binary; there is nothing to share. `ruby-gems-coverage` copies the downloaded binaries to the `target/release` paths its tests resolve, so no test needed changing. And `sarif-rust-binaries` is no longer restricted to same-repo pull requests -- the coverage jobs consume it and they run on pushes. The SARIF jobs keep that restriction, which is about where a SARIF upload may come from, not about compiling anything. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uf8MndFjJ9y6eUZzSySSwa
The gem SARIF analyzers scanned giga-ui's browser bundle as project JavaScript: a hand-written `app.js` and a content-hashed, minified diff viewer that is build output. Neither is code anyone writes or reviews here. `assets` joins the ignored path components. Every supported-extension file under an `assets/` directory in this repository is of that kind -- the rest are SimpleCov's and RubyCritic's own report JavaScript, already excluded by `coverage` and `vendor`, so this newly affects only giga-ui. The UI's actual source is not in one of those directories and stays in scope: `gems/gigasail/ui/src/*.tsx` is hand-written React, and `giga-ui/src/ui/ui.rs` is 12,000 lines of hand-written axum and askama. Excluding either would drop real code, which is the opposite of the point. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uf8MndFjJ9y6eUZzSySSwa
There was a problem hiding this comment.
Decomplex found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.
There was a problem hiding this comment.
Nil-Kill found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.
There was a problem hiding this comment.
Espalier found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.
…-analysis
Two failures from the last run, and the first is mine.
`FactMine Rust coverage` got the shared binaries but only through the
environment, and several tests resolve `target/release` directly:
SlopCop::Classifier cannot find executable decomplex-rust at
.../gems/decomplex/target/release/decomplex-rust
Required integration test binary not found: .../fact-mine-rust
It now installs them there, as `ruby-gems-coverage` already did.
`Architecture SARIF` was killed at its 45-minute job ceiling and
`SlopCop constraint coverage SARIF` at its 20-minute step budget --
`timeout`'s exit 124, the same overrun the other three SARIF jobs hit on
a branch this size. Their budgets go up with them, and every step budget
is now under its job ceiling so an overrun reports as a step timeout
rather than the job being killed around it. `boobytrap-sarif` and
`slopcop-sarif` had a 60-minute step under a 25-minute ceiling already.
Still a budget, not a fix: >2.7s per file over 335 files is the number
to look at if these recur on a small PR.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uf8MndFjJ9y6eUZzSySSwa
The architecture SARIF job took over 30 minutes. It was not the graph work: a single fact-mine syntax-facts call on giga-ui's bundled diff viewer ran 38 minutes at 100% CPU and had not finished. The file is 222KB across 61 lines, one of them 122,875 characters, and tree-sitter degrades badly on it. Its hand-written neighbour app.js parses in 0.19s. `assets` holds what a program serves rather than what it is, which is why tools/generate_lint_sarif.rb already ignores it elsewhere; the espalier corpus never got the same treatment. Excluding it drops two files from a 746-file corpus and reports the same cycles. cycle_report 30m+ -> 191s, reach_through_report likewise, both pinned to two cores to match the runner. Co-authored-by: Codex <codex@openai.com>
parse_files already fanned out across workers, but the projection that follows it ran as a serial iter().map(). Projection is the bulk of the work: it derives the per-function dataflow (liveness, dominators, reaching definitions, def-use, path conditions), which is why 120 Ruby files cost 12s while a 2.2MB but structurally empty get-pip.py costs 0.5s. The serial map capped a whole-corpus run at ~1.5 cores regardless of how many were available. map_ordered preserves document order, so output is unchanged: the emitted JSON is byte-identical to the serial binary's on the same 120-file corpus, on both 2 cores and 32. 2 cores: 14.8s @ 126% -> 10.7s @ 178% 32 cores: 12.2s @ 157% -> 5.3s @ 362% call-resolution already reaches 164%/309% on the same corpus and is left alone. Co-authored-by: Codex <codex@openai.com>
A full projection of this repository is ~1.08 GB of JSON across 40 keys per document. The architecture reports read five of them - 8% - and discard the dataflow bulk (clone_candidates alone is 32%, liveness 9%). Everything else was serialized here and JSON.parse'd back in Ruby only to be dropped, which was most of that stage's runtime. --fields keeps only the named top-level keys. Selection happens after the document is built, so the analysis is unchanged and the retained values are byte-identical to a full projection's; only what crosses the pipe shrinks. Omitting the flag emits everything, as before. Whole corpus on two cores, 744 files: syntax-facts 93.4s -> 64.4s, and the per-batch payload 151 MB -> 13.1 MB. Both architecture SARIFs are unchanged. Note this does not yet SKIP the discarded work: the keys are still built, then dropped. Making construction lazy is a further change. Co-authored-by: Codex <codex@openai.com>
cycle_report.rb and reach_through_report.rb were introduced as "WIP anti-pattern experiment tools" (beb2fe8) and never left that state. Each costs a whole-corpus FactMine projection; together they were the entire runtime of the Architecture SARIF job. reach_through also cannot model package-scoped languages. It derives owners per file, so two files in one Go package read as a cross-module private call - Go has no private, lowercase is package-private and same-package access is legal. Its 81 self-quarantined "suspect" findings are that bug, and suspects were never uploaded to SARIF anyway. change_coupling.rb stays: it runs in 0.83s and does not use FactMine, so the job no longer needs the shared Rust binaries at all. The tools and their tests stay in the tree for whenever they earn the cost. Job budget 75m -> 15m. Co-authored-by: Codex <codex@openai.com>
| @@ -0,0 +1,524 @@ | |||
| //! The top-level diff summary ("funnel"): a language-aware breakdown of the | |||
| @@ -0,0 +1,524 @@ | |||
| //! The top-level diff summary ("funnel"): a language-aware breakdown of the | |||
| @@ -0,0 +1,630 @@ | |||
| //! `gigasail diff` — an interactive terminal UI for reviewing changes by risk. | |||
| @@ -0,0 +1,630 @@ | |||
| //! `gigasail diff` — an interactive terminal UI for reviewing changes by risk. | |||
| @@ -0,0 +1,1282 @@ | |||
| // Hot observation loop for the Ruby runtime-SCIP collector. | |||
| @@ -0,0 +1,1282 @@ | |||
| // Hot observation loop for the Ruby runtime-SCIP collector. | |||
The SlopCop constraint SARIF job hit its 60-minute timeout. Same root cause as the architecture job: giga-ui's content-hashed, minified diff viewer is 222KB across 61 lines, one of them 122,875 characters, and tree-sitter takes tens of minutes on it. SlopCop has its own file discovery, so the espalier-side fix did not reach it, and it scanned the bundle three separate times. The exclusion goes in LanguageProvider rather than each of the thirteen providers' EXCLUDED_DIRS: a served bundle is not a language-specific concern. It matches path segments, so lib/assets_helper.rb still scans. Whole run against origin/master: 60m timeout -> 26s, exit 0, 83 results across 32 rules, no asset paths among them. Co-authored-by: Codex <codex@openai.com>
There was a problem hiding this comment.
SlopCop found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.
No description provided.