[PR #3583] [CLOSED] fix(native): check every slice of a signed universal Mach-O #5837

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

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/3583
Author: @hemanthrayuduu
Created: 10/14/2026
Status: ❌ Closed

Base: main ← Head: fix/signature-unsigned-slices


📝 Commits (1)

  • 37c5216 fix(native): check every slice of a signed universal Mach-O

📊 Changes

7 files changed (+217 additions, -34 deletions)

View changed files

📝 src/native/NativeMacOSProvider.ts (+43 -24)
📝 tests/boundary/providers/native/nativeInventory.golden.test.ts (+110 -5)
📝 tests/boundary/providers/native/nativeSignatureTargetBinding.test.ts (+7 -5)
➕ tests/fixtures/native-macos/codesign-universal-slices/README.md (+25 -0)
➕ tests/fixtures/native-macos/codesign-universal-slices/display.txt (+30 -0)
➕ tests/fixtures/native-macos/codesign-universal-slices/requirements.txt (+1 -0)
➕ tests/fixtures/native-macos/codesign-universal-slices/slice-unsigned.txt (+1 -0)

📄 Description

Summary

inspect_signature reports a universal Mach-O as fully signed when one of its slices is unsigned, as long as the signed slices carry an identity signature rather than an ad hoc one. On macOS 27.0.1, a copy of /bin/ls with its x86_64 slice unsigned returns signed: true and the same limitations as the real /bin/ls, with nothing about the unsigned slice.

The mixed-signature handling from #701 (for #684) looks at individual slices only when the aggregate codesign -d -r- or --entitlements query reports "not signed". That works for ad hoc signatures, because an ad hoc designated requirement lists every slice's CDHash. An identity requirement such as identifier "com.apple.ls" and anchor apple comes from codesign's default slice, so the query succeeds and the unsigned slice is never noticed.

With this change, a signed universal file is checked slice by slice and unsigned slices are reported with the existing Unsigned Mach-O slices: … limitation. I didn't open an issue first: this is the case #684's acceptance criterion describes ("that result should state that the x86_64 slice is unsigned rather than report the file as signed without qualification"), only for identity-signed files, and the result shape doesn't change.

Problem and expected behavior

Smallest trigger: rebuild /bin/ls with an unsigned x86_64 slice and inspect it. The system file isn't modified.

lipo /bin/ls -thin x86_64 -output ls-x86_64
lipo /bin/ls -thin arm64e -output ls-arm64e
lipo /bin/ls -thin arm64e.x1 -output ls-x1
codesign --remove-signature ls-x86_64
lipo -create ls-x86_64 ls-arm64e ls-x1 -output mixed-x86
rea inspect-signature mixed-x86 --format json

codesign -d --verbose=4, codesign -d -r- and codesign -d --entitlements :- all exit 0 on that file. Only codesign -d -a x86_64 reports "code object is not signed at all". The broken invariant: when slices of one file are signed differently, the result should say which slice is unsigned instead of reporting signed: true without qualification.

A second, smaller defect is in the same function. codeSignArchitectures kept only i386|x86_64|armv7|arm64|arm64e from codesign's Format=Mach-O universal (…) list. macOS 27 system binaries also have an arm64e.x1 slice, which codesign -a arm64e.x1 accepts, so that slice was never queried even on the existing mixed-signature path.

Change and scope

All in src/native/NativeMacOSProvider.ts:

  • When codesign displays a signed universal file that lists more than one slice, inspect_signature now runs codesign -d -a <architecture> --verbose=4 for each slice. Before, it did this only when the aggregate requirement or entitlements query had already reported "not signed".
  • The slice names come from codesign's own Format= line, and any name token it prints is accepted, so arm64e.x1 is now included.
  • The "One or more Mach-O slices are unsigned, but their architectures could not be classified" limitation is now added only when the aggregate queries reported an unsigned slice. A fully signed universal file gets no slice limitation.
  • The aggregate requirement and entitlements limitations are unchanged; they still appear only when those queries fail.
  • #inspectMixedSignatureSlices and MixedSignatureSlices are renamed #inspectSignatureSlices and SignatureSlices, since they now run for every signed universal file.

The cost is one extra codesign run per slice for signed universal files: 3 for /bin/ls. Each run goes through the same #captureSignature path, so it reads the registered snapshot and checks the target identity before and after.

Not included:

  • When codesign's default slice is the unsigned one, the aggregate display itself says "not signed at all". rea then reports the whole file as signed: false with "Artifact is not signed.", even if its other slices are signed. On this Mac (M2, macOS 27.0.1), codesign's default slice is arm64e.x1, so a copy of /bin/ls with only that slice unsigned returns signed: false. Fixing that needs a decision about what signed should mean for a partly signed file, and the per-slice names would have to come from somewhere other than the unsigned display, so I've left it out. I'm happy to open an issue for it.

Contribution scope: an ordinary fix within the existing inspect_signature boundary.

Contract and boundary impact

  • Semantic owner and earliest changed stage: per-slice signature classification in the native macOS provider (#inspectBoundSignature and #inspectSignatureSlices). The codesign output parser is unchanged.
  • Contribution scope fit and linked maintainer decision: not applicable (ordinary fix within existing boundaries).
  • CLI and MCP/tool-catalog contract: no schema change. For an identity-signed universal file with an unsigned slice, limitations now includes Unsigned Mach-O slices: <arch>.. Signed universal files now have extra codesign -d -a <arch> --verbose=4 entries in provenance.
  • Provider, bridge, target-format, or platform compatibility: native macOS provider only. Thin files and fully unsigned files take the same path as before.
  • Evidence, artifact, provenance, or reconstruction contract: each per-slice query is recorded in provenance with its exit status. Unsigned slices are named in a limitation, and slices whose state codesign couldn't establish keep the existing "could not be classified" limitation.
  • Target selection, authority, upstream behavior, and cleanup details: the extra codesign calls read the same digest-verified snapshot as the existing ones; nothing else changes.
  • Generated metadata (docs/public/product-catalog.json), package, or installation impact: none.

Expected effects:

  • Read existing files or captured data.
  • Launch or attach to a process.
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

Evidence and regression coverage

  • Tests added or updated:

    • tests/boundary/providers/native/nativeInventory.golden.test.ts:
      • x86_64 or arm64e unsigned while the aggregate signature and requirement succeed, using real codesign captures from the mixed-x86 file above. These are in tests/fixtures/native-macos/codesign-universal-slices/, with a README.
      • An unsigned arm64e.x1 slice on the existing ad hoc mixed path.
      • A fully signed universal file, which must get no slice limitation.
      • The existing signatureRunner helper gained two options, a successful aggregate requirement and a list of unsigned slices, and its defaults keep the earlier tests unchanged.
    • tests/boundary/providers/native/nativeSignatureTargetBinding.test.ts: the real-codesign directory-swap test copies /usr/bin/true, which is universal (x86_64, arm64e, arm64e.x1). It expected exactly three codesign calls. It now checks that every call, including the per-slice ones, reads the registered snapshot ($ARTIFACT).
  • Base reproduction or other evidence: with only the test changes applied on c7105d9, nativeInventory.golden.test.ts gave 3 failed and 18 passed. The two identity-signed cases had no Unsigned Mach-O slices limitation, and the arm64e.x1 case got "could not be classified" because that slice was never queried. The fully signed control and the existing #701 test passed.

  • User-visible CLI/MCP output: node scripts/rea.mjs inspect-signature <path> --format json on macOS 27.0.1 (26A434), Apple M2, built from c7105d9 before the change and from this branch after it. The composites are copies of /bin/ls built as above, and the #684 control is clang -arch x86_64 -arch arm64 with clang's default signing:

    Target Real slice states Before After
    /bin/ls all signed signed: true, no slice limitation the same, with 3 per-slice queries, all exit 0
    mixed-x86 x86_64 unsigned signed: true, no slice limitation, the same output as /bin/ls signed: true, Unsigned Mach-O slices: x86_64.
    mixed-arm64e arm64e unsigned signed: true, no slice limitation signed: true, Unsigned Mach-O slices: arm64e.
    #684 control arm64 ad hoc signed, x86_64 unsigned Unsigned Mach-O slices: x86_64. plus the aggregate requirement limitation unchanged
    /bin/ls with only arm64e.x1 unsigned x1 unsigned (codesign's default slice here) signed: false, "Artifact is not signed." unchanged (not included, above)
  • Remaining proof gaps:

    • I ran this on one Apple Silicon Mac. Which slice codesign uses by default may differ on other hardware, which changes which files take the aggregate-unsigned path.
    • I didn't test x86_64h or other variant names in a codesign Format= line, beyond arm64e.x1.
    • I didn't measure how much the extra per-slice queries add to run time.

For evidence-bearing changes:

  • Observed, derived, and inferred claims remain distinguishable.
  • Artifact identity, source provenance, and failed attempts remain preserved.
  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

All with Node 24.18.0 and npm 11.16.0 on macOS 27.0.1, arm64. I developed on c7105d9 and then rebased onto 569ef41 (the rebase was clean). The last list below is what I re-ran on the rebased branch.

  • npm ci: installed.
  • npm run test:focused -- tests/boundary/providers/native/nativeInventory.golden.test.ts with only the test changes on c7105d9: 3 failed, 18 passed. After the fix: 21 passed.
  • npm run test:focused -- tests/boundary/providers/native/nativeInventory.golden.test.ts src/native/SignatureTargetBinding.test.ts tests/boundary/cli/nativeSignatureCli.test.ts tests/boundary/mcp/nativeSignatureTargetBindingMcp.test.ts tests/boundary/providers/native/nativeProvider.test.ts tests/boundary/providers/native/nativeSignatureTargetBinding.test.ts src/domain/apple/appleApplication.test.ts: 7 files, 119 tests passed.
  • npm run check: passed.
  • npm run check:fast: passed.
  • npm run verify:test-discovery: "Discovered all 1233 test files exactly once."
  • git diff --check: clean.
  • npm run build:cached: passed, before and after.
  • npm run test:fast: 7264 passed, 5 failed, 13 skipped. The 5 failures are in JavaScriptSemanticGraphResources.test.ts, electronWrappedCallPaths.test.ts, javascriptSemanticAmbientWrites.test.ts, javascriptSemanticAnalysis.native_bindings.test.ts and IdaNativeProtocol.test.ts. The same 5 fail on c7105d9 without this change (5 failed, 87 passed in those files).
  • The CLI runs in the table above, before and after.

After rebasing onto 569ef41:

  • npm ci, then the same 7-file npm run test:focused command: 125 tests passed.
  • npm run check: passed. npm run verify:test-discovery: "Discovered all 1285 test files exactly once."
  • npm run build:cached, then the same CLI runs: the same results as the "After" column.
  • I didn't re-run npm run test:fast after the rebase.

Compatibility, safety, and release

  • Breaking changes or migration steps: none. Callers see an added limitation for the affected files and extra provenance entries for signed universal files.
  • Real Hopper/Ghidra, browser, or OS coverage: real macOS 27.0.1 codesign, through the CLI runs above and the existing real-codesign directory-swap test. I didn't run Hopper or Ghidra, and neither is touched.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: no new tools or paths. The added codesign -d -a calls read the same snapshot under the same target-identity checks. Slice names passed to -a must match ^[A-Za-z0-9_]+(?:\.[A-Za-z0-9_]+)?$, so a name can't start with -.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🤖 Generated with Claude Code


🔄 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/3583 **Author:** [@hemanthrayuduu](https://github.com/hemanthrayuduu) **Created:** 10/14/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix/signature-unsigned-slices` --- ### 📝 Commits (1) - [`37c5216`](https://github.com/morluto/rea/commit/37c5216f8b4e0e4662255c95016f728ba944274d) fix(native): check every slice of a signed universal Mach-O ### 📊 Changes **7 files changed** (+217 additions, -34 deletions) <details> <summary>View changed files</summary> 📝 `src/native/NativeMacOSProvider.ts` (+43 -24) 📝 `tests/boundary/providers/native/nativeInventory.golden.test.ts` (+110 -5) 📝 `tests/boundary/providers/native/nativeSignatureTargetBinding.test.ts` (+7 -5) ➕ `tests/fixtures/native-macos/codesign-universal-slices/README.md` (+25 -0) ➕ `tests/fixtures/native-macos/codesign-universal-slices/display.txt` (+30 -0) ➕ `tests/fixtures/native-macos/codesign-universal-slices/requirements.txt` (+1 -0) ➕ `tests/fixtures/native-macos/codesign-universal-slices/slice-unsigned.txt` (+1 -0) </details> ### 📄 Description ## Summary `inspect_signature` reports a universal Mach-O as fully signed when one of its slices is unsigned, as long as the signed slices carry an identity signature rather than an ad hoc one. On macOS 27.0.1, a copy of `/bin/ls` with its x86_64 slice unsigned returns `signed: true` and the same limitations as the real `/bin/ls`, with nothing about the unsigned slice. The mixed-signature handling from #701 (for #684) looks at individual slices only when the aggregate `codesign -d -r-` or `--entitlements` query reports "not signed". That works for ad hoc signatures, because an ad hoc designated requirement lists every slice's CDHash. An identity requirement such as `identifier "com.apple.ls" and anchor apple` comes from codesign's default slice, so the query succeeds and the unsigned slice is never noticed. With this change, a signed universal file is checked slice by slice and unsigned slices are reported with the existing `Unsigned Mach-O slices: …` limitation. I didn't open an issue first: this is the case #684's acceptance criterion describes ("that result should state that the x86_64 slice is unsigned rather than report the file as signed without qualification"), only for identity-signed files, and the result shape doesn't change. ## Problem and expected behavior Smallest trigger: rebuild `/bin/ls` with an unsigned x86_64 slice and inspect it. The system file isn't modified. ```sh lipo /bin/ls -thin x86_64 -output ls-x86_64 lipo /bin/ls -thin arm64e -output ls-arm64e lipo /bin/ls -thin arm64e.x1 -output ls-x1 codesign --remove-signature ls-x86_64 lipo -create ls-x86_64 ls-arm64e ls-x1 -output mixed-x86 rea inspect-signature mixed-x86 --format json ``` `codesign -d --verbose=4`, `codesign -d -r-` and `codesign -d --entitlements :-` all exit 0 on that file. Only `codesign -d -a x86_64` reports "code object is not signed at all". The broken invariant: when slices of one file are signed differently, the result should say which slice is unsigned instead of reporting `signed: true` without qualification. A second, smaller defect is in the same function. `codeSignArchitectures` kept only `i386|x86_64|armv7|arm64|arm64e` from codesign's `Format=Mach-O universal (…)` list. macOS 27 system binaries also have an `arm64e.x1` slice, which `codesign -a arm64e.x1` accepts, so that slice was never queried even on the existing mixed-signature path. ## Change and scope All in `src/native/NativeMacOSProvider.ts`: - When codesign displays a signed universal file that lists more than one slice, `inspect_signature` now runs `codesign -d -a <architecture> --verbose=4` for each slice. Before, it did this only when the aggregate requirement or entitlements query had already reported "not signed". - The slice names come from codesign's own `Format=` line, and any name token it prints is accepted, so `arm64e.x1` is now included. - The "One or more Mach-O slices are unsigned, but their architectures could not be classified" limitation is now added only when the aggregate queries reported an unsigned slice. A fully signed universal file gets no slice limitation. - The aggregate requirement and entitlements limitations are unchanged; they still appear only when those queries fail. - `#inspectMixedSignatureSlices` and `MixedSignatureSlices` are renamed `#inspectSignatureSlices` and `SignatureSlices`, since they now run for every signed universal file. The cost is one extra codesign run per slice for signed universal files: 3 for `/bin/ls`. Each run goes through the same `#captureSignature` path, so it reads the registered snapshot and checks the target identity before and after. Not included: - When codesign's default slice is the unsigned one, the aggregate display itself says "not signed at all". rea then reports the whole file as `signed: false` with "Artifact is not signed.", even if its other slices are signed. On this Mac (M2, macOS 27.0.1), codesign's default slice is `arm64e.x1`, so a copy of `/bin/ls` with only that slice unsigned returns `signed: false`. Fixing that needs a decision about what `signed` should mean for a partly signed file, and the per-slice names would have to come from somewhere other than the unsigned display, so I've left it out. I'm happy to open an issue for it. Contribution scope: an ordinary fix within the existing `inspect_signature` boundary. ## Contract and boundary impact - Semantic owner and earliest changed stage: per-slice signature classification in the native macOS provider (`#inspectBoundSignature` and `#inspectSignatureSlices`). The codesign output parser is unchanged. - Contribution scope fit and linked maintainer decision: not applicable (ordinary fix within existing boundaries). - CLI and MCP/tool-catalog contract: no schema change. For an identity-signed universal file with an unsigned slice, `limitations` now includes `Unsigned Mach-O slices: <arch>.`. Signed universal files now have extra `codesign -d -a <arch> --verbose=4` entries in `provenance`. - Provider, bridge, target-format, or platform compatibility: native macOS provider only. Thin files and fully unsigned files take the same path as before. - Evidence, artifact, provenance, or reconstruction contract: each per-slice query is recorded in provenance with its exit status. Unsigned slices are named in a limitation, and slices whose state codesign couldn't establish keep the existing "could not be classified" limitation. - Target selection, authority, upstream behavior, and cleanup details: the extra codesign calls read the same digest-verified snapshot as the existing ones; nothing else changes. - Generated metadata (`docs/public/product-catalog.json`), package, or installation impact: none. Expected effects: - [x] Read existing files or captured data. - [ ] Launch or attach to a process. - [ ] Inject instrumentation or run scripts/code. - [ ] Change process memory, registers, files, or configuration. - [ ] Contact network services. - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [ ] Not sure yet; investigation or maintainer guidance needed. ## Evidence and regression coverage - Tests added or updated: - `tests/boundary/providers/native/nativeInventory.golden.test.ts`: - x86_64 or arm64e unsigned while the aggregate signature and requirement succeed, using real codesign captures from the `mixed-x86` file above. These are in `tests/fixtures/native-macos/codesign-universal-slices/`, with a README. - An unsigned `arm64e.x1` slice on the existing ad hoc mixed path. - A fully signed universal file, which must get no slice limitation. - The existing `signatureRunner` helper gained two options, a successful aggregate requirement and a list of unsigned slices, and its defaults keep the earlier tests unchanged. - `tests/boundary/providers/native/nativeSignatureTargetBinding.test.ts`: the real-codesign directory-swap test copies `/usr/bin/true`, which is universal (x86_64, arm64e, arm64e.x1). It expected exactly three codesign calls. It now checks that every call, including the per-slice ones, reads the registered snapshot (`$ARTIFACT`). - Base reproduction or other evidence: with only the test changes applied on c7105d9, `nativeInventory.golden.test.ts` gave 3 failed and 18 passed. The two identity-signed cases had no `Unsigned Mach-O slices` limitation, and the `arm64e.x1` case got "could not be classified" because that slice was never queried. The fully signed control and the existing #701 test passed. - User-visible CLI/MCP output: `node scripts/rea.mjs inspect-signature <path> --format json` on macOS 27.0.1 (26A434), Apple M2, built from c7105d9 before the change and from this branch after it. The composites are copies of `/bin/ls` built as above, and the #684 control is `clang -arch x86_64 -arch arm64` with clang's default signing: | Target | Real slice states | Before | After | | --- | --- | --- | --- | | `/bin/ls` | all signed | `signed: true`, no slice limitation | the same, with 3 per-slice queries, all exit 0 | | `mixed-x86` | x86_64 unsigned | `signed: true`, no slice limitation, the same output as `/bin/ls` | `signed: true`, `Unsigned Mach-O slices: x86_64.` | | `mixed-arm64e` | arm64e unsigned | `signed: true`, no slice limitation | `signed: true`, `Unsigned Mach-O slices: arm64e.` | | #684 control | arm64 ad hoc signed, x86_64 unsigned | `Unsigned Mach-O slices: x86_64.` plus the aggregate requirement limitation | unchanged | | `/bin/ls` with only arm64e.x1 unsigned | x1 unsigned (codesign's default slice here) | `signed: false`, "Artifact is not signed." | unchanged (not included, above) | - Remaining proof gaps: - I ran this on one Apple Silicon Mac. Which slice codesign uses by default may differ on other hardware, which changes which files take the aggregate-unsigned path. - I didn't test x86_64h or other variant names in a codesign `Format=` line, beyond `arm64e.x1`. - I didn't measure how much the extra per-slice queries add to run time. For evidence-bearing changes: - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed All with Node 24.18.0 and npm 11.16.0 on macOS 27.0.1, arm64. I developed on c7105d9 and then rebased onto 569ef41 (the rebase was clean). The last list below is what I re-ran on the rebased branch. - `npm ci`: installed. - `npm run test:focused -- tests/boundary/providers/native/nativeInventory.golden.test.ts` with only the test changes on c7105d9: 3 failed, 18 passed. After the fix: 21 passed. - `npm run test:focused -- tests/boundary/providers/native/nativeInventory.golden.test.ts src/native/SignatureTargetBinding.test.ts tests/boundary/cli/nativeSignatureCli.test.ts tests/boundary/mcp/nativeSignatureTargetBindingMcp.test.ts tests/boundary/providers/native/nativeProvider.test.ts tests/boundary/providers/native/nativeSignatureTargetBinding.test.ts src/domain/apple/appleApplication.test.ts`: 7 files, 119 tests passed. - `npm run check`: passed. - `npm run check:fast`: passed. - `npm run verify:test-discovery`: "Discovered all 1233 test files exactly once." - `git diff --check`: clean. - `npm run build:cached`: passed, before and after. - `npm run test:fast`: 7264 passed, 5 failed, 13 skipped. The 5 failures are in `JavaScriptSemanticGraphResources.test.ts`, `electronWrappedCallPaths.test.ts`, `javascriptSemanticAmbientWrites.test.ts`, `javascriptSemanticAnalysis.native_bindings.test.ts` and `IdaNativeProtocol.test.ts`. The same 5 fail on c7105d9 without this change (5 failed, 87 passed in those files). - The CLI runs in the table above, before and after. After rebasing onto 569ef41: - `npm ci`, then the same 7-file `npm run test:focused` command: 125 tests passed. - `npm run check`: passed. `npm run verify:test-discovery`: "Discovered all 1285 test files exactly once." - `npm run build:cached`, then the same CLI runs: the same results as the "After" column. - I didn't re-run `npm run test:fast` after the rebase. ## Compatibility, safety, and release - Breaking changes or migration steps: none. Callers see an added limitation for the affected files and extra provenance entries for signed universal files. - Real Hopper/Ghidra, browser, or OS coverage: real macOS 27.0.1 `codesign`, through the CLI runs above and the existing real-codesign directory-swap test. I didn't run Hopper or Ghidra, and neither is touched. - Package or release metadata impact: none. - Security, privacy, process, or containment review: no new tools or paths. The added `codesign -d -a` calls read the same snapshot under the same target-identity checks. Slice names passed to `-a` must match `^[A-Za-z0-9_]+(?:\.[A-Za-z0-9_]+)?$`, so a name can't start with `-`. ## Before merge - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:09:48 +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#5837
No description provided.