[PR #2505] [MERGED] feat(recorded-crash): decode AArch64 core register notes #5282

Closed
opened 2026-10-31 01:05:25 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/2505
Author: @NIU-123370
Created: 10/13/2026
Status: ✅ Merged
Merged: 10/13/2026
Merged by: @morluto

Base: main ← Head: feat/recorded-crash-aarch64


📝 Commits (6)

  • 6055dc2 feat(recorded-crash): decode AArch64 core register notes
  • 34dfab1 fix(recorded-crash): bind the core header check and Evidence CPU to the profile
  • 39c82c1 test(recorded-crash): fold the AArch64 provider case into the scenario table
  • 4f55897 chore(ci): merge current main verification fixes
  • 88dc16c docs(recorded-crash): advertise AArch64 target support
  • 7fea123 docs(recorded-crash): distinguish architecture register layouts

📊 Changes

13 files changed (+532 additions, -90 deletions)

View changed files

📝 bridge/pwntools/recorded_crash_impl.py (+31 -10)
📝 docs/recorded-crashes.md (+8 -4)
📝 src/application/binaryDiagnostics/RecordedCrashService.test.ts (+23 -0)
📝 src/application/binaryDiagnostics/RecordedCrashService.ts (+4 -1)
📝 src/contracts/native/binaryDiagnosticsToolContracts.ts (+1 -1)
📝 src/domain/native/recordedCrash.test.ts (+94 -1)
📝 src/domain/native/recordedCrash.ts (+97 -6)
➕ src/native/pwntools/RecordedCrashSourceBindings.test.ts (+135 -0)
📝 src/native/pwntools/RecordedCrashSourceBindings.ts (+14 -11)
📝 src/native/pwntools/RecordedCrashStructureBindings.ts (+7 -2)
📝 tests/boundary/binaryDiagnostics/RecordedCrashStructureBindings.test.ts (+34 -0)
📝 tests/boundary/binaryDiagnostics/recordedCrashProvider.test.ts (+18 -5)
📝 tests/fixtures/binaryDiagnostics/recordedCrash.ts (+66 -49)

📄 Description

Summary

inspect_recorded_crash only ever admitted ELF64 x86-64 cores: the bridge refused every other e_machine and the domain schema pinned architecture to a single literal, so a legitimately recorded Linux AArch64 crash could not be inspected at all.

This adds the AArch64 profile from unchanged pwntools 4.15.0 structures — no locally re-declared ABI — and turns the previously amd64-only constants into one owned profile table.

Fixes #2353

ABI facts, measured not assumed

Read directly out of pwnlib/elf/datatypes.py from the official pwntools-4.15.0 wheel via ctypes:

Profile e_machine elf_prstatus size pr_reg offset pr_cursig / pr_pid registers
x86-64 (existing) 62 336 (0x150) 112 12 / 32 27 × c_uint64
AArch64 (new) 183 392 (0x188) 112 12 / 32 34 × c_uint64 (x0…x30, sp, pc, pstate)

The AArch64 register order is user_regs_struct_aarch64._fields_ order, which is the order the bridge already uses to emit registers, so the domain list and the bridge cannot drift silently. The amd64 list in the domain file was verified the same way (it matches _fields_ exactly), which is also what proves the existing profile was not accidentally reinterpreted here.

What changed

  • src/domain/native/recordedCrash.ts — one owned profile table RECORDED_LINUX_CORE_PROFILES (machine id, register order, register width, register offset, PRSTATUS size) plus RECORDED_LINUX_CORE_ARCHITECTURES. architecture becomes z.enum over that list, and thread validation now checks each register name, count and width against the reported architecture's profile instead of a hardcoded amd64 list.
  • bridge/pwntools/recorded_crash_impl.py — CORE_MACHINES = (62, 183); the profile selects elf_prstatus_aarch64 / user_regs_struct_aarch64 and the architecture label. Truncation messages name the selected profile. The unsupported-target refusal now reports the observed e_machine instead of only saying "requires x86-64".
  • src/native/pwntools/RecordedCrashSourceBindings.ts — register source offsets and the minimum descriptor length now come from the same profile table, so a 34-register/392-byte AArch64 thread is bound slot by slot exactly like amd64's 27/336.
  • tests/fixtures/binaryDiagnostics/recordedCrash.ts — the source-owned fixtures derive note, owner and descriptor ranges from the profile (identical bytes to today for x86-64: 0x80/0x8c/0x94, 0x164, 0x150) and now stamp the matching e_machine.
  • docs/recorded-crashes.md — states both profiles and that any other machine is refused before note interpretation.

Verification

Real decode, run locally. I assembled the decoder's actual dependencies and ran the repo's recorded_crash_impl.py unchanged against crafted cores:

  • AArch64 core: architecture = aarch64-little-endian, 34 registers named x0…x30, sp, pc, pstate, every reported register offset equal to descriptor + 112 + index*8, all values round-tripped, PID and cursor signal recovered from pr_pid@32 / pr_cursig@12, and the SIGSEGV fault address decoded from NT_SIGINFO.
  • x86-64 core: unchanged behaviour — 27 registers, x86_64-little-endian, same offsets.
  • 391-byte AArch64 descriptor → format: Linux AArch64 NT_PRSTATUS descriptor is truncated.
  • e_machine = 243 (RISC-V) → unsupported-target naming the observed machine.

Honest limits of that harness: pyelftools 0.33 is the real package and pwnlib/elf/datatypes.py is the verbatim file from the official 4.15.0 wheel, but unicorn 2.1.2 is satisfied by a metadata stub because no macOS arm64 wheel builds here — the recorded-crash path never imports unicorn, only the version preflight reads it. The harness lives in /tmp and is not part of the commit. If you want it in-repo I will add it as a unittest that skips when pwntools 4.15.0 is not importable, so test:python stays green without the dependency.

TypeScript. New src/native/pwntools/RecordedCrashSourceBindings.test.ts (7 cases) binds every register for both profiles, pins each profile's numbers against the ABI table above rather than only using them consistently, asserts the crafted core's e_machine equals its profile's machine, and rejects: a register bound one slot off, a descriptor shorter than the profile size, an amd64 name inside an AArch64 window, and a reported PID that differs from the source bytes. src/domain/native/recordedCrash.test.ts gains 6 cases: the full AArch64 window accepted, its note ranges inside the segment, and rejection of an amd64 name, the amd64 count, a 4-byte register source, and an architecture outside the profiles.

Gate Result
vitest --project domain --project services --project adapters 388 files / 5044 tests passed, 7 skipped
my four touched suites (domain, adapters pwntools, services binaryDiagnostics, boundary binaryDiagnostics) 67 passed, 71 skipped (Linux/x64-only lanes)
tsc --noEmit -p tsconfig.json clean
oxfmt --check clean
npx knip clean
oxlint 0 errors; the 2 warnings are the same on untouched origin/main for the same files

The provider suite for this lane (tests/boundary/binaryDiagnostics/recordedCrashProvider.test.ts, 34 cases) is runIf(linux && x64) and the adapter itself refuses non-Linux hosts, so to check my fixture rewrite I temporarily bypassed both gates, ran all 34 green, then reverted both. The committed diff contains no bypass; git diff for that test file is empty.

npx vitest --project boundary on this machine shows 8 failures in four files (setupSkill, two inspector/javascriptRuntime*, nativeDmgArtifactReader). None of them read recorded-crash code, and on untouched origin/main at the same commit the same four files fail 14 cases — after normalizing names, my failure set is a strict subset with zero cases unique to this diff. So these are macOS host/pre-existing failures, not regressions here.

Mutation arms (each run, each killed)

Arm Killed by
bridge machine not in CORE_MACHINES → machine != 62 harness AArch64 decode refused
bridge truncation check forced to the amd64 structure harness accepted a 391-byte AArch64 descriptor
profile prstatusBytes: 392 → 336 4 binding/domain cases
profile registerOffset: 112 → 120 the pinned ABI numbers case
drop AArch64 from the architecture enum 2 domain cases
validation ignores the reported architecture (always amd64) 2 AArch64 domain cases

Deliberately not in this PR

  • docs/recorded-crashes.md's "Bounds and verification" paragraph is untouched on purpose: my own #2486 rewrites that exact paragraph, and editing it twice would guarantee a conflict between the two PRs.
  • Live AArch64 recording. The real-recorded-crash.yml lane builds its fixture with gcc on ubuntu-24.04, so it can only ever produce x86-64 cores; an AArch64 recording needs an arm64 runner or qemu and is a CI decision, not a decoder change. The acceptance criteria here are met with profile-bound synthetic bytes plus the real decode above.
  • Sibling profiles #2355 (Windows minidump) and #2369 (BTF) reuse this table shape but need their own structs.

Collision surface

I indexed the changed files of all 202 open PRs earlier in this session: all seven files this PR touches were free of any in-flight PR. That index is a snapshot, so a rebase before merge is still worth doing; the branch is currently rebased onto c74142e6 with one commit.

Base: c74142e6. Head: 3 commits, 12 files, +529 −88. Trunk has moved 58 commits since that base and git log HEAD..origin/main -- <these twelve paths> returns 0 hits (positive control: the same command finds 3 hits for a file trunk did change), so nothing has been rewritten under this branch. The round-1 files (RecordedCrashStructureBindings.ts, RecordedCrashService.ts and its test) were not in the 202-PR index above, so that snapshot does not cover them; a re-scan or rebase before merge is still worth doing.

Review round 1 (Greptile P1 ×2)

Both findings were correct: the AArch64 profile reached the bridge and the domain, but two downstream consumers still pinned amd64, so nothing actually arrived. Fixed in the second commit.

site was now
src/native/pwntools/RecordedCrashStructureBindings.ts header.readUInt16LE(18) !== 62, so PwntoolsRecordedCrashProvider refused an AArch64 core before the widened register checks ran compares the header against RECORDED_LINUX_CORE_PROFILES[report.architecture].machine
src/application/binaryDiagnostics/RecordedCrashService.ts literal architecture: "x86_64" on every created Evidence RECORDED_LINUX_CORE_PROFILES[value.architecture].evidenceArchitecture
src/domain/native/recordedCrash.ts profile had no Evidence CPU family profile owns evidenceArchitecture: BinaryArchitecture (x86_64 / arm64)

New cases: each profile is admitted by its own e_machine and rejected when the header carries the other profile's machine; created Evidence is pinned per profile; and success-aarch64 runs an AArch64 core through the full provider pipeline as a row of the existing scenario table.

Mutation arms (each run, then reverted from backup and cmp-verified)

arm mutation result
A machine hard-coded back to 62 structure bindings 2 failed / 6 passed
B accept 62 or 183 regardless of the reported profile 2 failed / 6 passed — the guard is bound to the report, not merely widened
C service literal back to "x86_64" service 1 failed / 11 passed
D profile maps AArch64 to arm service 1 failed / 11 passed
E arm A with the Linux lane opened (below) success-aarch64 fails with Reported core structure differs from its original ELF/note headers.

How the host-gated provider case was executed here

tests/boundary/binaryDiagnostics/recordedCrashProvider.test.ts is .runIf(process.platform === "linux" && process.arch === "x64") and PwntoolsDecoder refuses any other host, so all 35 of its cases skip on macOS. To run them I temporarily (1) turned that host check into if (false) and (2) set the test file's host constant to true, ran the file — 35 passed / 0 failed — then restored both files from backup and re-verified with cmp plus grep -c = 0 for each marker. The bridge is stubbed by the test's own launcher, so no pwntools/Python executed in that experiment; the Linux CI lane still covers the real decode.

Local gates for this commit

tsc --noEmit clean. oxfmt --check clean on all six changed files. oxlint on those six: 0 errors, 4 warnings — the same four warnings as at 6055dc26, verified by linting both trees, so no new warning is introduced. Platform-independent selection: structure bindings 8, RecordedCrashService 12, domain 29, source bindings 8 passed; the MCP + CLI-cleanup + stage-retirement selection passed 11 with 35 skipped (only the host-gated provider file).

Static checks round (jscpd)

34dfab14 failed one CI lane: Static checks → step Run npm run check:ci → jscpd, with
ERROR: jscpd found too many duplicates (3.0%) over threshold (3.0%) — 2368 files, 1484 clones, 3.01% duplicated
lines
against a 3.0% budget. The clone was mine: the standalone AArch64 case restated that file's own bridge stub
(recordedCrashProvider.test.ts lines 91:68–101:14 ↔ 153:5–163:14 and 109:20–121:28 ↔ 169:35–181:28).

39c82c17 drops the second copy and makes success-aarch64 a row of the scenario table that already drives a reply
through the structure, source and register bindings, so the assertion set is the same one its sibling scenarios in that table run,
plus expect(result.value.architecture).toBe(architecture).

Measured locally with npm run jscpd on the same .jscpd.json: 6055dc26 = 1429 clones / 2.98%, 34dfab14 = 1431
clones / 2.99%, 39c82c17 = 1429 clones / 2.98% — back on the baseline the previously-green commit sat at, and
jscpd:details no longer lists this file. Local totals differ slightly from CI's (CI counts generated files too), so
the claim is the delta, not the absolute. tsc --noEmit, oxfmt --check and the platform-independent suites are
unchanged by this commit.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/2505 **Author:** [@NIU-123370](https://github.com/NIU-123370) **Created:** 10/13/2026 **Status:** ✅ Merged **Merged:** 10/13/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `feat/recorded-crash-aarch64` --- ### 📝 Commits (6) - [`6055dc2`](https://github.com/morluto/rea/commit/6055dc2609cc514ec09401c823ced39e01de69fd) feat(recorded-crash): decode AArch64 core register notes - [`34dfab1`](https://github.com/morluto/rea/commit/34dfab14c85147c180cc41e067fc93bdad720948) fix(recorded-crash): bind the core header check and Evidence CPU to the profile - [`39c82c1`](https://github.com/morluto/rea/commit/39c82c17934f5a492aa14a90bbb73f8bee1aace6) test(recorded-crash): fold the AArch64 provider case into the scenario table - [`4f55897`](https://github.com/morluto/rea/commit/4f55897925682e11a73b911ac9ffa54dfd14bc09) chore(ci): merge current main verification fixes - [`88dc16c`](https://github.com/morluto/rea/commit/88dc16c0ab5794c822de59c43733250d55f1233d) docs(recorded-crash): advertise AArch64 target support - [`7fea123`](https://github.com/morluto/rea/commit/7fea12343827432b9d1a361c68a4a4fcf99db66c) docs(recorded-crash): distinguish architecture register layouts ### 📊 Changes **13 files changed** (+532 additions, -90 deletions) <details> <summary>View changed files</summary> 📝 `bridge/pwntools/recorded_crash_impl.py` (+31 -10) 📝 `docs/recorded-crashes.md` (+8 -4) 📝 `src/application/binaryDiagnostics/RecordedCrashService.test.ts` (+23 -0) 📝 `src/application/binaryDiagnostics/RecordedCrashService.ts` (+4 -1) 📝 `src/contracts/native/binaryDiagnosticsToolContracts.ts` (+1 -1) 📝 `src/domain/native/recordedCrash.test.ts` (+94 -1) 📝 `src/domain/native/recordedCrash.ts` (+97 -6) ➕ `src/native/pwntools/RecordedCrashSourceBindings.test.ts` (+135 -0) 📝 `src/native/pwntools/RecordedCrashSourceBindings.ts` (+14 -11) 📝 `src/native/pwntools/RecordedCrashStructureBindings.ts` (+7 -2) 📝 `tests/boundary/binaryDiagnostics/RecordedCrashStructureBindings.test.ts` (+34 -0) 📝 `tests/boundary/binaryDiagnostics/recordedCrashProvider.test.ts` (+18 -5) 📝 `tests/fixtures/binaryDiagnostics/recordedCrash.ts` (+66 -49) </details> ### 📄 Description ## Summary `inspect_recorded_crash` only ever admitted ELF64 x86-64 cores: the bridge refused every other `e_machine` and the domain schema pinned `architecture` to a single literal, so a legitimately recorded Linux AArch64 crash could not be inspected at all. This adds the AArch64 profile from **unchanged pwntools 4.15.0 structures** — no locally re-declared ABI — and turns the previously amd64-only constants into one owned profile table. Fixes #2353 ## ABI facts, measured not assumed Read directly out of `pwnlib/elf/datatypes.py` from the official `pwntools-4.15.0` wheel via `ctypes`: | Profile | `e_machine` | `elf_prstatus` size | `pr_reg` offset | `pr_cursig` / `pr_pid` | registers | | --- | --- | --- | --- | --- | --- | | x86-64 (existing) | 62 | 336 (`0x150`) | 112 | 12 / 32 | 27 × `c_uint64` | | AArch64 (new) | 183 | 392 (`0x188`) | 112 | 12 / 32 | 34 × `c_uint64` (`x0`…`x30`, `sp`, `pc`, `pstate`) | The AArch64 register order is `user_regs_struct_aarch64._fields_` order, which is the order the bridge already uses to emit registers, so the domain list and the bridge cannot drift silently. The amd64 list in the domain file was verified the same way (it matches `_fields_` exactly), which is also what proves the existing profile was not accidentally reinterpreted here. ## What changed - `src/domain/native/recordedCrash.ts` — one owned profile table `RECORDED_LINUX_CORE_PROFILES` (machine id, register order, register width, register offset, PRSTATUS size) plus `RECORDED_LINUX_CORE_ARCHITECTURES`. `architecture` becomes `z.enum` over that list, and thread validation now checks each register name, count and width **against the reported architecture's profile** instead of a hardcoded amd64 list. - `bridge/pwntools/recorded_crash_impl.py` — `CORE_MACHINES = (62, 183)`; the profile selects `elf_prstatus_aarch64` / `user_regs_struct_aarch64` and the `architecture` label. Truncation messages name the selected profile. The `unsupported-target` refusal now reports the observed `e_machine` instead of only saying "requires x86-64". - `src/native/pwntools/RecordedCrashSourceBindings.ts` — register source offsets and the minimum descriptor length now come from the same profile table, so a 34-register/392-byte AArch64 thread is bound slot by slot exactly like amd64's 27/336. - `tests/fixtures/binaryDiagnostics/recordedCrash.ts` — the source-owned fixtures derive note, owner and descriptor ranges from the profile (identical bytes to today for x86-64: `0x80`/`0x8c`/`0x94`, `0x164`, `0x150`) and now stamp the matching `e_machine`. - `docs/recorded-crashes.md` — states both profiles and that any other machine is refused before note interpretation. ## Verification **Real decode, run locally.** I assembled the decoder's actual dependencies and ran the repo's `recorded_crash_impl.py` unchanged against crafted cores: - AArch64 core: `architecture = aarch64-little-endian`, 34 registers named `x0…x30, sp, pc, pstate`, every reported register offset equal to `descriptor + 112 + index*8`, all values round-tripped, PID and cursor signal recovered from `pr_pid@32` / `pr_cursig@12`, and the SIGSEGV fault address decoded from `NT_SIGINFO`. - x86-64 core: unchanged behaviour — 27 registers, `x86_64-little-endian`, same offsets. - 391-byte AArch64 descriptor → `format: Linux AArch64 NT_PRSTATUS descriptor is truncated.` - `e_machine = 243` (RISC-V) → `unsupported-target` naming the observed machine. Honest limits of that harness: `pyelftools 0.33` is the real package and `pwnlib/elf/datatypes.py` is the verbatim file from the official 4.15.0 wheel, but `unicorn 2.1.2` is satisfied by a metadata stub because no macOS arm64 wheel builds here — the recorded-crash path never imports unicorn, only the version preflight reads it. The harness lives in `/tmp` and is not part of the commit. If you want it in-repo I will add it as a `unittest` that skips when pwntools 4.15.0 is not importable, so `test:python` stays green without the dependency. **TypeScript.** New `src/native/pwntools/RecordedCrashSourceBindings.test.ts` (7 cases) binds every register for *both* profiles, pins each profile's numbers against the ABI table above rather than only using them consistently, asserts the crafted core's `e_machine` equals its profile's machine, and rejects: a register bound one slot off, a descriptor shorter than the profile size, an amd64 name inside an AArch64 window, and a reported PID that differs from the source bytes. `src/domain/native/recordedCrash.test.ts` gains 6 cases: the full AArch64 window accepted, its note ranges inside the segment, and rejection of an amd64 name, the amd64 count, a 4-byte register source, and an architecture outside the profiles. | Gate | Result | | --- | --- | | `vitest --project domain --project services --project adapters` | 388 files / 5044 tests passed, 7 skipped | | my four touched suites (domain, adapters pwntools, services binaryDiagnostics, boundary binaryDiagnostics) | 67 passed, 71 skipped (Linux/x64-only lanes) | | `tsc --noEmit -p tsconfig.json` | clean | | `oxfmt --check` | clean | | `npx knip` | clean | | `oxlint` | 0 errors; the 2 warnings are the same on untouched `origin/main` for the same files | The provider suite for this lane (`tests/boundary/binaryDiagnostics/recordedCrashProvider.test.ts`, 34 cases) is `runIf(linux && x64)` **and** the adapter itself refuses non-Linux hosts, so to check my fixture rewrite I temporarily bypassed both gates, ran all 34 green, then reverted both. The committed diff contains no bypass; `git diff` for that test file is empty. `npx vitest --project boundary` on this machine shows 8 failures in four files (`setupSkill`, two `inspector/javascriptRuntime*`, `nativeDmgArtifactReader`). None of them read recorded-crash code, and on untouched `origin/main` at the same commit the same four files fail 14 cases — after normalizing names, my failure set is a strict **subset** with zero cases unique to this diff. So these are macOS host/pre-existing failures, not regressions here. ## Mutation arms (each run, each killed) | Arm | Killed by | | --- | --- | | bridge `machine not in CORE_MACHINES` → `machine != 62` | harness AArch64 decode refused | | bridge truncation check forced to the amd64 structure | harness accepted a 391-byte AArch64 descriptor | | profile `prstatusBytes: 392` → `336` | 4 binding/domain cases | | profile `registerOffset: 112` → `120` | the pinned ABI numbers case | | drop AArch64 from the architecture enum | 2 domain cases | | validation ignores the reported architecture (always amd64) | 2 AArch64 domain cases | ## Deliberately not in this PR - `docs/recorded-crashes.md`'s "Bounds and verification" paragraph is untouched on purpose: my own #2486 rewrites that exact paragraph, and editing it twice would guarantee a conflict between the two PRs. - Live AArch64 recording. The `real-recorded-crash.yml` lane builds its fixture with `gcc` on `ubuntu-24.04`, so it can only ever produce x86-64 cores; an AArch64 recording needs an arm64 runner or qemu and is a CI decision, not a decoder change. The acceptance criteria here are met with profile-bound synthetic bytes plus the real decode above. - Sibling profiles #2355 (Windows minidump) and #2369 (BTF) reuse this table shape but need their own structs. ## Collision surface I indexed the changed files of all 202 open PRs earlier in this session: all seven files this PR touches were free of any in-flight PR. That index is a snapshot, so a rebase before merge is still worth doing; the branch is currently rebased onto `c74142e6` with one commit. Base: `c74142e6`. Head: 3 commits, 12 files, +529 −88. Trunk has moved 58 commits since that base and `git log HEAD..origin/main -- <these twelve paths>` returns 0 hits (positive control: the same command finds 3 hits for a file trunk did change), so nothing has been rewritten under this branch. The round-1 files (`RecordedCrashStructureBindings.ts`, `RecordedCrashService.ts` and its test) were not in the 202-PR index above, so that snapshot does not cover them; a re-scan or rebase before merge is still worth doing. ## Review round 1 (Greptile P1 ×2) Both findings were correct: the AArch64 profile reached the bridge and the domain, but two downstream consumers still pinned amd64, so nothing actually arrived. Fixed in the second commit. | site | was | now | | --- | --- | --- | | `src/native/pwntools/RecordedCrashStructureBindings.ts` | `header.readUInt16LE(18) !== 62`, so `PwntoolsRecordedCrashProvider` refused an AArch64 core before the widened register checks ran | compares the header against `RECORDED_LINUX_CORE_PROFILES[report.architecture].machine` | | `src/application/binaryDiagnostics/RecordedCrashService.ts` | literal `architecture: "x86_64"` on every created Evidence | `RECORDED_LINUX_CORE_PROFILES[value.architecture].evidenceArchitecture` | | `src/domain/native/recordedCrash.ts` | profile had no Evidence CPU family | profile owns `evidenceArchitecture: BinaryArchitecture` (`x86_64` / `arm64`) | New cases: each profile is admitted by its own `e_machine` and rejected when the header carries the other profile's machine; created Evidence is pinned per profile; and `success-aarch64` runs an AArch64 core through the full provider pipeline as a row of the existing scenario table. ### Mutation arms (each run, then reverted from backup and `cmp`-verified) | arm | mutation | result | | --- | --- | --- | | A | machine hard-coded back to `62` | structure bindings **2 failed / 6 passed** | | B | accept `62` *or* `183` regardless of the reported profile | **2 failed / 6 passed** — the guard is bound to the report, not merely widened | | C | service literal back to `"x86_64"` | service **1 failed / 11 passed** | | D | profile maps AArch64 to `arm` | service **1 failed / 11 passed** | | E | arm A with the Linux lane opened (below) | `success-aarch64` fails with `Reported core structure differs from its original ELF/note headers.` | ### How the host-gated provider case was executed here `tests/boundary/binaryDiagnostics/recordedCrashProvider.test.ts` is `.runIf(process.platform === "linux" && process.arch === "x64")` and `PwntoolsDecoder` refuses any other host, so all 35 of its cases skip on macOS. To run them I temporarily (1) turned that host check into `if (false)` and (2) set the test file's `host` constant to `true`, ran the file — **35 passed / 0 failed** — then restored both files from backup and re-verified with `cmp` plus `grep -c` = 0 for each marker. The bridge is stubbed by the test's own launcher, so no pwntools/Python executed in that experiment; the Linux CI lane still covers the real decode. ### Local gates for this commit `tsc --noEmit` clean. `oxfmt --check` clean on all six changed files. `oxlint` on those six: **0 errors, 4 warnings — the same four warnings as at `6055dc26`**, verified by linting both trees, so no new warning is introduced. Platform-independent selection: structure bindings 8, `RecordedCrashService` 12, domain 29, source bindings 8 passed; the MCP + CLI-cleanup + stage-retirement selection passed 11 with 35 skipped (only the host-gated provider file). ## Static checks round (jscpd) `34dfab14` failed one CI lane: `Static checks` → step `Run npm run check:ci` → `jscpd`, with `ERROR: jscpd found too many duplicates (3.0%) over threshold (3.0%)` — 2368 files, 1484 clones, **3.01% duplicated lines** against a 3.0% budget. The clone was mine: the standalone AArch64 case restated that file's own bridge stub (`recordedCrashProvider.test.ts` lines 91:68–101:14 ↔ 153:5–163:14 and 109:20–121:28 ↔ 169:35–181:28). `39c82c17` drops the second copy and makes `success-aarch64` a row of the scenario table that already drives a reply through the structure, source and register bindings, so the assertion set is the same one its sibling scenarios in that table run, plus `expect(result.value.architecture).toBe(architecture)`. Measured locally with `npm run jscpd` on the same `.jscpd.json`: `6055dc26` = 1429 clones / 2.98%, `34dfab14` = 1431 clones / 2.99%, `39c82c17` = **1429 clones / 2.98%** — back on the baseline the previously-green commit sat at, and `jscpd:details` no longer lists this file. Local totals differ slightly from CI's (CI counts generated files too), so the claim is the delta, not the absolute. `tsc --noEmit`, `oxfmt --check` and the platform-independent suites are unchanged by this commit. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:05:25 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#5282
No description provided.