Skip to content

anchor audit PDFs under audit/protofire/ so the org health scan sees them - #56

Open
thedavidmeister wants to merge 2 commits into
mainfrom
2026-07-25-audit-anchors
Open

anchor audit PDFs under audit/protofire/ so the org health scan sees them#56
thedavidmeister wants to merge 2 commits into
mainfrom
2026-07-25-audit-anchors

Conversation

@thedavidmeister

Copy link
Copy Markdown
Collaborator

This repo carries two real Protofire audit reports, and the org health
scanner counts neither of them. health.json (generated 2026-07-25T18:16:00Z)
currently publishes:

{ "name": "cyclo.sol", "org": "cyclofinance",
  "hasProtofireAudit": false, "externalAudit": "never",
  "auditPdfs": [], "auditedRef": null, "anchorKind": null }

so cyclo.sol is one of the 16 of 42 repos sitting in the org's external-audit
coverage gap, despite having been audited twice.

What moved

before after
audit/Cyclo audit report dev v.1.0.pdf audit/protofire/cyclo.sol.2ee2b15fa8daa81e6eb432822f570f363c111415.nov-2024.pdf
audit/report-cyclo-dec-2025-1.2.pdf audit/protofire/cyclo.sol.63d11553006bf24421c033b19f6dab0ba1bc4573.dec-2025.pdf

Both files are byte-identical to what was there; only the path and name changed.

Anchor evidence

…nov-2024.pdf2ee2b15fa8daa81e6eb432822f570f363c111415

  • Vendor: cover page reads Protofire, Version: 1.0, November, 2024; the
    disclaimer names Protofire. The commit that added it is 4e9755c "add
    protofire audit".
  • Audited ref: the report's "The Rain audit report" section names the initially
    audited commit 34074b93e912dce11415cb464cc0c8b4f9bd2493, and then three
    update sections re-review later states — Update 1
    6d6ea0c8ee27b07597472d60f6cb0de26e21f695, Update 2
    8d1ad33044076e0cea75b6e25e285b8174cd590e, Update 3
    2ee2b15fa8daa81e6eb432822f570f363c111415 (all cited as
    https://github.com/cyclofinance/cyclo.sol/commit/…). The anchor is the last
    state actually reviewed, Update 3. That is consistent with the file's history:
    the PDF was last updated in 0546ef8 "updated audit" on 2025-01-30, and
    2ee2b15 is dated 2025-01-13.
  • Resolves: gh api repos/cyclofinance/cyclo.sol/commits/2ee2b15fa8daa81e6eb432822f570f363c111415
    2ee2b15f 2025-01-13T18:32:55Z "fix tests", and
    git merge-base --is-ancestor 2ee2b15… origin/main passes.

…dec-2025.pdf63d11553006bf24421c033b19f6dab0ba1bc4573

  • Vendor: the cover page carries the Protofire logo and wordmark (the text layer
    does not name the vendor; the logo does) over "Smart contract audit / Cyclo",
    dated December 2025.
  • Audited ref: the report's own "Reviews" table — 18/12/25 | cyclo | 63d11553006bf24421c033b19f6dab0ba1bc4573. Cross-checks against history: that
    is the merge commit of ethgild bump #38, and it is the base the audit branch
    2025-12-22-audit was cut from.
  • Resolves: gh api repos/cyclofinance/cyclo.sol/commits/63d11553006bf24421c033b19f6dab0ba1bc4573
    63d11553 2025-11-28T11:20:43Z "Merge pull request #38 …", ancestor of
    main.

Nothing was invented: every anchor is a commit the report itself names, and both
resolve in this repo. This repo has zero tags (gh api …/tags[]), so
the commit form is the only applicable anchor kind — there is no tag for the
tag-wins rule to prefer.

Naming mirrors the known-good example
rainlanguage/rain.solmem@audit/protofire/rain.solmem.228b35c6725877e7fbcd2432b4c692357f16f510.jan-2026.pdf:
<repo>.<audited sha>.<month>-<year>.pdf, where the date token is the report's
date rather than the anchor commit's date (same as solmem, whose jan-2026
report anchors a 2025-12-06 commit, and rain.math.float's feb-2026 anchoring
2025-12-01).

Before / after in scanner terms

roh-scan walks audit/protofire at depth 2 (main.rs ~1024) and deliberately
not all of audit/ — a non-Protofire report elsewhere under audit/ must not
be counted as a Protofire audit (protofire.rs ~5-8). A PDF at audit/*.pdf is
therefore invisible, which is exactly why this repo reports never.

  • Before: hasProtofireAudit: false, externalAudit: "never", auditPdfs: [],
    counted in the org's coverage gap.
  • After: both PDFs are found, each filename yields a resolving commit anchor
    (anchorKind: "commit"), the newest audit by audited date — the Dec 2025 one —
    becomes the reference, and drift is measured compare/63d1155…...main: 10
    commits, 8 files, 0 changed lines of src/**.sol. Because the repo has no
    tags, classify_external_audit returns na (has a PDF, no tags to compare) —
    not never. It leaves the coverage gap and gains a real, honest drift figure.

Why a bare git mv would not have been enough

Neither old filename encodes an anchor: parse_audited_tag finds no vX.Y.Z
(Cyclo audit report dev v.1.0.pdf has v.1.0, which is not v<major>.<minor>.<patch>)
and parse_commit_candidate finds no 7–40 hex token in either name. Both would
classify Unanchored even sitting in the right directory.

Unanchored means the audit's date falls back to the commit that last touched the
file (main.rs ~757-773, commits?path=…&per_page=1, newest first) — and a move
is a commit touching the file. A git mv alone would have made a November 2024
audit and a December 2025 audit both report as freshly audited today, with
zero drift. That is worse than invisible: it would launder stale coverage into
apparent currency. The rename is the substantive half of the fix; the directory
is only what makes it visible.

Also

  • README.md gains an ## Audits section naming both reports and the commit
    each one reviewed, so the anchor is discoverable without opening the PDFs.
  • REUSE.toml's existing audit/**/ annotation still covers the new paths —
    verified with reuse lint-file on both new files and README.md (exit 0).

Related: rainlanguage/rainix#287 proposes the static check that would have caught
this (enforce audit/protofire/ + an anchor that resolves).

Both Protofire reports sat loose at the audit/ top level with names that
encode no audited ref. The org health scanner reads audit/protofire/ only,
and dates an audit from the commit anchor in the filename, so cyclo.sol
published "externalAudit": "never" despite two real audits.

Each PDF now sits under audit/protofire/ and carries the commit of this
repo the report states it reviewed:

- Protofire v1.0 (November 2024, through Report Update 3) reviewed
  2ee2b15.
- Protofire December 2025 reviewed 63d1155.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@thedavidmeister thedavidmeister self-assigned this Jul 25, 2026
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@thedavidmeister thedavidmeister added the ai:needs-work Needs rework — the producer's inbox (vetter verdict or human ruling) label Jul 28, 2026
@thedavidmeister

Copy link
Copy Markdown
Collaborator Author

🤖 ai:vetter
Reviewed 18e66bc: reject — Missing QA evidence block (QA-GUIDE §8) — no ## QA section in body, no trusted producer comment carrying one. The renames themselves verify clean locally (byte-identical moves, REUSE audit/**/ covers new paths, README matches filenames); resubmit with the block. Refs rainlanguage/rainix#287.
cost 183 — artifact rename, anchor-sha verification

@thedavidmeister thedavidmeister added ai:blocked-on AI producer: blocked on a dependency PR and removed ai:needs-work Needs rework — the producer's inbox (vetter verdict or human ruling) labels Jul 28, 2026
@thedavidmeister

Copy link
Copy Markdown
Collaborator Author

🤖 ai:producer
Blocked-on: Blocked on rainlanguage/rainix#289 (fork-RPC failover preflight), which is now ai:design pending a human ruling. This diff only moves audit PDFs under audit/protofire/, so it cannot affect Solidity tests. The failures are the archive trap that rainix issue 288 documents: failed to get account for 0xA4b000000000000000000073657175656e636572 with error code -32000 metadata is not found, and missing trie node 8f330debb4319e73d804b417789d55ee25806bf99c0725b31d01ae18fa65113f is not available -- the shared Arbitrum endpoint is answering historical reads from a pruning backend. No code change in this repo can pick a different upstream; the archive-aware preflight in rainix#289 is the fix. Goes green once that lands on rainix main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai:blocked-on AI producer: blocked on a dependency PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants