[PR #7160] fix(pe): admit Authenticode nesting depth of signed Windows binaries #7685

Open
opened 2026-11-03 13:39:38 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/7160
Author: @AmmarJamil23
Created: 10/25/2026
Status: 🔄 Open

Base: main ← Head: fix/pe-certificate-authenticode-depth


📝 Commits (1)

  • c5b624f fix(pe): admit Authenticode nesting depth of signed Windows binaries

📊 Changes

3 files changed (+79 additions, -4 deletions)

View changed files

📝 src/native/pe/PeCertificateAsn1.ts (+7 -1)
📝 src/native/pe/PeCertificateParser.test.ts (+30 -0)
📝 src/native/pe/PeCertificates.fixture.ts (+42 -3)

📄 Description

Summary

inspect_pe_certificates (CLI inspect-pe-certificates) rejected genuine Authenticode signatures on signed Windows system binaries as invalid_request / PKCS#7 signedData is malformed: ASN.1 nesting exceeds 32 levels., returning no certificate inventory. In a sweep of 860 binaries from a Windows 11 x64 C:\Windows\System32 (all .exe, all drivers\*.sys, every fifth .dll), 133 failed this way, including bcdedit.exe and audiodg.exe; Get-AuthenticodeSignature reports each as Valid. With this change all 133 return the outer signature's certificate inventory and signer. Since #7920 (rebased onto here), such signers report coverage.status: partial with UNSIGNED_ATTRIBUTES_LIMITATION, because the nested signature and timestamp contents are not yet inventoried (#7767); this PR only removes the depth refusal that hid the outer inventory.

No issue is linked: this was found by the sweep above, and searches found no existing report. #6574 (closed) concerned BER indefinite lengths in the same decoder and is a different defect.

Problem and expected behavior

Smallest trigger: any PE whose embedded PKCS#7 nests more than 32 levels. Windows dual signing produces that routinely. An independent DER walk of the bcdedit.exe certificate table (not REA's decoder) gives depth 34 along this path:

  • levels 1-6: outer SignedData, SignerInfo, unauthenticated attributes [1]
  • level 7: 1.3.6.1.4.1.311.2.4.1 (nested signature) holding a second complete SignedData
  • level 15: 1.3.6.1.4.1.311.3.3.1 (RFC 3161 timestamp) holding a third SignedData
  • levels 23-34: the timestamp's signed ESS signingCertificateV2 (1.2.840.113549.1.9.16.2.47), issuerSerial, GeneralNames, directoryName, Name, RDN, attribute

Files that pass today measure 26 (no nested signature). Violated invariant (AGENTS.md): limits must follow real format constraints. This cap was inherited from the shared reader's default rather than derived from Authenticode, so it rejected valid input as malformed.

Change and scope

PeCertificateAsn1.ts already owns PE-specific decoding budgets (ASN1_NODE_BUDGET, with a format-based comment) but passed no depth, so it inherited the Asn1BerReader default of 32. The fix gives that owner an explicit ASN1_DEPTH_BUDGET = 64, documented from the Authenticode structure: each embedded SignedData adds eight levels, real dual-signed timestamped files reach 34, and 64 still bounds recursion for hostile input. 64 matches the stack budgets of REA's other recursive decoders (protobuf, source maps, CBOR metadata).

Intentionally not changed: the shared reader's default and the APK v1 signature reader, which sets its own justified 32-level cap and tests that exceeding it is malformed; how a depth-cap breach is classified (it remains a malformed-input refusal, now only beyond a format-derived bound); and the separate 64 MiB file-size limit, which two files in the sweep (MRT.exe, OneDriveSetup.exe) still hit as resource_constraint. No speculative complexity is added.

Follow the contribution scope.
Unresolved scope, authority, side effects, or required verification block
integration. Link the required maintainer scope decision for new providers or
capabilities involving target execution, injection, mutation, or protection
recovery; ordinary fixes within existing boundaries may state "not applicable".
Draft PRs may leave the scope decision pending and the readiness and merge checklists
unchecked. Maintainers can help resolve open questions.

Contract and boundary impact

  • Semantic owner and earliest changed stage: src/native/pe/PeCertificateAsn1.ts readAsn1 (PE certificate decoding budget). Consumers: PeCertificateParser and the inspect_pe_certificates CLI/MCP workflow. No superseded path; the shared Asn1BerReader is unchanged.
  • Contribution scope fit and linked maintainer decision: not applicable; a correctness fix within existing static PE inspection.
  • CLI and MCP/tool-catalog contract: no schema or catalog change. Signatures nested 33-64 levels now return a certificate inventory instead of invalid_request.
  • Provider, bridge, target-format, or platform compatibility: PE/Authenticode only; host-independent parsing, exercised on Windows 11 x64 system binaries.
  • Evidence, artifact, provenance, or reconstruction contract: unchanged; affected files now produce the existing certificate Evidence.
  • Target selection, authority, upstream behavior, and cleanup details (if applicable): not applicable; static read-only parsing, no target execution.
  • Generated metadata (docs/public/product-catalog.json), package, or installation impact (CI generates and validates ignored catalogs and skills/; edit authored instructions in .agents/skills/reverse-engineer-anything/ and never commit build outputs): none; npm run docs:check passed with no generated changes.

Expected effects (check known effects; use documentation-only on its own).
Unchecked items do not establish absence; leave uncertainties visible.

  • 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: src/native/pe/PeCertificateParser.test.ts: (1) a dual-signed, timestamped fixture (pkcs7DualSignedTimestampedFixture, new in PeCertificates.fixture.ts) parses to the outer signer with its unsigned attribute OID, coverage.status: partial and UNSIGNED_ATTRIBUTES_LIMITATION (the nested envelopes are not inventoried, per #7920); it reproduces the bcdedit.exe embedding path and its depth of 34, verified with the independent DER walk; (2) a payload one level beyond ASN1_DEPTH_BUDGET is still rejected with the nesting message. pkcs7SignedDataFixture's unsignedAttributes argument (from #7920) now also accepts a complete encoded attribute, and an optional fifth signedAttributes argument was added; existing callers are unchanged.
  • Base reproduction or other evidence: with PeCertificateAsn1.ts stashed, both new tests fail, and the dual-signed case fails with the same ASN.1 nesting exceeds 32 levels. refusal seen on the real binaries. Real files: before, 133 of 860 returned invalid_request; after (measured before the rebase onto #7920), those 133 returned the inventory with one signer each, the other 725 were unchanged, and the 2 oversize files keep their resource_constraint.
  • User-visible CLI/MCP output (if applicable): before, rea inspect-pe-certificates C:\Windows\System32\bcdedit.exe --json returned code: invalid_request with details PKCS#7 signedData is malformed: ASN.1 nesting exceeds 32 levels.; after (rebased on current main), it returns the certificate inventory with signer unsigned_attribute_oids: [1.3.6.1.4.1.311.3.3.1, 1.3.6.1.4.1.311.2.4.1], coverage: {status: partial, examined_entries: 1, certificates: 2} and UNSIGNED_ATTRIBUTES_LIMITATION.
  • Remaining proof gaps: the sweep sampled every fifth System32 DLL and stopped after 5,160 planned runs (860 files), so it is not exhaustive. Signatures deeper than 64 levels were not observed in real files and are exercised only synthetically. macOS/Linux hosts were not run locally; the change is host-independent parsing.

For boundary fixes, identify the applicable boundary regressions
and lifecycle regressions
covered by the evidence above, and explain relevant gaps.

Boundary coverage: malformed input (the depth cap is still enforced), capacity (node budget unchanged and tested) and real target identity (system binaries) are exercised. Lifecycle regressions are not applicable: the change touches no process, cancellation or cleanup path.

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

Windows 11 x64, Node.js 24.22.1 (pinned), locked dependencies, and the published rea-agents@6.8.0 Windows native addon (sha512 verified) for the test runner.

  • After rebasing on main (d3ecf6800): npm run test:focused -- src/native/pe/PeCertificateParser.test.ts tests/acceptance/peCertificatesCli.test.ts — 55/55 passed; with the depth argument removed from readAsn1, the two new tests fail (ASN.1 nesting exceeds 32 levels.). npm run check:fast, npm run docs:check and npm run build:cached passed; bcdedit.exe output above re-run on the rebased build.
  • Before the rebase: npm run test:focused -- src/native/pe/PeCertificateParser.test.ts — 34/34 passed; with PeCertificateAsn1.ts stashed, 2 failed (the two new tests).
  • npm run test:focused -- tests/acceptance/peCertificatesCli.test.ts src/domain/apkSignature/apkV1SignatureBlock.test.ts — passed.
  • npm run test:focused -- tests/boundary/filesystem/peCertificates.test.ts — 1 failed with EPERM creating a symlink (Windows without Developer Mode); fails identically with the change stashed.
  • npm run test:focused -- tests/boundary/mcp/peCertificatesMcp.test.ts — 1 test timed out at 30 s; times out identically with the change stashed (slow MCP startup on this host).
  • npm run build:cached, then inspect-pe-certificates on the 860 swept binaries — results above.
  • Get-AuthenticodeSignature on five failing files — all Valid.
  • npm run check:fast — passed. npm run docs:check — passed.

Compatibility, safety, and release

  • Breaking changes or migration steps: none.
  • Real Hopper/Ghidra, browser, or OS coverage: Windows 11 x64 system binaries only; no analysis provider involved.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: the depth cap still bounds recursion (64, enforced and tested); the node budget is unchanged; parsing is static and executes nothing.

Author readiness

Human owner: @AmmarJamil23

  • I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work.
  • I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps.
  • I declare this PR ready for initial maintainer review.

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/7160 **Author:** [@AmmarJamil23](https://github.com/AmmarJamil23) **Created:** 10/25/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `fix/pe-certificate-authenticode-depth` --- ### 📝 Commits (1) - [`c5b624f`](https://github.com/morluto/rea/commit/c5b624f27253e0b09831ab00a5c9e9835026e68b) fix(pe): admit Authenticode nesting depth of signed Windows binaries ### 📊 Changes **3 files changed** (+79 additions, -4 deletions) <details> <summary>View changed files</summary> 📝 `src/native/pe/PeCertificateAsn1.ts` (+7 -1) 📝 `src/native/pe/PeCertificateParser.test.ts` (+30 -0) 📝 `src/native/pe/PeCertificates.fixture.ts` (+42 -3) </details> ### 📄 Description <!-- PR title: type(optional-scope): imperative outcome The title becomes the squash-merge commit subject and generated changelog entry. --> ## Summary <!-- What user, agent, or maintainer problem does this solve? Link the issue with "Fixes #123" when applicable. Keep the prior behavior, expected contract, and new behavior understandable without private context. --> `inspect_pe_certificates` (CLI `inspect-pe-certificates`) rejected genuine Authenticode signatures on signed Windows system binaries as `invalid_request` / `PKCS#7 signedData is malformed: ASN.1 nesting exceeds 32 levels.`, returning no certificate inventory. In a sweep of 860 binaries from a Windows 11 x64 `C:\Windows\System32` (all `.exe`, all `drivers\*.sys`, every fifth `.dll`), 133 failed this way, including `bcdedit.exe` and `audiodg.exe`; `Get-AuthenticodeSignature` reports each as `Valid`. With this change all 133 return the outer signature's certificate inventory and signer. Since #7920 (rebased onto here), such signers report `coverage.status: partial` with `UNSIGNED_ATTRIBUTES_LIMITATION`, because the nested signature and timestamp contents are not yet inventoried (#7767); this PR only removes the depth refusal that hid the outer inventory. No issue is linked: this was found by the sweep above, and searches found no existing report. #6574 (closed) concerned BER indefinite lengths in the same decoder and is a different defect. ## Problem and expected behavior <!-- For fixes, give the smallest trigger and violated invariant. For features, describe the use case and observable outcome. --> Smallest trigger: any PE whose embedded PKCS#7 nests more than 32 levels. Windows dual signing produces that routinely. An independent DER walk of the `bcdedit.exe` certificate table (not REA's decoder) gives depth 34 along this path: - levels 1-6: outer SignedData, SignerInfo, unauthenticated attributes `[1]` - level 7: `1.3.6.1.4.1.311.2.4.1` (nested signature) holding a second complete SignedData - level 15: `1.3.6.1.4.1.311.3.3.1` (RFC 3161 timestamp) holding a third SignedData - levels 23-34: the timestamp's signed ESS `signingCertificateV2` (`1.2.840.113549.1.9.16.2.47`), issuerSerial, GeneralNames, directoryName, Name, RDN, attribute Files that pass today measure 26 (no nested signature). Violated invariant (AGENTS.md): limits must follow real format constraints. This cap was inherited from the shared reader's default rather than derived from Authenticode, so it rejected valid input as malformed. ## Change and scope <!-- Explain the chosen approach, why it fits REA's architecture, and what is intentionally not included. If adding complexity for a speculative or vanishingly unlikely race or security edge case, record the concrete failure mode, likelihood, complexity cost, and the user's buy-in obtained before implementation. Do not silently expand scope for theoretical robustness. --> `PeCertificateAsn1.ts` already owns PE-specific decoding budgets (`ASN1_NODE_BUDGET`, with a format-based comment) but passed no depth, so it inherited the `Asn1BerReader` default of 32. The fix gives that owner an explicit `ASN1_DEPTH_BUDGET = 64`, documented from the Authenticode structure: each embedded SignedData adds eight levels, real dual-signed timestamped files reach 34, and 64 still bounds recursion for hostile input. 64 matches the stack budgets of REA's other recursive decoders (protobuf, source maps, CBOR metadata). Intentionally not changed: the shared reader's default and the APK v1 signature reader, which sets its own justified 32-level cap and tests that exceeding it is malformed; how a depth-cap breach is classified (it remains a malformed-input refusal, now only beyond a format-derived bound); and the separate 64 MiB file-size limit, which two files in the sweep (`MRT.exe`, `OneDriveSetup.exe`) still hit as `resource_constraint`. No speculative complexity is added. Follow the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope). Unresolved scope, authority, side effects, or required verification block integration. Link the required maintainer scope decision for new providers or capabilities involving target execution, injection, mutation, or protection recovery; ordinary fixes within existing boundaries may state "not applicable". Draft PRs may leave the scope decision pending and the readiness and merge checklists unchecked. Maintainers can help resolve open questions. ## Contract and boundary impact <!-- Short answers are welcome. Complete applicable lines; mark unresolved facts as "unknown". Use "none" or "not applicable" only when established. --> - Semantic owner and earliest changed stage: `src/native/pe/PeCertificateAsn1.ts` `readAsn1` (PE certificate decoding budget). Consumers: `PeCertificateParser` and the `inspect_pe_certificates` CLI/MCP workflow. No superseded path; the shared `Asn1BerReader` is unchanged. <!-- Name the producer of parsed facts or resources and its affected consumers. Summarize superseded paths removed and any distinct policy, lifecycle, lazy-loading, or compatibility responsibility retained. --> - Contribution scope fit and linked maintainer decision: not applicable; a correctness fix within existing static PE inspection. - CLI and MCP/tool-catalog contract: no schema or catalog change. Signatures nested 33-64 levels now return a certificate inventory instead of `invalid_request`. - Provider, bridge, target-format, or platform compatibility: PE/Authenticode only; host-independent parsing, exercised on Windows 11 x64 system binaries. - Evidence, artifact, provenance, or reconstruction contract: unchanged; affected files now produce the existing certificate Evidence. - Target selection, authority, upstream behavior, and cleanup details (if applicable): not applicable; static read-only parsing, no target execution. - Generated metadata (`docs/public/product-catalog.json`), package, or installation impact (CI generates and validates ignored catalogs and `skills/`; edit authored instructions in `.agents/skills/reverse-engineer-anything/` and never commit build outputs): none; `npm run docs:check` passed with no generated changes. Expected effects (check known effects; use documentation-only on its own). Unchecked items do not establish absence; leave uncertainties visible. - [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 <!-- State whether evidence is executed, source-derived, or proposed. For fixes, show the original failure and explain how the regression would fail on the affected base revision when practical. Include the most useful proof inline; link long logs or artifacts, or put them in optional details. Documentation-only changes can use source, link, or rendered-document checks. --> - Tests added or updated: `src/native/pe/PeCertificateParser.test.ts`: (1) a dual-signed, timestamped fixture (`pkcs7DualSignedTimestampedFixture`, new in `PeCertificates.fixture.ts`) parses to the outer signer with its unsigned attribute OID, `coverage.status: partial` and `UNSIGNED_ATTRIBUTES_LIMITATION` (the nested envelopes are not inventoried, per #7920); it reproduces the `bcdedit.exe` embedding path and its depth of 34, verified with the independent DER walk; (2) a payload one level beyond `ASN1_DEPTH_BUDGET` is still rejected with the nesting message. `pkcs7SignedDataFixture`'s `unsignedAttributes` argument (from #7920) now also accepts a complete encoded attribute, and an optional fifth `signedAttributes` argument was added; existing callers are unchanged. - Base reproduction or other evidence: with `PeCertificateAsn1.ts` stashed, both new tests fail, and the dual-signed case fails with the same `ASN.1 nesting exceeds 32 levels.` refusal seen on the real binaries. Real files: before, 133 of 860 returned `invalid_request`; after (measured before the rebase onto #7920), those 133 returned the inventory with one signer each, the other 725 were unchanged, and the 2 oversize files keep their `resource_constraint`. - User-visible CLI/MCP output (if applicable): before, `rea inspect-pe-certificates C:\Windows\System32\bcdedit.exe --json` returned `code: invalid_request` with details `PKCS#7 signedData is malformed: ASN.1 nesting exceeds 32 levels.`; after (rebased on current `main`), it returns the certificate inventory with signer `unsigned_attribute_oids: [1.3.6.1.4.1.311.3.3.1, 1.3.6.1.4.1.311.2.4.1]`, `coverage: {status: partial, examined_entries: 1, certificates: 2}` and `UNSIGNED_ATTRIBUTES_LIMITATION`. - Remaining proof gaps: the sweep sampled every fifth System32 DLL and stopped after 5,160 planned runs (860 files), so it is not exhaustive. Signatures deeper than 64 levels were not observed in real files and are exercised only synthetically. macOS/Linux hosts were not run locally; the change is host-independent parsing. For boundary fixes, identify the applicable [boundary regressions](https://github.com/morluto/rea/blob/main/docs/testing.md#boundary-regressions) and [lifecycle regressions](https://github.com/morluto/rea/blob/main/docs/testing.md#lifecycle-regressions) covered by the evidence above, and explain relevant gaps. Boundary coverage: malformed input (the depth cap is still enforced), capacity (node budget unchanged and tested) and real target identity (system binaries) are exercised. Lifecycle regressions are not applicable: the change touches no process, cancellation or cleanup path. 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 <!-- List only commands that actually ran, with observed results. Include the relevant real-provider or platform workflow, or explain why it was unavailable. Keep these results current after changes; a command without its result is incomplete. --> Windows 11 x64, Node.js 24.22.1 (pinned), locked dependencies, and the published `rea-agents@6.8.0` Windows native addon (sha512 verified) for the test runner. - After rebasing on `main` (d3ecf6800): `npm run test:focused -- src/native/pe/PeCertificateParser.test.ts tests/acceptance/peCertificatesCli.test.ts` — 55/55 passed; with the depth argument removed from `readAsn1`, the two new tests fail (`ASN.1 nesting exceeds 32 levels.`). `npm run check:fast`, `npm run docs:check` and `npm run build:cached` passed; `bcdedit.exe` output above re-run on the rebased build. - Before the rebase: `npm run test:focused -- src/native/pe/PeCertificateParser.test.ts` — 34/34 passed; with `PeCertificateAsn1.ts` stashed, 2 failed (the two new tests). - `npm run test:focused -- tests/acceptance/peCertificatesCli.test.ts src/domain/apkSignature/apkV1SignatureBlock.test.ts` — passed. - `npm run test:focused -- tests/boundary/filesystem/peCertificates.test.ts` — 1 failed with `EPERM` creating a symlink (Windows without Developer Mode); fails identically with the change stashed. - `npm run test:focused -- tests/boundary/mcp/peCertificatesMcp.test.ts` — 1 test timed out at 30 s; times out identically with the change stashed (slow MCP startup on this host). - `npm run build:cached`, then `inspect-pe-certificates` on the 860 swept binaries — results above. - `Get-AuthenticodeSignature` on five failing files — all `Valid`. - `npm run check:fast` — passed. `npm run docs:check` — passed. ## Compatibility, safety, and release <!-- Call out breaking changes, migrations, package effects, platform/provider limits, security/privacy/containment implications, and meaningful proof gaps. --> - Breaking changes or migration steps: none. <!-- For ! / BREAKING CHANGE: show a previously valid call/configuration, its new behavior and migration, and why compatibility/deprecation cannot preserve it. Every release increments minor, including breaking changes; keep breaking markers and migration notes so callers can assess compatibility. See docs/releasing.md. --> - Real Hopper/Ghidra, browser, or OS coverage: Windows 11 x64 system binaries only; no analysis provider involved. - Package or release metadata impact: none. - Security, privacy, process, or containment review: the depth cap still bounds recursion (64, enforced and tested); the node budget is unchanged; parsing is static and executes nothing. ## Author readiness <!-- The human owner completes these declarations before requesting review. The PR author is the owner by default. A different owner must explicitly accept ownership on this PR. AI agents must leave these declarations to a human to dictate to them or there could be catastrophic consequences for many users of REA. Draft PRs may leave them unchecked. These declarations record initial readiness when opening the PR for review; later pushes do not require a new human sign-off. Keep the description and validation evidence current as the work changes. See CONTRIBUTING.md#pull-request-ownership-and-readiness. --> Human owner: @AmmarJamil23 <!-- @GitHub-handle --> - [x] I reviewed the final diff and relevant existing code, understand the change and its edge cases, and take responsibility for the complete PR, including AI-assisted work. - [x] I checked the evidence above, confirmed it supports the current change, and recorded meaningful validation gaps. - [x] I declare this PR ready for initial maintainer review. ## Before merge <!-- Draft PRs may leave pending items unchecked. Resolve material scope and authority questions before integration. --> - [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>
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#7685
No description provided.