prpl
prplOS · merge request !3019 · Ambiorix v11.44.1 upstep + QoS forward-port

One merge request, 1,013 commits

What the v11 upstep carries, and what an audit found inside it.

The change looks like a twelve-file diff. It re-points 27 packages onto a new branch and brings in every commit on that branch. This deck sizes the change and states its risks.

latest-24.10 27 components audit 7–8 Sep 2026
32d4b74 · 2026-09-09
Magnitude

The reviewable diff is 12 files. The shipped change is 1,013 commits.

The merge request edits two feed-pin files. Those pins decide which code 27 packages are built from, so the real change is everything between the old pin and the new one.

What GitLab shows reviewers
12files in the MR diff
4commits in the MR

2 feed-pin YAML files + 10 test fixtures. The description says “three files, two commits”, which is wrong.

What actually changes in the product
1,013commits imported
27components re-pinned
+125klines added
−21klines removed

23 Ambiorix libraries and tools plus the 4 QoS components (34 commits). 3,253 file touches in total.

Ambiorix is the middleware layer under the whole prplOS data model: the message bus, the data-model engine, the config parser and the CLI tools all live here.

Where the change lands

Half of all changed lines are in the message bus library

Lines added and removed per component, old pin to new pin. The ten largest components carry 94% of all changed lines; the other 17 share the rest.

Layers touched

  • Message bus — libamxb, mod-amxb-ubus. Everything that talks to the data model goes through here.
  • Data-model core — libamxd, libamxc. Object tree, parameters, containers.
  • Config & CLI tooling — libamxo, amx-cli, amxo-cg, mod-ba-cli.
  • Tracing, Lua, QoS — libsahtrace, lua-amx, the four QoS packages and their TR-181 surface.

A defect in the first two layers is not local to one feature. It surfaces wherever the data model is used.

How it was audited

Every one of the 1,013 commits was classified. Nothing was sampled.

Deterministic checks

Ten scripted, read-only checks over git and the GitLab API: re-authored commits, sign-offs, test and CI metrics, pin consistency, feed anomalies, description accuracy, lost ticket references, default-branch coverage.

Two independent readers per commit

381 docs-only and version-bump commits were auto-rated OK. The remaining 632 were each read by two AI raters with opposite briefs: one assumes something could be hidden, one classifies as a maintainer would.

Adjudication and blind re-check

All 197 disagreements plus a 5% sample of agreements (219 commits) were re-read against the full diff by a separate model. Round-two findings were re-derived blind before publication.

10scripted checks
632commits read twice
219adjudicated on full diff
2 daysthree rounds, self-corrected once

Static analysis only. No build, no test run, no memory measurement. That is a stated scope limit, and it means every statement here is about what the code says, not how it behaves on a device.

What was found

734 clean, 257 need a closer look, 22 must be fixed before merge

734
257
22
OK · routine, self-contained SCRUTINIZE · needs an owner’s review BLOCKER · defect or removed safeguard

What the 257 SCRUTINIZE commits are. New features and public-interface changes arriving inside a maintenance upstep dominate.

  • 61 new features ride in a change described as an upstep. None are listed in the MR.
  • 53 public API and 6 binary-interface changes need a compatibility check by each component owner.
  • 51 build, packaging and CI changes can alter what ships or what gets tested without touching product code.
  • The 22 blockers started as 75 candidates. 53 were downgraded after adjudication, mostly because a later commit in the same range already fixes them.
The 22 blockers

20 of the 22 are still present in the code this MR would ship

#Defect typeWhat it means for the product
12Memory-safety and crash defects in bus and core librariesDangling pointers, use-after-free, a NULL dereference, an infinite loop and a quadratic slowdown across libamxb, libamxc, libamxd and five more. Crashes or hangs in the layer everything else depends on.
3Public interface changed without safeguardsIncludes the MR’s only memory-optimization commit: it changes public header types, stores an unowned pointer and deletes 10 test assertions. Code built against the old headers can misbehave.
2Destructive default-config scriptacl-manager gains a script that deletes a device’s saved ACL configuration on any transient read error. Only an unrelated makefile line keeps it uninstalled today.
2Silently broken CLI toolingA renamed config-generator option writes output to the wrong place; a CLI tool quietly stops running one of its own tests.
1Tests removed alongside an admitted defectSix error-handling tests for malformed config files are deleted; the commit message says the parser now leaks memory on bad input.
1Resource leak in an always-on serviceThe bus statistics module leaks memory on every reset call.
1Logging defaults changed unconditionallyTrace colours, user traces and syslog console logging are forced on regardless of configuration.

Two of the 22 (libamxb, libamxp) were repaired by later commits inside the same range and only need confirmation.

Traceability and supply chain

Who wrote it, why, and what exactly gets built are all harder to answer after this merge

80%of commits carry no sign-off

808 of 1,013. 802 of those come from one bot account. Contributions from six external organizations now terminate at that bot with no way back to the real author.

102re-imported commits lose their prpl ticket reference

206 commits are copies of earlier prpl commits under a new identity. Half lose every Jira key; 21 lose their whole description. The 172 back-pointers they carry resolve nowhere public.

27 / 27packages switch to an unverified branch fetch

Every package moves from a hash-checked release tarball to a moving git branch, with the mirror-hash check disabled. A build tomorrow may not contain the 1,013 commits that were audited.

Default branch vs. pinned branch. 171 commits on the components’ real default branches have no exact twin in the pinned branch. Hand review shows most are present in re-implemented form. 2 upstream bug fixes are confirmed missing from what this MR would ship; 71 commits remain unverified by automation.

Impact on the product

Four things management should know before this ships

The memory-saving claim is unproven

Of 1,013 commits, 2 are memory optimizations and 9 are performance work: 1.1% of the import. One of the two memory commits is a blocker. No measurement was performed on either side; the audit makes no claim about footprint in either direction.

Data-model surface is withdrawn without notice

Seven TR-181 QoS classification parameters are removed as a RAM optimization. The MR does not say so. Anything that reads those parameters, including operator ACS integrations, will find them gone.

Crash risk sits in the foundation layer

Twelve memory-safety defects are in the bus and data-model libraries. A fault there is not scoped to one feature; it shows up wherever the data model is used, and is hard to attribute back to this merge later.

Test totals grow, targeted tests vanish

Test content grows overall: +181 files, +1,765 cases, +2,390 assertions. Inside that growth two undisclosed removals sit exactly where defects were introduced. CI pass/fail data for either pin is not retrievable, so no suite’s status is confirmable.

Recommendation

Seven conditions before merge

Ordered by how cheaply they close the gap. The first two are hours of work and remove the biggest unknowns.

  1. Pin exact commits and restore hash verification for all 27 packages, so what was audited is what gets built.
  2. Correct the MR description: real file and commit counts, valid hashes, and the test-fixture changes it omits.
  3. Fix the 20 outstanding blockers; confirm the 2 already repaired in range.
  4. Disclose the removed TR-181 QoS parameters and get sign-off from whoever owns data-model compatibility.
  5. Restore attribution: original authors, sign-offs and ticket references, or a public mapping back to the source commits.
  6. Split the MR or publish a per-component changelog. 1,013 commits in one pin bump cannot be reviewed as a unit.
  7. Account for default-branch content: state for each unmatched commit whether it is present, superseded or intentionally dropped, and land the 2 missing fixes.
The ask

Treat this as a platform upgrade, not a version bump

Do not merge as-is

Twenty confirmed defects and an unpinned supply chain are each sufficient on their own.

Require conditions 1–4 first

Pinning, an honest description, blocker fixes and the data-model disclosure. Cheap, and they make the rest reviewable.

Then plan the real work

Attribution restore, per-component changelog, default-branch reconciliation. This is integration effort, and it should be scheduled as such.

Full report with per-commit evidence: prplware-v11-upstep-audit.pages.dev. Every number in this deck has a source pointer in the speaker notes.

32d4b74 · 2026-09-09