Skip to content

review: ten rules a board-support PR walked straight through - #2452

Merged
openipc-ai merged 3 commits into
masterfrom
review-rules-2446-v2
Sep 19, 2026
Merged

openipc-ai merged 3 commits into
masterfrom
review-rules-2446-v2

Conversation

@openipc-ai

Copy link
Copy Markdown
Collaborator

Problem

PR #2446 (Imou Cue 2 board support) is exactly the kind of change best_practices.md and
pr_compliance_checklist.yaml exist to catch: a whole retail camera filed into the shared
tree, with a binary blob, a boot-time download, and a sensor patch against one of our own
repositories. The automated review found eight of the twelve problems in it. The four
it missed and the five it half-caught are gaps in what we wrote down, not in the reviewer —
so this writes them down.

No hardware; this is review configuration only.

What was missing

The binaries gate could not see a binary. It enumerated .ko/.so/.a/.bin, so
general/overlay/etc/ir/nrxset — an executable with no extension — came back from the
describe pass as "the supplied patch contains no textual changes", which is precisely what
a blob looks like to anything reading a diff as text. The gate now keys on the
Binary files ... differ marker, which is the one signal that always survives, and says
outright that general/overlay/ is never the place for a compiled artefact. A register
table copied out of a vendor's driver is folded in as the same failure written in C.

ipctool is not on a camera. general/package/ipctool/ipctool.mk installs ipcinfo
and nothing else; /usr/sbin/ipctool is a symlink to extutils, whose ipctool) arm curls
the tool from the latest release into /tmp on first use. In a boot script that is a
network fetch during boot, from a floating tag, repeated every boot because /tmp is tmpfs,
and a silent no-op until the network is up. #2446 ran ipctool i2cset from rc.local
twelve seconds in, on a WiFi-only board.

An overlay file needs no Config.in, so nothing catches one nothing reads. Nothing in
firmware or builder reads /etc/ir/nrxset or /etc/ir/nrx_night_06.txt, and the rc.local
the same PR ships never invokes nrxset — while the comment above that code says it does.
Its own two comments also contradict each other about whether the files are needed. Cost
lands on every board, several of which sit within 32 KB of their cap.

S95majestic is not a thin wrapper. It passes -s, finds the daemon with
start-stop-daemon -x rather than a pidfile, waits up to ten seconds for the sensor HAL to
be released, and starts under trap '' HUP — its own comment records 25 deaths out of 25
without that, measured on a hi3516ev200. A hand-rolled killall majestic; sleep 3; majestic &
throws all of it away, which is what #2446 shipped, on that same SoC.

Every patch in this tree targets an upstream we cannot commit to — ffmpeg, mbedTLS,
vtund, libre, siproxd, ZeroTier, libwebsockets, f2fs-tools, the Realtek drivers. A patch
against hisilicon-opensdk does not: its SITE is openipc/openhisilicon, and the file
being patched is checked in there. OpenIPC/openhisilicon and OpenIPC/sensors join the
redirect table, which listed only linux, builder, ipctool and majestic.

And the tree's per-device seams are documented nowhere. customizer.sh, muxes.sh,
gpio.conf, late-overlays.list and the excludes lists are a complete mechanism, shipped
per device in builder at the same paths (96, 15, 18 and 9 devices respectively) — and absent
from the wiki, which is why somebody writes an S01leds with GPIO 0, 4 and 9 typed into it.
"Move it to builder" is half an answer; review should say which seam it becomes. Two smaller
notes ride along: the additive, so it changes nothing exemption belongs to load_<vendor>
case arms and not to the overlay, where etc/wireless/usb has quietly reached 46
retail-model arms in 327 lines; and an excludes list added here is keyed
<model>_<variant>, the generic board's key too, so #2446's list took libsns_imx307.so
and default.ini away from hi3516ev200_lite itself.

devmem in a shipped script is now a question. It is the worst way to record what is
soldered to a pad — undone by anything that later exports it, lost at the next reflash —
and the camera can be told instead, through the /api/v1/pinmux surface that the pins page
in OpenIPC/majestic-webui draws.

Changes

File
best_practices.md new §1.4, §1.5, §2.5, §3.5, §4.4, §6.3, §7.3, §7.4; §2.4 and the §8 summary extended
pr_compliance_checklist.yaml 3 new gates (OpenIPC-package patches, reachability, commands on the image); binaries, device-specific values and script conventions extended — 13 gates to 16
.pr_agent.toml the same, as reviewer guidance
CLAUDE.md two rows in the redirect table, four bullets in "what the tree will not accept", the seams named

#2446 is still open. best_practices.md's header said every rule traces to a closed PR;
that sentence now admits the occasional open one, rather than the citations quietly being
wrong.

