Skip to content

feat(analysis): wire calibration in (#48); fix both red CI checks - #107

Merged
hyperpolymath merged 1 commit into
mainfrom
arena/01a0dad6-oikosbot
Sep 25, 2026
Merged

hyperpolymath merged 1 commit into
mainfrom
arena/01a0dad6-oikosbot

Conversation

@arena-ai-coding-agent

Copy link
Copy Markdown
Contributor

Closes the two red checks on main and lands the blocking per-file debt behind one of them (issue #48).

Please read "What this change cannot prove" before merging.

1. Hypatia — the one high/critical finding, diagnosed and fixed

Hypatia Neurosymbolic Analysis has failed on every run since 2026-09-15 with exactly one high/critical finding. It is research_extensions RE008 (critical): .github/workflows/dependabot-automerge.yml gated auto-merge on

if: github.actor == 'dependabot[bot]' && github.event.pull_request.user.login == 'dependabot[bot]'

github.actor is the run-triggering user, which a fork/branch/rerun event can set without the PR being Dependabot's. RE008 matches it with a raw-text regex over .github/workflows/* (no YAML parse, no comment filtering), which is why the explanatory comment in this change describes the pattern instead of quoting it — quoting it would re-arm the finding.

Fix: drop the github.actor == conjunct, keep the PR-author gate. I re-ran RE008's own regex over all 15 workflows after the edit: zero matches.

2. Publish Image — root cause confirmed

Build and push exited 101 in 21s. tree-sitter 0.27.0 declares rust-version = "1.90" / edition = "2024"; the Containerfile builder was rust:1.88-slim. CI passed because ubuntu-latest ships a newer rustc — the container is the only place the floor is enforced. Builder is now the rolling rust:1-slim (arrow-rs 59.3.0 needs only 1.88, so tree-sitter is the binding constraint).

3. #48 — calibration wired in

  • calibration::operation_for_pattern maps a detected pattern onto the OperationKind that best explains its cost: nested-loops→Sort, busy-wait→MathCompute, string-concat-in-loop→StringOp, clone-in-loop→Allocation, unbuffered-io→FileIO, large-allocation→Allocation. redundant-allocation is deliberately unmapped (multiplier 1.2) so a marginal finding cannot inherit calibrated confidence.
  • estimate_operation() prices recognised units; its ResourceRange carries min/typical/max and the confidence that row has earned — Calibrated for HashLookup/Sort/Allocation/MathCompute, Estimated for the host-dependent FileIO/StringOp/NetworkCall, Unknown for Generic.
  • Unrecognised code keeps the naive complexity × constant path, labelled Estimated, with no band claimed.
  • ResourceRange moves to oikosbot-metrics and rides on AnalysisResult (#[serde(default, skip_serializing_if = "Option::is_none")] — additive, old JSON still loads). SARIF emits properties.resource_range.
  • Deleted: calibrated_estimate() (the unwired, duplicate multiplier table) and standard_objectives() (dead code).

Falsifier tests

  • calibration: the per-kind confidence ladder, min ≤ typical ≤ max on all four axes for every row, and the pattern→kind mapping including the deliberate hole.
  • analyzer: a recognised pattern earns Calibrated + a band; unrecognised code stays Estimated with no band; the calibrated path actually changes the number.
  • crates/oikosbot-cli/tests/check_gate.rs (new, runs the real binary): an undocumented calibrated regression exits 1; the same regression without --check exits 0; a documented Pareto-Trade-off: is accepted; a heuristic regression refuses to block and says so.

Before/after (derived by reasoning, NOT measured — see below)

A depth-3 nested-loop unit of ~63 AST nodes:

energy eco score confidence
before (naive) ~6.3 J (0.1 J/node) ~78 Estimated
after (calibrated Sort) ~0.019 J 100 (clamped) Calibrated

Every resource figure and every downstream score moves with it.

What this change cannot prove

  • There is no Rust toolchain in the authoring environment. cargo fmt --check, cargo test --workspace --locked, cargo clippy and the container build have not been run. This PR's CI is the first compile. The changes were written to be rustfmt-canonical (100-col, existing brace style) but that is a claim, not a result.
  • The before/after table above is reasoned, not measured. No fixture was executed.
  • The eco-score scale is now mismatched with the estimator. EcoScore is 100 − 10·ln(E), anchored at 1 J. Calibrated energies are microjoule-scale, so most units clamp at 100 and check's eco threshold discriminates far less than it did. The Pareto verdicts (base vs head) are unaffected. This is documented in STATUS.adoc, QUICKSTART.adoc, README.adoc and action.yml, and it needs an owner ruling on the score scale — I did not invent a new formula.

Also in this change

  • docs/usage.adoc (end-user guide) and docs/ci-runbook.adoc (gate inventory, actions.lock rules, how to read a red check from annotations, just targets, pre-release checklist), both indexed in docs/README.adoc.
  • Per-crate guides for all ten crates and analyzers/code-haskell/README.adoc.
  • Deleted policy-engine/deepproblog/eco_problog.pl (dead by the 2026-07-28 ruling; EXPLAINME.adoc updated).
  • instant-sync.yml's header now records its settings-level disabled state, which is invisible from the repository contents.
  • DEBT.adoc, CHANGELOG.adoc and STATE.a2ml updated: resolved entries marked, the eco-saturation caveat recorded.

Still open (not in this PR)

Two long-standing red checks on `main`, plus the blocking per-file debt
behind one of them.

CI
---
* Hypatia's single high/critical finding was research_extensions RE008:
  `dependabot-automerge.yml` gated auto-merge on the dispatch actor rather
  than the PR author. The PR-author gate is kept, the actor conjunct is
  gone. The explanatory comment describes the pattern instead of quoting
  it, because RE008 is a raw-text scan with no comment filtering and
  quoting it would re-arm the finding.
* `Publish Image` failed with `cargo build --release --locked -p
  oikosbot-cli` exit 101: tree-sitter 0.27.0 declares rust-version 1.90 /
  edition 2024 while the builder was rust:1.88-slim. CI on ubuntu-latest
  passed because the runner ships a newer rustc. Builder is now the
  rolling rust:1-slim.

Calibration (#48)
-----------------
`Analyzer::estimate_resources()` maps a detected pattern onto an
`OperationKind` via the new `calibration::operation_for_pattern` and prices
it with `estimate_operation()`, whose `ResourceRange` carries the
min/typical/max band and the confidence that row has earned — `Calibrated`
for the measured kinds, `Estimated` for the host-dependent ones. Units with
no recognised pattern keep the naive complexity path, labelled `Estimated`
with no band claimed. `ResourceRange` moves to `oikosbot-metrics` and rides
on `AnalysisResult` (serde-default, skipped when absent), and SARIF emits it
as `properties.resource_range`.

`calibrated_estimate()` and its duplicated multiplier table are deleted;
`standard_objectives()` is deleted as dead code.

Tests
-----
* calibration: per-kind confidence ladder, min<=typical<=max on every axis,
  the pattern→kind mapping (including the deliberate `redundant-allocation`
  hole).
* analyzer: a recognised pattern earns Calibrated + a band; unrecognised
  code stays Estimated with no band; the calibrated path changes the
  numbers.
* `crates/oikosbot-cli/tests/check_gate.rs`: end-to-end proof that
  `compare --check` can block — an undocumented calibrated regression exits
  1, the same regression without `--check` exits 0, a documented
  `Pareto-Trade-off:` is accepted, and a heuristic regression refuses to
  block *and says so*.

Docs
----
`docs/usage.adoc` and `docs/ci-runbook.adoc` (both indexed), per-crate
guides, and `analyzers/code-haskell/README.adoc`. The "`--check` cannot
block a merge" caveats in README/QUICKSTART/STATUS/action.yml/COMPARISON
now describe what is true, and name the eco-score saturation that follows
from calibrated microjoule-scale estimates.

Also: delete `policy-engine/deepproblog/eco_problog.pl` (dead by the
2026-07-28 ruling) and record `instant-sync.yml`'s settings-level disabled
state in its header.

NOT verified in CI by this change: there is no Rust toolchain in the
authoring environment, so `cargo fmt/test` results are unknown until the PR
runs. Before/after figures in the docs are derived by reasoning and labelled
as such.

Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Sep 25, 2026

Copy link
Copy Markdown

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 1326b49d-4b85-44ff-9800-56304cd188fa

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@hyperpolymath
hyperpolymath merged commit 97a3393 into main Sep 25, 2026
8 checks passed
@hyperpolymath
hyperpolymath deleted the arena/01a0dad6-oikosbot branch September 25, 2026 23:54
hyperpolymath added a commit that referenced this pull request Sep 26, 2026
## What

`DEBT.adoc` re-verified against the tree. Six entries listed fixes that
had
**already landed** as still open; each is now marked resolved with its
date and
the evidence, and the Summary rows are corrected to match.

| Entry | Evidence it is resolved |
|---|---|
| `LICENSES/AGPL-3.0-or-later.txt` orphaned | absent from the working
tree *and* from the base commit — `git ls-tree -r 7781489 -- LICENSES/`
lists only `CC-BY-SA-4.0.txt` and `MPL-2.0.txt` |
| `GOVERNANCE.md` no SPDX header | file deleted; the surviving
`GOVERNANCE.adoc` carries `CC-BY-SA-4.0` on line 1 |
| `ARCHITECTURE.md` boilerplate | deleted; `ARCHITECTURE.adoc` is the
only architecture document |
| `GOVERNANCE.md` same defect | deleted |
| `ARCHITECTURE.adoc` names unbuilt components | the `[WARNING]` block
now names each one inline (OCaml docs analyzer, superseded "Python +
Datalog" line, fourth bot role, Praxis Loop / DeepProbLog) |
| `push-email-notify.yml` dormant | gone from `.github/workflows/` (15
workflows, none so named), removed under the dual-use ruling |

The **wiki stub** is recorded as *claimed* resolved rather than
verified: wiki
pages are not part of the repository tree, and this register's own rule
is that
an unverifiable claim says so.

Two entries were corrected rather than closed:

* the licence-identifier counts were re-measured — **159 MPL-2.0 / 65
CC-BY-SA-4.0** occurrences via `grep -rhoP "SPDX-License-Identifier:
\K[A-Za-z0-9.+-]+"`,
with the two headers quoted inside `docs/superpowers/plans/` called out
as
  quotations rather than declarations;
* the #16/#17 entry now names what the 2026-09-26 documentation pass
actually
  delivered (`docs/usage.adoc`, `docs/ci-runbook.adoc`, the per-crate
  `README.adoc` set) instead of pointing at a bare `docs/README.adoc`.

One deliberate restraint: the AGPL entry does **not** restate the
licence
identifier verbatim. A quoted `SPDX-License-Identifier:` line inside a
document
is indistinguishable from a real declaration to `grep`, and this
register has
already recorded that class of defect once (the duplicated header in
`docs/README.adoc`). Writing the identifier out in full would have
re-created it.

`ROADMAP.adoc` follows: candidate (B) is marked landed, with its two
consequences recorded rather than hidden (the naive path is still
collinear and
still `Estimated`; calibrated energies saturate `calculate_eco_score`
near 100,
so the `check` eco-threshold gate is near-vacuous and needs an owner
ruling on
the EnergyScore scale). "Policy rules in Datalog and DeepProbLog" no
longer
claims the DeepProbLog asset retired by the 2026-07-28 ruling.

`CHANGELOG.adoc` and `STATE.a2ml` record the same.

## Why now

PR #107 landed and CI verified it — the debt register is the repo's
authority on
what is outstanding, so a register that over-reports open debt is its
own kind of
dishonesty, and it hides the entries that genuinely are open.

## Verification

* `tools/ci/linter-verify.sh` → PASS on all four steps (SPDX headers,
  permissions declaration, actions lockfile coverage, `lockcheck.sh`).
* `grep -rhoP "SPDX-License-Identifier: \K[A-Za-z0-9.+-]+" | sort | uniq
-c` →
  `65 CC-BY-SA-4.0`, `159 MPL-2.0`, `2 MPL-2.0+` (the two quoted in
  `docs/superpowers/plans/`). No third licence is declared.
* Every claim above was re-checked against the tree before being
written.

No code changes; documentation only.

Co-authored-by: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com>
Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant