Skip to content

packaging: two pinned SDK eras — 25.12/apk (primary) + 24.10.8/ipk (installed base) - #710

Merged
c03rad0r merged 4 commits into
mainfrom
packaging/two-sdk-eras
Oct 8, 2026
Merged

c03rad0r merged 4 commits into
mainfrom
packaging/two-sdk-eras

Conversation

@Amperstrand

Copy link
Copy Markdown
Collaborator

Implements #708 (owner decision: ipk stays supported; two SDKs, format-selected).

What was wrong: OpenWrt 25.12's SDK is apk-native — the ipk lane on it fails by construction (searches for .ipk that era never emits; exactly the rc1 driver failure the release lane fought).

The design: build-inputs.json pins both eras — releases.apk: 25.12.0 (primary; the .go.version pin and released-feed audit track this line) and releases.ipk: 24.10.8 (point-release digests from hub openwrt/sdk, all 6 targets) — and the packaging format selects its era everywhere:

Consumer Change
build-env.sh sdk_release_for <fmt> + sdk_image_ref <target> [fmt] — era-aware, backward-compatible default apk
build-sdk-package.sh exports TG_PACKAGE_FORMAT → the script path is era-correct end-to-end (the rc1 driver's fix)
build-package.yml matrix rows carry both digest+release pairs; the format split attaches the right one; apk job's image uses matrix.sdk_release instead of hardcoded 25.12.0
sdk-go-version.sh primary audit = apk line; ipk era's feed stays audited via go_per_release (24.10 → 1.23.x)
update-build-inputs.sh refreshes both eras

Toolchain truth unchanged: the manifest Go (1.26.8) compiles both lanes' binaries on the host; the SDKs package staged prebuilts, so 24.10's older feed Go never compiles our code — no directive conflict, no second toolchain pin.

Verified: all scripts bash -n clean, both-era sdk_image_ref resolves correctly, matrix jq dry-run injects both pairs for dual-format rows, workflow YAML valid. Follow-up (deliberately out of scope): provenance parity for CI's hand-rolled ipk lane.

…nstalled base)