Hardware tested on

Not applicable, and not hedging: this is review configuration, documentation and repository
metadata, which pr_compliance_checklist.yaml and the template both name as exempt. No file
here reaches an image.

Evidence

The checks this change class does admit:

$ python3 .github/scripts/ci-matrix.py --self-test
ci-matrix: self-test ok (99 boards, 136 packages, 56 cases)

$ python3 .github/scripts/lint-workflow-shell.py --self-test
self-test passed

$ git diff --name-only origin/master | python3 .github/scripts/ci-matrix.py --stdin
ci-matrix: 0/99 boards (needs_build=False) --- nothing that reaches a build

Both edited config files still parse, and .pr_agent.toml still carries no token that trips
Qodo's hardened loader (the failure mode from #2268):

$ python3 -c "import yaml; d=yaml.safe_load(open('pr_compliance_checklist.yaml')); print(len(d['pr_compliances']), 'gates')"
16 gates

$ python3 -c "import tomllib; d=tomllib.load(open('.pr_agent.toml','rb')); print(list(d))"
['github_app', 'review_agent']

$ grep -ciE 'ld_preload|@(json|format|py|get)' .pr_agent.toml
0

Scope

  • No kernel patches under general/package/all-patches/linux/ (those go to OpenIPC/linux)
  • No files specific to a single retail camera model (those go to OpenIPC/builder)
  • No probing or bring-up tooling (that goes to OpenIPC/ipctool)
  • Nothing under general/overlay/ or in a shared load_<vendor> script hardcodes a value specific to my board
  • No LD_PRELOAD, and no binaries that cannot be rebuilt from source

#2446 (Imou Cue 2 board support) is the shape of PR these files exist to
catch, and the automated review caught eight of twelve problems in it. The
four it missed, and the five it half-caught, are all gaps in what we wrote
down rather than gaps in the reviewer.

The binaries gate enumerated .ko/.so/.a/.bin, so an executable with no
extension at all -- general/overlay/etc/ir/nrxset -- was reported back as
"contains no textual changes", which is exactly what a blob looks like to
anything reading a diff as text. The gate now keys on the "Binary files ...
differ" marker, which is the one signal that survives, and says outright
that general/overlay/ is never the place for a compiled artefact. A
register table copied out of a vendor's driver gets the same treatment: it
is the same provenance failure written in C.

Three things the tree already owns had no rule at all. ipctool is not on a
camera -- the package installs ipcinfo, and /usr/sbin/ipctool is an
extutils arm that curls the tool from a "latest" release into tmpfs at
first use -- so calling it from rc.local twelve seconds into boot on a
WiFi-only board is four bad properties at once. An overlay file needs no
Config.in, so nothing caught /etc/ir/nrxset and nrx_night_06.txt, which
nothing in firmware or builder reads and which the same PR's rc.local
never invokes, whatever its comment says. And S95majestic carries an -s
argument, a start-stop-daemon lookup, a ten-second wait for the sensor HAL
and a trap '' HUP that its own comment measured at 25 deaths out of 25 on
a hi3516ev200 -- all of which a hand-rolled killall-and-relaunch throws
away, on that same SoC.

Every patch in this tree targets an upstream we cannot commit to. A patch
against hisilicon-opensdk does not: its SITE is openipc/openhisilicon, and
the file being patched is checked in there. That repository and
OpenIPC/sensors join the redirect table, which listed only linux, builder,
ipctool and majestic.

The rest is telling contributors what already exists. customizer.sh,
muxes.sh, gpio.conf, late-overlays.list and the excludes lists are a
complete per-device mechanism, shipped per device in builder at the same
paths -- and documented nowhere, which is why somebody writes an S01leds
with GPIO 0, 4 and 9 typed into it instead. "Move it to builder" is half an
answer; say which seam it becomes. Two smaller notes go with it: the
"additive, so it changes nothing" exemption belongs to load_<vendor> case
arms and not to the overlay, where etc/wireless/usb has quietly reached 46
retail-model arms; and an excludes list added here is keyed <model>_<variant>,
which is the generic board's key too, so #2446's list took libsns_imx307.so
away from hi3516ev200_lite itself.

Lastly, devmem in a shipped script is now a question rather than a given.
It is the worst way to record what is soldered to a pad -- undone by
anything that later exports it, lost at the next reflash -- and the camera
can be told instead, through the /api/v1/pinmux surface the pins page in
OpenIPC/majestic-webui draws.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Expand review gates for board-support changes

📝 Documentation ⚙️ Configuration changes ✨ Enhancement 🕐 20-40 Minutes

Grey Divider

AI Description

• Adds gates for package patches, shipped-file reachability, and command availability.
• Strengthens binary, board-specific, pinmux, and majestic lifecycle review guidance.
• Documents OpenIPC ownership boundaries and per-device builder seams.
Diagram

graph TD
  PR["Board-support PR"] --> BP["Best practices"] --> REVIEW["Automated review"] --> ROUTE["Owner repository"]
  PR --> GATES["Compliance gates"] --> REVIEW
  PR --> AGENT["PR agent"] --> REVIEW
  BP --> GUIDE["Contributor guide"] --> ROUTE
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Generate guidance from one policy source
  • ➕ Reduces duplication across Markdown, YAML, and TOML.
  • ➕ Prevents terminology and rule details from drifting.
  • ➖ Requires a generator and validation workflow.
  • ➖ Consumer-specific formats still need tailored wording and detail.
2. Implement deterministic repository linters
  • ➕ Provides reproducible enforcement without relying solely on review prompts.
  • ➕ Can precisely detect paths, binary markers, package sites, and installed commands.
  • ➖ Semantic checks such as provenance and repository ownership remain judgment-based.
  • ➖ Reachability and defconfig checks may require cross-repository builder context.

Recommendation: The current layered approach is appropriate because maintainers, contributors, and automated review consume different formats. Merge these synchronized rules, then consider generation or deterministic linting for mechanically checkable gates if policy duplication begins to drift.

Files changed (4) +395 / -19

Documentation (2) +235 / -10
CLAUDE.mdDocument repository ownership and new hard review rules +23/-3

Document repository ownership and new hard review rules

• Adds OpenIPC/openhisilicon and OpenIPC/sensors to the repository redirect table. Summarizes the new binary, package-patch, reachability, command-availability, and per-device seam requirements for contributors.

CLAUDE.md

best_practices.mdAdd detailed board-support review standards +212/-7

Add detailed board-support review standards

• Introduces guidance for builder device seams, devmem and pinmux configuration, extensionless binaries, vendor register tables, OpenIPC package ownership, unreachable overlay files, installed command validation, and safe majestic restarts. The hard-gate summary and rule provenance wording are updated accordingly.

best_practices.md

Other (2) +160 / -9
.pr_agent.tomlExtend automated reviewer guidance for board-support risks +62/-2

Extend automated reviewer guidance for board-support risks

• Adds reviewer instructions for extensionless binaries, vendor-derived register tables, OpenIPC-owned package patches, per-device seams, overlay reachability, image command availability, devmem usage, and majestic restarts. It also narrows the additive sensor exemption to shared loader case arms rather than overlays.

.pr_agent.toml

pr_compliance_checklist.yamlExpand compliance checks from thirteen to sixteen gates +98/-7

Expand compliance checks from thirteen to sixteen gates

• Adds hard gates for patches against OpenIPC-owned packages, unreachable shipped files, and commands absent from firmware images. Existing binary provenance, generic configuration, and shipped-script convention checks are strengthened with marker-based detection, device-seam guidance, and mandatory init-script restarts.

pr_compliance_checklist.yaml

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Valid package patches fail compliance ✓ Resolved 🐞 Bug ≡ Correctness
Description
The new package-patch gate unconditionally fails patches against OpenIPC repositories, even though
libevent-openipc already carries such a patch and the accompanying guidance permits a documented
delta to ride ahead of a version bump. Any necessary short-lived integration patch against an
OpenIPC package therefore fails the automated hard gate despite following the documented exception.
Code

pr_compliance_checklist.yaml[R180-183]

+      A new *.patch sits in a package whose *_SITE names a third-party upstream. Every
+      patch in the tree today does — ffmpeg, mbedtls, vtund, libre, siproxd, zerotier,
+      libwebsockets, f2fs-tools, webrtc-audio-processing and the Realtek drivers.
+      A fix to OpenIPC-org code lands in that repository and arrives here as a
Evidence
The changed checklist claims every current patch targets a third party and makes any OpenIPC-site
patch fail, but libevent-openipc fetches OpenIPC/libevent and carries a patch against its CMake
configuration. The newly added best-practices section also explicitly permits a minimal patch to
ride ahead of a version bump, directly contradicting the hard gate.

pr_compliance_checklist.yaml[172-190]
general/package/libevent-openipc/libevent-openipc.mk[7-18]
general/package/libevent-openipc/0001-CMakeLists-remove-epoll_pwait2-check.patch[1-12]
best_practices.md[396-403]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new hard gate rejects every patch against an OpenIPC-owned repository, contradicting both the existing libevent package and the documented allowance for a minimal patch that must ride ahead of a version bump.
## Fix Focus Areas
- pr_compliance_checklist.yaml[172-190]
- best_practices.md[384-403]
- CLAUDE.md[157-159]
- .pr_agent.toml[89-93]
## Recommended Fix
Make the rule reject patches that should already have landed in the owning repository, while allowing a narrowly scoped, documented temporary integration patch tied to an upstream pull request and planned version bump. Remove the false claim that every existing patch targets a third-party repository, or explicitly document and justify grandfathered OpenIPC-package patches.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Valid runtime assets fail compliance ✓ Resolved 🐞 Bug ≡ Correctness
Description
The reachability gate requires every package asset to be found through its installed path, but
established packages install assets with globs and consume them later by basename or naming
convention. A valid module, firmware file, or sensor asset added to one of these existing sets can
consequently be classified as unreachable even though its loader demonstrably uses it at runtime.
Code

pr_compliance_checklist.yaml[R198-201]

+    success_criteria: >
+      Every added file under general/overlay/ or a package's files/ directory is read at
+      its installed path by a script, init file, package, or configuration somewhere in
+      firmware or builder. Documentation and license text shipped on purpose are fine.
Evidence
The Fullhan package installs firmware and modules through wildcards, while load_fullhan changes
into the module directory and references modules and firmware only by basename. Literal
installed-path searching therefore finds no reader for assets that are actively consumed by the
shipped loader.

pr_compliance_checklist.yaml[192-207]
general/package/fullhan-osdrv-fh8852v100/fullhan-osdrv-fh8852v100.mk[13-28]
general/package/fullhan-osdrv-fh8852v100/files/script/load_fullhan[13-28]
general/package/hisilicon-osdrv-hi3516cv200/files/script/load_hisilicon[359-363]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new reachability check assumes consumers reference an asset's literal installed path, while existing packages install files through globs and load them by basename, relative path, or naming convention.
## Fix Focus Areas
- pr_compliance_checklist.yaml[192-207]
- best_practices.md[513-533]
- .pr_agent.toml[150-154]
## Recommended Fix
Define reachability semantically rather than as a literal installed-path match. Treat existing install globs plus runtime basename, relative-directory, generated-name, or documented naming-convention lookups as valid consumers, and require reviewers to trace those mechanisms before failing an asset.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can describe a rule in plain language on the Rules page and Qodo drafts it for you

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread pr_compliance_checklist.yaml Outdated
Comment thread pr_compliance_checklist.yaml Outdated
Both come from the bot review on the pull request that added them, and
both were right.

The patch rule claimed no patch in the tree targets an OpenIPC-org
repository. That is false: libevent-openipc carries
0001-CMakeLists-remove-epoll_pwait2-check.patch against
github.com/OpenIPC/libevent. My own check missed it because the SITE
grep matched LIBEVENT_OPENIPC_SITE_METHOD first and took that line.
Counted properly it is 22 of 23, not 23 of 23 -- and the one exception
is the legitimate shape the rule should have described from the start:
one hunk, a build fix, obviously temporary, riding ahead of a bump.
So the gate no longer refuses every such patch. It asks whether the
patch is a bridge or a substitute -- is the upstream pull request named,
is it the minimal delta, does it go at the next *_VERSION bump -- which
still catches #2446, whose 114-entry table replacement is none of those.

The reachability rule was worse than the bot said. It asked that an
added file be "read at its installed path", but most of this tree's data
is never named by anyone: hisilicon-osdrv-hi3516ev200 installs
files/sensor/config/*.ini by wildcard and the one that gets used is
chosen at runtime from the configured sensor, a module is reached by
`modprobe <name>`, an IQ profile through isp.iqProfile. A new sensor ini
would have failed the gate while working perfectly. It also contradicted
a gate five entries above it in the same file, which already exempts a
data file landing under a path an existing install rule globs. Both now
say the same thing: trace the mechanism -- path, basename, a name built
at runtime, or an install glob a convention selects from -- and raise
only the residue, which is what /etc/ir/ actually is.

A rule that fires on correct work costs more than the rule is worth, and
best_practices.md already carries one warning about a false finding this
project has seen made. These two would have been the next.
The rule now asks whether a patch against an OpenIPC-owned package is a
bridge to an upstream pull request or a substitute for one, but it was
still titled "No patches against OpenIPC's own packages". A title is
what gets quoted back in a finding, so on a legitimate libevent-shaped
patch this one would have delivered exactly the message the rule was
just corrected to stop delivering.
@openipc-ai
openipc-ai merged commit aa49569 into master Sep 19, 2026
19 checks passed
@openipc-ai
openipc-ai deleted the review-rules-2446-v2 branch September 19, 2026 07:05
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