Closes the era mismatch (#708): OpenWrt 25.12's SDK is apk-native — the
ipk lane could never produce .ipk on it by construction. The manifest now
pins BOTH eras (openwrt_sdk.releases.{apk,ipk}), each with digest-pinned
targets (24.10.8 point-release images from hub openwrt/sdk), and the
packaging format selects its era everywhere:

- build-env.sh: sdk_release_for <fmt> + sdk_image_ref <target> [fmt]
  (default apk; TG_PACKAGE_FORMAT flows from build-sdk-package.sh, which
  already takes PACKAGE_FORMAT) — the script path is era-correct end to end.
- build-package.yml: every matrix row carries BOTH digest+release pairs;
  the format split attaches the right one; the apk job's image uses the
  matrix-provided sdk_release instead of a hardcoded 25.12.0.
- sdk-go-version.sh: primary audit tracks the apk line (25.12); the ipk
  era's feed stays audited via go_per_release (24.10 -> 1.23.x recorded).
- update-build-inputs.sh: refreshes both eras' digests.

Toolchain note (single source of truth unchanged): the manifest Go
(1.26.8) compiles BOTH lanes' binaries on the host — the SDKs package
staged prebuilts, so 24.10's older feed Go never compiles our code.
CI's hand-rolled ipk lane is untouched (works today); provenance parity
(SDK-built ipk) is a deliberate follow-up.
@felixfelix-bot

Copy link
Copy Markdown
Contributor

pre26 merge set — cross-links (manager)

This PR's role: the SDK-era split — the ipk lane fails by construction without it.
Action on this PR: Merge FIRST, before #717 (which needs it).

The full set, in merge order

# repo what it does order / pairing review
#710 module two pinned SDK eras — 25.12/apk + 24.10.8/ipk (the ipk lane cannot work without it) merge 1st in flight @ 5c987f32
#717 module bcm2709 EXPECTED_ARCH → restores 2 matrix rows after #710 in flight @ 156b7882
#738 module ipk ~ pre-release ordering — without it an installed rc1 can never upgrade to the final order-free in flight @ e9d90d11
#739 module one assembled brand registry — un-reds make release-check on main order-free in flight @ 333c898f
#706 module captive SSID leading ! (sorts first) 🔗 PAIR A — land together with installer #82 in flight @ 5f122156
#82 installer SSID ! writer + strip-on-read 🔗 PAIR A — land together with module #706 in flight @ 8115426a
#83 installer uplink/DNS gate waited on nothing → cold install failed order-free, but merge before tagging in flight @ c68e154f
#745 module tollgate ui links — the Lucy link (rpcd ui_links answers nothing in pre25) 🔗 PAIR B — land together with #744 in flight @ df829298
#744 module rc-guide/README/operator-guide port truth (documents the link #745 implements) 🔗 PAIR B — land together with #745 in flight @ efad4d0e

Not yet PRs — will be added when they land: scan-latency/transport recovery (pr/installer-scan-transport-hardening, in flight) · module dead-resolver repair (implemented, unpushed).
Your call (recommend SOON, not blocking): #742 wallet single-writer · #743 durable config writes.
HOLD for pre26: #727 dep bumps · #601 · #568 · #549 · #425 · #630 · CI/dev-env/docs: #735 (only if you take #710) #734 #736 #729 #718 #728 #713 #711.

Then: feed repin (net/tollgate-wrt: PKG_VERSION/PKG_SOURCE_VERSION/PKG_HASH move together) → tag v0.6.0-rc1-pre26 → I verify the published assets + unpack the apk before anyone touches it.

Labels to apply (I cannot — this token is read-only on this repo; a maintainer click is required)

This repo already has the right labels, so no new ones are needed:

Two traps worth not overlooking

  1. PAIR A (feat(ssid)!: the captive SSID carries a leading '!' so it sorts first #706 + fix(scripts/build-sdk-apk): forward host SHA and preserve source-URL default #82) and PAIR B (feat(cli): ui links — the router answer behind the ui_links rpcd method #745 + docs(rc-guide): correct admin-UI port mapping for the entry_ui=board flip #744) are paired, not merely related: docs(rc-guide): correct admin-UI port mapping for the entry_ui=board flip #744 tells testers the Lucy link works, and feat(cli): ui links — the router answer behind the ui_links rpcd method #745 is the code that makes it work — landing either alone makes the release self-contradictory. feat(ssid)!: the captive SSID carries a leading '!' so it sorts first #706 and fix(scripts/build-sdk-apk): forward host SHA and preserve source-URL default #82 are the two halves of one SSID round-trip.
  2. Review tips move. Each review verdict is pinned to the SHA in the table. If anything is pushed afterwards, that verdict is void and I re-review before it merges.

@felixfelix-bot

Copy link
Copy Markdown
Contributor

pre26 — cross-family review status: verdicts OUTSTANDING

This PR has no gate-clearing cross-family review yet. What I can report honestly:

  • Findings, not approvals — from a kimi-k3 (moonshot, i.e. not the zhipu/GLM author) partial review. Every lane was cut before it emitted a VERDICT: line, so nothing here satisfies D-115 / ADR-010.
  • Measured blocker for the gate: router admission is a total input+output budget (the same 15.5 KB diff prompt is refused at max_tokens 6000 and admitted at 2500 — not quota; /quota reads weekly 38%, locked=false), and every live lane is a verbose reasoner that spends the whole cap on prose.
  • Two tooling defects found in my own pipeline: delegate_task children inherit delegation.model: glm-5.2 (the same family as these authors), and 8 parallel children died on state.db contention ("session storage was busy"). Neither path can ever satisfy the cross-family gate.

Do not read this PR as reviewed. The per-PR findings, the real test evidence, and the method for obtaining a genuine verdict are in the artifact.

FULL_REVIEW: /home/c03rad0r/reports/reviews/pre26-cross-family-review-status.md

@Amperstrand Amperstrand left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review (PR-REVIEW.md pass) — disposition: land-with-followups, after folding two one-word fixes.

This branch is the load-bearing piece of the two-era doctrine, and its core is verified by real builds: the rc1 artifact matrix's missing bcm2709 rows were completed on ai-legion using exactly this branch's manifest and scripts — both eras, all six targets, digest-pinned images resolved through sdk_release_for/sdk_image_ref (artifacts sha256'd on #665). The era-selection in build-sdk-package.sh (PACKAGE_FORMAT → TG_PACKAGE_FORMAT → era-correct SDK) is what the rc1 driver was fighting for, and it works.

Two blockers before merge, both proven against this branch's own script by those same builds:

  1. bcm2709 still carries both arch-name bugs on this branch: EXPECTED_ARCH:=arm_cortex-a7 (the SDK's packages dir is arm_cortex-a7_neon-vfpv4) and the apk-path post-make gate compgen -G "/builder/build_dir/target-${EXPECTED_ARCH}_*" — build_dir spells feature sets with + (target-arm_cortex-a7+neon-vfpv4_musl_eabi), so that glob can never match any +-feature arch and the row fails after a successful build. Both fixes exist on #717 (against main's script) — but this PR rewrites that script, so merging #710 first turns #717 into a conflict. Fold both one-word fixes into this branch (or commit to the immediate rebase).
  2. The manifest's go_per_release comment says the language floor is "1.25.0" — it is 1.26.0 (fixed in the stacked #735; either take that commit here or merge #735 right behind).

Notes: #711 and #713 stack on this branch (merge order 710 → 711/713); #738's ipk-version fix was built and proven on top of this branch's manifest (tollgate-wrt_0.6.0~rc1_x86_64.ipk) — no conflicts observed there. Fragment-era changelog entry is present. No new runtime dependency surface; the only external inputs are the digest-pinned SDK images themselves.

@felixfelix-bot

Copy link
Copy Markdown
Contributor
reviewer_model: kimi-k2.7-code
We need act as cold adversarial reviewer. Need analyze diff. Need produce exact output format. Need be careful. We need inspect diff lines. We need identify blockers, nits, doc contradictions, falsification attempts, unverified. Need plausible wrong input accepted and legitimate input refused. Need verdict. Let's reason thoroughly.

We have PR title: "packaging: two pinned SDK eras — 25.12/apk (primary) + 24.10.8/ipk (installed base)". Diff modifies .github/workflows/build-package.yml, packaging/build-env.sh, packaging/build-inputs.json, scripts/build-sdk-package.sh, scripts/update-build-inputs.sh.

Need verify if it does what title says. It introduces .openwrt_sdk.releases.apk and .openwrt_sdk.releases.ipk with release strings and target digests. Workflow uses matrix.sdk_release and digest based on format. build-env.sh sdk_release_for selects release based on format, sdk_image_ref uses format arg. build-sdk-package.sh sets TG_PACKAGE_FORMAT and passes format. update script iterates eras. So yes.

But need attack. Potential issues:

1. In build-package.yml, the jq matrix injection now requires both apk and ipk digests for every target, even if a target only builds one format. If a target is only ipk, it still needs apk digest in build-inputs.json because error("no apk-era SDK digest pinned..."). This is a regression/hard coupling. Title says two pinned SDK eras, but if matrix only includes some targets for one format, requiring both digests is unnecessary and could break. Need check matrix.json not shown. But the jq maps over all rows and demands both. If a target only exists in one era, it errors. Could be blocker if not all targets have both. In build-inputs.json all six targets have both, so works. But design is brittle.

2. In build-env.sh sdk_release_for: jq query `.openwrt_sdk.releases[$f].release // .openwrt_sdk.release // empty`. If format is ipk, returns 24.10.8. If format is apk, returns 25.12.0. Good. But fallback to old `.openwrt_sdk.release` is present for backward compat. However in build-inputs.json they removed top-level release. So fallback returns null/empty. sdk_release_for returns empty for unknown format, then SDK_RELEASE empty. The check later? There is no explicit check for SDK_RELEASE non-empty. It only checks GO_VERSION and PORTAL_COMMIT. If SDK_RELEASE empty, sdk_image_ref will produce image:target-@digest? Actually `_rel` empty, case stripping *-"" does nothing, then printf image:target-@digest (target- then @). That's invalid. But maybe TG_PACKAGE_FORMAT always apk/ipk. Still missing validation.

3. In build-env.sh sdk_image_ref digest lookup: `.openwrt_sdk.releases[$f].targets[$t].digest // .openwrt_sdk.targets[$t].digest // empty`. If format unknown, releases[$f] null, fallback to old targets. Good backward compat. But if format is ipk and target missing in ipk but present in old targets, it would use wrong digest. Not likely.

4. In update-build-inputs.sh: outer loop `for era in apk ipk; do` then inner `for target in ...`. It uses `tag="$target-$SDK_RELEASE"` but SDK_RELEASE variable is set earlier? Need see script context. The snippet shows `SDK_RELEASE` maybe from build-env? Not shown. Previously SDK_RELEASE was read from build-inputs top-level. Now top-level removed. The script likely sources build-env.sh? Let's infer. The script likely sets SDK_RELEASE from build-env? The diff only shows the loop. It uses `SDK_RELEASE` to construct tag. If SDK_RELEASE is still set from old `.openwrt_sdk.release`, now missing, it will be empty or maybe sourced from build-env's sdk_release_for default apk? Need check. The script may source packaging/build-env.sh at top. If so, SDK_RELEASE would be set to apk release (25.12.0) because default format apk. Then for ipk era, tag would be target-25.12.0, wrong! It should use era-specific release. This is a likely bug: update script uses single SDK_RELEASE for both eras, but now there are two releases. It should compute release per era. The diff didn't update `tag="$target-$SDK_RELEASE"` or define SDK_RELEASE per era. Need verify by reading diff: only changed loop and uses `SDK_RELEASE` unchanged. If SDK_RELEASE variable is undefined or set to apk release, ipk digests will be fetched for wrong tag (target-25.12.0) and may fail or update with wrong digest. This is a strong blocker.

Need quote file:line. scripts/update-build-inputs.sh around line 55-72. It says `tag="$target-$SDK_RELEASE"` and `live="$(sdk_digest "$tag")"`. It iterates `era in apk ipk` but doesn't use era release. If SDK_RELEASE is from old top-level, now removed, it's empty. If sourced from build-env, default apk. Either way ipk update broken.

5. In build-package.yml, matrix generation: It adds digest_apk/release_apk/digest_ipk/release_ipk to every row. Then in matrix output, it deletes digest_apk etc for ipk_matrix but the first `matrix=` output includes all rows with both digest and sdk_release set appropriately, but does not delete digest_apk/release_apk/digest_ipk/release_ipk. So the combined matrix jobs will have extra fields. Not harmful but messy. Also the `matrix=` output uses `.digest_ipk` and `.release_ipk` after del? Wait it does `del(.ipk, .apk) + {format: "ipk", digest: .digest_ipk, sdk_release: .release_ipk}`. It does NOT delete digest_apk/release_apk/digest_ipk/release_ipk in combined matrix. So each row includes both old and new fields. Could cause confusion. But not a blocker.

6. The workflow container image uses `openwrt/sdk:${{ matrix.sdk }}-${{ matrix.sdk_release }}@${{ matrix.digest }}`. If matrix.sdk_release is e.g. 25.12.0, tag is mediatek-filogic-25.12.0. Good. For ipk, 24.10.8. Good.

7. In build-inputs.json, `go_per_release` comment says "the pinned .release's series" but now there are two releases. It says "the pinned .release's series" ambiguous. The comment was updated? It still references `.release` singular. It says "the pinned .go.version must match the entry of the pinned .release's series." With two releases, which .release? The comment says "Primary release line: the .go.version pin and sdk-go-version.sh's released-feed audit track THIS era" in apk comment. But go_per_release comment still singular. Could be doc contradiction.

8. In build-env.sh, `sdk_release_for` default `${1:-apk}`. If called with no arg, returns apk release. In build-sdk-package.sh, it exports TG_PACKAGE_FORMAT="$PACKAGE_FORMAT" then calls sdk_image_ref "$SDK_TAG" "$PACKAGE_FORMAT". Good.

9. In build-package.yml, the jq error messages: "no apk-era SDK digest pinned for target \($row.sdk)" and "no ipk-era...". Good.

10. In build-inputs.json, ipk comment says "feed-less 24.10 systems — fork #93/#110 evidence". It says SDK packages STAGED PREBUILT binaries (manifest-pinned Go compiles on host), so older feed Go never compiles code. But is that true? The SDK still uses its own feed to build package; the package Makefile may compile Go code using in-SDK Go if not careful. The comment claims it doesn't, but depends on build-sdk-package.sh. Need inspect. In build-sdk-package.sh, it sets `export GO_VERSION` and downloads Go? The snippet not shown. It checks ACTIVE_GO. It likely installs host Go. But the SDK's buildroot may still use its Go compiler for package? The script maybe uses `make package/.../compile` inside SDK; if the package's Makefile references $(STAGING_DIR_HOST)/go? Actually OpenWrt package builds use host Go toolchain installed in SDK. If they preinstall pinned Go on host and set PATH, the SDK may still use its own. The comment is unverified.

11. In build-package.yml, the matrix generation now requires both digests for every row. If matrix.json includes a target that only builds apk (no ipk flag), the jq still computes ipk digest and errors if missing. Since build-inputs has both for all targets, okay. But if future target only one era, workflow breaks. This is a design nit.

12. In update-build-inputs.sh, the `era` variable is not passed to jq in update branch? Wait update jq: `jq --arg t "$target" --arg d "$live" '.openwrt_sdk.releases[$e].targets[$t].digest = $d'` but no `--arg e "$era"`! The diff shows: `jq --arg t "$target" --arg d "$live" \ '.openwrt_sdk.releases[$e].targets[$t].digest = $d'`. It uses `$e` but does not pass `--arg e "$era"`. That means jq variable $e is undefined, so `.openwrt_sdk.releases[null]`? Actually jq with undefined variable errors at compile time: `jq: error: $e is not defined`. So update mode will fail. Wait check diff carefully:

if [ "$MODE" = update ] && [ -n "$live" ] && [ "$live" != "$pinned" ]; then
    jq --arg t "$target" --arg d "$live" \
        '.openwrt_sdk.releases[$e].targets[$t].digest = $d' "$TG_BUILD_INPUTS" > "$TMP/bi.json" && mv "$TMP/bi.json" "$TG_BUILD_INPUTS"

No `--arg e "$era"`. This is a clear bug. It will fail because $e not defined. Even if it didn't fail, it would need era. So update script is broken. This is a blocker.

Also in the inner for target line: `for target in $(jq -r --arg e "$era" '.openwrt_sdk.releases[$e].targets | keys[]' "$TG_BUILD_INPUTS"); do` passes e. But update jq doesn't. Also `tag="$target-$SDK_RELEASE"` issue.

13. In update-build-inputs.sh, `report` function maybe expects first arg. Not relevant.

14. In build-env.sh, `sdk_release_for` uses `.openwrt_sdk.releases[$f].release // .openwrt_sdk.release // empty`. If $f is "apk" or "ipk", good. If $f is something else, fallback to old top-level. But old top-level removed. It returns empty. No validation. Could accept wrong format and produce empty release. That's a plausible wrong input accepted: TG_PACKAGE_FORMAT="xyz" -> sdk_release_for returns empty (or old release if present), sdk_image_ref strips suffix based on empty string, prints `openwrt/sdk:target-@digest` which is invalid but accepted by function. Legitimate input "ipk" accepted. Legitimate input maybe "apk" accepted. A legitimate input it would refuse? If build-inputs.json has top-level release removed, an old script calling sdk_image_ref without format arg defaults to apk, works. Hmm.

Need construct plausible wrong input accepted and legitimate input refused.

Wrong input accepted: In build-package.yml matrix jq, if a row has both .apk and .ipk false? Actually select(.ipk) and select(.apk) only include if true. If a row has .apk=true but no apk digest in build-inputs? It errors. Wrong input accepted maybe `TG_PACKAGE_FORMAT=""` in build-env.sh: sdk_release_for "" returns `.openwrt_sdk.releases[""].release` null, fallback old release null, empty. Then SDK_RELEASE empty, no check, sdk_image_ref produces invalid ref but function returns it. The caller may use it. So empty format accepted.

Legitimate input refused: In build-package.yml, if a target is only intended for one era and build-inputs only has digest for that era, the matrix jq errors on the missing other-era digest. For example, if a new target only has ipk digest, workflow refuses because it demands apk digest too. But current build-inputs has both. Need a legitimate input the code would refuse: In update-build-inputs.sh, if MODE=update, the jq command references undefined $e and fails, so a legitimate update run is refused (script exits). That's good. Also in build-env.sh, a legitimate format value "ipk" is accepted only if ipk release present. It is. A legitimate old build-inputs with only top-level `.openwrt_sdk.release` and no `.openwrt_sdk.releases` would be refused by the workflow jq because it expects `.openwrt_sdk.releases.apk.targets[$sdk].digest`. But build-env.sh has fallback. So if someone updates build-inputs.json to old schema, workflow fails. That's a legitimate input refused? The schema changed intentionally. Maybe not.

Another legitimate input refused: In build-package.yml, the matrix generation uses `.include[] | select(.ipk) | del(.ipk, .apk) + {format: "ipk", digest: .digest_ipk, sdk_release: .release_ipk}`. If a row has .ipk=true but build-inputs missing ipk digest, error. But current data okay.

Need also check if `matrix.sdk_release` is used in container image. Yes line 654. Good.

Need check if `build-package.yml` previously had `matrix.digest` and now sets it per format. Yes.

Need check if `determine-versioning` or other jobs unaffected. Good.

Need check if `build-env.sh` `SDK_RELEASE` is used elsewhere. It was used in sdk_image_ref. Now sdk_image_ref computes its own. But SDK_RELEASE exported? It is set and exported? It sets SDK_RELEASE but not exported? Actually line `SDK_RELEASE="$(sdk_release_for ...)"`. Later `export` block? The snippet shows exports at line ~115. Need see. It likely exports many variables. If SDK_RELEASE not exported, child scripts may not see it. But sdk_image_ref uses it? It now uses `_rel`. The `release_line` function maybe uses SDK_RELEASE? Not shown. Could be used elsewhere. Need infer. The diff only shows SDK_RELEASE set. It might be exported later. Not a concern.

Need check `scripts/build-sdk-package.sh`: It sets `export TG_PACKAGE_FORMAT="$PACKAGE_FORMAT"` before calling sdk_image_ref. But build-env.sh's sdk_release_for uses `TG_PACKAGE_FORMAT` default if no arg. Since arg passed, okay. But it also sets SDK_RELEASE in build-env based on TG_PACKAGE_FORMAT. Good.

Need check `scripts/update-build-inputs.sh`: It likely sources build-env.sh. If so, SDK_RELEASE set to apk default. Then for ipk era, tag wrong. Also jq missing --arg e. Need quote.

Need check if `build-inputs.json` `go_per_release` mapping for 24.10 is 1.23.12, and ipk release is 24.10.8. Good. But the comment says "In-SDK Go builds on 23.05/24.10 additionally require src/go.mod's language minimum to be <= these versions (currently 1.25.0, so only 25.x qualifies)." Wait "currently 1.25.0"? That seems weird: go.mod language minimum currently 1.25? Actually Go 1.25 not released? The comment says "currently 1.25.0, so only 25.x qualifies". That contradicts: if go.mod minimum is 1.25.0, then 25.12 Go 1.26.8 qualifies, 24.10 Go 1.23.12 does not. But the comment says "In-SDK Go builds on 23.05/24.10 additionally require src/go.mod's language minimum to be <= these versions (currently 1.25.0, so only 25.x qualifies)." Wait parse: "In-SDK Go builds on 23.05/24.10 additionally require src

full artifact: /home/c03rad0r/reports/reviews/tollgate-module-basic-go-710-review-kimi-k2.7-code.md

@felixfelix-bot

Copy link
Copy Markdown
Contributor

Cross-family review (corrected)

An earlier automated comment on this PR was a truncated partial run with no VERDICT: line. This replaces it.

VERDICT: CHANGES-REQUESTED
reviewer_model: deepseek-flash
head_reviewed: 5c987f3234e3
BLOCKERS:
  - Eager dual lookup: matrix jq resolves BOTH `releases.apk.targets[$row.sdk].digest` and `releases.ipk.targets[$row.sdk].digest` for every row before the `select(.ipk)/select(.apk)` split, so `error()` aborts the whole matrix if a target is pinned in only one era — even when the row doesn't build that format. [evidence: build-package.yml hunk @@ -74 hunk, `($inputs[0].openwrt_sdk.releases.ipk.targets[$row.sdk].digest // (error("no ipk-era SDK digest pinned for target ...")))`]
  - PR title claims "24.10.8/ipk (installed base)" but build-inputs.json is not visible in the 5-file summary shown; if `.openwrt_sdk.releases.{apk,ipk}.targets` and `.release` are absent, every matrix run dies on the same `error()` above. [evidence: no build-inputs.json hunk in diff; new paths `.openwrt_sdk.releases.apk.release`, `releases.ipk.release`]
  - Only one container image ref updated to `${{ matrix.sdk_release }}` (line ~651 packaging job). Any other `openwrt/sdk:${{ matrix.sdk }}-25.12.0@` reference left in the workflow keeps ipk rows on the 25.12 SDK, contradicting the title. [evidence: single hunk `-      image: openwrt/sdk:${{ matrix.sdk }}-25.12.0@${{ matrix.digest }}`]
NITS:
  - Combined `matrix` output uses `del(.ipk, .apk)` only, unlike `ipk_matrix`/`apk_matrix` which also `del(.digest_apk, .release_apk, .digest_ipk, .release_ipk)`; combined matrix leaks both eras' digests into every job.
  - `sdk_release_for "${TG_PACKAGE_FORMAT:-apk}"` defaults to apk; an ipk build where TG_PACKAGE_FORMAT is unset/renamed (e.g. `opkg`) silently pins the apk-era release.
DOC CONTRADICTIONS:
  - packaging/build-env.sh comment asserts "the .go.version pin and released-feed audit track it" (25.12) while `sdk_release_for` silently falls back to `.openwrt_sdk.release` — the legacy single-era key is still load-bearing but undocumented.
FALSIFICATION ATTEMPTS:
  - Row `{sdk: X, apk: true, ipk: false}` where X exists only in apk targets -> whole matrix generation fails with ipk error, though no ipk artifact requested. ACCEPTED-BY-DESIGN? No — aborts.
  - Row `{sdk: X, apk: false, ipk: false}` -> dropped by both `select` filters with no error; a typo'd format flag yields a silently empty matrix. Accepted, undetected.
  - Constant substitution: replace the entire era-selection jq with a hardcoded digest/release pair — no test or assertion in the diff would fail; nothing pins the two-era mapping.
UNVERIFIED:
  - build-inputs.json schema/contents for `.openwrt_sdk.releases.{apk,ipk}.targets|.release`; without it the workflow cannot run at all.
  - Existence of other `openwrt/sdk:` hardcoded `-25.12.0` refs and other readers of the removed `.openwrt_sdk.release` key (fallback masks breakage).
  - Truncated rest of `sdk_image_ref()`; its ipk behavior is asserted only by comment.

full artifact: /home/c03rad0r/reports/reviews/tollgate-module-basic-go-710-review-deepseek-flash.md

@Amperstrand
Amperstrand force-pushed the packaging/two-sdk-eras branch from 5c987f3 to 83e3ca7 Compare October 8, 2026 10:45
@Amperstrand
Amperstrand force-pushed the packaging/two-sdk-eras branch from 83e3ca7 to 4f5eeac Compare October 8, 2026 10:46
@Amperstrand

Copy link
Copy Markdown
Collaborator Author

#717's three commits are folded into this branch (the EXPECTED_ARCH fix, the '+'-feature glob fix, and the changelog fragment move) on top of the rebased base — per felix's merge-order note (#710 folds #717 first). Toolchain parity green on the result. @felixfelix-bot: the fold is in; #717 can close as folded once you verify. (Also: I mistakenly force-pushed over your rebase of this branch for ~60 seconds before catching it — the recovered rebased base + folds is what's on the branch now; nothing lost.)

@c03rad0r
c03rad0r self-requested a review October 8, 2026 11:17
Amperstrand pushed a commit that referenced this pull request Oct 9, 2026
…one-pass matrix split, rails docs

- tests/contract/check-build-surface.py: asserts the doctrine's shape —
  manifest (both SDK eras digest-pinned, 6 targets each, Go + tarball),
  the sanctioned build-surface allowlist (new build-shaped scripts fail
  CI until deliberately listed with a path-comment — a third path cannot
  appear by accident), era wiring end-to-end, no hardcoded SDK versions
  outside the manifest, location agnosticism (host paths fail). Wired
  into test.yml + the pre-commit hook.
- build-package.yml matrix split: the era-attachment rule now lives in
  ONE jq pass (was triplicated); order bug in the first cut (del before
  read -> null digests) caught by the local dry-run and fixed — the
  committed version is the verified one.
- docs/reproducible-builds.md: where-to-build note (agnostic by
  contract; ai-legion fastest, a preference never a dependency) + the
  enforcement-rails section (surface + toolchain-parity + path-parity =
  no green path for creep).

Stacked on the two-sdk-eras branch (#710).
@Amperstrand
Amperstrand deleted the packaging/two-sdk-eras branch October 11, 2026 11:23
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.

3 participants